From 507b691024c457d7e30bf7451b0d18117c4f56d4 Mon Sep 17 00:00:00 2001 From: layou233 Date: Thu, 18 Jul 2024 17:01:34 +0800 Subject: [PATCH] chore: Improve domain matcher --- .github/workflows/build.yml | 206 ++++++++++++++++++---------------- common/domain/builder.go | 3 +- common/domain/matcher.go | 10 +- common/domain/matcher_test.go | 36 ++++++ common/domain/set.go | 15 ++- 5 files changed, 162 insertions(+), 108 deletions(-) create mode 100644 common/domain/matcher_test.go diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 57e5e22..8dc23e7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,79 +1,81 @@ name: build on: - release: workflow_dispatch: - + inputs: + version: + description: "Tag name of release" + jobs: build: strategy: - matrix: - # Include amd64 on all platforms. - goos: [ windows, linux, darwin ] - goarch: [ amd64, 386 ] - goamd64: [ v1, v3 ] - exclude: - # Exclude GOAMD64 v3 on i386 - - goarch: 386 - goamd64: v3 - # Exclude i386 on darwin and dragonfly. - - goarch: 386 - goos: dragonfly - - goarch: 386 - goos: darwin - include: - # BEGIN macOS ARM64 - - goos: darwin - goarch: arm64 - # END macOS ARM64 - # BEGIN Linux ARM 5 6 7 - - goos: linux - goarch: arm - goarm: 7 - - goos: linux - goarch: arm - goarm: 6 - - goos: linux - goarch: arm - goarm: 5 - # END Linux ARM 5 6 7 - # BEGIN Android ARM 8 - - goos: android - goarch: arm64 - # END Android ARM 8 - # Windows ARM - - goos: windows - goarch: arm64 - - goos: windows - goarch: arm - goarm: 7 - # BEGIN Other architectures - # BEGIN riscv64 & ARM64 - - goos: linux - goarch: arm64 - - goos: linux - goarch: riscv64 - # END riscv64 & ARM64 - # BEGIN MIPS - - goos: linux - goarch: mips64 - - goos: linux - goarch: mips64le - - goos: linux - goarch: mipsle - - goos: linux - goarch: mips - # END MIPS - # BEGIN LOONGARCH - - goos: linux - goarch: loong64 - # END LOONGARCH - # BEGIN S390X - - goos: linux - goarch: s390x - # END S390X - # END Other architectures - + matrix: + # Include amd64 on all platforms. + goos: [ windows, linux, darwin ] + goarch: [ amd64, 386 ] + goamd64: [ v1, v3 ] + exclude: + # Exclude GOAMD64 v3 on i386 + - goarch: 386 + goamd64: v3 + # Exclude i386 on darwin and dragonfly. + - goarch: 386 + goos: dragonfly + - goarch: 386 + goos: darwin + include: + # BEGIN macOS ARM64 + - goos: darwin + goarch: arm64 + # END macOS ARM64 + # BEGIN Linux ARM 5 6 7 + - goos: linux + goarch: arm + goarm: 7 + - goos: linux + goarch: arm + goarm: 6 + - goos: linux + goarch: arm + goarm: 5 + # END Linux ARM 5 6 7 + # BEGIN Android ARM 8 + - goos: android + goarch: arm64 + # END Android ARM 8 + # Windows ARM + - goos: windows + goarch: arm64 + - goos: windows + goarch: arm + goarm: 7 + # BEGIN Other architectures + # BEGIN riscv64 & ARM64 + - goos: linux + goarch: arm64 + - goos: linux + goarch: riscv64 + # END riscv64 & ARM64 + # BEGIN MIPS + - goos: linux + goarch: mips64 + - goos: linux + goarch: mips64le + - goos: linux + goarch: mipsle + - goos: linux + goarch: mips + # END MIPS + # BEGIN LOONGARCH + - goos: linux + goarch: loong64 + # END LOONGARCH + # BEGIN S390X + - goos: linux + goarch: s390x + # END S390X + # END Other architectures + runs-on: ubuntu-latest env: GOOS: ${{ matrix.goos }} @@ -81,40 +83,48 @@ jobs: GOARM: ${{ matrix.goarm }} GOAMD64: ${{ matrix.goamd64 }} CGO_ENABLED: 0 - + BUILD_NAME: ZBProxy-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}${{ matrix.goamd64 }}${{ matrix.goos == 'windows' && '.exe' || '' }} + steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: ^1.20 - check-latest: true + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ^1.20 + check-latest: true - - name: Tidy up Go Modules - run: go mod tidy + - name: Tidy up Go Modules + run: go mod tidy - - name: Get Git Commit Hash - id: hash - run: echo "git_hash=$(git rev-parse --short HEAD || echo "unknown version")" >> $GITHUB_OUTPUT + - name: Get Git Commit Hash + id: hash + run: echo "git_hash=$(git rev-parse --short HEAD || echo "unknown version")" >> $GITHUB_OUTPUT - - name: Build - run: go build -v -trimpath -ldflags '-X "github.com/layou233/zbproxy/v3/version.CommitHash=${{ steps.hash.outputs.git_hash }}" -s -w -buildid=' -o ZBProxy-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}${{ matrix.goamd64 }} ./cmd/zbproxy + - name: Build + run: go build -v -trimpath -ldflags '-X "github.com/layou233/zbproxy/v3/version.CommitHash=${{ steps.hash.outputs.git_hash }}" -s -w -buildid=' -o $BUILD_NAME ./cmd/zbproxy - - name: Handle for Windows Build - if: ${{ env.GOOS == 'windows' }} - run: mv ZBProxy-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}${{ matrix.goamd64 }} ZBProxy-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}${{ matrix.goamd64 }}.exe + - name: Upload Build Artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ env.BUILD_NAME }} + path: ${{ env.BUILD_NAME }} - - name: Upload a Non-Windows Build Artifact - uses: actions/upload-artifact@v4 - if: ${{ env.GOOS != 'windows' }} - with: - name: ZBProxy-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}${{ matrix.goamd64 }} - path: ZBProxy-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}${{ matrix.goamd64 }} + Publish: + permissions: write-all + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version }} + needs: [ build ] + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v4 + with: + path: bin/ + merge-multiple: true - - name: Upload a Windows Build Artifact - uses: actions/upload-artifact@v4 - if: ${{ env.GOOS == 'windows' }} - with: - name: ZBProxy-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}${{ matrix.goamd64 }}.exe - path: ZBProxy-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}${{ matrix.goamd64 }}.exe + - name: Upload Release + uses: softprops/action-gh-release@v2 + if: ${{ success() }} + with: + tag_name: ${{ github.event.inputs.version }} + files: bin/* + prerelease: true diff --git a/common/domain/builder.go b/common/domain/builder.go index 772df48..f96e841 100644 --- a/common/domain/builder.go +++ b/common/domain/builder.go @@ -22,8 +22,7 @@ func (b *MatcherBuilder) AddDomainSuffix(domain string) { if domain[0] == '.' { b.domainList = append(b.domainList, reverseDomainSuffix(domain)) } else { - b.domainList = append(b.domainList, reverseDomain(domain)) - b.domainList = append(b.domainList, reverseRootDomainSuffix(domain)) + b.domainList = append(b.domainList, reverseDomainRoot(domain)) } } diff --git a/common/domain/matcher.go b/common/domain/matcher.go index 07fd3a4..8c36c40 100644 --- a/common/domain/matcher.go +++ b/common/domain/matcher.go @@ -20,8 +20,7 @@ func NewMatcher(domains []string, domainSuffix []string) *Matcher { if domain[0] == '.' { domainList = append(domainList, reverseDomainSuffix(domain)) } else { - domainList = append(domainList, reverseDomain(domain)) - domainList = append(domainList, reverseRootDomainSuffix(domain)) + domainList = append(domainList, reverseDomainRoot(domain)) } } for _, domain := range domains { @@ -62,15 +61,14 @@ func reverseDomainSuffix(domain string) string { return string(b) } -func reverseRootDomainSuffix(domain string) string { +func reverseDomainRoot(domain string) string { l := len(domain) - b := make([]byte, l+2) + b := make([]byte, l+1) for i := 0; i < l; { r, n := utf8.DecodeRuneInString(domain[i:]) i += n utf8.EncodeRune(b[l-i:], r) } - b[l] = '.' - b[l+1] = prefixLabel + b[l] = rootLabel return string(b) } diff --git a/common/domain/matcher_test.go b/common/domain/matcher_test.go new file mode 100644 index 0000000..34ac1ab --- /dev/null +++ b/common/domain/matcher_test.go @@ -0,0 +1,36 @@ +package domain + +import "testing" + +func TestMatcher(t *testing.T) { + matcher := NewMatcher( + []string{ // domain + "example.com", "example.org", + }, []string{ // domain suffix + "example.net", ".example.invalid", + }) + if !matcher.Match("example.com") { + t.Error("example.com is not matched") + } + if !matcher.Match("example.org") { + t.Error("example.org is not matched") + } + if matcher.Match("sub.example.org") { + t.Error("sub.example.org is matched") + } + if !matcher.Match("example.net") { + t.Error("example.net is not matched") + } + if !matcher.Match("any.example.net") { + t.Error("any.example.net is not matched") + } + if !matcher.Match("any.one.example.net") { + t.Error("any.one.one.example.net is not matched") + } + if matcher.Match("example.invalid") { + t.Error("example.invalid is matched") + } + if !matcher.Match("any.example.invalid") { + t.Error("any.example.invalid is not matched") + } +} diff --git a/common/domain/set.go b/common/domain/set.go index 2019b87..c4d4b30 100644 --- a/common/domain/set.go +++ b/common/domain/set.go @@ -2,7 +2,10 @@ package domain import "math/bits" -const prefixLabel = '\r' +const ( + prefixLabel = '\r' + rootLabel = '\n' +) // modified from https://github.com/openacid/succinct @@ -52,6 +55,13 @@ func (ss *succinctSet) Has(key string) bool { if nextLabel == prefixLabel { return true } + if nextLabel == rootLabel { + nextNodeId := countZeros(ss.labelBitmap, ss.ranks, bmIdx+1) + hasNext := getBit(ss.leaves, nextNodeId) != 0 + if currentChar == '.' && hasNext { + return true + } + } if nextLabel == currentChar { break } @@ -66,7 +76,8 @@ func (ss *succinctSet) Has(key string) bool { if getBit(ss.labelBitmap, bmIdx) != 0 { return false } - if ss.labels[bmIdx-nodeId] == prefixLabel { + nextLabel := ss.labels[bmIdx-nodeId] + if nextLabel == prefixLabel || nextLabel == rootLabel { return true } }