diff options
Diffstat (limited to 'tunnel/tools/libwg-go')
-rw-r--r-- | tunnel/tools/libwg-go/.gitignore | 3 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/Makefile | 35 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/api-android.go | 34 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/dhcp.go | 248 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/go.mod | 16 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/go.sum | 197 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/goruntime-boottime-over-monotonic.diff | 16 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/http-proxy.go | 702 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/jni.c | 13 | ||||
-rw-r--r-- | tunnel/tools/libwg-go/service.go | 246 |
10 files changed, 1489 insertions, 21 deletions
diff --git a/tunnel/tools/libwg-go/.gitignore b/tunnel/tools/libwg-go/.gitignore index d1638636..d69ee823 100644 --- a/tunnel/tools/libwg-go/.gitignore +++ b/tunnel/tools/libwg-go/.gitignore @@ -1 +1,2 @@ -build/
\ No newline at end of file +build/ +/gen/ diff --git a/tunnel/tools/libwg-go/Makefile b/tunnel/tools/libwg-go/Makefile index a2aefef7..ba3ab19e 100644 --- a/tunnel/tools/libwg-go/Makefile +++ b/tunnel/tools/libwg-go/Makefile @@ -19,13 +19,21 @@ export CC := $(ANDROID_C_COMPILER) export GOARCH := $(NDK_GO_ARCH_MAP_$(ANDROID_ARCH_NAME)) export GOOS := android export CGO_ENABLED := 1 +export GOPATH ?= $(HOME)/go -GO_VERSION := 1.18.2 +GO_VERSION := 1.19.5 GO_PLATFORM := $(shell uname -s | tr '[:upper:]' '[:lower:]')-$(NDK_GO_ARCH_MAP_$(shell uname -m)) GO_TARBALL := go$(GO_VERSION).$(GO_PLATFORM).tar.gz -GO_HASH_darwin-amd64 := 1f5f539ce0baa8b65f196ee219abf73a7d9cf558ba9128cc0fe4833da18b04f2 -GO_HASH_darwin-arm64 := 6c7df9a2405f09aa9bab55c93c9c4ce41d3e58127d626bc1825ba5d0a0045d5c -GO_HASH_linux-amd64 := e54bec97a1a5d230fc2f9ad0880fcbabb5888f30ed9666eca4a91c5a32e86cbc +GO_HASH_darwin-amd64 := 03e8323f63043d13c309a4ebbfc0b0e6c65b835ad4384b445f1a0c39d2c335d7 +GO_HASH_darwin-arm64 := 4fbbf81242a1c6cdd7e505684c12422570b9c628108d021d4354fed07d79d443 +GO_HASH_linux-amd64 := 36519702ae2fd573c9869461990ae550c8c0d955cd28d2827a6b159fda81ff95 + +PROTOC_VERSION := 3.20.1 +PROTOC_GEN_GO := $(GOPATH)/bin/protoc-gen-go +PROTOC := $(GRADLE_USER_HOME)/caches/protoc-$(PROTOC_VERSION)/protoc +PROTODIR = $(CURDIR)/../../src/main/proto +PROTO_INCLUDEDIR = $(CURDIR)/../../build/extracted-include-protos/debug +PBDIR = $(GOPATH)/pkg/mod default: $(DESTDIR)/libwg-go.so @@ -45,8 +53,25 @@ $(BUILDDIR)/go-$(GO_VERSION)/.prepared: $(GRADLE_USER_HOME)/caches/golang/$(GO_T patch -p1 -f -N -r- -d "$(dir $@)" < goruntime-boottime-over-monotonic.diff && \ touch "$@"' +$(PROTOC_GEN_GO): export GOARCH := +$(PROTOC_GEN_GO): export GOOS := +$(PROTOC_GEN_GO): export PATH := $(BUILDDIR)/go-$(GO_VERSION)/bin/:$(PATH) +$(PROTOC_GEN_GO): $(BUILDDIR)/go-$(GO_VERSION)/.prepared Makefile + go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 + go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2 + +gen/%.pb.go: export PATH := $(GOPATH)/bin:$(PATH) +gen/%.pb.go: $(PROTODIR)/%.proto $(BUILDDIR)/go-$(GO_VERSION)/.prepared $(PROTOC_GEN_GO) + test -d gen || mkdir gen + $(PROTOC) -I $(PROTODIR) -I $(PROTO_INCLUDEDIR) --go_out=paths=source_relative:./gen $< + +gen/%_grpc.pb.go: export PATH := $(GOPATH)/bin:$(PATH) +gen/%_grpc.pb.go: $(PROTODIR)/%.proto $(BUILDDIR)/go-$(GO_VERSION)/.prepared $(PROTOC_GEN_GO) + test -d gen || mkdir gen + $(PROTOC) -I $(PROTODIR) -I $(PROTO_INCLUDEDIR) --go-grpc_out=./gen --go-grpc_opt=paths=source_relative $< + $(DESTDIR)/libwg-go.so: export PATH := $(BUILDDIR)/go-$(GO_VERSION)/bin/:$(PATH) -$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(GO_VERSION)/.prepared go.mod +$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(GO_VERSION)/.prepared go.mod api-android.go http-proxy.go service.go gen/libwg.pb.go gen/libwg_grpc.pb.go jni.c go build -tags linux -ldflags="-X golang.zx2c4.com/wireguard/ipc.socketDirectory=/data/data/$(ANDROID_PACKAGE_NAME)/cache/wireguard" -v -trimpath -o "$@" -buildmode c-shared .DELETE_ON_ERROR: diff --git a/tunnel/tools/libwg-go/api-android.go b/tunnel/tools/libwg-go/api-android.go index d47c5d76..0ab80be9 100644 --- a/tunnel/tools/libwg-go/api-android.go +++ b/tunnel/tools/libwg-go/api-android.go @@ -48,10 +48,16 @@ func (l AndroidLogger) Printf(format string, args ...interface{}) { type TunnelHandle struct { device *device.Device uapi net.Listener + logger *device.Logger } var tunnelHandles map[int32]TunnelHandle +func GetTunnel(handle int32) (tunnelHandle TunnelHandle, ok bool) { + tunnelHandle, ok = tunnelHandles[handle] + return +} + func init() { tunnelHandles = make(map[int32]TunnelHandle) signals := make(chan os.Signal) @@ -208,20 +214,40 @@ func wgGetConfig(tunnelHandle int32) *C.char { //export wgVersion func wgVersion() *C.char { + return C.CString(Version()) +} + +func Version() string { info, ok := debug.ReadBuildInfo() if !ok { - return C.CString("unknown") + return "unknown" } for _, dep := range info.Deps { if dep.Path == "golang.zx2c4.com/wireguard" { parts := strings.Split(dep.Version, "-") if len(parts) == 3 && len(parts[2]) == 12 { - return C.CString(parts[2][:7]) + return parts[2][:7] } - return C.CString(dep.Version) + return dep.Version } } - return C.CString("unknown") + return "unknown" +} + +//export wgStartGrpc +func wgStartGrpc(sock_path string) C.int{ + tag := cstring("WireGuard/GoBackend/gRPC") + logger := &device.Logger{ + Verbosef: AndroidLogger{level: C.ANDROID_LOG_DEBUG, tag: tag}.Printf, + Errorf: AndroidLogger{level: C.ANDROID_LOG_ERROR, tag: tag}.Printf, + } + + res, errmsg := StartGrpc(sock_path, logger) + if res < 0 { + logger.Verbosef("wgStartGrpc: %v (%v)", errmsg, res) + } + + return C.int(res) } func main() {} diff --git a/tunnel/tools/libwg-go/dhcp.go b/tunnel/tools/libwg-go/dhcp.go new file mode 100644 index 00000000..70a95f27 --- /dev/null +++ b/tunnel/tools/libwg-go/dhcp.go @@ -0,0 +1,248 @@ +package main + +import ( + "context" + "fmt" + "log" + "net" + "net/netip" + + "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv6" + "github.com/insomniacslk/dhcp/dhcpv6/nclient6" + "github.com/insomniacslk/dhcp/iana" +) + +const ( + ENABLE_PD = false + //ENABLE_PD = true + ENABLE_TA = false + //ENABLE_TA = true + //ENABLE_4O6 = false + ENABLE_4O6 = true +) + +func withDHCPv4Msg(msg *dhcpv4.DHCPv4) dhcpv6.Modifier { + return func(d dhcpv6.DHCPv6) { + opt := dhcpv6.OptDHCPv4Msg{ + Msg: msg, + } + d.UpdateOption(&opt) + } +} + +func newDHCPv4Query(flags uint32, modifiers ...dhcpv6.Modifier) (*dhcpv6.Message, error) { + msg, err := dhcpv6.NewMessage() + if err != nil { + return nil, err + } + msg.MessageType = dhcpv6.MessageTypeDHCPv4Query + msg.TransactionID = dhcpv6.TransactionID{byte(flags >> 16), byte(flags >> 8), byte(flags)} + //msg.AddOption(dhcpv6.OptElapsedTime(0)) + + for _, mod := range modifiers { + mod(msg) + } + return msg, nil +} + +// type DHCPv4o6Client struct { +// nclient4.Client +// } + +func dhcpv4Query(ctx context.Context, client *nclient6.Client, dest *net.UDPAddr, msg *dhcpv4.DHCPv4) (*dhcpv4.DHCPv4, error) { + query, err := newDHCPv4Query(0x800000, withDHCPv4Msg(msg)) + if err != nil { + return nil, err + } + + resp, err := client.SendAndRead(ctx, dest, query, nil) + if err != nil { + return nil, err + } + + msgOpt := resp.GetOneOption(dhcpv6.OptionDHCPv4Msg) + if msgOpt == nil { + return nil, fmt.Errorf("Missing DHCPv4Msg option in response") + } + + offer := msgOpt.(*dhcpv6.OptDHCPv4Msg).Msg + return offer, nil +} + +func newClientIDOpt(duid *dhcpv6.Duid) dhcpv4.Option { + iaid := []byte{0, 0, 0, 3} + ident := []byte{255} // Type IAID+DUID + ident = append(ident, iaid...) // IAID + ident = append(ident, duid.ToBytes()...) // DUID + return dhcpv4.OptClientIdentifier(ident) +} + +func runDhcp4o6(ctx context.Context, client *nclient6.Client, v4o6 *dhcpv6.OptDHCP4oDHCP6Server, duid *dhcpv6.Duid, hwAddr net.HardwareAddr, hostName string) (*netip.Prefix, error) { + serverAddr := nclient6.AllDHCPRelayAgentsAndServers + if len(v4o6.DHCP4oDHCP6Servers) > 0 { + // TODO use all servers + serverAddr = &net.UDPAddr{ + IP: v4o6.DHCP4oDHCP6Servers[0], + Port: dhcpv6.DefaultServerPort, + } + } + + modHostName := dhcpv4.WithGeneric(dhcpv4.OptionHostName, []byte(hostName)) + disc, err := dhcpv4.NewDiscovery(hwAddr, dhcpv4.WithOption(newClientIDOpt(duid)), modHostName) + if err != nil { + return nil, err + } + offer, err := dhcpv4Query(ctx, client, serverAddr, disc) + if err != nil { + return nil, err + } + req, err := dhcpv4.NewRequestFromOffer(offer, modHostName) + if err != nil { + return nil, err + } + ack, err := dhcpv4Query(ctx, client, serverAddr, req) + if err != nil { + return nil, err + } + + // client.Close() + fmt.Println("doClient end", ack.YourIPAddr, ack.SubnetMask()) + if ip4 := ack.YourIPAddr.To4(); ip4 == nil { + return nil, fmt.Errorf("Not IPv4! %v", ack.YourIPAddr) + } else { + log.Println("IPv4", ip4) + } + + addr, _ := netip.AddrFromSlice(ack.YourIPAddr) + prefix := netip.PrefixFrom(addr, 32) // TODO use SubnetMask + log.Printf("Append %v", prefix) + return &prefix, nil +} + +func RunDhcp(ctx context.Context, conn *net.UDPConn, hwAddr net.HardwareAddr) ([]netip.Prefix, error) { + client, err := nclient6.NewWithConn(conn, hwAddr, nclient6.WithDebugLogger()) + if err != nil { + return nil, err + } + + duid := dhcpv6.Duid{ + Type: dhcpv6.DUID_LL, + HwType: iana.HWTypeEthernet, + LinkLayerAddr: hwAddr, + } + + hostName := "gvisor" + fqdn := hostName + ".m7n.se" + fqdnOpt := dhcpv6.WithFQDN(0x1, fqdn) + + solicitMods := []dhcpv6.Modifier{} + + if ENABLE_PD { + _, iaIPNet, err := net.ParseCIDR("::/64") + if err != nil { + return nil, err + } + iaPrefix := dhcpv6.OptIAPrefix{ + 0, 0, iaIPNet, dhcpv6.PrefixOptions{}, + } + solicitMods = append(solicitMods, dhcpv6.WithIAPD([4]byte{0, 0, 0, 1}, &iaPrefix)) + } + + if ENABLE_TA { + solicitMods = append(solicitMods, dhcpv6.WithIATA([4]byte{0, 0, 0, 1})) + } + + oro := dhcpv6.WithRequestedOptions(dhcpv6.OptionDHCP4oDHCP6Server, dhcpv6.OptionFQDN) + + solicitMods = append(solicitMods, dhcpv6.WithIAID([4]byte{0, 0, 0, 1})) + solicitMods = append(solicitMods, fqdnOpt) + solicitMods = append(solicitMods, dhcpv6.WithClientID(duid)) + solicitMods = append(solicitMods, oro) + + adv, err := client.Solicit(ctx, solicitMods...) + if err != nil { + return nil, err + } + + requestMods := []dhcpv6.Modifier{} + requestMods = append(requestMods, fqdnOpt) + requestMods = append(requestMods, oro) + + if ENABLE_TA { + // Add IA_TA from advertise which is not added by default. + withIaTa := func(req dhcpv6.DHCPv6) { + if iaTa := adv.GetOneOption(dhcpv6.OptionIATA); iaTa != nil { + req.AddOption(iaTa) + } + } + requestMods = append(requestMods, withIaTa) + } + + msg, err := client.Request(ctx, adv, requestMods...) + if err != nil { + return nil, err + } + + iana := msg.GetOneOption(dhcpv6.OptionIANA).(*dhcpv6.OptIANA) + ianaOpts := iana.Options.Get(dhcpv6.OptionIAAddr) + + var iapdOpts []dhcpv6.Option + + if ENABLE_PD { + iapd := msg.GetOneOption(dhcpv6.OptionIAPD).(*dhcpv6.OptIAPD) + iapdOpts = iapd.Options.Get(dhcpv6.OptionIAPrefix) + } + + addrs := make([]netip.Prefix, 0, len(ianaOpts)+len(iapdOpts)+1) + + opt4o6 := msg.GetOneOption(dhcpv6.OptionDHCP4oDHCP6Server) + if ENABLE_4O6 && opt4o6 != nil { + v4o6 := opt4o6.(*dhcpv6.OptDHCP4oDHCP6Server) + log.Println("dhcp4o6: ", v4o6) + + prefix, err := runDhcp4o6(ctx, client, v4o6, &duid, hwAddr, hostName) + if err == nil { + addrs = append(addrs, *prefix) + } else { + return nil, err + } + } + + for _, addr := range ianaOpts { + prefix := netip.PrefixFrom(netip.IPv6Unspecified(), 128) + ip, ok := netip.AddrFromSlice(addr.(*dhcpv6.OptIAAddress).IPv6Addr) + if ok { + prefix = netip.PrefixFrom(ip, 128) + } + + log.Printf("IANA %v", prefix) + addrs = append(addrs, prefix) + } + + for _, addr := range iapdOpts { + ipnet := addr.(*dhcpv6.OptIAPrefix).Prefix + addr, _ := netip.AddrFromSlice(ipnet.IP) // TODO use ok + prefixlen, _ := ipnet.Mask.Size() + prefix := netip.PrefixFrom(addr, prefixlen) + + log.Printf("IAPD %v", prefix) + addrs = append(addrs, prefix) + } + + opt := msg.GetOneOption(dhcpv6.OptionIATA) + if opt != nil { + iata := opt.(*dhcpv6.OptIATA) + taOpts := iata.Options.Get(dhcpv6.OptionIAAddr) + + for _, addr := range taOpts { + ip := addr.(*dhcpv6.OptIAAddress).IPv6Addr + addr, _ := netip.AddrFromSlice(ip) // TODO use ok + prefix := netip.PrefixFrom(addr, 128) + + log.Printf("IATA %v", prefix) + } + } + + return addrs, nil +} diff --git a/tunnel/tools/libwg-go/go.mod b/tunnel/tools/libwg-go/go.mod index e64d2fb1..19ee576f 100644 --- a/tunnel/tools/libwg-go/go.mod +++ b/tunnel/tools/libwg-go/go.mod @@ -1,14 +1,24 @@ module golang.zx2c4.com/wireguard/android -go 1.18 +go 1.19 require ( - golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a + github.com/elazarl/goproxy v0.0.0-20211114080932-d06c3be7c11b + golang.org/x/net v0.0.0-20220516155154-20f960328961 + golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d + google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84 + google.golang.org/protobuf v1.27.1 + gopkg.in/olebedev/go-duktape.v3 v3.0.0-20210326210528-650f7c854440 ) require ( + github.com/golang/protobuf v1.5.2 // indirect + github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8 // indirect + github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531 // indirect + github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect golang.org/x/crypto v0.0.0-20220516162934-403b01795ae8 // indirect - golang.org/x/net v0.0.0-20220516155154-20f960328961 // indirect + golang.org/x/text v0.3.7 // indirect golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect + google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect ) diff --git a/tunnel/tools/libwg-go/go.sum b/tunnel/tools/libwg-go/go.sum index 633bbf7a..19eb83b7 100644 --- a/tunnel/tools/libwg-go/go.sum +++ b/tunnel/tools/libwg-go/go.sum @@ -1,10 +1,207 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/elazarl/goproxy v0.0.0-20211114080932-d06c3be7c11b h1:1XqENn2YoYZd6w3Awx+7oa+aR87DFIZJFLF2n1IojA0= +github.com/elazarl/goproxy v0.0.0-20211114080932-d06c3be7c11b/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= +github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8 h1:Z72DOke2yOK0Ms4Z2LK1E1OrRJXOxSj5DllTz2FYTRg= +github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8/go.mod h1:m5WMe03WCvWcXjRnhvaAbAAXdCnu20J5P+mmH44ZzpE= +github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531 h1:3HNVAxEgGca1i23Ai/8DeCmibx02jBvTHAT11INaVfU= +github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= +github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= +github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= +github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= +github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= +github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= +github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= +github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= +github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/u-root/uio v0.0.0-20221213070652-c3537552635f h1:dpx1PHxYqAnXzbryJrWP1NQLzEjwcVgFLhkknuFQ7ww= +github.com/u-root/uio v0.0.0-20221213070652-c3537552635f/go.mod h1:IogEAUBXDEwX7oR/BMmCctShYs80ql4hF0ySdzGxf7E= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20220516162934-403b01795ae8 h1:y+mHpWoQJNAHt26Nhh6JP7hvM71IRZureyvZhoVALIs= golang.org/x/crypto v0.0.0-20220516162934-403b01795ae8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/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= +golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220516155154-20f960328961 h1:+W/iTMPG0EL7aW+/atntZwZrvSRIj3m3yX414dSULUU= golang.org/x/net v0.0.0-20220516155154-20f960328961/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a h1:N2T1jUrTQE9Re6TFF5PhvEHXHCguynGhKjWVsIUt5cY= golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 h1:wEZYwx+kK+KlZ0hpvP2Ls1Xr4+RWnlzGFwPP0aiDjIU= +golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +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= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY= golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d h1:q4JksJ2n0fmbXC0Aj0eOs6E0AcPqnKglxWXWFqGD6x0= golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f h1:YORWxaStkWBnWgELOHTmDrqNlFXuVGEbhwbB5iK94bQ= +google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84 h1:hZAzgyItS2MPyqvdC8wQZI99ZLGP9Vwijyfr0dmYWc4= +google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20210326210528-650f7c854440 h1:SxFAMd+8zfpL/Rk4pgdb8leeZDiL3M/gCWCbBvmLkoE= +gopkg.in/olebedev/go-duktape.v3 v3.0.0-20210326210528-650f7c854440/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/tunnel/tools/libwg-go/goruntime-boottime-over-monotonic.diff b/tunnel/tools/libwg-go/goruntime-boottime-over-monotonic.diff index 5cbc2256..52369503 100644 --- a/tunnel/tools/libwg-go/goruntime-boottime-over-monotonic.diff +++ b/tunnel/tools/libwg-go/goruntime-boottime-over-monotonic.diff @@ -144,18 +144,18 @@ index fd69ee70a5..ff6bc8355b 100644 MOVD R1, R15 // R15 is unchanged by C code MOVD g_m(g), R21 // R21 = m diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s -index c15a1d5364..f52c4d5098 100644 +index 1448670b91..7d2ee3231c 100644 --- a/src/runtime/sys_linux_s390x.s +++ b/src/runtime/sys_linux_s390x.s -@@ -207,7 +207,7 @@ TEXT runtime·walltime1(SB),NOSPLIT,$16 +@@ -296,7 +296,7 @@ fallback: RET - TEXT runtime·nanotime1(SB),NOSPLIT,$16 -- MOVW $1, R2 // CLOCK_MONOTONIC -+ MOVW $7, R2 // CLOCK_BOOTTIME - MOVD $tp-16(SP), R3 - MOVW $SYS_clock_gettime, R1 - SYSCALL + TEXT runtime·nanotime1(SB),NOSPLIT,$32-8 +- MOVW $1, R2 // CLOCK_MONOTONIC ++ MOVW $7, R2 // CLOCK_BOOTTIME + + MOVD R15, R7 // Backup stack pointer + -- 2.30.1 diff --git a/tunnel/tools/libwg-go/http-proxy.go b/tunnel/tools/libwg-go/http-proxy.go new file mode 100644 index 00000000..a44aaac6 --- /dev/null +++ b/tunnel/tools/libwg-go/http-proxy.go @@ -0,0 +1,702 @@ +package main + +import ( + "fmt" + "io" + "net" + "net/http" + "net/netip" + "net/url" + "strings" + "sync" + + "github.com/elazarl/goproxy" + + "golang.zx2c4.com/wireguard/device" + + net_proxy "golang.org/x/net/proxy" + + "gopkg.in/olebedev/go-duktape.v3" +) + +const ( + // Imported from Firefox' ProxyAutoConfig.cpp + // https://searchfox.org/mozilla-central/source/netwerk/base/ProxyAutoConfig.cpp + // This Source Code Form is subject to the terms of the Mozilla Public + // License, v. 2.0. If a copy of the MPL was not distributed with this + // file, You can obtain one at http://mozilla.org/MPL/2.0/. + ASCII_PAC_UTILS = "function dnsDomainIs(host, domain) {\n" + + " return (host.length >= domain.length &&\n" + + " host.substring(host.length - domain.length) == domain);\n" + + "}\n" + + "" + + "function dnsDomainLevels(host) {\n" + + " return host.split('.').length - 1;\n" + + "}\n" + + "" + + "function isValidIpAddress(ipchars) {\n" + + " var matches = " + + "/^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(ipchars);\n" + + " if (matches == null) {\n" + + " return false;\n" + + " } else if (matches[1] > 255 || matches[2] > 255 || \n" + + " matches[3] > 255 || matches[4] > 255) {\n" + + " return false;\n" + + " }\n" + + " return true;\n" + + "}\n" + + "" + + "function convert_addr(ipchars) {\n" + + " var bytes = ipchars.split('.');\n" + + " var result = ((bytes[0] & 0xff) << 24) |\n" + + " ((bytes[1] & 0xff) << 16) |\n" + + " ((bytes[2] & 0xff) << 8) |\n" + + " (bytes[3] & 0xff);\n" + + " return result;\n" + + "}\n" + + "" + + "function isInNet(ipaddr, pattern, maskstr) {\n" + + " if (!isValidIpAddress(pattern) || !isValidIpAddress(maskstr)) {\n" + + " return false;\n" + + " }\n" + + " if (!isValidIpAddress(ipaddr)) {\n" + + " ipaddr = dnsResolve(ipaddr);\n" + + " if (ipaddr == null) {\n" + + " return false;\n" + + " }\n" + + " }\n" + + " var host = convert_addr(ipaddr);\n" + + " var pat = convert_addr(pattern);\n" + + " var mask = convert_addr(maskstr);\n" + + " return ((host & mask) == (pat & mask));\n" + + " \n" + + "}\n" + + "" + + "function isPlainHostName(host) {\n" + + " return (host.search('(\\\\.)|:') == -1);\n" + + "}\n" + + "" + + "function isResolvable(host) {\n" + + " var ip = dnsResolve(host);\n" + + " return (ip != null);\n" + + "}\n" + + "" + + "function localHostOrDomainIs(host, hostdom) {\n" + + " return (host == hostdom) ||\n" + + " (hostdom.lastIndexOf(host + '.', 0) == 0);\n" + + "}\n" + + "" + + "function shExpMatch(url, pattern) {\n" + + " pattern = pattern.replace(/\\./g, '\\\\.');\n" + + " pattern = pattern.replace(/\\*/g, '.*');\n" + + " pattern = pattern.replace(/\\?/g, '.');\n" + + " var newRe = new RegExp('^'+pattern+'$');\n" + + " return newRe.test(url);\n" + + "}\n" + + "" + + "var wdays = {SUN: 0, MON: 1, TUE: 2, WED: 3, THU: 4, FRI: 5, SAT: 6};\n" + + "var months = {JAN: 0, FEB: 1, MAR: 2, APR: 3, MAY: 4, JUN: 5, JUL: 6, " + + "AUG: 7, SEP: 8, OCT: 9, NOV: 10, DEC: 11};\n" + + "" + + "function weekdayRange() {\n" + + " function getDay(weekday) {\n" + + " if (weekday in wdays) {\n" + + " return wdays[weekday];\n" + + " }\n" + + " return -1;\n" + + " }\n" + + " var date = new Date();\n" + + " var argc = arguments.length;\n" + + " var wday;\n" + + " if (argc < 1)\n" + + " return false;\n" + + " if (arguments[argc - 1] == 'GMT') {\n" + + " argc--;\n" + + " wday = date.getUTCDay();\n" + + " } else {\n" + + " wday = date.getDay();\n" + + " }\n" + + " var wd1 = getDay(arguments[0]);\n" + + " var wd2 = (argc == 2) ? getDay(arguments[1]) : wd1;\n" + + " return (wd1 == -1 || wd2 == -1) ? false\n" + + " : (wd1 <= wd2) ? (wd1 <= wday && wday " + + "<= wd2)\n" + + " : (wd2 >= wday || wday " + + ">= wd1);\n" + + "}\n" + + "" + + "function dateRange() {\n" + + " function getMonth(name) {\n" + + " if (name in months) {\n" + + " return months[name];\n" + + " }\n" + + " return -1;\n" + + " }\n" + + " var date = new Date();\n" + + " var argc = arguments.length;\n" + + " if (argc < 1) {\n" + + " return false;\n" + + " }\n" + + " var isGMT = (arguments[argc - 1] == 'GMT');\n" + + "\n" + + " if (isGMT) {\n" + + " argc--;\n" + + " }\n" + + " // function will work even without explict handling of this case\n" + + " if (argc == 1) {\n" + + " var tmp = parseInt(arguments[0]);\n" + + " if (isNaN(tmp)) {\n" + + " return ((isGMT ? date.getUTCMonth() : date.getMonth()) ==\n" + + " getMonth(arguments[0]));\n" + + " } else if (tmp < 32) {\n" + + " return ((isGMT ? date.getUTCDate() : date.getDate()) == " + + "tmp);\n" + + " } else { \n" + + " return ((isGMT ? date.getUTCFullYear() : date.getFullYear()) " + + "==\n" + + " tmp);\n" + + " }\n" + + " }\n" + + " var year = date.getFullYear();\n" + + " var date1, date2;\n" + + " date1 = new Date(year, 0, 1, 0, 0, 0);\n" + + " date2 = new Date(year, 11, 31, 23, 59, 59);\n" + + " var adjustMonth = false;\n" + + " for (var i = 0; i < (argc >> 1); i++) {\n" + + " var tmp = parseInt(arguments[i]);\n" + + " if (isNaN(tmp)) {\n" + + " var mon = getMonth(arguments[i]);\n" + + " date1.setMonth(mon);\n" + + " } else if (tmp < 32) {\n" + + " adjustMonth = (argc <= 2);\n" + + " date1.setDate(tmp);\n" + + " } else {\n" + + " date1.setFullYear(tmp);\n" + + " }\n" + + " }\n" + + " for (var i = (argc >> 1); i < argc; i++) {\n" + + " var tmp = parseInt(arguments[i]);\n" + + " if (isNaN(tmp)) {\n" + + " var mon = getMonth(arguments[i]);\n" + + " date2.setMonth(mon);\n" + + " } else if (tmp < 32) {\n" + + " date2.setDate(tmp);\n" + + " } else {\n" + + " date2.setFullYear(tmp);\n" + + " }\n" + + " }\n" + + " if (adjustMonth) {\n" + + " date1.setMonth(date.getMonth());\n" + + " date2.setMonth(date.getMonth());\n" + + " }\n" + + " if (isGMT) {\n" + + " var tmp = date;\n" + + " tmp.setFullYear(date.getUTCFullYear());\n" + + " tmp.setMonth(date.getUTCMonth());\n" + + " tmp.setDate(date.getUTCDate());\n" + + " tmp.setHours(date.getUTCHours());\n" + + " tmp.setMinutes(date.getUTCMinutes());\n" + + " tmp.setSeconds(date.getUTCSeconds());\n" + + " date = tmp;\n" + + " }\n" + + " return (date1 <= date2) ? (date1 <= date) && (date <= date2)\n" + + " : (date2 >= date) || (date >= date1);\n" + + "}\n" + + "" + + "function timeRange() {\n" + + " var argc = arguments.length;\n" + + " var date = new Date();\n" + + " var isGMT= false;\n" + + "" + + " if (argc < 1) {\n" + + " return false;\n" + + " }\n" + + " if (arguments[argc - 1] == 'GMT') {\n" + + " isGMT = true;\n" + + " argc--;\n" + + " }\n" + + "\n" + + " var hour = isGMT ? date.getUTCHours() : date.getHours();\n" + + " var date1, date2;\n" + + " date1 = new Date();\n" + + " date2 = new Date();\n" + + "\n" + + " if (argc == 1) {\n" + + " return (hour == arguments[0]);\n" + + " } else if (argc == 2) {\n" + + " return ((arguments[0] <= hour) && (hour <= arguments[1]));\n" + + " } else {\n" + + " switch (argc) {\n" + + " case 6:\n" + + " date1.setSeconds(arguments[2]);\n" + + " date2.setSeconds(arguments[5]);\n" + + " case 4:\n" + + " var middle = argc >> 1;\n" + + " date1.setHours(arguments[0]);\n" + + " date1.setMinutes(arguments[1]);\n" + + " date2.setHours(arguments[middle]);\n" + + " date2.setMinutes(arguments[middle + 1]);\n" + + " if (middle == 2) {\n" + + " date2.setSeconds(59);\n" + + " }\n" + + " break;\n" + + " default:\n" + + " throw 'timeRange: bad number of arguments'\n" + + " }\n" + + " }\n" + + "\n" + + " if (isGMT) {\n" + + " date.setFullYear(date.getUTCFullYear());\n" + + " date.setMonth(date.getUTCMonth());\n" + + " date.setDate(date.getUTCDate());\n" + + " date.setHours(date.getUTCHours());\n" + + " date.setMinutes(date.getUTCMinutes());\n" + + " date.setSeconds(date.getUTCSeconds());\n" + + " }\n" + + " return (date1 <= date2) ? (date1 <= date) && (date <= date2)\n" + + " : (date2 >= date) || (date >= date1);\n" + + "\n" + + "}\n" +) + +type HttpProxy struct { + listener net.Listener + tlsListener net.Listener + logger *device.Logger + addrPort netip.AddrPort + tlsAddrPort netip.AddrPort + ctx *duktape.Context + defaultProxy *goproxy.ProxyHttpServer + uidRequest chan UidRequest + handlers []*HttpHandler +} + +func NewHttpProxy(uidRequest chan UidRequest, logger *device.Logger) *HttpProxy { + logger.Verbosef("NewHttpProxy") + return &HttpProxy{ + listener: nil, + logger: logger, + uidRequest: uidRequest, + handlers: make([]*HttpHandler, 0, 2), + } +} + +var ( + ASCII_PAC_UTILS_NAMES = []string{"dnsDomainIs", "dnsDomainLevels", "isValidIpAddress", "convert_addr", "isInNet", "isPlainHostName", "isResolvable", "localHostOrDomainIs", "shExpMatch", "weekdayRange", "dateRange", "timeRange"} +) + +func (p *HttpProxy) GetAddrPort() netip.AddrPort { + return p.addrPort +} + +type Logger struct { + logger *device.Logger +} + +func (l *Logger) Printf(format string, v ...interface{}) { + l.logger.Verbosef(format, v...) +} + +func (p *HttpProxy) newGoProxy(cat, proxyUrl string) (*goproxy.ProxyHttpServer, error) { + proxy := goproxy.NewProxyHttpServer() + proxy.Logger = &Logger{logger: p.logger} + proxy.Verbose = true + if cat == "SOCKS5" { + socksDialer, err := net_proxy.SOCKS5("tcp", proxyUrl, nil, nil) + if err != nil { + return nil, err + } + proxy.Tr.Dial = socksDialer.Dial + } + proxy.NonproxyHandler = http.HandlerFunc(func (w http.ResponseWriter, req *http.Request) { + if req.Host == "" { + fmt.Fprintln(w, "Cannot handle requests without Host header, e.g., HTTP 1.0") + return + } + req.URL.Scheme = "http" + req.URL.Host = req.Host + proxy.ServeHTTP(w, req) + }) + + if cat == "PROXY" { + proxy.Tr.Proxy = func(req *http.Request) (*url.URL, error) { + return url.Parse(proxyUrl) + } + proxy.ConnectDial = proxy.NewConnectDialToProxy(proxyUrl) + } + + return proxy, nil +} + +func FindProxyForURL(ctx *duktape.Context, url, host string, logger *device.Logger) (res string, err error) { + if !ctx.GetGlobalString("FindProxyForURL") { + ctx.Pop() + return "", fmt.Errorf("FindProxyForURL not found") + } + + ctx.PushString(url) + ctx.PushString(host) + + res = "DIRECT" + logger.Verbosef("Before pcall") + r := ctx.Pcall(2) + logger.Verbosef("After pcall") + if r == 0 { + res = ctx.GetString(-1) + } else if ctx.IsError(-1) { + ctx.GetPropString(-1, "stack") + err = fmt.Errorf("Error: %v", ctx.SafeToString(-1)) + } else { + err = fmt.Errorf("Error: %v", ctx.SafeToString(-1)) + } + ctx.Pop() + return +} + + +func FindProxyForPkg(ctx *duktape.Context, pkg string, logger *device.Logger) (res string, err error) { + if !ctx.GetGlobalString("FindProxyForPkg") { + ctx.Pop() + return "", fmt.Errorf("FindProxyForPkg not found") + } + + ctx.PushString(pkg) + + res = "DIRECT" + logger.Verbosef("Before pcall") + r := ctx.Pcall(1) + logger.Verbosef("After pcall") + if r == 0 { + res = ctx.GetString(-1) + } else if ctx.IsError(-1) { + ctx.GetPropString(-1, "stack") + err = fmt.Errorf("Error: %v", ctx.SafeToString(-1)) + } else { + err = fmt.Errorf("Error: %v", ctx.SafeToString(-1)) + } + ctx.Pop() + return +} + +func newPacBodyCtx(body string, logger *device.Logger) *duktape.Context { + ctx := duktape.New() + ctx.PushGlobalGoFunction("dnsResolve", + func(ctx *duktape.Context) int { + // Check stack + host := ctx.GetString(-1) + ctx.Pop() + ips, err := net.LookupIP(host) + if err != nil { + return 0 + } + + for _, ip := range(ips) { + ipStr := string(ip) + if strings.Contains(ipStr, ".") { + // Found IPv4 + ctx.PushString(ipStr) + return 1 + } + } + // No IPv4 + return 0 + }) + + ctx.PevalString(ASCII_PAC_UTILS) + logger.Verbosef("ASCII_PAC_UTILS result is: %v stack:%v", ctx.GetType(-1), ctx.GetTop()) + ctx.Pop() + + ctx.PevalString(string(body)) + logger.Verbosef("result is: %v stack:%v", ctx.GetType(-1), ctx.GetTop()) + ctx.Pop() + FindProxyForURL(ctx, "http://www.jabra.se/", "www.jabra.se", logger) + return ctx +} + +func (p *HttpProxy) newPacFileCtx(pacFileUrl *url.URL) (*duktape.Context, error) { + var pacFileBody = "" + if pacFileUrl == nil { + return nil, nil + } + + resp, err := http.Get(pacFileUrl.String()) + p.logger.Verbosef("pacFile: %v, %v", resp, err) + + if err == nil { + defer resp.Body.Close() + ct, ok := resp.Header["Content-Type"] + if ok && len(ct) == 1 && ct[0] == "application/x-ns-proxy-autoconfig" { + body, err := io.ReadAll(resp.Body) + if err == nil { + pacFileBody = string(body) + return newPacBodyCtx(pacFileBody, p.logger), nil + } + } + } + + return nil, err +} + +func (p *HttpProxy) SetPacFileUrl(pacFileUrl *url.URL) error { + ctx, err := p.newPacFileCtx(pacFileUrl) + if err != nil { + return err + } + + for _, handler := range(p.handlers) { + handler.setPacCtx(ctx) + } + + if p.ctx != nil { + p.ctx.Destroy() + } + p.ctx = ctx + return nil +} + +func (p *HttpProxy) Start() (listen_port uint16, err error) { + p.logger.Verbosef("HttpProxy.Start()") + listen_port = 0 + + + proxyMap := make(map[string]*goproxy.ProxyHttpServer) + + p.defaultProxy, err = p.newGoProxy("", "") + if err != nil { + return + } + proxyMap[""] = p.defaultProxy + + listen_port, handler, err := p.startRegularProxy(proxyMap) + if err != nil { + return + } + p.handlers = append(p.handlers, handler) + + return +} + +func (p *HttpProxy) startRegularProxy(proxyMap map[string]*goproxy.ProxyHttpServer) (listen_port uint16, handler *HttpHandler, err error) { + p.listener, err = net.Listen("tcp", "[::]:") + if err != nil { + return + } + + p.addrPort, err = netip.ParseAddrPort(p.listener.Addr().String()) + if err != nil { + return + } + + listen_port = p.addrPort.Port() + + handler = NewHttpHandler(p, p.defaultProxy, proxyMap, p.logger) + + go http.Serve(NewListener(p.listener, handler, p.logger), handler) + return +} + +func (p *HttpProxy) Stop() { + if p.listener != nil { + p.logger.Verbosef("Close: %v", p.listener) + p.listener.Close() +// p.listener = nil + } + if p.tlsListener != nil { + p.logger.Verbosef("Close: %v", p.tlsListener) + p.tlsListener.Close() +// p.tlsListener = nil + } + if p.ctx != nil { + p.ctx.DestroyHeap() + p.ctx = nil + } +} + +type HttpHandler struct { + p *HttpProxy + defaultProxy *goproxy.ProxyHttpServer + logger *device.Logger + remoteAddrPkgMapMutex sync.RWMutex + remoteAddrPkgMap map[string]*goproxy.ProxyHttpServer + uidRequest chan UidRequest + ctx *duktape.Context + proxyMap map[string]*goproxy.ProxyHttpServer // FIXME include type in map key +} + +func NewHttpHandler(p *HttpProxy, defaultProxy *goproxy.ProxyHttpServer, proxyMap map[string]*goproxy.ProxyHttpServer, logger *device.Logger) *HttpHandler{ + h := &HttpHandler{ + p: p, + defaultProxy: defaultProxy, + logger: logger, + remoteAddrPkgMapMutex: sync.RWMutex{}, + remoteAddrPkgMap: make(map[string]*goproxy.ProxyHttpServer), + uidRequest: p.uidRequest, + proxyMap: proxyMap, + } + + return h +} + +// TODO fix multi-threading +func (h *HttpHandler) setPacCtx(ctx *duktape.Context) { + h.ctx = ctx +} + +func (h *HttpHandler) addConnToProxyMap(c net.Conn) error { + h.logger.Verbosef("Accept: %v -> %v", c.RemoteAddr().String(), c.LocalAddr().String()) + local, err := netip.ParseAddrPort(c.RemoteAddr().String()) + if err != nil { + return fmt.Errorf("Bad local address (%v): %v", c.RemoteAddr(), err) + } + // Remove IPv6 zone, NOOP on IPv4 + local = netip.AddrPortFrom(local.Addr().WithZone(""), local.Port()) + + remote, err := netip.ParseAddrPort(c.LocalAddr().String()) + if err != nil { + return fmt.Errorf("Bad remote address (%v): %v", c.LocalAddr(), err) + } + + h.logger.Verbosef("uidRequest: %v -> %v", local, remote) + addrPortPair := AddrPortPair{local: local, remote: remote} + retCh := make(chan string) + h.uidRequest <- UidRequest{Data: addrPortPair, RetCh: retCh} + + select { + case pkg := <-retCh: + h.logger.Verbosef("uidResponse: '%v'", pkg) + + proxy, ok := h.proxyMap[pkg] + if !ok { + proxy, err = h.findProxyForPkg(pkg) + if err != nil { + return err + } + } + + if proxy != nil { + h.remoteAddrPkgMapMutex.Lock() + h.remoteAddrPkgMap[c.RemoteAddr().String()] = proxy + h.remoteAddrPkgMapMutex.Unlock() + } + } + + return nil +} + +func (h *HttpHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + h.remoteAddrPkgMapMutex.Lock() + proxy, ok := h.remoteAddrPkgMap[req.RemoteAddr] + if ok && proxy != nil { + delete(h.remoteAddrPkgMap, req.RemoteAddr) + h.remoteAddrPkgMapMutex.Unlock() + + proxyStr := "nil" + proxyUrl, err := proxy.Tr.Proxy(req) + if err == nil && proxyUrl != nil { + proxyStr = proxyUrl.String() + } + h.logger.Verbosef("ServeHTTP remote:%s proxy:%v", req.RemoteAddr, proxyStr) + + proxy.ServeHTTP(rw, req) + } else { + h.remoteAddrPkgMapMutex.Unlock() + h.defaultProxy.ServeHTTP(rw, req) + } +} + +func (h *HttpHandler) findProxyForPkg(pkg string) (*goproxy.ProxyHttpServer, error) { + if h.ctx == nil { + return nil, fmt.Errorf("Null context") + } + + find := func() (cat string, res string, err error) { + h.logger.Verbosef("Call FindProxyForPkg %v %v", pkg) + res, err = FindProxyForPkg(h.ctx, pkg, h.logger) + h.logger.Verbosef("FindProxyForPkg res %v %v", res, err) + if err != nil { + h.logger.Verbosef("FindProxyForPkg result is: %v stack:%v", res, h.ctx.GetTop()) + return "", "", err + } else if res == "" { + return "DIRECT", "", nil + } else { + values := strings.Split(strings.Trim(res, " "), ";") + for _, v := range values { + value := strings.Trim(v, " ") + parts := strings.SplitN(value, " ", 2) + if parts[0] == "PROXY" || parts[0] == "HTTP" { + return "PROXY", "http://" + parts[1], nil + } else if parts[0] == "HTTPS" { + return "PROXY", "https://" + parts[1], nil + } else if parts[0] == "DIRECT" { + return parts[0], "", nil + } else if parts[0] == "SOCKS" || parts[0] == "SOCKS5" { + return "SOCKS5", parts[1], nil + } + } + } + return "", "", fmt.Errorf("No result") + } + cat, res, err := find() + if err != nil { + return nil, err + } + + var proxy *goproxy.ProxyHttpServer + if cat == "DIRECT" { + proxy = h.defaultProxy + } else { + proxy, err = h.p.newGoProxy(cat, res) + if err != nil { + return nil, err + } + } + h.proxyMap[pkg] = proxy + + return proxy, nil +} + +type AddrPortPair struct { + local netip.AddrPort + remote netip.AddrPort +} + +// Listener +type Listener struct { + l net.Listener + handler *HttpHandler + logger *device.Logger +} + +func NewListener(listener net.Listener, handler *HttpHandler, logger *device.Logger) *Listener{ + l := &Listener{ + l: listener, + handler: handler, + logger: logger, + } + + return l +} + +func (l *Listener) Accept() (net.Conn, error) { + c, err := l.l.Accept() + if err != nil { + l.logger.Verbosef("Accept failed: %v", err) + return c, err + } + + if err := l.handler.addConnToProxyMap(c); err != nil { + err = fmt.Errorf("Reject connection (%v): %v", c, err) + c.Close() + return nil, err + } + + return c, nil +} + +func (l *Listener) Close() error { + return l.l.Close() +} + +func (l *Listener) Addr() net.Addr { + return l.l.Addr() +} diff --git a/tunnel/tools/libwg-go/jni.c b/tunnel/tools/libwg-go/jni.c index 7ad94d35..121729a7 100644 --- a/tunnel/tools/libwg-go/jni.c +++ b/tunnel/tools/libwg-go/jni.c @@ -14,6 +14,7 @@ extern int wgGetSocketV4(int handle); extern int wgGetSocketV6(int handle); extern char *wgGetConfig(int handle); extern char *wgVersion(); +extern int wgStartGrpc(); JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOn(JNIEnv *env, jclass c, jstring ifname, jint tun_fd, jstring settings) { @@ -69,3 +70,15 @@ JNIEXPORT jstring JNICALL Java_com_wireguard_android_backend_GoBackend_wgVersion free(version); return ret; } + +JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgStartGrpc(JNIEnv *env, jclass c, jstring sockname) +{ + const char *sockname_str = (*env)->GetStringUTFChars(env, sockname, 0); + size_t sockname_len = (*env)->GetStringUTFLength(env, sockname); + jint res = wgStartGrpc((struct go_string){ + .str = sockname_str, + .n = sockname_len + }); + (*env)->ReleaseStringUTFChars(env, sockname, sockname_str); + return res; +} diff --git a/tunnel/tools/libwg-go/service.go b/tunnel/tools/libwg-go/service.go new file mode 100644 index 00000000..1f2e629c --- /dev/null +++ b/tunnel/tools/libwg-go/service.go @@ -0,0 +1,246 @@ +package main + +import ( + "context" + "fmt" + "io" + "net" + "net/url" + "os" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + gen "golang.zx2c4.com/wireguard/android/gen" + "golang.zx2c4.com/wireguard/device" +) + +const ( + IPPROTO_TCP = 6 +) + +type UidRequest struct { + Data AddrPortPair + RetCh chan string +} + +type LibwgServiceImpl struct { + gen.UnimplementedLibwgServer + logger *device.Logger + httpProxy *HttpProxy + uidRequest chan UidRequest + stopReverse chan bool +} + +var service *LibwgServiceImpl +var server *grpc.Server + +func NewLibwgService(logger *device.Logger) gen.LibwgServer { + return &LibwgServiceImpl{ + logger: logger, + uidRequest: make(chan UidRequest), + stopReverse: make(chan bool), + } +} + +func StartGrpc(sock_path string, logger *device.Logger) (int, string) { + if server != nil { + return -1, "Already started" + } + + if _, err := os.Stat(sock_path); err == nil { + if err := os.RemoveAll(sock_path); err != nil { + return -1, fmt.Sprintf("Cleanup failed: %v %v", sock_path, err) + } + } + + listener, err := net.Listen("unix", sock_path) + if err != nil { + return -1, fmt.Sprintf("Listen failed: %v %v", sock_path, err) + } + + server = grpc.NewServer() + service = NewLibwgService(logger).(*LibwgServiceImpl) + + gen.RegisterLibwgServer(server, service) + + go func() { + server.Serve(listener) + }() + + logger.Verbosef("gRPC started") + + return 0, "" +} + +func (e *LibwgServiceImpl) Version(ctx context.Context, req *gen.VersionRequest) (*gen.VersionResponse, error) { + + r := &gen.VersionResponse{ + Version: Version(), + } + + return r, nil +} + +func (e *LibwgServiceImpl) StopGrpc(ctx context.Context, req *gen.StopGrpcRequest) (*gen.StopGrpcResponse, error) { + if server != nil { + server.Stop() + server = nil + service = nil + } + + r := &gen.StopGrpcResponse{ + } + + return r, nil +} + +func buildStartHttpProxyError(message string) (*gen.StartHttpProxyResponse, error) { + r := &gen.StartHttpProxyResponse{ + Error: &gen.Error{ + Message: message, + }, + } + return r, nil +} + +func (e *LibwgServiceImpl) StartHttpProxy(ctx context.Context, req *gen.StartHttpProxyRequest) (*gen.StartHttpProxyResponse, error) { + var listenPort uint16 + if e.httpProxy == nil { + e.httpProxy = NewHttpProxy(e.uidRequest, e.logger) + var err error + listenPort, err = e.httpProxy.Start() + + if err != nil { + e.httpProxy = nil + return buildStartHttpProxyError(fmt.Sprintf("Http proxy start failed: %v", err)) + } + } else { + listenPort = e.httpProxy.GetAddrPort().Port() + } + + pacFileUrl, err := url.Parse(req.PacFileUrl) + if err != nil { + return buildStartHttpProxyError(fmt.Sprintf("Bad pacFileUrl: %v (%s)", err, req.PacFileUrl)) + } + + err = e.httpProxy.SetPacFileUrl(pacFileUrl) + if err != nil { + return buildStartHttpProxyError(fmt.Sprintf("Bad pacFileUrl: %v (%s)", req.PacFileUrl)) + } + + r := &gen.StartHttpProxyResponse{ + ListenPort: uint32(listenPort), + } + return r, nil +} + +func (e *LibwgServiceImpl) StopHttpProxy(ctx context.Context, req *gen.StopHttpProxyRequest) (*gen.StopHttpProxyResponse, error) { + if e.httpProxy == nil { + r := &gen.StopHttpProxyResponse{ + Error: &gen.Error{ + Message: fmt.Sprintf("Http proxy not running"), + }, + } + return r, nil + } + + e.httpProxy.Stop() + e.httpProxy = nil + e.stopReverse <- true + r := &gen.StopHttpProxyResponse{} + return r, nil +} + +func (e *LibwgServiceImpl) Reverse(stream gen.Libwg_ReverseServer) error { + e.logger.Verbosef("Reverse enter loop") + for e.httpProxy != nil { + var err error + + // err := contextError(stream.Context()) + err = stream.Context().Err() + if err != nil { + e.logger.Verbosef("Reverse: context: %v", err) + return err + } + + select { + case <-e.stopReverse: + e.logger.Verbosef("Reverse: stop") + break + case uidReq := <-e.uidRequest: + addrPortPair := uidReq.Data + local := addrPortPair.local + remote := addrPortPair.remote + r := &gen.ReverseResponse{ + Request: &gen.ReverseResponse_Uid{ + Uid: &gen.GetConnectionOwnerUidRequest{ + Protocol: IPPROTO_TCP, + Local: &gen.InetSocketAddress{ + Address: &gen.InetAddress{ + Address: local.Addr().AsSlice(), + }, + Port: uint32(local.Port()), + }, + Remote: &gen.InetSocketAddress{ + Address: &gen.InetAddress{ + Address: remote.Addr().AsSlice(), + }, + Port: uint32(remote.Port()), + }, + }, + }, + } + + stream.Send(r) + + req, err := stream.Recv() + if err == io.EOF { + e.logger.Verbosef("no more data") + uidReq.RetCh <- "" + break + } + if err != nil { + err = status.Errorf(codes.Unknown, "cannot receive stream request: %v", err) + e.logger.Verbosef("Reverse: %v", err) + uidReq.RetCh <- "" + return err + } + + e.logger.Verbosef("Reverse: received, wait: %v", req) + uidReq.RetCh <- req.GetUid().GetPackage() + } + } + + + e.logger.Verbosef("Reverse returns") + return nil +} + +func (e *LibwgServiceImpl) IpcSet(ctx context.Context, req *gen.IpcSetRequest) (*gen.IpcSetResponse, error) { + tunnel, ok := GetTunnel(req.GetTunnel().GetHandle()) + if !ok { + r := &gen.IpcSetResponse{ + Error: &gen.Error{ + Message: fmt.Sprintf("Invalid tunnel"), + }, + } + return r, nil + } + + err := tunnel.device.IpcSet(req.GetConfig()) + if err != nil { + r := &gen.IpcSetResponse{ + Error: &gen.Error{ + Message: fmt.Sprintf("IpcSet failed: %v", err), + }, + } + return r, nil + } + + r := &gen.IpcSetResponse{ + } + + return r, nil +} |