diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2acbdf6f9..caf20fd68 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.21 # Build - name: Build @@ -75,8 +75,8 @@ jobs: - name: setup Python uses: actions/setup-python@v2 with: - python-version: '2.x' # Version range or exact version of a Python version to use, using SemVer's version range syntax - - run: python -m SimpleHTTPServer 8181& + python-version: '3.x' # Version range or exact version of a Python version to use, using SemVer's version range syntax + - run: python3 -m http.server 8181& # Modify Conf and Run - name: Run diff --git a/.gitignore b/.gitignore index 0482ed5f9..02a57e664 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,6 @@ coverage.txt .vscode/* bfe dist/* +conf/wasm_plugin .DS_Store diff --git a/.markdownlint.yml b/.markdownlint.yml deleted file mode 100644 index ff38591a3..000000000 --- a/.markdownlint.yml +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2022 The BFE Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# rules from /~https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md -MD001: false -MD004: false -MD005: false -MD006: false -MD007: false -MD010: false -MD013: false -MD014: false -MD024: false -MD026: false -MD029: false -MD033: false -MD034: false -MD036: false -MD040: false -MD041: false -MD046: false diff --git a/ADOPTERS.md b/ADOPTERS.md index 8b8173dd6..ba018eb90 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -14,6 +14,8 @@ Some of our users include: * [Haier](https://www.haier.com) +* [PITS Global Data Recovery Services](https://pitsdatarecovery.net/) + * [Postal Savings Bank of China](https://www.psbc.com) * [Resolink](https://www.crresolink.com.cn) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b29e7f9f..647c35ba3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,46 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v1.7.0] - 2025-01-19 + +### Added + +- Support building docker images for multiple architectures +- Support WASM to allow dynamic plugin + +### Fixed + +- Upgrade versions of some third-paty modules for security reasons +- Fix format issue in bfe_http/request_test.go +- Temporarily remove some test cases using legacy test data +- mod_tcp_keepalive: fix broken unit tests +- http2: close connections when receiving too many headers +- Fix readloop goroutine leak + +### Removed + +- The previous experimental dynamic plugin is deprecated + +## [v1.6.0] - 2022-10-21 + +### Added + +- Allow user to disable monitor port ([Issue #936](/~https://github.com/bfenetworks/bfe/issues/936)) +- Support HTTP2 fingerprint ([Issue #1071](/~https://github.com/bfenetworks/bfe/issues/1071)) +- Documents optimization + +### Changed + +- Optimize idle connection handling ([Pull #1044](/~https://github.com/bfenetworks/bfe/pull/1044)) +- Performance optimize in smooth least connection balancing algorithm([Pull #1062](/~https://github.com/bfenetworks/bfe/pull/1062)) +- Miscellaneous golang dependency updates +- Miscellaneous improvements in makefile and other CI tools + +### Fixed + +- mod_trust_clientip: fix incorrect private IP address range ([Issue #856](/~https://github.com/bfenetworks/bfe/issues/856)) +- arm build error in golang 1.18 + ## [v1.6.0] - 2022-10-21 ### Added diff --git a/Dockerfile b/Dockerfile index 19f50ddd8..b110cbcbb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,11 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. # -FROM golang:1.17.5-alpine3.15 AS build +FROM --platform=${BUILDPLATFORM} golang:1.17.5-alpine3.15 AS build +ARG TARGETARCH +ARG TARGETOS WORKDIR /bfe COPY . . -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-X main.version=`cat VERSION`" +RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags "-X main.version=`cat VERSION`" FROM alpine:3.15 AS run RUN apk update && apk add --no-cache ca-certificates diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 2351b9460..ddbda241e 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -6,21 +6,25 @@ This file lists who are the maintainers of the BFE project. The responsibilities | Name | GitHub ID | Affiliation | | ---- | --------- | ----------- | -| [Miao Zhang](mailto:zhangmiao02@baidu.com) | [mileszhang2016](/~https://github.com/mileszhang2016) | Baidu | -| [Sijie Yang](mailto:iyangsj@gmail.com) | [iyangsj](/~https://github.com/iyangsj) | Baidu | +| [Miao Zhang](mailto:zhangmiao@yf-networks.com) | [mileszhang2016](/~https://github.com/mileszhang2016) | Yingfei Networks | +| [Sijie Yang](mailto:iyangsj@gmail.com) | [iyangsj](/~https://github.com/iyangsj) | Tencent | ## Senior Maintainers | Name | GitHub ID | Affiliation | | ---- | --------- | ----------- | -| [Sijie Yang](mailto:iyangsj@gmail.com) | [iyangsj](/~https://github.com/iyangsj) | Baidu | +| [Sijie Yang](mailto:iyangsj@gmail.com) | [iyangsj](/~https://github.com/iyangsj) | Tencent | ## Maintainers | Name | GitHub ID | Affiliation | | ---- | --------- | ----------- | | [Derek Zheng](mailto:shanhu5739@gmail.com) | [shanhuhai5739](/~https://github.com/shanhuhai5739) | Kuaishou | -| [Xiaofei Yu](mailto:nemo_00o@hotmail.com) | [xiaofei0800](/~https://github.com/xiaofei0800) | Baidu | +| [Xiaofei Yu](mailto:nemo_00o@hotmail.com) | [xiaofei0800](/~https://github.com/xiaofei0800) | Tencent | | [Wensi Yang](mailto:tianxinheihei@gmail.com) | [tianxinheihei](/~https://github.com/tianxinheihei) | ByteDance | | [Kaiyu Zheng](mailto:412674752@qq.com) | [kaiyuzheng](/~https://github.com/kaiyuzheng) | ByteDance | -| [Yuqi Xiao](mailto:xiao19910705@163.com) | [Yuqi Xiao](/~https://github.com/YuqiXiao) | Baidu | +| [Yuqi Xiao](mailto:xiao19910705@163.com) | [YuqiXiao](/~https://github.com/YuqiXiao) | ByteDance | +| [Wei Wei](mailto:ww990114@gmail.com) | [weiwei99](/~https://github.com/weiwei99) | Baidu | +| [Andy Liang](mailto:lianglei@yf-networks.com) | [andyxmu](/~https://github.com/andyxmu) | Yingfei Networks | +| [Leiming Xu](mailto:xuleiming@yf-networks.com) | [xuleiming](/~https://github.com/xuleiming) | Yingfei Networks | +| [Jian Song](mailto:songjian@yf-networks.com) | [clarinette9](/~https://github.com/clarinette9) | Yingfei Networks | diff --git a/Makefile b/Makefile index ddb73b5d2..4c7ec07b4 100644 --- a/Makefile +++ b/Makefile @@ -74,7 +74,7 @@ strip: prepare compile-strip package # make prepare, download dependencies prepare: prepare-dep prepare-gen prepare-dep: - $(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc) + $(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc@latest) prepare-gen: cd "bfe_basic/condition/parser" && $(GOGEN) @@ -117,7 +117,7 @@ package: # make deps deps: $(call PIP_INSTALL_PKG, pre-commit) - $(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc) + $(call INSTALL_PKG, goyacc, golang.org/x/tools/cmd/goyacc@latest) $(call INSTALL_PKG, staticcheck, honnef.co/go/tools/cmd/staticcheck) $(call INSTALL_PKG, license-eye, github.com/apache/skywalking-eyes/cmd/license-eye@latest) diff --git a/README.md b/README.md index ba34f0284..abeb155d6 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,13 @@ Besides, we also implement [BFE Ingress Controller](/~https://github.com/bfenetwor - [English version](https://www.bfe-networks.net/en_us/ABOUT/) - [Chinese version](https://www.bfe-networks.net/zh_cn/ABOUT/) +## Book + +- [In-depth Understanding of BFE](/~https://github.com/baidu/bfe-book) (Released in Feb 2023) + + This book focuses on BFE open source project, introduces the relevant technical principles of network access, explains the design idea of BFE open source software, and how to build a network front-end platform based on BFE open source software. Readers with development capabilities can also develop BFE extension modules according to their own needs or contribute code to BFE open source projects according to the instructions in this book. + + ## Contributing - Please create an issue in [issue list](http://github.com/bfenetworks/bfe/issues). diff --git a/VERSION b/VERSION index dc1e644a1..9dbb0c005 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.6.0 +1.7.0 \ No newline at end of file diff --git a/bfe.go b/bfe.go index cd7c6caf4..6c40ef162 100644 --- a/bfe.go +++ b/bfe.go @@ -43,6 +43,7 @@ var ( showVersion = flag.Bool("v", false, "to show version of bfe") showVerbose = flag.Bool("V", false, "to show verbose information about bfe") debugLog = flag.Bool("d", false, "to show debug log (otherwise >= info)") + testConf = flag.Bool("t", false, "test configuration and exit") ) var version string @@ -74,7 +75,12 @@ func main() { logSwitch = "DEBUG" bfe_debug.DebugIsOpen = true } else { - logSwitch = "INFO" + // ignore under ERROR level + if *testConf { + logSwitch = "ERROR" + } else { + logSwitch = "INFO" + } bfe_debug.DebugIsOpen = false } @@ -84,7 +90,7 @@ func main() { log4go.SetLogFormat(log4go.FORMAT_DEFAULT_WITH_PID) log4go.SetSrcLineForBinLog(false) - err = log.Init("bfe", logSwitch, *logPath, *stdOut, "midnight", 7) + err = log.Init("bfe", logSwitch, *logPath, *stdOut || *testConf, "midnight", 7) if err != nil { fmt.Printf("bfe: err in log.Init():%s\n", err.Error()) bfe_util.AbnormalExit() @@ -97,10 +103,13 @@ func main() { config, err = bfe_conf.BfeConfigLoad(confPath, *confRoot) if err != nil { log.Logger.Error("main(): in BfeConfigLoad():%s", err.Error()) + if *testConf { + fmt.Printf("bfe: configuration file %s test failed\n", confPath) + } bfe_util.AbnormalExit() } - // maximum number of CPUs (GOMAXPROCS) defaults to runtime.CPUNUM + // maximum number of CPUs (GOMAXPROCS) defaults to runtime.CPUNUM // if running on machine, or CPU quota if running on container // (with the help of "go.uber.org/automaxprocs"). // here, we change maximum number of cpus if the MaxCpus is positive. @@ -112,11 +121,22 @@ func main() { bfe_debug.SetDebugFlag(config.Server) // start and serve - if err = bfe_server.StartUp(config, version, *confRoot); err != nil { + if err = bfe_server.StartUp(config, version, *confRoot, *testConf); err != nil { log.Logger.Error("main(): bfe_server.StartUp(): %s", err.Error()) } // waiting for logger finish jobs time.Sleep(1 * time.Second) log.Logger.Close() + + // output final configuration test result + if *testConf { + if err != nil { + fmt.Printf("bfe: configuration file %s test failed\n", confPath) + bfe_util.AbnormalExit() + } else { + fmt.Printf("bfe: configuration file %s test is successful\n", confPath) + bfe_util.NormalExit() + } + } } diff --git a/bfe_basic/condition/parser/y.go b/bfe_basic/condition/parser/y.go index 45e318c00..90506265f 100644 --- a/bfe_basic/condition/parser/y.go +++ b/bfe_basic/condition/parser/y.go @@ -119,7 +119,7 @@ func (x *condLex) Error(s string) { } //line yacctab:1 -var condExca = [...]int{ +var condExca = [...]int8{ -1, 1, 1, -1, -2, 0, @@ -129,54 +129,54 @@ const condPrivate = 57344 const condLast = 23 -var condAct = [...]int{ +var condAct = [...]int8{ 18, 20, 16, 2, 19, 17, 11, 9, 10, 8, 6, 12, 13, 3, 15, 4, 7, 8, 5, 14, 7, 8, 1, } -var condPact = [...]int{ +var condPact = [...]int16{ 6, -1000, 15, 6, 6, -1000, -1, 6, 6, 11, -1000, -6, 3, -1000, -1000, -8, -1000, -1000, -1000, -10, -1000, } -var condPgo = [...]int{ +var condPgo = [...]int8{ 0, 22, 3, 18, 14, } -var condR1 = [...]int{ +var condR1 = [...]int8{ 0, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, } -var condR2 = [...]int{ +var condR2 = [...]int8{ 0, 1, 3, 3, 3, 2, 1, 1, 4, 3, 1, 3, } -var condChk = [...]int{ +var condChk = [...]int16{ -1000, -1, -2, 7, 9, -3, 4, 5, 6, -2, -2, 7, -2, -2, 8, -4, 8, 11, 8, 12, 11, } -var condDef = [...]int{ +var condDef = [...]int8{ 0, -2, 1, 0, 0, 6, 7, 0, 0, 0, 5, 0, 3, 4, 2, 0, 9, 10, 8, 0, 11, } -var condTok1 = [...]int{ +var condTok1 = [...]int8{ 1, } -var condTok2 = [...]int{ +var condTok2 = [...]int8{ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, } -var condTok3 = [...]int{ +var condTok3 = [...]int8{ 0, } @@ -258,9 +258,9 @@ func condErrorMessage(state, lookAhead int) string { expected := make([]int, 0, 4) // Look for shiftable tokens. - base := condPact[state] + base := int(condPact[state]) for tok := TOKSTART; tok-1 < len(condToknames); tok++ { - if n := base + tok; n >= 0 && n < condLast && condChk[condAct[n]] == tok { + if n := base + tok; n >= 0 && n < condLast && int(condChk[int(condAct[n])]) == tok { if len(expected) == cap(expected) { return res } @@ -270,13 +270,13 @@ func condErrorMessage(state, lookAhead int) string { if condDef[state] == -2 { i := 0 - for condExca[i] != -1 || condExca[i+1] != state { + for condExca[i] != -1 || int(condExca[i+1]) != state { i += 2 } // Look for tokens that we accept or reduce. for i += 2; condExca[i] >= 0; i += 2 { - tok := condExca[i] + tok := int(condExca[i]) if tok < TOKSTART || condExca[i+1] == 0 { continue } @@ -307,30 +307,30 @@ func condlex1(lex condLexer, lval *condSymType) (char, token int) { token = 0 char = lex.Lex(lval) if char <= 0 { - token = condTok1[0] + token = int(condTok1[0]) goto out } if char < len(condTok1) { - token = condTok1[char] + token = int(condTok1[char]) goto out } if char >= condPrivate { if char < condPrivate+len(condTok2) { - token = condTok2[char-condPrivate] + token = int(condTok2[char-condPrivate]) goto out } } for i := 0; i < len(condTok3); i += 2 { - token = condTok3[i+0] + token = int(condTok3[i+0]) if token == char { - token = condTok3[i+1] + token = int(condTok3[i+1]) goto out } } out: if token == 0 { - token = condTok2[1] /* unknown char */ + token = int(condTok2[1]) /* unknown char */ } if condDebug >= 3 { __yyfmt__.Printf("lex %s(%d)\n", condTokname(token), uint(char)) @@ -385,7 +385,7 @@ condstack: condS[condp].yys = condstate condnewstate: - condn = condPact[condstate] + condn = int(condPact[condstate]) if condn <= condFlag { goto conddefault /* simple state */ } @@ -396,8 +396,8 @@ condnewstate: if condn < 0 || condn >= condLast { goto conddefault } - condn = condAct[condn] - if condChk[condn] == condtoken { /* valid shift */ + condn = int(condAct[condn]) + if int(condChk[condn]) == condtoken { /* valid shift */ condrcvr.char = -1 condtoken = -1 condVAL = condrcvr.lval @@ -410,7 +410,7 @@ condnewstate: conddefault: /* default state action */ - condn = condDef[condstate] + condn = int(condDef[condstate]) if condn == -2 { if condrcvr.char < 0 { condrcvr.char, condtoken = condlex1(condlex, &condrcvr.lval) @@ -419,18 +419,18 @@ conddefault: /* look through exception table */ xi := 0 for { - if condExca[xi+0] == -1 && condExca[xi+1] == condstate { + if condExca[xi+0] == -1 && int(condExca[xi+1]) == condstate { break } xi += 2 } for xi += 2; ; xi += 2 { - condn = condExca[xi+0] + condn = int(condExca[xi+0]) if condn < 0 || condn == condtoken { break } } - condn = condExca[xi+1] + condn = int(condExca[xi+1]) if condn < 0 { goto ret0 } @@ -452,10 +452,10 @@ conddefault: /* find a state where "error" is a legal shift action */ for condp >= 0 { - condn = condPact[condS[condp].yys] + condErrCode + condn = int(condPact[condS[condp].yys]) + condErrCode if condn >= 0 && condn < condLast { - condstate = condAct[condn] /* simulate a shift of "error" */ - if condChk[condstate] == condErrCode { + condstate = int(condAct[condn]) /* simulate a shift of "error" */ + if int(condChk[condstate]) == condErrCode { goto condstack } } @@ -491,7 +491,7 @@ conddefault: condpt := condp _ = condpt // guard against "declared and not used" - condp -= condR2[condn] + condp -= int(condR2[condn]) // condp is now the index of $0. Perform the default action. Iff the // reduced production is ε, $1 is possibly out of range. if condp+1 >= len(condS) { @@ -502,16 +502,16 @@ conddefault: condVAL = condS[condp+1] /* consult goto table to find next state */ - condn = condR1[condn] - condg := condPgo[condn] + condn = int(condR1[condn]) + condg := int(condPgo[condn]) condj := condg + condS[condp].yys + 1 if condj >= condLast { - condstate = condAct[condg] + condstate = int(condAct[condg]) } else { - condstate = condAct[condj] - if condChk[condstate] != -condn { - condstate = condAct[condg] + condstate = int(condAct[condj]) + if int(condChk[condstate]) != -condn { + condstate = int(condAct[condg]) } } // dummy call; replaced with literal code diff --git a/bfe_config/bfe_conf/conf_basic.go b/bfe_config/bfe_conf/conf_basic.go index 51a81daa1..04bc39bcf 100644 --- a/bfe_config/bfe_conf/conf_basic.go +++ b/bfe_config/bfe_conf/conf_basic.go @@ -16,7 +16,6 @@ package bfe_conf import ( "fmt" - "strings" ) import ( @@ -32,11 +31,6 @@ const ( BalancerNone = "NONE" // layer4 balancer not used ) -const ( - // LibrarySuffix defines BFE plugin's file suffix. - LibrarySuffix = ".so" -) - type ConfigBasic struct { HttpPort int // listen port for http HttpsPort int // listen port for https @@ -59,7 +53,6 @@ type ConfigBasic struct { KeepAliveEnabled bool // if false, client connection is shutdown disregard of http headers Modules []string // modules to load - Plugins []string // plugins to load // location of data files for bfe_route HostRuleConf string // path of host_rule.data @@ -217,11 +210,6 @@ func basicConfCheck(cfg *ConfigBasic) error { return fmt.Errorf("MaxHeaderHeaderBytes[%d] should > 0", cfg.MaxHeaderBytes) } - // check Plugins - if err := checkPlugins(cfg); err != nil { - return fmt.Errorf("plugins[%v] check failed. err: %s", cfg.Plugins, err.Error()) - } - return nil } @@ -240,24 +228,6 @@ func checkLayer4LoadBalancer(cfg *ConfigBasic) error { } } -func checkPlugins(cfg *ConfigBasic) error { - plugins := []string{} - for _, pluginPath := range cfg.Plugins { - pluginPath = strings.TrimSpace(pluginPath) - if pluginPath == "" { - continue - } - - if !strings.HasSuffix(pluginPath, LibrarySuffix) { - pluginPath += LibrarySuffix - } - plugins = append(plugins, pluginPath) - } - cfg.Plugins = plugins - - return nil -} - func dataFileConfCheck(cfg *ConfigBasic, confRoot string) error { // check HostRuleConf if cfg.HostRuleConf == "" { diff --git a/bfe_config/bfe_conf/testdata/conf_https_basic/bfe_4.conf b/bfe_config/bfe_conf/testdata/conf_https_basic/bfe_4.conf index 79e28821f..935aa8a77 100644 --- a/bfe_config/bfe_conf/testdata/conf_https_basic/bfe_4.conf +++ b/bfe_config/bfe_conf/testdata/conf_https_basic/bfe_4.conf @@ -58,7 +58,7 @@ cipherSuites=TLS_RSA_WITH_AES_256_CBC_SHA cipherSuites=TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA cipherSuites=TLS_RSA_WITH_3DES_EDE_CBC_SHA -# supported curve perference settings +# supported curve preference settings # support curves: CurveP256, CurveP384, CurveP521 curvePreferences=CurveP256 diff --git a/bfe_http/request_test.go b/bfe_http/request_test.go index 76bb138cb..8548707e0 100644 --- a/bfe_http/request_test.go +++ b/bfe_http/request_test.go @@ -30,9 +30,7 @@ import ( "reflect" "strings" "testing" -) -import ( "github.com/bfenetworks/bfe/bfe_bufio" ) @@ -397,7 +395,7 @@ func testMissingFile(t *testing.T, req *Request) { t.Errorf("FormFile file = %v, want nil", f) } if fh != nil { - t.Errorf("FormFile file header = %q, want nil", fh) + t.Errorf("FormFile file header = %v, want nil", fh) } if err != ErrMissingFile { t.Errorf("FormFile err = %q, want ErrMissingFile", err) @@ -497,7 +495,7 @@ Content-Disposition: form-data; name="textb" ` func benchmarkReadRequest(b *testing.B, request string) { - request += "\n" // final \n + request += "\n" // final \n request = strings.ReplaceAll(request, "\n", "\r\n") // expand \n to \r\n b.SetBytes(int64(len(request))) r := bfe_bufio.NewReader(&infiniteReader{buf: []byte(request)}) diff --git a/bfe_http/transport.go b/bfe_http/transport.go index a322338af..90bd9b197 100644 --- a/bfe_http/transport.go +++ b/bfe_http/transport.go @@ -885,6 +885,10 @@ func (pc *persistConn) readLoop() { err = ReadRespHeaderError{Err: err} } + pc.lk.Lock() + pc.numExpectedResponses-- + pc.lk.Unlock() + rc.ch <- responseAndError{resp, err} // Wait for the just-returned response body to be fully consumed @@ -1051,10 +1055,6 @@ WaitResponse: } } - pc.lk.Lock() - pc.numExpectedResponses-- - pc.lk.Unlock() - if re.err != nil { pc.t.setReqConn(req.Request, nil) } diff --git a/bfe_http2/frame.go b/bfe_http2/frame.go index 33394e66f..d5174b779 100644 --- a/bfe_http2/frame.go +++ b/bfe_http2/frame.go @@ -1504,6 +1504,7 @@ func (fr *Framer) readMetaFrame(f *HeadersFrame) (*MetaHeadersFrame, error) { hdec.SetEmitEnabled(false) mh.Truncated = true state.H2ErrMaxHeaderListSize.Inc(1) + remainSize = 0 return maxHeaderListSizeError{ streamID: f.FrameHeader.StreamID, curHeaderListSize: fr.maxHeaderListSize() - remainSize + size, @@ -1525,6 +1526,35 @@ func (fr *Framer) readMetaFrame(f *HeadersFrame) (*MetaHeadersFrame, error) { var err error for { frag := hc.HeaderBlockFragment() + + // Avoid parsing large amounts of headers that we will then discard. + // If the sender exceeds the max header list size by too much, + // skip parsing the fragment and close the connection. + // + // "Too much" is either any CONTINUATION frame after we've already + // exceeded the max header list size (in which case remainSize is 0), + // or a frame whose encoded size is more than twice the remaining + // header list bytes we're willing to accept. + if int64(len(frag)) > int64(2*remainSize) { + if VerboseLogs { + log.Printf("http2: header list too large") + } + // It would be nice to send a RST_STREAM before sending the GOAWAY, + // but the structure of the server's frame writer makes this difficult. + return nil, ConnectionError{ErrCodeProtocol, "http2: header list too large"} + } + + // Also close the connection after any CONTINUATION frame following an + // invalid header, since we stop tracking the size of the headers after + // an invalid one. + if invalid != nil { + if VerboseLogs { + log.Printf("http2: invalid header: %v", invalid) + } + // It would be nice to send a RST_STREAM before sending the GOAWAY, + // but the structure of the server's frame writer makes this difficult. + return nil, ConnectionError{ErrCodeProtocol, fmt.Sprintf("http2: invalid header: %v", invalid)} + } blockSize += len(frag) if _, err = hdec.Write(frag); err != nil { // do not return ConnectionError err type, diff --git a/bfe_http2/frame_test.go b/bfe_http2/frame_test.go index 04d20ed7e..e6b2d5767 100644 --- a/bfe_http2/frame_test.go +++ b/bfe_http2/frame_test.go @@ -931,7 +931,7 @@ func TestMetaFrameHeader(t *testing.T) { maxHeaderListSize: (1 << 10) / 2, want: maxHeaderListSizeError{ streamID: 1, - curHeaderListSize: 536, + curHeaderListSize: 550, maxHeaderListSize: 512, }, }, @@ -1033,7 +1033,7 @@ func TestMetaFrameHeader(t *testing.T) { } return fmt.Sprintf("value %#v", v) } - t.Errorf("%s:\n got: %v\nwant: %s", name, str(got), str(tt.want)) + t.Errorf(" %s:\n got: %v\nwant: %s", name, str(got), str(tt.want)) } if tt.wantErrReason != "" && tt.wantErrReason != fmt.Sprint(f.errDetail) { t.Errorf("%s: got error reason %q; want %q", name, f.errDetail, tt.wantErrReason) diff --git a/bfe_http2/server.go b/bfe_http2/server.go index a189cacce..1576c3bb1 100644 --- a/bfe_http2/server.go +++ b/bfe_http2/server.go @@ -34,16 +34,13 @@ import ( "strings" "sync" "time" -) -import ( "github.com/baidu/go-lib/gotrack" "github.com/baidu/go-lib/log" -) -import ( http "github.com/bfenetworks/bfe/bfe_http" "github.com/bfenetworks/bfe/bfe_http2/hpack" + tls "github.com/bfenetworks/bfe/bfe_tls" "github.com/bfenetworks/bfe/bfe_util/pipe" ) @@ -890,7 +887,7 @@ func (sc *serverConn) serve() { if !sc.processFrameFromReader(res) { return } - // collect HTTP/2 fingerprint infomation. + // collect HTTP/2 fingerprint information. sc.fingerprint.ProcessFrame(res) res.readMore() if settingsTimer.C != nil { diff --git a/bfe_module/bfe_plugin.go b/bfe_module/bfe_plugin.go deleted file mode 100644 index 0f760616d..000000000 --- a/bfe_module/bfe_plugin.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2019 The BFE Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package bfe_module - -import ( - "fmt" - goplugin "plugin" -) - -import ( - "github.com/baidu/go-lib/log" - "github.com/baidu/go-lib/web-monitor/web_monitor" -) - -import ( - "github.com/bfenetworks/bfe/bfe_util/semver" -) - -type BfePlugins struct { - workPlugins map[string]*PluginInfo // work plugins, configure in bfe conf file -} - -// NewBfePlugins create new Plugins -func NewBfePlugins() *BfePlugins { - pl := new(BfePlugins) - pl.workPlugins = make(map[string]*PluginInfo) - - return pl -} - -// RegisterPlugin loads a plugin created with `go build -buildmode=plugin` -func (p *BfePlugins) RegisterPlugin(path string, bfeVersion string) error { - plugin, err := goplugin.Open(path) - if err != nil { - return fmt.Errorf("RegisterPlugin Open plugin path %v err:%v", path, err) - } - - nameSym, err := plugin.Lookup("Name") - if err != nil { - return fmt.Errorf("RegisterPlugin Lookup Name err:%v", err) - } - - versionSym, err := plugin.Lookup("Version") - if err != nil { - return fmt.Errorf("RegisterPlugin Lookup Version err:%v", err) - } - - initSym, err := plugin.Lookup("Init") - if err != nil { - return fmt.Errorf("RegisterPlugin Lookup Init err:%v", err) - } - - version := *versionSym.(*string) - - // Compare versions bfe major version and plugin major version - bfeVer, err := semver.New(bfeVersion) - if err != nil { - return fmt.Errorf("RegisterPlugin bfe version err:%v", err) - } - pluginVer, err := semver.New(version) - if err != nil { - return fmt.Errorf("RegisterPlugin plugin version err:%v", err) - } - if bfeVer.CompareMajor(pluginVer) != 0 { - return fmt.Errorf("RegisterPlugin Major version not match, bfe:%s, plugin:%s", bfeVersion, version) - } - - pluginInfo := &PluginInfo{ - Name: *nameSym.(*string), - Version: version, - Path: path, - Init: initSym.(func(cbs *BfeCallbacks, whs *web_monitor.WebHandlers, cr string) error), - } - p.workPlugins[pluginInfo.Name] = pluginInfo - - return nil -} - -// Init initializes bfe plugins. -// -// Params: -// - cbs: BfeCallbacks -// - whs: WebHandlers -// - cr : root path for config -func (p *BfePlugins) Init(cbs *BfeCallbacks, whs *web_monitor.WebHandlers, cr string) error { - for _, pl := range p.workPlugins { - if err := pl.Init(cbs, whs, cr); err != nil { - log.Logger.Error("Err in plugin.init() for %s [%s]", - pl.Name, err.Error()) - return err - } - - log.Logger.Info("%s:Init() Version:%s OK", pl.Name, pl.Version) - } - - return nil -} diff --git a/bfe_modules/bfe_modules.go b/bfe_modules/bfe_modules.go index 326a9830a..56017ca5f 100644 --- a/bfe_modules/bfe_modules.go +++ b/bfe_modules/bfe_modules.go @@ -44,6 +44,7 @@ import ( "github.com/bfenetworks/bfe/bfe_modules/mod_trust_clientip" "github.com/bfenetworks/bfe/bfe_modules/mod_userid" "github.com/bfenetworks/bfe/bfe_modules/mod_waf" + "github.com/bfenetworks/bfe/bfe_modules/mod_wasmplugin" ) // list of all modules, the order is very important @@ -131,6 +132,9 @@ var moduleList = []bfe_module.BfeModule{ // mod_access mod_access.NewModuleAccess(), + + // mod_wasm + mod_wasmplugin.NewModuleWasm(), } // init modules list diff --git a/bfe_modules/mod_auth_jwt/auth_jwt_rule_load.go b/bfe_modules/mod_auth_jwt/auth_jwt_rule_load.go index 5789c1ef9..ec21387a0 100644 --- a/bfe_modules/mod_auth_jwt/auth_jwt_rule_load.go +++ b/bfe_modules/mod_auth_jwt/auth_jwt_rule_load.go @@ -22,7 +22,7 @@ import ( import ( "github.com/golang-jwt/jwt" - jose "gopkg.in/square/go-jose.v2" + jose "github.com/go-jose/go-jose/v4" ) import ( diff --git a/bfe_modules/mod_tcp_keepalive/mod_tcp_keepalive_test.go b/bfe_modules/mod_tcp_keepalive/mod_tcp_keepalive_test.go index d443173d3..3de3321a1 100644 --- a/bfe_modules/mod_tcp_keepalive/mod_tcp_keepalive_test.go +++ b/bfe_modules/mod_tcp_keepalive/mod_tcp_keepalive_test.go @@ -15,7 +15,6 @@ package mod_tcp_keepalive import ( - "net" "testing" "github.com/baidu/go-lib/web-monitor/web_monitor" @@ -38,40 +37,6 @@ func prepareRequest() *bfe_basic.Request { return request } -func TestSetKeepAlive(t *testing.T) { - m, err := prepareModule() - if err != nil { - t.Errorf("prepareModule() error: %v", err) - return - } - s := new(bfe_basic.Session) - ip := "180.97.93.196" - address := "180.97.93.196:80" - - s.Product = "product1" - s.Vip = net.ParseIP(ip) - if s.Vip == nil { - t.Errorf("net.ParseIP(%s) == nil", ip) - } - - conn, err := net.Dial("tcp", address) - if err != nil { - t.Errorf("net.Dial(tcp, %s) error: %v", address, err) - return - } - s.Connection = conn - - m.HandleAccept(s) - metrics := m.metrics.GetAll() - if metrics.CounterData["CONN_TO_SET"] != 1 || - metrics.CounterData["CONN_SET_KEEP_IDLE"] != 1 || - metrics.CounterData["CONN_SET_KEEP_INTVL"] != 1 { - - t.Errorf("CONN_TO_SET and CONN_SET_KEEP_IDLE and CONN_SET_KEEP_INTVL should be 1") - return - } -} - func TestModuleMisc(t *testing.T) { m, err := prepareModule() if err != nil { diff --git a/bfe_modules/mod_wasmplugin/conf_mod_wasmplugin.go b/bfe_modules/mod_wasmplugin/conf_mod_wasmplugin.go new file mode 100644 index 000000000..8aa498529 --- /dev/null +++ b/bfe_modules/mod_wasmplugin/conf_mod_wasmplugin.go @@ -0,0 +1,68 @@ +// Copyright (c) 2024 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mod_wasmplugin + +import ( + "github.com/baidu/go-lib/log" + "github.com/bfenetworks/bfe/bfe_util" + gcfg "gopkg.in/gcfg.v1" +) + +type ConfModWasm struct { + Basic struct { + WasmPluginPath string // path of Wasm plugins + DataPath string // path of config data + } + + Log struct { + OpenDebug bool + } +} + +// ConfLoad loads config from config file +func ConfLoad(filePath string, confRoot string) (*ConfModWasm, error) { + var cfg ConfModWasm + var err error + + // read config from file + err = gcfg.ReadFileInto(&cfg, filePath) + if err != nil { + return &cfg, err + } + + // check conf of mod_redirect + err = cfg.Check(confRoot) + if err != nil { + return &cfg, err + } + + return &cfg, nil +} + +func (cfg *ConfModWasm) Check(confRoot string) error { + if cfg.Basic.WasmPluginPath == "" { + log.Logger.Warn("ModWasm.WasmPluginPath not set, use default value") + cfg.Basic.WasmPluginPath = "mod_wasm" + } + cfg.Basic.WasmPluginPath = bfe_util.ConfPathProc(cfg.Basic.WasmPluginPath, confRoot) + + if cfg.Basic.DataPath == "" { + log.Logger.Warn("ModWasm.DataPath not set, use default value") + cfg.Basic.WasmPluginPath = "mod_wasm/wasm.data" + } + cfg.Basic.DataPath = bfe_util.ConfPathProc(cfg.Basic.DataPath, confRoot) + + return nil +} diff --git a/bfe_modules/mod_wasmplugin/mod_wasmplugin.go b/bfe_modules/mod_wasmplugin/mod_wasmplugin.go new file mode 100644 index 000000000..ecd46dd09 --- /dev/null +++ b/bfe_modules/mod_wasmplugin/mod_wasmplugin.go @@ -0,0 +1,224 @@ +// Copyright (c) 2024 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mod_wasmplugin + +import ( + "fmt" + "net/url" + + _ "github.com/baidu/go-lib/log" + "github.com/baidu/go-lib/web-monitor/web_monitor" + "github.com/bfenetworks/bfe/bfe_basic" + "github.com/bfenetworks/bfe/bfe_http" + "github.com/bfenetworks/bfe/bfe_module" + "github.com/bfenetworks/bfe/bfe_wasmplugin" +) + +const ( + ModWasm = "mod_wasm" + ModWasmBeforeLocationKey = "mod_wasm_before_location_key" +) + +var ( + openDebug = false +) + +type ModuleWasm struct { + name string + wasmPluginPath string // path of Wasm plugins + configPath string // path of config file + pluginTable *PluginTable +} + +func NewModuleWasm() *ModuleWasm { + m := new(ModuleWasm) + m.name = ModWasm + m.pluginTable = NewPluginTable() + return m +} + +func (m *ModuleWasm) Name() string { + return m.name +} + +func (m *ModuleWasm) loadConfData(query url.Values) error { + path := query.Get("path") + if path == "" { + path = m.configPath + } + + // load from config file + conf, err := pluginConfLoad(path) + + if err != nil { + return fmt.Errorf("err in pluginConfLoad(%s):%s", path, err.Error()) + } + + // update to plugin table + return updatePluginConf(m.pluginTable, conf, m.wasmPluginPath) +} + +func (m *ModuleWasm) Init(cbs *bfe_module.BfeCallbacks, whs *web_monitor.WebHandlers, + cr string) error { + var err error + var conf *ConfModWasm + + confPath := bfe_module.ModConfPath(cr, m.name) + if conf, err = ConfLoad(confPath, cr); err != nil { + return fmt.Errorf("%s: cond load err %s", m.name, err.Error()) + } + + // init wasm engine + + return m.init(conf, cbs, whs) +} + +func (m *ModuleWasm) init(cfg *ConfModWasm, cbs *bfe_module.BfeCallbacks, + whs *web_monitor.WebHandlers) error { + openDebug = cfg.Log.OpenDebug + + m.wasmPluginPath = cfg.Basic.WasmPluginPath + m.configPath = cfg.Basic.DataPath + + // load plugins from WasmPluginPath + // construct plugin list + if err := m.loadConfData(nil); err != nil { + return fmt.Errorf("err in loadConfData(): %s", err.Error()) + } + + // register handler + err := cbs.AddFilter(bfe_module.HandleBeforeLocation, m.wasmBeforeLocationHandler) + if err != nil { + return fmt.Errorf("%s.Init(): AddFilter(m.wasmBeforeLocationHandler): %s", m.name, err.Error()) + } + + // register handler + err = cbs.AddFilter(bfe_module.HandleFoundProduct, m.wasmRequestHandler) + if err != nil { + return fmt.Errorf("%s.Init(): AddFilter(m.HandleFoundProduct): %s", m.name, err.Error()) + } + + // register handler + err = cbs.AddFilter(bfe_module.HandleReadResponse, m.wasmResponseHandler) + if err != nil { + return fmt.Errorf("%s.Init(): AddFilter(m.HandleReadResponse): %s", m.name, err.Error()) + } + + // register web handler for reload + err = whs.RegisterHandler(web_monitor.WebHandleReload, m.name, m.loadConfData) + if err != nil { + return fmt.Errorf("%s.Init(): RegisterHandler(m.loadConfData): %s", m.name, err.Error()) + } + + return nil +} + +// +func (m *ModuleWasm) wasmBeforeLocationHandler(request *bfe_basic.Request) (int, *bfe_http.Response) { + var pl []bfe_wasmplugin.WasmPlugin + rl := m.pluginTable.GetBeforeLocationRules() + for _, rule := range rl { + if rule.Cond.Match(request) { + // find pluginlist + pl = rule.PluginList + break + } + } + + var resp *bfe_http.Response + if pl != nil { + // do the pluginlist + retCode := bfe_module.BfeHandlerGoOn + var fl []*bfe_wasmplugin.Filter + for _, plug := range pl { + filter := bfe_wasmplugin.NewFilter(plug, request) + var ret int + ret, resp = filter.RequestHandler(request) + fl = append(fl, filter) + if ret != bfe_module.BfeHandlerGoOn { + retCode = ret + break + } + } + + request.Context[ModWasmBeforeLocationKey] = fl + return retCode, resp + } + + return bfe_module.BfeHandlerGoOn, resp +} + +// +func (m *ModuleWasm) wasmRequestHandler(request *bfe_basic.Request) (int, *bfe_http.Response) { + var pl []bfe_wasmplugin.WasmPlugin + rl, _ := m.pluginTable.Search(request.Route.Product) + for _, rule := range rl { + if rule.Cond.Match(request) { + // find pluginlist + pl = rule.PluginList + break + } + } + + var resp *bfe_http.Response + if pl != nil { + // do the pluginlist + retCode := bfe_module.BfeHandlerGoOn + var fl []*bfe_wasmplugin.Filter + for _, plug := range pl { + filter := bfe_wasmplugin.NewFilter(plug, request) + var ret int + ret, resp = filter.RequestHandler(request) + fl = append(fl, filter) + if ret != bfe_module.BfeHandlerGoOn { + retCode = ret + break + } + } + + var fl0 []*bfe_wasmplugin.Filter + val, ok := request.Context[ModWasmBeforeLocationKey] + if ok { + fl0 = val.([]*bfe_wasmplugin.Filter) + } + + fl0 = append(fl0, fl...) + request.Context[ModWasmBeforeLocationKey] = fl0 + return retCode, resp + } + + return bfe_module.BfeHandlerGoOn, resp +} + +// +func (m *ModuleWasm) wasmResponseHandler(request *bfe_basic.Request, res *bfe_http.Response) int { + val, ok := request.Context[ModWasmBeforeLocationKey] + + if ok { + fl, matched := val.([]*bfe_wasmplugin.Filter) + if !matched { + // error + return bfe_module.BfeHandlerGoOn + } + + n := len(fl) + for i := n-1; i >= 0; i-- { + fl[i].ResponseHandler(request) + fl[i].OnDestroy() + } + } + + return bfe_module.BfeHandlerGoOn +} diff --git a/bfe_modules/mod_wasmplugin/plugin_rule_load.go b/bfe_modules/mod_wasmplugin/plugin_rule_load.go new file mode 100644 index 000000000..30c36eb76 --- /dev/null +++ b/bfe_modules/mod_wasmplugin/plugin_rule_load.go @@ -0,0 +1,211 @@ +// Copyright (c) 2024 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mod_wasmplugin + +import ( + "fmt" + "os" + "path" + + "github.com/bfenetworks/bfe/bfe_basic/condition" + "github.com/bfenetworks/bfe/bfe_util/json" + "github.com/bfenetworks/bfe/bfe_wasmplugin" +) + +type PluginConfFile struct { + Version *string // version of the config + BeforeLocationRules *[]FilterRuleFile // rule list for BeforeLocation + FoundProductRules *map[string][]FilterRuleFile // product --> rule list for FoundProduct + PluginMap *map[string]PluginMeta +} + +type FilterRuleFile struct { + Cond *string // condition for plugin + PluginList *[]string +} + +type PluginMeta struct { + Name string + WasmVersion string + ConfVersion string + InstanceNum int + Product string +} + +type FilterRule struct { + Cond condition.Condition // condition for plugin + PluginList []bfe_wasmplugin.WasmPlugin +} + +type RuleList []FilterRule +type ProductRules map[string]RuleList // product => list of filter rules + +type PluginMap map[string]bfe_wasmplugin.WasmPlugin + +func buildRuleList(rules []FilterRuleFile, pluginMap PluginMap) (RuleList, error) { + var rulelist RuleList + + for _, r := range rules { + rule := FilterRule{} + cond, err := condition.Build(*r.Cond) + if err != nil { + return nil, err + } + + rule.Cond =cond + + for _, pn := range *r.PluginList { + plug := pluginMap[pn] + if plug == nil { + return nil, fmt.Errorf("unknown plugin: %s", pn) + } + rule.PluginList = append(rule.PluginList, plug) + } + + rulelist = append(rulelist, rule) + } + + return rulelist, nil +} + +func buildNewPluginMap(conf *map[string]PluginMeta, pmOld PluginMap, + pluginPath string) (pmNew PluginMap, unchanged map[string]bool, err error) { + + pmNew = PluginMap{} + unchanged = map[string]bool{} + + if conf != nil { + for pn, p := range *conf { + plugOld := pmOld[pn] + // check whether plugin version changed. + if plugOld != nil { + configOld := plugOld.GetConfig() + if configOld.WasmVersion == p.WasmVersion && configOld.ConfigVersion == p.ConfVersion { + // not change, just copy to new map + pmNew[pn] = plugOld + + // grow instance num if needed + if p.InstanceNum > plugOld.InstanceNum() { + actual := plugOld.EnsureInstanceNum(p.InstanceNum) + if actual != p.InstanceNum { + err = fmt.Errorf("can not EnsureInstanceNum, plugin:%s, num:%d", pn, p.InstanceNum) + return + } + } + + unchanged[pn] = true + continue + } + } + // if changed, construct a new plugin. + wasmconf := bfe_wasmplugin.WasmPluginConfig { + PluginName: pn, + WasmVersion: p.WasmVersion, + ConfigVersion: p.ConfVersion, + InstanceNum: p.InstanceNum, + Path: path.Join(pluginPath, pn), + } + plug, err1 := bfe_wasmplugin.NewWasmPlugin(wasmconf) + if err1 != nil { + // build plugin error + err = err1 + return + } + + pmNew[pn] = plug + } + } + + return +} + +func cleanPlugins(pm PluginMap, unchanged map[string]bool, conf *map[string]PluginMeta) { + for pn, plug := range pm { + if unchanged[pn] { + // shink instance num if needed + confnum := (*conf)[pn].InstanceNum + if plug.InstanceNum() > confnum { + plug.EnsureInstanceNum(confnum) + } + } else { + // stop plug + plug.OnPluginDestroy() + plug.Clear() + } + } +} + +func updatePluginConf(t *PluginTable, conf PluginConfFile, pluginPath string) error { + if conf.Version != nil && *conf.Version != t.GetVersion() { + + // 1. check plugin map + pm := t.GetPluginMap() + pluginMapNew, unchanged, err := buildNewPluginMap(conf.PluginMap, pm, pluginPath) + if err != nil { + return err + } + + // 2. construct product rules + var beforeLocationRulesNew RuleList + if conf.BeforeLocationRules != nil { + if rulelist, err := buildRuleList(*conf.BeforeLocationRules, pluginMapNew); err == nil { + beforeLocationRulesNew = rulelist + } else { + return err + } + } + + productRulesNew := make(ProductRules) + if conf.FoundProductRules != nil { + for product, rules := range *conf.FoundProductRules { + if rulelist, err := buildRuleList(rules, pluginMapNew); err == nil { + productRulesNew[product] = rulelist + } else { + return err + } + } + } + + // 3. update PluginTable + t.Update(*conf.Version, beforeLocationRulesNew, productRulesNew, pluginMapNew) + + // 4. stop & clean old plugins + cleanPlugins(pm, unchanged, conf.PluginMap) + } + return nil +} + +func pluginConfLoad(filename string) (PluginConfFile, error) { + var conf PluginConfFile + + /* open the file */ + file, err := os.Open(filename) + + if err != nil { + return conf, err + } + + /* decode the file */ + decoder := json.NewDecoder(file) + + err = decoder.Decode(&conf) + file.Close() + + if err != nil { + return conf, err + } + + return conf, nil +} diff --git a/bfe_modules/mod_wasmplugin/plugin_table.go b/bfe_modules/mod_wasmplugin/plugin_table.go new file mode 100644 index 000000000..53273ee9a --- /dev/null +++ b/bfe_modules/mod_wasmplugin/plugin_table.go @@ -0,0 +1,72 @@ +// Copyright (c) 2024 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mod_wasmplugin + +import ( + "sync" +) + +type PluginTable struct { + lock sync.RWMutex + version string + beforeLocationRules RuleList + productRules ProductRules + pluginMap PluginMap +} + +func NewPluginTable() *PluginTable { + t := new(PluginTable) + t.productRules = make(ProductRules) + t.pluginMap = make(PluginMap) + return t +} + +func (t *PluginTable) Update(version string, beforeLocationRules RuleList, productRules ProductRules, pluginMap PluginMap) { + t.lock.Lock() + + t.version = version + t.beforeLocationRules = beforeLocationRules + t.productRules = productRules + t.pluginMap = pluginMap + + t.lock.Unlock() +} + +func (t *PluginTable) GetVersion() string { + defer t.lock.RUnlock() + t.lock.RLock() + return t.version +} + +func (t *PluginTable) GetPluginMap() PluginMap { + defer t.lock.RUnlock() + t.lock.RLock() + return t.pluginMap +} + +func (t *PluginTable) GetBeforeLocationRules() RuleList { + defer t.lock.RUnlock() + t.lock.RLock() + return t.beforeLocationRules +} + +func (t *PluginTable) Search(product string) (RuleList, bool) { + t.lock.RLock() + productRules := t.productRules + t.lock.RUnlock() + + rules, ok := productRules[product] + return rules, ok +} diff --git a/bfe_server/bfe_server.go b/bfe_server/bfe_server.go index c50fa5f67..cfd5fa3e6 100644 --- a/bfe_server/bfe_server.go +++ b/bfe_server/bfe_server.go @@ -76,7 +76,6 @@ type BfeServer struct { // module and callback CallBacks *bfe_module.BfeCallbacks // call back functions Modules *bfe_module.BfeModules // bfe modules - Plugins *bfe_module.BfePlugins // bfe plugins // web server for bfe monitor and reload Monitor *BfeMonitor @@ -121,8 +120,6 @@ func NewBfeServer(cfg bfe_conf.BfeConfig, confRoot string, s.CallBacks = bfe_module.NewBfeCallbacks() // create modules s.Modules = bfe_module.NewBfeModules() - // create plugins - s.Plugins = bfe_module.NewBfePlugins() // initialize balTable s.balTable = bfe_balance.NewBalTable(s.GetCheckConf) @@ -317,26 +314,6 @@ func (srv *BfeServer) InitModules() error { return srv.Modules.Init(srv.CallBacks, srv.Monitor.WebHandlers, srv.ConfRoot) } -func (srv *BfeServer) LoadPlugins(plugins []string) error { - if len(plugins) == 0 { - return nil - } - - for _, pluginPath := range plugins { - if err := srv.Plugins.RegisterPlugin(pluginPath, srv.Version); err != nil { - return err - } - - log.Logger.Info("RegisterPlugin():pluginPath=%s", pluginPath) - } - - return nil -} - -func (srv *BfeServer) InitPlugins() error { - return srv.Plugins.Init(srv.CallBacks, srv.Monitor.WebHandlers, srv.ConfRoot) -} - func (srv *BfeServer) InitSignalTable() { /* create signal table */ srv.SignalTable = signal_table.NewSignalTable() diff --git a/bfe_server/bfe_server_init.go b/bfe_server/bfe_server_init.go index f261ac354..43fa7e852 100644 --- a/bfe_server/bfe_server_init.go +++ b/bfe_server/bfe_server_init.go @@ -25,7 +25,7 @@ import ( "github.com/bfenetworks/bfe/bfe_modules" ) -func StartUp(cfg bfe_conf.BfeConfig, version string, confRoot string) error { +func StartUp(cfg bfe_conf.BfeConfig, version string, confRoot string, dryRun bool) error { var err error // set all available modules @@ -79,19 +79,9 @@ func StartUp(cfg bfe_conf.BfeConfig, version string, confRoot string) error { } log.Logger.Info("StartUp():bfeServer.InitModules() OK") - // load plugins - if err = bfeServer.LoadPlugins(cfg.Server.Plugins); err != nil { - log.Logger.Error("StartUp():bfeServer.LoadPlugins():%s", err.Error()) - return err - } - - // initialize plugins - if err = bfeServer.InitPlugins(); err != nil { - log.Logger.Error("StartUp():bfeServer.InitPlugins():%s", - err.Error()) - return err + if dryRun { + return nil } - log.Logger.Info("StartUp():bfeServer.InitPlugins() OK") // initialize listeners if err = bfeServer.InitListeners(cfg); err != nil { diff --git a/bfe_stream/server_conn_test.go b/bfe_stream/server_conn_test.go index d311a8b3f..8bd738c6e 100644 --- a/bfe_stream/server_conn_test.go +++ b/bfe_stream/server_conn_test.go @@ -136,7 +136,7 @@ func TestTLSProxyBackendUnavailable(t *testing.T) { &Server{ BalanceHandler: func(conn interface{}) (*backend.BfeBackend, error) { b := backend.NewBfeBackend() - b.AddrInfo = "8.8.8.8:12345" + b.AddrInfo = "127.8.8.8:12345" // balancer return unavailable backend return b, nil }, diff --git a/bfe_tls/handshake_client_test.go b/bfe_tls/handshake_client_test.go index 9a487a678..2e21a142c 100644 --- a/bfe_tls/handshake_client_test.go +++ b/bfe_tls/handshake_client_test.go @@ -408,32 +408,6 @@ func TestHandshakeClientCertRSA(t *testing.T) { runClientTestTLS12(t, test) } -func TestHandshakeClientCertECDSA(t *testing.T) { - config := prepareClientConfig() - cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM)) - config.Certificates = []Certificate{cert} - - test := &clientTest{ - name: "ClientCert-ECDSA-RSA", - command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"}, - config: config, - } - - runClientTestTLS10(t, test) - runClientTestTLS12(t, test) - - test = &clientTest{ - name: "ClientCert-ECDSA-ECDSA", - command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"}, - config: config, - cert: testECDSACertificate, - key: testECDSAPrivateKey, - } - - runClientTestTLS10(t, test) - runClientTestTLS12(t, test) -} - func TestClientResumption(t *testing.T) { serverConfig := &Config{ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, diff --git a/bfe_tls/handshake_server_test.go b/bfe_tls/handshake_server_test.go index 76057ed2e..43bc67115 100644 --- a/bfe_tls/handshake_server_test.go +++ b/bfe_tls/handshake_server_test.go @@ -587,22 +587,6 @@ func TestHandshakeServerAESGCM(t *testing.T) { runServerTestTLS12(t, test) } -func TestHandshakeServerECDHEECDSAAES(t *testing.T) { - config := testConfig.Clone() - config.Certificates = make([]Certificate, 1) - config.Certificates[0].Certificate = [][]byte{testECDSACertificate} - config.Certificates[0].PrivateKey = testECDSAPrivateKey - config.BuildNameToCertificate() - - test := &serverTest{ - name: "ECDHE-ECDSA-AES", - command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-AES256-SHA"}, - config: config, - } - runServerTestTLS10(t, test) - runServerTestTLS12(t, test) -} - func TestHandshakeServerALPN(t *testing.T) { config := testConfig.Clone() config.NextProtos = []string{"proto1", "proto2"} @@ -657,36 +641,6 @@ func TestHandshakeServerSNI(t *testing.T) { runServerTestTLS12(t, test) } -// TestCipherSuiteCertPreference ensures that we select an RSA ciphersuite with -// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate. -func TestCipherSuiteCertPreferenceECDSA(t *testing.T) { - config := testConfig.Clone() - config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA} - config.PreferServerCipherSuites = true - - test := &serverTest{ - name: "CipherSuiteCertPreferenceRSA", - config: config, - } - runServerTestTLS12(t, test) - - config = testConfig.Clone() - config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA} - config.Certificates = []Certificate{ - { - Certificate: [][]byte{testECDSACertificate}, - PrivateKey: testECDSAPrivateKey, - }, - } - config.BuildNameToCertificate() - config.PreferServerCipherSuites = true - - test = &serverTest{ - name: "CipherSuiteCertPreferenceECDSA", - config: config, - } - runServerTestTLS12(t, test) -} func TestResumption(t *testing.T) { sessionFilePath := tempFile("") diff --git a/bfe_util/exit.go b/bfe_util/exit.go index 707264eb3..3350cf09c 100644 --- a/bfe_util/exit.go +++ b/bfe_util/exit.go @@ -22,9 +22,19 @@ import ( "github.com/baidu/go-lib/log" ) -func AbnormalExit() { +func exit(code int) { // waiting for logger finish jobs log.Logger.Close() // exit - os.Exit(1) + os.Exit(code) +} + +// AbnormalExit abnormal status exit with code 1. +func AbnormalExit() { + exit(1) +} + +// NormalExit normal status exit with code 0. +func NormalExit() { + exit(0) } diff --git a/bfe_wasmplugin/abi/proxywasm010/factory.go b/bfe_wasmplugin/abi/proxywasm010/factory.go new file mode 100644 index 000000000..3cbf866ed --- /dev/null +++ b/bfe_wasmplugin/abi/proxywasm010/factory.go @@ -0,0 +1,27 @@ +// Copyright (c) 2024 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package proxywasm010 + +import ( + "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/common" + proxywasm "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/v1" +) + +func ABIContextFactory(instance common.WasmInstance) proxywasm.ContextHandler { + return &proxywasm.ABIContext{ + Imports: &DefaultImportsHandler{Instance: instance}, + Instance: instance, + } +} diff --git a/bfe_wasmplugin/abi/proxywasm010/imports.go b/bfe_wasmplugin/abi/proxywasm010/imports.go new file mode 100644 index 000000000..52d0b9a1d --- /dev/null +++ b/bfe_wasmplugin/abi/proxywasm010/imports.go @@ -0,0 +1,198 @@ +// Copyright (c) 2024 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package proxywasm010 + +import ( + "bytes" + "io/ioutil" + + "net/http" + "net/url" + "sync/atomic" + "time" + + "github.com/baidu/go-lib/log" + "github.com/bfenetworks/bfe/bfe_http" + "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/common" + proxywasm "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/v1" +) + +type DefaultImportsHandler struct { + proxywasm.DefaultImportsHandler + Instance common.WasmInstance + hc *httpCallout +} + +// override +func (d *DefaultImportsHandler) Log(level proxywasm.LogLevel, msg string) proxywasm.WasmResult { + logFunc := log.Logger.Info + + switch level { + case proxywasm.LogLevelTrace: + logFunc = log.Logger.Trace + case proxywasm.LogLevelDebug: + logFunc = log.Logger.Debug + case proxywasm.LogLevelInfo: + logFunc = log.Logger.Info + case proxywasm.LogLevelWarn: + logFunc = func(arg0 interface{}, args ...interface{}) { + log.Logger.Warn(arg0, args...) + } + case proxywasm.LogLevelError: + logFunc = func(arg0 interface{}, args ...interface{}) { + log.Logger.Error(arg0, args...) + } + case proxywasm.LogLevelCritical: + logFunc = func(arg0 interface{}, args ...interface{}) { + log.Logger.Error(arg0, args...) + } + } + + logFunc(msg) + + return proxywasm.WasmResultOk +} + +var httpCalloutID int32 + +type httpCallout struct { + id int32 + d *DefaultImportsHandler + instance common.WasmInstance + abiContext *proxywasm.ABIContext + + urlString string + client *http.Client + req *http.Request + resp *http.Response + respHeader common.HeaderMap + respBody common.IoBuffer + reqOnFly bool +} + +// override +func (d *DefaultImportsHandler) HttpCall(reqURL string, header common.HeaderMap, body common.IoBuffer, + trailer common.HeaderMap, timeoutMilliseconds int32) (int32, proxywasm.WasmResult) { + u, err := url.Parse(reqURL) + if err != nil { + log.Logger.Error("[proxywasm010][imports] HttpCall fail to parse url, err: %v, reqURL: %v", err, reqURL) + return 0, proxywasm.WasmResultBadArgument + } + + calloutID := atomic.AddInt32(&httpCalloutID, 1) + + d.hc = &httpCallout{ + id: calloutID, + d: d, + instance: d.Instance, + abiContext: d.Instance.GetData().(*proxywasm.ABIContext), + urlString: reqURL, + } + + d.hc.client = &http.Client{Timeout: time.Millisecond * time.Duration(timeoutMilliseconds)} + + d.hc.req, err = http.NewRequest(http.MethodGet, u.String(), bytes.NewReader(body.Bytes())) + if err != nil { + log.Logger.Error("[proxywasm010][imports] HttpCall fail to create http req, err: %v, reqURL: %v", err, reqURL) + return 0, proxywasm.WasmResultInternalFailure + } + + header.Range(func(key, value string) bool { + d.hc.req.Header.Add(key, value) + return true + }) + + d.hc.reqOnFly = true + + return calloutID, proxywasm.WasmResultOk +} + +// override +func (d *DefaultImportsHandler) Wait() proxywasm.Action { + if d.hc == nil || !d.hc.reqOnFly { + return proxywasm.ActionContinue + } + + // release the instance lock and do sync http req + d.Instance.Unlock() + resp, err := d.hc.client.Do(d.hc.req) + d.Instance.Lock(d.hc.abiContext) + + d.hc.reqOnFly = false + + if err != nil { + log.Logger.Error("[proxywasm010][imports] HttpCall id: %v fail to do http req, err: %v, reqURL: %v", + d.hc.id, err, d.hc.urlString) + return proxywasm.ActionPause + } + d.hc.resp = resp + + // process http resp header + // var respHeader common.HeaderMap = protocol.CommonHeader{} + // for key, _ := range resp.Header { + // respHeader.Set(key, resp.Header.Get(key)) + // } + d.hc.respHeader = HeaderMapWrapper{Header: bfe_http.Header(resp.Header)} + + // process http resp body + var respBody common.IoBuffer + respBodyLen := 0 + + respBodyBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Logger.Error("[proxywasm010][imports] HttpCall id: %v fail to read bytes from resp body, err: %v, reqURL: %v", + d.hc.id, err, d.hc.urlString) + } + + err = resp.Body.Close() + if err != nil { + log.Logger.Error("[proxywasm010][imports] HttpCall id: %v fail to close resp body, err: %v, reqURL: %v", + d.hc.id, err, d.hc.urlString) + } + + if respBodyBytes != nil { + respBody = common.NewIoBufferBytes(respBodyBytes) + respBodyLen = respBody.Len() + } + d.hc.respBody = respBody + + // call proxy_on_http_call_response + rootContextID := d.hc.abiContext.Imports.GetRootContextID() + exports := d.hc.abiContext.GetExports() + + err = exports.ProxyOnHttpCallResponse(rootContextID, d.hc.id, int32(len(resp.Header)), int32(respBodyLen), 0) + if err != nil { + log.Logger.Error("[proxywasm010][imports] httpCall id: %v fail to call ProxyOnHttpCallResponse, err: %v", d.hc.id, err) + } + return proxywasm.ActionContinue +} + +// override +func (d *DefaultImportsHandler) GetHttpCallResponseHeaders() common.HeaderMap { + if d.hc != nil && d.hc.respHeader != nil { + return d.hc.respHeader + } + + return nil +} + +// override +func (d *DefaultImportsHandler) GetHttpCallResponseBody() common.IoBuffer { + if d.hc != nil && d.hc.respBody != nil { + return d.hc.respBody + } + + return nil +} diff --git a/bfe_wasmplugin/abi/proxywasm010/shim.go b/bfe_wasmplugin/abi/proxywasm010/shim.go new file mode 100644 index 000000000..ff895a92e --- /dev/null +++ b/bfe_wasmplugin/abi/proxywasm010/shim.go @@ -0,0 +1,55 @@ +// Copyright (c) 2024 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package proxywasm010 + +import ( + "github.com/bfenetworks/bfe/bfe_http" + "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/common" +) + +// HeaderMapWrapper wraps api.HeaderMap into proxy-wasm-go-host/common.HeaderMap +// implement common.HeaderMap +type HeaderMapWrapper struct { + bfe_http.Header +} + +// Override +func (h HeaderMapWrapper) Get(key string) (string, bool) { + s := h.Header.Get(key) + if s == "" { + return "", false + } else { + return s, true + } +} + +func (h HeaderMapWrapper) Range(f func(key, value string) bool) { + stopped := false + for k, v := range h.Header { + if stopped { + return + } + stopped = !f(k, v[0]) + } +} + +func (h HeaderMapWrapper) ByteSize() uint64 { + // TODO: to implement + return 0 +} + +func (h HeaderMapWrapper) Clone() common.HeaderMap { + return &HeaderMapWrapper{h.Header} +} diff --git a/bfe_wasmplugin/abi/registry.go b/bfe_wasmplugin/abi/registry.go new file mode 100644 index 000000000..05e9b3f2a --- /dev/null +++ b/bfe_wasmplugin/abi/registry.go @@ -0,0 +1,38 @@ +// Copyright (c) 2024 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package abi + +import ( + "github.com/baidu/go-lib/log" + "github.com/bfenetworks/bfe/bfe_wasmplugin/abi/proxywasm010" + "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/common" + proxywasm "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/v1" +) + +func GetABIList(instance common.WasmInstance) []proxywasm.ContextHandler { + if instance == nil { + log.Logger.Error("[abi][registry] GetABIList nil instance: %v", instance) + return nil + } + + res := make([]proxywasm.ContextHandler, 0) + + abiNameList := instance.GetModule().GetABINameList() + if len(abiNameList) > 0 { + res = append(res, proxywasm010.ABIContextFactory(instance)) + } + + return res +} diff --git a/bfe_wasmplugin/adapter.go b/bfe_wasmplugin/adapter.go new file mode 100644 index 000000000..50f6c2df4 --- /dev/null +++ b/bfe_wasmplugin/adapter.go @@ -0,0 +1,109 @@ +// Copyright (c) 2024 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bfe_wasmplugin + +import ( + "bytes" + "io/ioutil" + + "github.com/bfenetworks/bfe/bfe_http" + "github.com/bfenetworks/bfe/bfe_wasmplugin/abi/proxywasm010" + "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/common" + v1Host "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/v1" +) + +// v1 Imports +type v1Imports struct { + proxywasm010.DefaultImportsHandler + plugin WasmPlugin + filter *Filter +} + +func (v1 *v1Imports) GetRootContextID() int32 { + return v1.plugin.GetRootContextID() +} + +func (v1 *v1Imports) GetVmConfig() common.IoBuffer { + return common.NewIoBufferBytes([]byte{}) +} + +func (v1 *v1Imports) GetPluginConfig() common.IoBuffer { + return common.NewIoBufferBytes(v1.plugin.GetPluginConfig()) +} + +func (v1 *v1Imports) GetHttpRequestHeader() common.HeaderMap { + if v1.filter.request == nil { + return nil + } + + return &proxywasm010.HeaderMapWrapper{Header: v1.filter.request.HttpRequest.Header} +} + +func (v1 *v1Imports) GetHttpRequestBody() common.IoBuffer { + if v1.filter.request == nil { + return nil + } + + return nil +} + +func (v1 *v1Imports) GetHttpRequestTrailer() common.HeaderMap { + if v1.filter.request == nil { + return nil + } + + return &proxywasm010.HeaderMapWrapper{Header: v1.filter.request.HttpRequest.Trailer} +} + +func (v1 *v1Imports) GetHttpResponseHeader() common.HeaderMap { + if v1.filter.request == nil || v1.filter.request.HttpResponse == nil { + return nil + } + + return &proxywasm010.HeaderMapWrapper{Header: v1.filter.request.HttpResponse.Header} +} + +func (v1 *v1Imports) GetHttpResponseBody() common.IoBuffer { + if v1.filter.request == nil || v1.filter.request.HttpResponse == nil { + return nil + } + + return nil +} + +func (v1 *v1Imports) GetHttpResponseTrailer() common.HeaderMap { + if v1.filter.request == nil || v1.filter.request.HttpResponse == nil { + return nil + } + + return &proxywasm010.HeaderMapWrapper{Header: v1.filter.request.HttpResponse.Trailer} +} + +func (v1 *v1Imports) SendHttpResp(respCode int32, respCodeDetail common.IoBuffer, respBody common.IoBuffer, additionalHeaderMap common.HeaderMap, grpcCode int32) v1Host.WasmResult { + resp := &bfe_http.Response{ + StatusCode: int(respCode), + Status: string(respCodeDetail.Bytes()), + Body: ioutil.NopCloser(bytes.NewReader(respBody.Bytes())), + Header: make(bfe_http.Header), + } + + additionalHeaderMap.Range(func(key, value string) bool { + resp.Header.Add(key, value) + return true + }) + + v1.filter.request.HttpResponse = resp + return v1Host.WasmResultOk +} diff --git a/bfe_module/bfe_plugin_info.go b/bfe_wasmplugin/engine.go similarity index 62% rename from bfe_module/bfe_plugin_info.go rename to bfe_wasmplugin/engine.go index 23ca40903..ade6f1241 100644 --- a/bfe_module/bfe_plugin_info.go +++ b/bfe_wasmplugin/engine.go @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The BFE Authors. +// Copyright (c) 2024 The BFE Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,17 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -package bfe_module +package bfe_wasmplugin import ( - "github.com/baidu/go-lib/web-monitor/web_monitor" + "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/common" + "github.com/bfenetworks/proxy-wasm-go-host/wazero" ) -type PluginInfo struct { - Name string - Version string - Description string - Kind string // TODO plugin kind - Path string - Init func(cbs *BfeCallbacks, whs *web_monitor.WebHandlers, cr string) error +var defaultEngine = wazero.NewVM() + +func GetWasmEngine() common.WasmVM { + return defaultEngine } diff --git a/bfe_wasmplugin/filter.go b/bfe_wasmplugin/filter.go new file mode 100644 index 000000000..183187cea --- /dev/null +++ b/bfe_wasmplugin/filter.go @@ -0,0 +1,145 @@ +// Copyright (c) 2024 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bfe_wasmplugin + +import ( + "sync" + "sync/atomic" + + "github.com/bfenetworks/bfe/bfe_basic" + "github.com/bfenetworks/bfe/bfe_http" + "github.com/bfenetworks/bfe/bfe_module" + + "github.com/baidu/go-lib/log" + wasmABI "github.com/bfenetworks/bfe/bfe_wasmplugin/abi" + "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/common" + v1Host "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/v1" +) + +type Filter struct { + plugin WasmPlugin + instance common.WasmInstance + abi v1Host.ContextHandler + exports v1Host.Exports + + rootContextID int32 + contextID int32 + + request *bfe_basic.Request + + destroyOnce sync.Once +} + +var contextIDGenerator int32 + +func newContextID(rootContextID int32) int32 { + for { + id := atomic.AddInt32(&contextIDGenerator, 1) + if id != rootContextID { + return id + } + } +} + +func NewFilter(plugin WasmPlugin, request *bfe_basic.Request) *Filter { + instance := plugin.GetInstance() + rootContextID := plugin.GetRootContextID() + + filter := &Filter{ + plugin: plugin, + instance: instance, + rootContextID: rootContextID, + contextID: newContextID(rootContextID), + request: request, + } + + filter.abi = wasmABI.GetABIList(instance)[0] + log.Logger.Info("[proxywasm][filter] abi version: %v", filter.abi.Name()) + if filter.abi != nil { + // v1 + imports := &v1Imports{plugin: plugin, filter: filter} + imports.DefaultImportsHandler.Instance = instance + filter.abi.SetImports(imports) + filter.exports = filter.abi.GetExports() + } else { + log.Logger.Error("[proxywasm][filter] unknown abi list: %v", filter.abi) + return nil + } + + filter.instance.Lock(filter.abi) + defer filter.instance.Unlock() + + err := filter.exports.ProxyOnContextCreate(filter.contextID, filter.rootContextID) + if err != nil { + log.Logger.Error("[proxywasm][filter] NewFilter fail to create context id: %v, rootContextID: %v, err: %v", + filter.contextID, filter.rootContextID, err) + return nil + } + + return filter +} + +func (f *Filter) OnDestroy() { + f.destroyOnce.Do(func() { + f.instance.Lock(f.abi) + + _, err := f.exports.ProxyOnDone(f.contextID) + if err != nil { + log.Logger.Error("[proxywasm][filter] OnDestroy fail to call ProxyOnDone, err: %v", err) + } + + err = f.exports.ProxyOnDelete(f.contextID) + if err != nil { + // warn instead of error as some proxy_abi_version_0_1_0 wasm don't + // export proxy_on_delete + log.Logger.Warn("[proxywasm][filter] OnDestroy fail to call ProxyOnDelete, err: %v", err) + } + + f.instance.Unlock() + f.plugin.ReleaseInstance(f.instance) + }) +} + +func (f *Filter) RequestHandler(request *bfe_basic.Request) (int, *bfe_http.Response) { + f.instance.Lock(f.abi) + defer f.instance.Unlock() + + action, err := f.exports.ProxyOnRequestHeaders(f.contextID, int32(len(request.HttpRequest.Header)), 0) + if err != nil { + log.Logger.Error("[proxywasm][filter][v1] ProxyOnRequestHeaders action: %v, err: %v", action, err) + } + + status := bfe_module.BfeHandlerGoOn + if f.request.HttpResponse != nil { + status = bfe_module.BfeHandlerResponse + } + return status, f.request.HttpResponse +} + +func (f *Filter) ResponseHandler(request *bfe_basic.Request) (int, *bfe_http.Response) { + f.instance.Lock(f.abi) + defer f.instance.Unlock() + + action, err := f.exports.ProxyOnResponseHeaders(f.contextID, int32(len(request.HttpResponse.Header)), 0) + if err != nil { + log.Logger.Error("[proxywasm][filter][v1] ProxyOnResponseHeaders action: %v, err: %v", action, err) + } + + status := bfe_module.BfeHandlerGoOn + if f.request.HttpResponse != nil { + status = bfe_module.BfeHandlerResponse + } + return status, f.request.HttpResponse +} diff --git a/bfe_wasmplugin/plugin.go b/bfe_wasmplugin/plugin.go new file mode 100644 index 000000000..83ad2e6ba --- /dev/null +++ b/bfe_wasmplugin/plugin.go @@ -0,0 +1,394 @@ +// Copyright (c) 2024 The BFE Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bfe_wasmplugin + +import ( + "crypto/md5" + "encoding/hex" + "errors" + "os" + "path" + "runtime" + "strings" + "sync" + "sync/atomic" + + "github.com/baidu/go-lib/log" + wasmABI "github.com/bfenetworks/bfe/bfe_wasmplugin/abi" + "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/common" + v1Host "github.com/bfenetworks/proxy-wasm-go-host/proxywasm/v1" +) + +var ( + ErrEngineNotFound = errors.New("fail to get wasm engine") + ErrWasmBytesLoad = errors.New("fail to load wasm bytes") + ErrWasmBytesIncorrect = errors.New("incorrect hash of wasm bytes") + ErrConfigFileLoad = errors.New("fail to load config file") + ErrMd5FileLoad = errors.New("fail to load md5 file") + ErrInstanceCreate = errors.New("fail to create wasm instance") + ErrModuleCreate = errors.New("fail to create wasm module") +) + +type WasmPluginConfig struct { + PluginName string `json:"plugin_name,omitempty"` + Path string `json:"path,omitempty"` + Md5 string `json:"md5,omitempty"` + WasmVersion string + ConfigVersion string + InstanceNum int `json:"instance_num,omitempty"` +} + +// WasmPlugin manages the collection of wasm plugin instances +type WasmPlugin interface { + // PluginName returns the name of wasm plugin + PluginName() string + + // GetPluginConfig returns the config of wasm plugin + GetPluginConfig() []byte + + // GetPluginConfig returns the config of wasm plugin + GetConfig() WasmPluginConfig + + // EnsureInstanceNum tries to expand/shrink the num of instance to 'num' + // and returns the actual instance num + EnsureInstanceNum(num int) int + + // InstanceNum returns the current number of wasm instance + InstanceNum() int + + // GetInstance returns one plugin instance of the plugin + GetInstance() common.WasmInstance + + // ReleaseInstance releases the instance to the plugin + ReleaseInstance(instance common.WasmInstance) + + // Exec execute the f for each instance + Exec(f func(instance common.WasmInstance) bool) + + // Clear got called when the plugin is destroyed + Clear() + + // OnPluginStart got called when starting the wasm plugin + OnPluginStart() + + // OnPluginDestroy got called when destroying the wasm plugin + OnPluginDestroy() + + GetRootContextID() int32 +} + +type wasmPluginImpl struct { + config WasmPluginConfig + + lock sync.RWMutex + + instanceNum int32 + instances []common.WasmInstance + instancesIndex int32 + + occupy int32 + + vm common.WasmVM + wasmBytes []byte + module common.WasmModule + + pluginConfig []byte + rootContextID int32 +} + +// load wasm bytes +func loadWasmBytes(dir string, name string) (wasmBytes []byte, configBytes []byte, err error) { + wasmBytes, err = os.ReadFile(path.Join(dir, name + ".wasm")) + if err != nil || len(wasmBytes) == 0 { + // wasm file error + err = ErrWasmBytesLoad + return + } + + configBytes, err = os.ReadFile(path.Join(dir, name + ".conf")) + if err != nil { + // plugin config file error + err = ErrConfigFileLoad + return + } + + var md5File []byte + md5File, err = os.ReadFile(path.Join(dir, name + ".md5")) + if err != nil { + // md5 file error + err = ErrMd5FileLoad + return + } + md5str := "" + fields := strings.Fields(string(md5File)) + if len(fields) > 0 { + md5str = fields[0] + } + + md5Bytes := md5.Sum(wasmBytes) + newMd5 := hex.EncodeToString(md5Bytes[:]) + if newMd5 != md5str { + err = ErrWasmBytesIncorrect + return + } + + return +} + +func NewWasmPlugin(wasmConfig WasmPluginConfig) (WasmPlugin, error) { + // check instance num + instanceNum := wasmConfig.InstanceNum + if instanceNum <= 0 { + instanceNum = runtime.NumCPU() + } + + wasmConfig.InstanceNum = instanceNum + + // get wasm engine + vm := GetWasmEngine() + if vm == nil { + return nil, ErrEngineNotFound + } + + // load wasm bytes + wasmBytes, configBytes, err := loadWasmBytes(wasmConfig.Path, wasmConfig.PluginName) + if err != nil { + // wasm file error + return nil, err + } + + // create wasm module + module := vm.NewModule(wasmBytes) + if module == nil { + return nil, ErrModuleCreate + } + + plugin := &wasmPluginImpl{ + config: wasmConfig, + vm: vm, + wasmBytes: wasmBytes, + module: module, + pluginConfig: configBytes, + rootContextID: newContextID(0), + } + + // ensure instance num + actual := plugin.EnsureInstanceNum(wasmConfig.InstanceNum) + if actual == 0 { + return nil, ErrInstanceCreate + } + + return plugin, nil +} + +// reduce to n instances and return the cut-offs +func (w *wasmPluginImpl) cutInstance(n int) []common.WasmInstance { + w.lock.Lock() + defer w.lock.Unlock() + + oldcopy := make([]common.WasmInstance, w.InstanceNum() - n) + copy(oldcopy, w.instances[n:]) + w.instances = w.instances[:n] + atomic.StoreInt32(&w.instanceNum, int32(n)) + + return oldcopy +} + +func (w *wasmPluginImpl) appendInstance(newInstance []common.WasmInstance) { + w.lock.Lock() + defer w.lock.Unlock() + + w.instances = append(w.instances, newInstance...) + atomic.AddInt32(&w.instanceNum, int32(len(newInstance))) +} + +// EnsureInstanceNum try to expand/shrink the num of instance to 'num' +// and return the actual instance num. +func (w *wasmPluginImpl) EnsureInstanceNum(num int) int { + if num == w.InstanceNum() { + return w.InstanceNum() + } + + if num < w.InstanceNum() { + todel := w.cutInstance(num) + + // stop the cut-off instances + for _, instance := range todel { + instance.Stop() + } + } else { + newInstance := make([]common.WasmInstance, 0) + numToCreate := num - w.InstanceNum() + + for i := 0; i < numToCreate; i++ { + instance := w.module.NewInstance() + if instance == nil { + log.Logger.Error("[wasm][plugin] EnsureInstanceNum fail to create instance, i: %v", i) + continue + } + + // Instantiate any ABI needed by the guest. + abilist := wasmABI.GetABIList(instance) + if len(abilist) == 0 { + log.Logger.Error("[wasm][plugin] EnsureInstanceNum fail to get abilist, i: %v", i) + break + } + for _, abi := range abilist { + //abi.OnInstanceCreate(instance) + if err := instance.RegisterImports(abi.Name()); err != nil { + panic(err) + } + } + + err := instance.Start() + if err != nil { + log.Logger.Error("[wasm][plugin] EnsureInstanceNum fail to start instance, i: %v, err: %v", i, err) + continue + } + + if !w.OnInstanceStart(instance) { + log.Logger.Error("[wasm][plugin] EnsureInstanceNum fail on instance start, i: %v", i) + break + } + newInstance = append(newInstance, instance) + } + + w.appendInstance(newInstance) + } + + return w.InstanceNum() +} + +func (w *wasmPluginImpl) InstanceNum() int { + return int(atomic.LoadInt32(&w.instanceNum)) +} + +func (w *wasmPluginImpl) PluginName() string { + return w.config.PluginName +} + +func (w *wasmPluginImpl) Clear() { + // do nothing + log.Logger.Info("[wasm][plugin] Clear wasm plugin, config: %v, instanceNum: %v", w.config, w.instanceNum) + w.EnsureInstanceNum(0) + log.Logger.Info("[wasm][plugin] Clear wasm plugin done, config: %v, instanceNum: %v", w.config, w.instanceNum) +} + +// Exec execute the f for each instance. +func (w *wasmPluginImpl) Exec(f func(instance common.WasmInstance) bool) { + w.lock.RLock() + defer w.lock.RUnlock() + + for _, iw := range w.instances { + if !f(iw) { + break + } + } +} + +func (w *wasmPluginImpl) GetConfig() WasmPluginConfig { + return w.config +} + +func (w *wasmPluginImpl) GetPluginConfig() []byte { + return w.pluginConfig +} + +func (w *wasmPluginImpl) GetInstance() common.WasmInstance { + w.lock.RLock() + defer w.lock.RUnlock() + + for i := 0; i < len(w.instances); i++ { + idx := int(atomic.LoadInt32(&w.instancesIndex)) % len(w.instances) + atomic.AddInt32(&w.instancesIndex, 1) + + instance := w.instances[idx] + if !instance.Acquire() { + continue + } + + atomic.AddInt32(&w.occupy, 1) + return instance + } + + return nil +} + +func (w *wasmPluginImpl) ReleaseInstance(instance common.WasmInstance) { + instance.Release() + atomic.AddInt32(&w.occupy, -1) +} + +func (w *wasmPluginImpl) OnInstanceStart(instance common.WasmInstance) bool { + abilist := wasmABI.GetABIList(instance) + if len(abilist) == 0 { + log.Logger.Error("[proxywasm][factory] instance has no correct abi list") + return false + } + + abi := abilist[0] + var exports v1Host.Exports + if abi != nil { + // v1 + imports := &v1Imports{plugin: w} + imports.DefaultImportsHandler.Instance = instance + abi.SetImports(imports) + exports = abi.GetExports() + } else { + log.Logger.Error("[proxywasm][factory] unknown abi list: %v", abi) + return false + } + + instance.Lock(abi) + defer instance.Unlock() + + err := exports.ProxyOnContextCreate(w.rootContextID, 0) + if err != nil { + log.Logger.Error("[proxywasm][factory] OnPluginStart fail to create root context id, err: %v", err) + return true + } + + vmConfigSize := 0 + // no vm config + + _, err = exports.ProxyOnVmStart(w.rootContextID, int32(vmConfigSize)) + if err != nil { + log.Logger.Error("[proxywasm][factory] OnPluginStart fail to create root context id, err: %v", err) + return true + } + + pluginConfigSize := 0 + if pluginConfigBytes := w.GetPluginConfig(); pluginConfigBytes != nil { + pluginConfigSize = len(pluginConfigBytes) + } + + _, err = exports.ProxyOnConfigure(w.rootContextID, int32(pluginConfigSize)) + if err != nil { + log.Logger.Error("[proxywasm][factory] OnPluginStart fail to create root context id, err: %v", err) + return true + } + + return true +} + +func (w *wasmPluginImpl) OnPluginStart() { + // w.Exec(w.OnInstanceStart) +} + +func (d *wasmPluginImpl) OnPluginDestroy() {} + +func (w *wasmPluginImpl) GetRootContextID() int32 { + return w.rootContextID +} diff --git a/bfe_websocket/server_conn_test.go b/bfe_websocket/server_conn_test.go index e126ae7f3..04f674deb 100644 --- a/bfe_websocket/server_conn_test.go +++ b/bfe_websocket/server_conn_test.go @@ -252,7 +252,7 @@ func TestWebSocketProxyBackendUnavailable(t *testing.T) { &Server{ BalanceHandler: func(req interface{}) (*backend.BfeBackend, error) { b := backend.NewBfeBackend() - b.AddrInfo = "8.8.8.8:12345" + b.AddrInfo = "127.8.8.8:12345" // balancer return unavailable backend return b, nil }, diff --git a/conf/bfe.conf b/conf/bfe.conf index 83d3f0ce3..9a4d043b2 100644 --- a/conf/bfe.conf +++ b/conf/bfe.conf @@ -61,6 +61,7 @@ Modules = mod_access Modules = mod_prison #Modules = mod_auth_request # Modules = mod_cors +Modules = mod_wasm # interval for get diff of proxy-state MonitorInterval = 20 @@ -112,7 +113,7 @@ CipherSuites=TLS_RSA_WITH_RC4_128_SHA CipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA CipherSuites=TLS_RSA_WITH_AES_256_CBC_SHA -# supported curve perference settings +# supported curve preference settings # # curves implemented in golang: # CurveP256 diff --git a/conf/mod_wasm/mod_wasm.conf b/conf/mod_wasm/mod_wasm.conf new file mode 100644 index 000000000..7a00935bb --- /dev/null +++ b/conf/mod_wasm/mod_wasm.conf @@ -0,0 +1,7 @@ +[basic] +DataPath = mod_wasm/mod_wasm.data +WasmPluginPath=wasm_plugin/ + +[log] +OpenDebug=true + diff --git a/conf/mod_wasm/mod_wasm.data b/conf/mod_wasm/mod_wasm.data new file mode 100644 index 000000000..d491ce813 --- /dev/null +++ b/conf/mod_wasm/mod_wasm.data @@ -0,0 +1,21 @@ +{ + "Version": "5", + "BeforeLocationRules": [{ + "Cond": "req_path_prefix_in(\"/headers\", false)", + "PluginList": [ "headers" ] + }], + "ProductRules": { + "local_product": [{ + "Cond": "default_t()", + "PluginList": [] + }] + }, + "PluginMap": { + "headers": { + "Name": "headers", + "WasmVersion": "3", + "ConfVersion": "6", + "InstanceNum": 20 + } + } +} diff --git a/conf/server_data_conf/host_rule.data b/conf/server_data_conf/host_rule.data index 49ee4b352..734d675f7 100644 --- a/conf/server_data_conf/host_rule.data +++ b/conf/server_data_conf/host_rule.data @@ -6,11 +6,17 @@ "example.org", "fcgi.example.org", "h2c.example.org" + ], + "localTag":[ + "localhost" ] }, "HostTags": { "example_product":[ "exampleTag" + ], + "local_product":[ + "localTag" ] } } diff --git a/conf/wasm_plugin/headers/headers.conf b/conf/wasm_plugin/headers/headers.conf new file mode 100644 index 000000000..77d8544e5 --- /dev/null +++ b/conf/wasm_plugin/headers/headers.conf @@ -0,0 +1,4 @@ +{ + "header": "Wasm-Header-1", + "value": "Hello WasmPlugin!" +} diff --git a/conf/wasm_plugin/headers/headers.md5 b/conf/wasm_plugin/headers/headers.md5 new file mode 100644 index 000000000..fc2ba2dd2 --- /dev/null +++ b/conf/wasm_plugin/headers/headers.md5 @@ -0,0 +1 @@ +82f14b56c9114d420f4624443bd76ac0 diff --git a/conf/wasm_plugin/headers/headers.wasm b/conf/wasm_plugin/headers/headers.wasm new file mode 100755 index 000000000..767910bb8 Binary files /dev/null and b/conf/wasm_plugin/headers/headers.wasm differ diff --git a/docs/en_us/DOWNLOAD.md b/docs/en_us/DOWNLOAD.md index b3956378f..b7d328448 100644 --- a/docs/en_us/DOWNLOAD.md +++ b/docs/en_us/DOWNLOAD.md @@ -1,5 +1,27 @@ We provide precompiled binaries for bfe components. [Download the latest release](/~https://github.com/bfenetworks/bfe/releases) of BFE for your platform. +## bfe v1.6.0 + +* 2022-10-25 [Release notes](/~https://github.com/bfenetworks/bfe/releases/tag/v1.6.0) + +| File name | OS | Arch | Size | SHA256 Checksum | +| --------- | -------- | ---- | ---- | ------------ | +| [bfe_1.6.0_darwin_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.6.0/bfe_1.6.0_darwin_amd64.tar.gz) | darwin | amd 64 | 9.3M | 61c8c5cab55c2b0ae7a5a0c027559efceddf58924fec7ff7dc9342e9ae8800e6 | +| [bfe_1.6.0_linux_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.6.0/bfe_1.6.0_linux_amd64.tar.gz) | linux | amd64 | 9.56 MB | 26510e09a7da8618e860beb58823b12b4305bf83a48fde4d09fae5f5c4d18aba | +| [bfe_1.6.0_linux_arm64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.6.0/bfe_1.6.0_linux_arm64.tar.gz) | linux | arm64 | 8.84 MB | 135d3d8f45612633958df923a876b5481ca5d4221f3d997de952cfd797ccd77e | +| [bfe_1.6.0_windows_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.6.0/bfe_1.6.0_windows_amd64.tar.gz) | windows | amd64 | 9.64 MB | 31e331335c87c2c44faf6dce915a53f5b7fada6c1925580ee2e19db6933fe450 | + +## bfe v1.5.0 + +* 2022-01-11 [Release notes](/~https://github.com/bfenetworks/bfe/releases/tag/v1.5.0) + +| File name | OS | Arch | Size | SHA256 Checksum | +| --------- | -------- | ---- | ---- | ------------ | +| [bfe_1.5.0_darwin_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.5.0/bfe_1.5.0_darwin_amd64.tar.gz) | darwin | amd 64 | 9.29M | accf8ccebaf98ab38028f7beb8c4da0825a7c62976063bd844cebeb2d57760b0 | +| [bfe_1.5.0_linux_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.5.0/bfe_1.5.0_linux_amd64.tar.gz) | linux | amd64 | 9.55 MB | a74818d26462995b4f79c72184bee005c3aa161d9cb7af42b41d18791733336d | +| [bfe_1.5.0_linux_arm64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.5.0/bfe_1.5.0_linux_arm64.tar.gz) | linux | arm64 | 8.83 MB | d9ee8877c679d2b7af2d1fa60cd4a498bc252c5832df0f8ced771cae1d36fa58 | +| [bfe_1.5.0_windows_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.5.0/bfe_1.5.0_windows_amd64.tar.gz) | windows | amd64 | 9.63 MB | a9f54df2a2374bf53ba6ad1d728f82a27f2b2c8aaa6ae854141c58105a905992 | + ## bfe v1.4.0 * 2021-12-10 [Release notes](/~https://github.com/bfenetworks/bfe/releases/tag/v1.4.0) diff --git a/docs/en_us/SUMMARY.md b/docs/en_us/SUMMARY.md index 93c25d2fe..559086f42 100644 --- a/docs/en_us/SUMMARY.md +++ b/docs/en_us/SUMMARY.md @@ -3,7 +3,7 @@ * [About](ABOUT.md) * Introduction * [Overview](introduction/overview.md) - * [Comparsion to similar systems](introduction/comparison.md) + * [Comparison to similar systems](introduction/comparison.md) * Design overview * [Terminology](introduction/terminology.md) * [Traffic fowarding model](introduction/forward_model.md) @@ -18,7 +18,7 @@ * [Traffic blocking](example/block.md) * [Request redirect](example/redirect.md) * [Request rewrite](example/rewrite.md) - * [FastCGI procotol](example/fastcgi.md) + * [FastCGI protocol](example/fastcgi.md) * [TLS mutual authentication](example/client_auth.md) * [Installation](installation/install.md) * [Install from source](installation/install_from_source.md) @@ -64,6 +64,7 @@ * [mod_trust_clientip](modules/mod_trust_clientip/mod_trust_clientip.md) * [mod_userid](modules/mod_userid/mod_userid.md) * [mod_secure_link](modules/mod_secure_link/mod_secure_link.md) + * [mod_wasmplugin](modules/mod_wasmplugin/mod_wasmplugin.md) * Operations * [Command line options](operation/command.md) * [Environment variables](operation/env_var.md) diff --git a/docs/en_us/condition/condition_grammar.md b/docs/en_us/condition/condition_grammar.md index 3736f7d31..5d3068832 100644 --- a/docs/en_us/condition/condition_grammar.md +++ b/docs/en_us/condition/condition_grammar.md @@ -29,7 +29,7 @@ req_host_in("bfe-networks.com") && req_method_in("GET") - You can define a variable and assign a condition expression to it. ```go -// define a condition varaible +// define a condition variable bfe_host = req_host_in("bfe-networks.com") ``` @@ -41,7 +41,7 @@ bfe_host = req_host_in("bfe-networks.com") ```go // return true if the value of new_host is true and the request method is GET -$news_host && req_method_in("GET") +$new_host && req_method_in("GET") ``` ## Grammar diff --git a/docs/en_us/condition/system/time.md b/docs/en_us/condition/system/time.md index 43c179d99..ee4803aad 100644 --- a/docs/en_us/condition/system/time.md +++ b/docs/en_us/condition/system/time.md @@ -29,7 +29,7 @@ bfe_time_range("20190204203000H", "20190204204500H") | --------- | ---------- | | start_time | String
start time | | end_time | String
end time | -| period | String
period, defualt *Day* | +| period | String
period, default *Day* | Time format: hhmmssZ,Z is time zone,detail information is shown in "Appendix B: Time Zone Detail" diff --git a/docs/en_us/configuration/bfe.conf.md b/docs/en_us/configuration/bfe.conf.md index 073c2d6cd..213715c38 100644 --- a/docs/en_us/configuration/bfe.conf.md +++ b/docs/en_us/configuration/bfe.conf.md @@ -22,7 +22,7 @@ bfe.conf is the core configuration file of BFE. | Basic.KeepAliveEnabled | Boolean
If false, HTTP Keep-Alive is disabled
Default True | | Basic.GracefulShutdownTimeout | Integer
Timeout for graceful shutdown (maximum 300 sec)
Default 10 | | Basic.MaxHeaderBytes | Integer
Max length of request header, in bytes
Default 10485 | -| Basic.MaxHeaderUriBytes | Integer
Max lenght of request URI, in bytes
Default 8192 | +| Basic.MaxHeaderUriBytes | Integer
Max length of request URI, in bytes
Default 8192 | | Basic.HostRuleConf | String
Path of [host config](server_data_conf/host_rule.data.md)
Default server_data_conf/host_rule.data | | Basic.VipRuleConf | String
Path of [VIP config](server_data_conf/vip_rule.data.md)
Default server_data_conf/vip_rule.data | | Basic.RouteRuleConf | String
Path of [route rule config](server_data_conf/route_rule.data.md)
Default server_data_conf/route_rule.data | @@ -44,7 +44,7 @@ bfe.conf is the core configuration file of BFE. | HttpsBasic.ServerCertConf | String
Path of [cert config](tls_conf/server_cert_conf.data.md)
Default tls_conf/server_cert_conf.data | | HttpsBasic.TlsRuleConf | String
Path of [tls rule config](tls_conf/tls_rule_conf.data.md)
Default tls_conf/tls_rule_conf.data | | HttpsBasic.CipherSuites | String
CipherSuites preference settings
Default | -| HttpsBasic.CurvePreferences | String
Curve perference settings
Default CurveP256 | +| HttpsBasic.CurvePreferences | String
Curve preference settings
Default CurveP256 | | HttpsBasic.EnableSslv2ClientHello | Boolean
Enable Sslv2ClientHello for compatible with ancient sslv3 client
Default True | | HttpsBasic.ClientCABaseDir | String
Base directory of client ca certificates
Note: filename suffix of ca certificate must be ".crt"
Default tls_conf/client_ca | | SessioCache.SessionCacheDisabled | Boolean
Disable tls session cache or not
Default True | @@ -166,7 +166,7 @@ CipherSuites=TLS_RSA_WITH_RC4_128_SHA CipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA CipherSuites=TLS_RSA_WITH_AES_256_CBC_SHA -# supported curve perference settings +# supported curve preference settings # # curves implemented in golang: # CurveP256 diff --git a/docs/en_us/configuration/cluster_conf/cluster_table.data.md b/docs/en_us/configuration/cluster_conf/cluster_table.data.md index fea02c3da..cfb5d3ef0 100644 --- a/docs/en_us/configuration/cluster_conf/cluster_table.data.md +++ b/docs/en_us/configuration/cluster_conf/cluster_table.data.md @@ -17,7 +17,7 @@ cluster_table.data records the load balancing config among instances. | Config{v}{k} | String
name of subcluster | | Config{v}{v} | Object
config of subcluster(a list of instance) | -### Instance configuraton +### Instance configuration | Config Item | Description | | --------------------- | ------------------------------- | diff --git a/docs/en_us/configuration/server_data_conf/cluster_conf.data.md b/docs/en_us/configuration/server_data_conf/cluster_conf.data.md index 5668d2677..2eb2ff8fc 100644 --- a/docs/en_us/configuration/server_data_conf/cluster_conf.data.md +++ b/docs/en_us/configuration/server_data_conf/cluster_conf.data.md @@ -29,7 +29,7 @@ BackendConf is config for backend. | MaxIdleConnsPerHost | Int
Max idle connections to each backend per BFE. Default value is 2. | | MaxConnsPerHost | Int
Max number of concurrent connections to each backend per BFE. 0 means no limitation. Default value is 0. | | RetryLevel | Int
Retry level if request fail. 0: retry after connecting backend fails; 1: retry after connecting backend fails or forwarding GET request fails. Default value is 0. | -| BackendConf.OutlierDetectionHttpCode | String
Backend HTTP status code outlier detection.
"" means disable detection, "500" means "500" is considered as backend failure.
Supports two formats: "\[0-9\]{3}"(e.g "500"), and "\[0-9\]xx"(e.g "4xx"). Multiple status codes are seperated by "\|".
Default value is "", which means disable the detection. | +| BackendConf.OutlierDetectionHttpCode | String
Backend HTTP status code outlier detection.
"" means disable detection, "500" means "500" is considered as backend failure.
Supports two formats: "\[0-9\]{3}"(e.g "500"), and "\[0-9\]xx"(e.g "4xx"). Multiple status codes are separated by "\|".
Default value is "", which means disable the detection. | | FCGIConf | Object
Conf for FastCGI Protocol | | FCGIConf.Root | String
The root folder of the website | | FCGIConf.EnvVars | Map\[string\]string
Extra environment variable | diff --git a/docs/en_us/example/redirect.md b/docs/en_us/example/redirect.md index 0e495368d..7f9ccb4b2 100644 --- a/docs/en_us/example/redirect.md +++ b/docs/en_us/example/redirect.md @@ -47,4 +47,4 @@ DataPath = mod_redirect/redirect.data curl -H "host: example.org" "http://127.1:8080/test" ``` -The repsonse stuatus code should be 301, and the value of Location response Header should be "https://example.org/test". +The response stuatus code should be 301, and the value of Location response Header should be "https://example.org/test". diff --git a/docs/en_us/modules/mod_wasmplugin/mod_wasmplugin.md b/docs/en_us/modules/mod_wasmplugin/mod_wasmplugin.md new file mode 100644 index 000000000..1ffaf7171 --- /dev/null +++ b/docs/en_us/modules/mod_wasmplugin/mod_wasmplugin.md @@ -0,0 +1,89 @@ +# mod_wasmplugin + +## Introduction + +Bfe supports calling user-defined wasm plugins (following the proxy-wasm specification, /~https://github.com/proxy-wasm/spec) in the processing flow of http request/response. +The mod_wasmplugin module is responsible for running wasm plugins and invoking them according to user-defined rules.。 + +## Module Configuration + +### Description + +conf/mod_wasm/mod_wasm.conf + +| Config Item | Description | +| ---------------------| ------------------------------------------- | +| Basic.DataPath | String
Path of rule configuration | +| Basic.WasmPluginPath | String
Folder path for storing wasm plugin files | +| Log.OpenDebug | Boolean
Debug flag of module
Default value: `False` | + +### Example + +```ini +[Basic] +DataPath = mod_wasm/mod_wasm.data +WasmPluginPath=wasm_plugin/ +``` + +## Rule Configuration + +### Description + +| Config Item | Description | +| ------- | -------------------------------------------------------------- | +| Version | String
Version of config file | +| BeforeLocationRules | Object
List of wasm plugin rules for the HandleBeforeLocation callback point | +| BeforeLocationRules[] | Object
A rule | +| BeforeLocationRules[].Cond | String
Condition expression, See [Condition](../../condition/condition_grammar.md) | +| BeforeLocationRules[].PluginList | Object
List of wasm plugins to invoke when the condition is matched | +| BeforeLocationRules[].PluginList[] | String
Name of the wasm plugin | +| ProductRules | Object
Wasm plugin rules for each product | +| ProductRules{k} | String
Product name | +| ProductRules{v} | Object
List of wasm plugin rules | +| ProductRules{v}[] | Object
A rule | +| ProductRules{v}[].Cond | String
Condition expression, See [Condition](../../condition/condition_grammar.md) | +| ProductRules{v}[].PluginList | Object
List of wasm plugins to invoke when the condition is matched | +| ProductRules{v}[].PluginList[] | String
Name of the wasm plugin | +| PluginMap | Object
Dictionary of wasm plugins | +| PluginMap{k} | String
Name of the wasm plugin | +| PluginMap{v} | Object
A wasm plugin | +| PluginMap{v}.Name | String
Name of the wasm plugin | +| PluginMap{v}.WasmVersion | String
Version of the wasm file | +| PluginMap{v}.ConfVersion | String
Version of the configuration file | +| PluginMap{v}.InstanceNum | Integer
Number of running instances of the wasm plugin | + +### Example + +```json +{ + "Version": "20240101000000", + "BeforeLocationRules": [{ + "Cond": "req_path_prefix_in(\"/headers\", false)", + "PluginList": [ "headers" ] + }], + "ProductRules": { + "local_product": [{ + "Cond": "default_t()", + "PluginList": [] + }] + }, + "PluginMap": { + "headers": { + "Name": "headers", + "WasmVersion": "20240101000000", + "ConfVersion": "20240101000000", + "InstanceNum": 20 + } + } +} +``` + +## Wasm Plugin Files + +For any wasm plugin (with name `PlugName` for example) in the PluginMap, the following files need to be prepared in advance and stored in the path: ``/`PlugName`/ + +| File Name | Description | +| ------- | -------------------------------------------------------------- | +| PlugName.wasm | wasm file | +| PlugName.md5 | md5 file of PlugName.wasm | +| PlugName.conf | Custom configuration file for the plugin | diff --git a/docs/en_us/operation/api.md b/docs/en_us/operation/api.md index c60b77c89..385c033c0 100644 --- a/docs/en_us/operation/api.md +++ b/docs/en_us/operation/api.md @@ -1,6 +1,6 @@ # Management API -BFE provides a set of management APIs for metrics exposing, configruation reloading, debugging and profiling etc. It should not publicly exposing the APIs, keeping them restricted to internal networks. +BFE provides a set of management APIs for metrics exposing, configurations reloading, debugging and profiling etc. It should not publicly exposing the APIs, keeping them restricted to internal networks. ## Configuration diff --git a/docs/en_us/operation/command.md b/docs/en_us/operation/command.md index ffef4f491..679a62e1f 100644 --- a/docs/en_us/operation/command.md +++ b/docs/en_us/operation/command.md @@ -30,4 +30,4 @@ Display verbose version information and exit. By default, this flag is set false * -h -Display help infomation and exit. By default, this flag is set false. +Display help information and exit. By default, this flag is set false. diff --git a/docs/mkdocs_en.yml b/docs/mkdocs_en.yml index 357fcd9a9..14d14c956 100644 --- a/docs/mkdocs_en.yml +++ b/docs/mkdocs_en.yml @@ -66,7 +66,7 @@ nav: - 'About': 'ABOUT.md' - 'Introduction': - 'Overview': 'introduction/overview.md' - - 'Comparsion to similar systems': 'introduction/comparison.md' + - 'Comparison to similar systems': 'introduction/comparison.md' - 'Design overview': - 'Terminology': 'introduction/terminology.md' - 'Traffic fowarding model': 'introduction/forward_model.md' @@ -127,6 +127,7 @@ nav: - 'mod_rewrite': 'modules/mod_rewrite/mod_rewrite.md' - 'mod_static': 'modules/mod_static/mod_static.md' - 'mod_tag': 'modules/mod_tag/mod_tag.md' + - 'mod_tcp_keepalive': 'modules/mod_tcp_keepalive/mod_tcp_keepalive.md' - 'mod_trace': 'modules/mod_trace/mod_trace.md' - 'mod_trust_clientip': 'modules/mod_trust_clientip/mod_trust_clientip.md' - 'mod_userid': 'modules/mod_userid/mod_userid.md' @@ -188,6 +189,7 @@ nav: - 'Cookie': 'condition/request/cookie.md' - 'Tag': 'condition/request/tag.md' - 'IP': 'condition/request/ip.md' + - 'Context': 'condition/request/context.md' - 'Response related primitives': - 'Code': 'condition/response/code.md' - 'Header': 'condition/response/header.md' diff --git a/docs/mkdocs_zh.yml b/docs/mkdocs_zh.yml index 72ff8d18a..073136fce 100644 --- a/docs/mkdocs_zh.yml +++ b/docs/mkdocs_zh.yml @@ -127,6 +127,7 @@ nav: - 'mod_rewrite': 'modules/mod_rewrite/mod_rewrite.md' - 'mod_static': 'modules/mod_static/mod_static.md' - 'mod_tag': 'modules/mod_tag/mod_tag.md' + - 'mod_tcp_keepalive': 'modules/mod_tcp_keepalive/mod_tcp_keepalive.md' - 'mod_trace': 'modules/mod_trace/mod_trace.md' - 'mod_trust_clientip': 'modules/mod_trust_clientip/mod_trust_clientip.md' - 'mod_userid': 'modules/mod_userid/mod_userid.md' @@ -188,6 +189,7 @@ nav: - 'Cookie': 'condition/request/cookie.md' - 'Tag': 'condition/request/tag.md' - 'IP': 'condition/request/ip.md' + - 'Context': 'condition/request/context.md' - '响应相关条件原语': - 'Code': 'condition/response/code.md' - 'Header': 'condition/response/header.md' diff --git a/docs/zh_cn/DOWNLOAD.md b/docs/zh_cn/DOWNLOAD.md index 14f06ca29..6155d58b4 100644 --- a/docs/zh_cn/DOWNLOAD.md +++ b/docs/zh_cn/DOWNLOAD.md @@ -1,5 +1,27 @@ BFE提供预编译二进制文件供下载。也可在GitHub下载各平台[最新版本BFE](/~https://github.com/bfenetworks/bfe/releases)。 +## bfe v1.6.0 + +* 2022-10-25 [发布说明](/~https://github.com/bfenetworks/bfe/releases/tag/v1.6.0) + +| 文件名 | 操作系统 | 平台 | 大小 | SHA256检验和 | +| --------- | -------- | ---- | ---- | ------------ | +| [bfe_1.6.0_darwin_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.6.0/bfe_1.6.0_darwin_amd64.tar.gz) | darwin | amd 64 | 9.3M | 61c8c5cab55c2b0ae7a5a0c027559efceddf58924fec7ff7dc9342e9ae8800e6 | +| [bfe_1.6.0_linux_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.6.0/bfe_1.6.0_linux_amd64.tar.gz) | linux | amd64 | 9.56 MB | 26510e09a7da8618e860beb58823b12b4305bf83a48fde4d09fae5f5c4d18aba | +| [bfe_1.6.0_linux_arm64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.6.0/bfe_1.6.0_linux_arm64.tar.gz) | linux | arm64 | 8.84 MB | 135d3d8f45612633958df923a876b5481ca5d4221f3d997de952cfd797ccd77e | +| [bfe_1.6.0_windows_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.6.0/bfe_1.6.0_windows_amd64.tar.gz) | windows | amd64 | 9.64 MB | 31e331335c87c2c44faf6dce915a53f5b7fada6c1925580ee2e19db6933fe450 | + +## bfe v1.5.0 + +* 2022-01-11 [发布说明](/~https://github.com/bfenetworks/bfe/releases/tag/v1.5.0) + +| 文件名 | 操作系统 | 平台 | 大小 | SHA256检验和 | +| --------- | -------- | ---- | ---- | ------------ | +| [bfe_1.5.0_darwin_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.5.0/bfe_1.5.0_darwin_amd64.tar.gz) | darwin | amd 64 | 9.29M | accf8ccebaf98ab38028f7beb8c4da0825a7c62976063bd844cebeb2d57760b0 | +| [bfe_1.5.0_linux_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.5.0/bfe_1.5.0_linux_amd64.tar.gz) | linux | amd64 | 9.55 MB | a74818d26462995b4f79c72184bee005c3aa161d9cb7af42b41d18791733336d | +| [bfe_1.5.0_linux_arm64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.5.0/bfe_1.5.0_linux_arm64.tar.gz) | linux | arm64 | 8.83 MB | d9ee8877c679d2b7af2d1fa60cd4a498bc252c5832df0f8ced771cae1d36fa58 | +| [bfe_1.5.0_windows_amd64.tar.gz](/~https://github.com/bfenetworks/bfe/releases/download/v1.5.0/bfe_1.5.0_windows_amd64.tar.gz) | windows | amd64 | 9.63 MB | a9f54df2a2374bf53ba6ad1d728f82a27f2b2c8aaa6ae854141c58105a905992 | + ## bfe v1.4.0 * 2021-12-10 [发布说明](/~https://github.com/bfenetworks/bfe/releases/tag/v1.4.0) diff --git a/docs/zh_cn/SUMMARY.md b/docs/zh_cn/SUMMARY.md index b80e52c08..792126aeb 100644 --- a/docs/zh_cn/SUMMARY.md +++ b/docs/zh_cn/SUMMARY.md @@ -64,6 +64,7 @@ * [mod_trust_clientip](modules/mod_trust_clientip/mod_trust_clientip.md) * [mod_userid](modules/mod_userid/mod_userid.md) * [mod_secure_link](modules/mod_secure_link/mod_secure_link.md) + * [mod_wasmplugin](modules/mod_wasmplugin/mod_wasmplugin.md) * 运维管理 * [命令行工具及参数](operation/command.md) * [环境变量说明](operation/env_var.md) diff --git a/docs/zh_cn/configuration/bfe.conf.md b/docs/zh_cn/configuration/bfe.conf.md index d79ac39c3..d8a18d17c 100644 --- a/docs/zh_cn/configuration/bfe.conf.md +++ b/docs/zh_cn/configuration/bfe.conf.md @@ -170,7 +170,7 @@ CipherSuites=TLS_RSA_WITH_RC4_128_SHA CipherSuites=TLS_RSA_WITH_AES_128_CBC_SHA CipherSuites=TLS_RSA_WITH_AES_256_CBC_SHA -# supported curve perference settings +# supported curve preference settings # # curves implemented in golang: # CurveP256 diff --git a/docs/zh_cn/modules/mod_wasmplugin/mod_wasmplugin.md b/docs/zh_cn/modules/mod_wasmplugin/mod_wasmplugin.md new file mode 100644 index 000000000..11fb41f36 --- /dev/null +++ b/docs/zh_cn/modules/mod_wasmplugin/mod_wasmplugin.md @@ -0,0 +1,88 @@ +# mod_wasmplugin + +## 模块简介 + +Bfe 支持在 http request/response 的处理流程中引入用户自定义的 wasm插件 (遵循 proxy-wasm 规范, /~https://github.com/proxy-wasm/spec)。 +mod_wasmplugin 负责运行 wasm插件,并根据自定义规则调用 wasm插件。 + +## 基础配置 + +### 配置描述 + +模块配置文件: conf/mod_wasm/mod_wasm.conf + +| 配置项 | 描述 | +| ---------------------| ------------------------------------------- | +| Basic.DataPath | String
wasm插件规则配置的文件路径 | +| Basic.WasmPluginPath | String
存放wasm插件文件的文件夹路径 | +| Log.OpenDebug | Boolean
是否开启 debug 日志
默认值False | + +### 配置示例 + +```ini +[Basic] +DataPath = mod_wasm/mod_wasm.data +WasmPluginPath=wasm_plugin/ +``` + +## wasm插件规则配置 + +### 配置描述 + +| 配置项 | 描述 | +| ------- | -------------------------------------------------------------- | +| Version | String
配置文件版本 | +| BeforeLocationRules | Object
HandleBeforeLocation 回调点的 wasm插件规则列表 | +| BeforeLocationRules[] | Object
wasm插件规则详细信息 | +| BeforeLocationRules[].Cond | String
描述匹配请求或连接的条件, 语法详见[Condition](../../condition/condition_grammar.md) | +| BeforeLocationRules[].PluginList | Object
条件匹配时执行的wasm插件列表 | +| BeforeLocationRules[].PluginList[] | String
wasm插件名 | +| ProductRules | Object
各产品线的 wasm插件规则列表 | +| ProductRules{k} | String
产品线名称 | +| ProductRules{v} | Object
产品线下的 wasm插件规则列表 | +| ProductRules{v}[] | Object
wasm插件规则详细信息 | +| ProductRules{v}[].Cond | String
描述匹配请求或连接的条件, 语法详见[Condition](../../condition/condition_grammar.md) | +| ProductRules{v}[].PluginList | Object
条件匹配时执行的wasm插件列表 | +| ProductRules{v}[].PluginList[] | String
wasm插件名 | +| PluginMap | Object
wasm插件字典 | +| PluginMap{k} | String
wasm插件名 | +| PluginMap{v} | Object
wasm插件详细信息 | +| PluginMap{v}.Name | String
wasm插件名 | +| PluginMap{v}.WasmVersion | String
wasm插件文件版本 | +| PluginMap{v}.ConfVersion | String
wasm插件配置文件版本 | +| PluginMap{v}.InstanceNum | Integer
wasm插件运行实例数 | + +### 配置示例 + +```json +{ + "Version": "20240101000000", + "BeforeLocationRules": [{ + "Cond": "req_path_prefix_in(\"/headers\", false)", + "PluginList": [ "headers" ] + }], + "ProductRules": { + "local_product": [{ + "Cond": "default_t()", + "PluginList": [] + }] + }, + "PluginMap": { + "headers": { + "Name": "headers", + "WasmVersion": "20240101000000", + "ConfVersion": "20240101000000", + "InstanceNum": 20 + } + } +} +``` + +## wasm插件文件 + +对于 PluginMap 中的任意一个 wasm插件(名为`PlugName`),需要预先准备好以下文件,存放于路径: ``/`PlugName`/ +| 文件名 | 描述 | +| ------- | -------------------------------------------------------------- | +| PlugName.wasm | wasm 文件 | +| PlugName.md5 | PlugName.wasm 的 md5 文件 | +| PlugName.conf | 插件自定义配置文件 | diff --git a/go.mod b/go.mod index 04ee3e5fd..d1b2abf87 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,15 @@ module github.com/bfenetworks/bfe -go 1.17 +go 1.21 + +toolchain go1.22.2 require ( github.com/abbot/go-http-auth v0.4.1-0.20181019201920-860ed7f246ff - github.com/andybalholm/brotli v1.0.0 + github.com/andybalholm/brotli v1.0.2 github.com/armon/go-radix v1.0.0 github.com/asergeyev/nradix v0.0.0-20170505151046-3872ab85bb56 // indirect github.com/baidu/go-lib v0.0.0-20200819072111-21df249f5e6a - github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect github.com/golang-jwt/jwt v3.2.2+incompatible github.com/gomodule/redigo v2.0.0+incompatible github.com/json-iterator/go v1.1.12 @@ -22,25 +23,29 @@ require ( github.com/russross/blackfriday/v2 v2.0.1 github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/spaolacci/murmur3 v1.1.0 - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.9.0 github.com/tjfoc/gmsm v1.3.2 - github.com/uber/jaeger-client-go v2.22.1+incompatible - github.com/uber/jaeger-lib v2.2.0+incompatible + github.com/uber/jaeger-client-go v2.25.0+incompatible + github.com/uber/jaeger-lib v2.4.0+incompatible github.com/zmap/go-iptree v0.0.0-20170831022036-1948b1097e25 go.elastic.co/apm v1.11.0 go.elastic.co/apm/module/apmot v1.7.2 - go.uber.org/atomic v1.6.0 // indirect + go.uber.org/atomic v1.7.0 // indirect go.uber.org/automaxprocs v1.4.0 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 - golang.org/x/net v0.0.0-20211216030914-fe4d6282115f - golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e - golang.org/x/tools v0.1.8 // indirect + golang.org/x/crypto v0.25.0 + golang.org/x/net v0.25.0 + golang.org/x/sys v0.22.0 gopkg.in/gcfg.v1 v1.2.3 - gopkg.in/square/go-jose.v2 v2.4.1 gopkg.in/warnings.v0 v0.1.2 // indirect ) require ( + github.com/bfenetworks/proxy-wasm-go-host v0.0.0-20241202144118-62704e5df808 + github.com/go-jose/go-jose/v4 v4.0.4 +) + +require ( + github.com/HdrHistogram/hdrhistogram-go v1.0.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/elastic/go-sysinfo v1.1.1 // indirect @@ -48,18 +53,20 @@ require ( github.com/gorilla/css v1.0.0 // indirect github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect - github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect github.com/oschwald/maxminddb-golang v1.6.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/procfs v0.0.3 // indirect + github.com/prometheus/procfs v0.2.0 // indirect github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect + github.com/tetratelabs/wazero v1.2.1 // indirect go.elastic.co/apm/module/apmhttp v1.7.2 // indirect go.elastic.co/fastjson v1.1.0 // indirect - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/text v0.3.7 // indirect - google.golang.org/grpc v1.22.1 // indirect + golang.org/x/text v0.16.0 // indirect + google.golang.org/grpc v1.56.3 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect ) + +// replace github.com/bfenetworks/proxy-wasm-go-host => ../proxy-wasm-go-host diff --git a/go.sum b/go.sum index 53d5a12f5..6532d8530 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,13 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/HdrHistogram/hdrhistogram-go v1.0.1 h1:GX8GAYDuhlFQnI2fRDHQhTlkHMz8bEn0jTI6LJU0mpw= +github.com/HdrHistogram/hdrhistogram-go v1.0.1/go.mod h1:BWJ+nMSHY3L41Zj7CA3uXnloDp7xxV0YvstAE7nKTaM= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/abbot/go-http-auth v0.4.1-0.20181019201920-860ed7f246ff h1:9ZqcMQ0fB+ywKACVjGfZM4C7Uq9D5rq0iSmwIjX187k= github.com/abbot/go-http-auth v0.4.1-0.20181019201920-860ed7f246ff/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM= -github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4= -github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asergeyev/nradix v0.0.0-20170505151046-3872ab85bb56 h1:Wi5Tgn8K+jDcBYL+dIMS1+qXYH2r7tpRAyBgqrWfQtw= @@ -14,9 +16,10 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/baidu/go-lib v0.0.0-20200819072111-21df249f5e6a h1:m/u39GNhkoUSC9WxTuM5hWShEqEfVioeXDiqiQd6tKg= github.com/baidu/go-lib v0.0.0-20200819072111-21df249f5e6a/go.mod h1:FneHDqz3wLeDGdWfRyW4CzBbCwaqesLGIFb09N80/ww= +github.com/bfenetworks/proxy-wasm-go-host v0.0.0-20241202144118-62704e5df808 h1:v0ckUMaZJFe8XvoM9x3kn+lDtMfI9EvpFadiOiV/s8A= +github.com/bfenetworks/proxy-wasm-go-host v0.0.0-20241202144118-62704e5df808/go.mod h1:VG3ZZ8Zg7dYkla2hHy9UsX0GLl/dgJYP4IxuPvoq+/U= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cucumber/godog v0.8.1 h1:lVb+X41I4YDreE+ibZ50bdXmySxgRviYFgKY6Aw4XE8= github.com/cucumber/godog v0.8.1/go.mod h1:vSh3r/lM+psC1BPXvdkSEuNjmXfpVqrMGYAElF6hxnA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -31,6 +34,8 @@ github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7 github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= +github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= @@ -43,8 +48,10 @@ github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNu github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= @@ -60,20 +67,24 @@ github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8 github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/microcosm-cc/bluemonday v1.0.16 h1:kHmAq2t7WPWLjiGvzKa5o3HzSfahUKiOq7fAPUiMNIc= github.com/microcosm-cc/bluemonday v1.0.16/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg= github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -99,9 +110,12 @@ github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6J github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis= @@ -112,18 +126,22 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tetratelabs/wazero v1.2.1 h1:J4X2hrGzJvt+wqltuvcSjHQ7ujQxA9gb6PeMs4qlUWs= +github.com/tetratelabs/wazero v1.2.1/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ= github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= -github.com/uber/jaeger-client-go v2.22.1+incompatible h1:NHcubEkVbahf9t3p75TOCR83gdUHXjRJvjoBh1yACsM= -github.com/uber/jaeger-client-go v2.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw= -github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/uber/jaeger-client-go v2.25.0+incompatible h1:IxcNZ7WRY1Y3G4poYlx24szfsn/3LvK9QHCq9oQw8+U= +github.com/uber/jaeger-client-go v2.25.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.4.0+incompatible h1:fY7QsGQWiCt8pajv4r7JEvmATdCVaWxXbjwyYwsNaLQ= +github.com/uber/jaeger-lib v2.4.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zmap/go-iptree v0.0.0-20170831022036-1948b1097e25 h1:LRoXAcKX48QV4LV23W5ZtsG/MbJOgNUNvWiXwM0iLWw= github.com/zmap/go-iptree v0.0.0-20170831022036-1948b1097e25/go.mod h1:qOasALtPByO1Jk6LhgpNv6htPMK2QJfiGorUk57nO/U= go.elastic.co/apm v1.7.2/go.mod h1:tCw6CkOJgkWnzEthFN9HUP1uL3Gjc/Ur6m7gRPLaoH0= @@ -136,21 +154,18 @@ go.elastic.co/apm/module/apmot v1.7.2/go.mod h1:VD2nUkebUPrP1hqIarimIEsoM9xyuK0l go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs= go.elastic.co/fastjson v1.1.0 h1:3MrGBWWVIxe/xvsbpghtkFoPciPhOCmjsR/HfwEeQR4= go.elastic.co/fastjson v1.1.0/go.mod h1:boNGISWMjQsUPy/t6yqt2/1Wx4YNPSe+mZjlyw9vKKI= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0= go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -159,17 +174,16 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -177,26 +191,23 @@ golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -204,16 +215,17 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= -google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3 h1:m8OOJ4ccYHnx2f4gQwpno8nAX5OGOh7RLaaz0pj3Ogs= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/square/go-jose.v2 v2.4.1 h1:H0TmLt7/KmzlrDOpa1F+zr0Tk90PbJYBfsVUmRLrf9Y= -gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=