feat: add sni-misdirect plugin for go (#720)

Signed-off-by: sjcsjc123 <1401189096@qq.com>
This commit is contained in:
SJC
2023-12-25 14:52:55 +08:00
committed by GitHub
parent 688247f4f9
commit c647ab3a08
6 changed files with 275 additions and 0 deletions

View File

@@ -0,0 +1 @@
1.0.0

View File

@@ -0,0 +1,14 @@
module wasm_go/higress/plugins/wasm-go/extensions/sni_misdirect
go 1.19
require (
github.com/alibaba/higress/plugins/wasm-go v1.3.1
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0
github.com/google/uuid v1.3.0 // indirect
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 // indirect
github.com/magefile/mage v1.14.0 // indirect
github.com/tidwall/gjson v1.14.3 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
)

View File

@@ -0,0 +1,20 @@
github.com/alibaba/higress/plugins/wasm-go v1.3.1 h1:d+t4W2NyqmqUz6DPZENflODfkLgdVlTfyso+nq0fSkg=
github.com/alibaba/higress/plugins/wasm-go v1.3.1/go.mod h1:WZ/68vwe8qWhusa6C4/gMwUqas0jvHWSOa1bp8iK8F4=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520 h1:IHDghbGQ2DTIXHBHxWfqCYQW1fKjyJ/I7W1pMyUDeEA=
github.com/higress-group/nottinygc v0.0.0-20231101025119-e93c4c2f8520/go.mod h1:Nz8ORLaFiLWotg6GeKlJMhv8cci8mM43uEnLA5t8iew=
github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0 h1:kS7BvMKN+FiptV4pfwiNX8e3q14evxAWkhYbxt8EI1M=
github.com/tetratelabs/proxy-wasm-go-sdk v0.22.0/go.mod h1:qkW5MBz2jch2u8bS59wws65WC+Gtx3x0aPUX5JL7CXI=
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -0,0 +1,94 @@
package main
import (
"strings"
"github.com/alibaba/higress/plugins/wasm-go/pkg/wrapper"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
)
func main() {
wrapper.SetCtx(
"sni-misdirect",
wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders),
)
}
type Config struct {
}
func onHttpRequestHeaders(ctx wrapper.HttpContext, config Config, log wrapper.Log) types.Action {
// no need to check HTTP/1.0 and HTTP/1.1
protocol, err := proxywasm.GetProperty([]string{"request", "protocol"})
if err != nil {
log.Errorf("failed to get request protocol: %v", err)
return types.ActionContinue
}
if strings.HasPrefix(string(protocol), "HTTP/1") {
return types.ActionContinue
}
// no need to check http scheme
scheme := ctx.Scheme()
if scheme != "https" {
return types.ActionContinue
}
// no need to check grpc
contentType, err := proxywasm.GetHttpRequestHeader("content-type")
if err != nil {
log.Errorf("failed to get request content-type: %v", err)
return types.ActionContinue
}
if strings.HasPrefix(contentType, "application/grpc") {
return types.ActionContinue
}
// get sni
sni, err := proxywasm.GetProperty([]string{"connection", "requested_server_name"})
if err != nil {
log.Errorf("failed to get requested_server_name: %v", err)
return types.ActionContinue
}
// get authority
host, err := proxywasm.GetHttpRequestHeader(":authority")
if err != nil {
log.Errorf("failed to get request authority: %v", err)
return types.ActionContinue
}
host = stripPortFromHost(host)
if string(sni) == host {
return types.ActionContinue
}
if !strings.HasPrefix(string(sni), "*.") {
proxywasm.SendHttpResponse(421, nil, []byte("Misdirected Request"), -1)
return types.ActionPause
}
if !strings.Contains(host, string(sni)[1:]) {
proxywasm.SendHttpResponse(421, nil, []byte("Misdirected Request"), -1)
return types.ActionPause
}
return types.ActionContinue
}
func stripPortFromHost(requestHost string) string {
// Find the last occurrence of ':' to locate the port.
portStart := strings.LastIndex(requestHost, ":")
// Check if ':' is found.
if portStart != -1 {
// According to RFC3986, IPv6 address is always enclosed in "[]".
// section 3.2.2.
v6EndIndex := strings.LastIndex(requestHost, "]")
// Check if ']' is found and its position is after the ':'.
if v6EndIndex == -1 || v6EndIndex < portStart {
// Check if there are characters after ':'.
if portStart+1 <= len(requestHost) {
// Return the substring without the port.
return requestHost[:portStart]
}
}
}
// If no port is found or the conditions are not met, return the original requestHost.
return requestHost
}