diff options
Diffstat (limited to '')
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | conn/bind_linux.go | 2 | ||||
-rw-r--r-- | conn/bind_std.go | 79 | ||||
-rw-r--r-- | conn/bind_windows.go | 2 | ||||
-rw-r--r-- | conn/bindtest/bindtest.go | 2 | ||||
-rw-r--r-- | conn/conn.go | 3 | ||||
-rw-r--r-- | device/allowedips.go | 3 | ||||
-rw-r--r-- | device/allowedips_rand_test.go | 3 | ||||
-rw-r--r-- | device/allowedips_test.go | 3 | ||||
-rw-r--r-- | device/device_test.go | 2 | ||||
-rw-r--r-- | device/endpoint_test.go | 3 | ||||
-rw-r--r-- | device/logger.go | 8 | ||||
-rw-r--r-- | device/pools.go | 12 | ||||
-rw-r--r-- | device/pools_test.go | 4 | ||||
-rw-r--r-- | device/uapi.go | 16 | ||||
-rw-r--r-- | go.mod | 9 | ||||
-rw-r--r-- | go.sum | 23 | ||||
-rw-r--r-- | ratelimiter/ratelimiter.go | 3 | ||||
-rw-r--r-- | ratelimiter/ratelimiter_test.go | 3 | ||||
-rw-r--r-- | tun/netstack/examples/http_client.go | 2 | ||||
-rw-r--r-- | tun/netstack/examples/http_server.go | 2 | ||||
-rw-r--r-- | tun/netstack/examples/ping_client.go | 76 | ||||
-rw-r--r-- | tun/netstack/go.mod | 17 | ||||
-rw-r--r-- | tun/netstack/go.sum | 27 | ||||
-rw-r--r-- | tun/netstack/tun.go | 284 | ||||
-rw-r--r-- | tun/tuntest/tuntest.go | 2 | ||||
-rw-r--r-- | version.go | 2 |
27 files changed, 439 insertions, 155 deletions
@@ -46,7 +46,7 @@ This will run on OpenBSD. It does not yet support sticky sockets. Fwmark is mapp ## Building -This requires an installation of [go](https://golang.org) ≥ 1.17. +This requires an installation of [go](https://golang.org) ≥ 1.18. ``` $ git clone https://git.zx2c4.com/wireguard-go diff --git a/conn/bind_linux.go b/conn/bind_linux.go index b3d755c..f11f031 100644 --- a/conn/bind_linux.go +++ b/conn/bind_linux.go @@ -8,13 +8,13 @@ package conn import ( "errors" "net" + "net/netip" "strconv" "sync" "syscall" "unsafe" "golang.org/x/sys/unix" - "golang.zx2c4.com/go118/netip" ) type ipv4Source struct { diff --git a/conn/bind_std.go b/conn/bind_std.go index de03b10..b6a7ab3 100644 --- a/conn/bind_std.go +++ b/conn/bind_std.go @@ -8,10 +8,9 @@ package conn import ( "errors" "net" + "net/netip" "sync" "syscall" - - "golang.zx2c4.com/go118/netip" ) // StdNetBind is meant to be a temporary solution on platforms for which @@ -28,49 +27,38 @@ type StdNetBind struct { func NewStdNetBind() Bind { return &StdNetBind{} } -type StdNetEndpoint net.UDPAddr +type StdNetEndpoint netip.AddrPort var ( _ Bind = (*StdNetBind)(nil) - _ Endpoint = (*StdNetEndpoint)(nil) + _ Endpoint = StdNetEndpoint{} ) func (*StdNetBind) ParseEndpoint(s string) (Endpoint, error) { e, err := netip.ParseAddrPort(s) - return (*StdNetEndpoint)(&net.UDPAddr{ - IP: e.Addr().AsSlice(), - Port: int(e.Port()), - Zone: e.Addr().Zone(), - }), err + return asEndpoint(e), err } -func (*StdNetEndpoint) ClearSrc() {} +func (StdNetEndpoint) ClearSrc() {} -func (e *StdNetEndpoint) DstIP() netip.Addr { - a, _ := netip.AddrFromSlice((*net.UDPAddr)(e).IP) - return a +func (e StdNetEndpoint) DstIP() netip.Addr { + return (netip.AddrPort)(e).Addr() } -func (e *StdNetEndpoint) SrcIP() netip.Addr { +func (e StdNetEndpoint) SrcIP() netip.Addr { return netip.Addr{} // not supported } -func (e *StdNetEndpoint) DstToBytes() []byte { - addr := (*net.UDPAddr)(e) - out := addr.IP.To4() - if out == nil { - out = addr.IP - } - out = append(out, byte(addr.Port&0xff)) - out = append(out, byte((addr.Port>>8)&0xff)) - return out +func (e StdNetEndpoint) DstToBytes() []byte { + b, _ := (netip.AddrPort)(e).MarshalBinary() + return b } -func (e *StdNetEndpoint) DstToString() string { - return (*net.UDPAddr)(e).String() +func (e StdNetEndpoint) DstToString() string { + return (netip.AddrPort)(e).String() } -func (e *StdNetEndpoint) SrcToString() string { +func (e StdNetEndpoint) SrcToString() string { return "" } @@ -163,32 +151,30 @@ func (bind *StdNetBind) Close() error { func (*StdNetBind) makeReceiveIPv4(conn *net.UDPConn) ReceiveFunc { return func(buff []byte) (int, Endpoint, error) { - n, endpoint, err := conn.ReadFromUDP(buff) - if endpoint != nil { - endpoint.IP = endpoint.IP.To4() - } - return n, (*StdNetEndpoint)(endpoint), err + n, endpoint, err := conn.ReadFromUDPAddrPort(buff) + return n, asEndpoint(endpoint), err } } func (*StdNetBind) makeReceiveIPv6(conn *net.UDPConn) ReceiveFunc { return func(buff []byte) (int, Endpoint, error) { - n, endpoint, err := conn.ReadFromUDP(buff) - return n, (*StdNetEndpoint)(endpoint), err + n, endpoint, err := conn.ReadFromUDPAddrPort(buff) + return n, asEndpoint(endpoint), err } } func (bind *StdNetBind) Send(buff []byte, endpoint Endpoint) error { var err error - nend, ok := endpoint.(*StdNetEndpoint) + nend, ok := endpoint.(StdNetEndpoint) if !ok { return ErrWrongEndpointType } + addrPort := netip.AddrPort(nend) bind.mu.Lock() blackhole := bind.blackhole4 conn := bind.ipv4 - if nend.IP.To4() == nil { + if addrPort.Addr().Is6() { blackhole = bind.blackhole6 conn = bind.ipv6 } @@ -200,6 +186,27 @@ func (bind *StdNetBind) Send(buff []byte, endpoint Endpoint) error { if conn == nil { return syscall.EAFNOSUPPORT } - _, err = conn.WriteToUDP(buff, (*net.UDPAddr)(nend)) + _, err = conn.WriteToUDPAddrPort(buff, addrPort) return err } + +// endpointPool contains a re-usable set of mapping from netip.AddrPort to Endpoint. +// This exists to reduce allocations: Putting a netip.AddrPort in an Endpoint allocates, +// but Endpoints are immutable, so we can re-use them. +var endpointPool = sync.Pool{ + New: func() any { + return make(map[netip.AddrPort]Endpoint) + }, +} + +// asEndpoint returns an Endpoint containing ap. +func asEndpoint(ap netip.AddrPort) Endpoint { + m := endpointPool.Get().(map[netip.AddrPort]Endpoint) + defer endpointPool.Put(m) + e, ok := m[ap] + if !ok { + e = Endpoint(StdNetEndpoint(ap)) + m[ap] = e + } + return e +} diff --git a/conn/bind_windows.go b/conn/bind_windows.go index 476e277..9268bc1 100644 --- a/conn/bind_windows.go +++ b/conn/bind_windows.go @@ -9,13 +9,13 @@ import ( "encoding/binary" "io" "net" + "net/netip" "strconv" "sync" "sync/atomic" "unsafe" "golang.org/x/sys/windows" - "golang.zx2c4.com/go118/netip" "golang.zx2c4.com/wireguard/conn/winrio" ) diff --git a/conn/bindtest/bindtest.go b/conn/bindtest/bindtest.go index 6fc1972..b38cae6 100644 --- a/conn/bindtest/bindtest.go +++ b/conn/bindtest/bindtest.go @@ -9,9 +9,9 @@ import ( "fmt" "math/rand" "net" + "net/netip" "os" - "golang.zx2c4.com/go118/netip" "golang.zx2c4.com/wireguard/conn" ) diff --git a/conn/conn.go b/conn/conn.go index 35fb6b1..5a93b2b 100644 --- a/conn/conn.go +++ b/conn/conn.go @@ -9,11 +9,10 @@ package conn import ( "errors" "fmt" + "net/netip" "reflect" "runtime" "strings" - - "golang.zx2c4.com/go118/netip" ) // A ReceiveFunc receives a single inbound packet from the network. diff --git a/device/allowedips.go b/device/allowedips.go index 06c5465..3cac694 100644 --- a/device/allowedips.go +++ b/device/allowedips.go @@ -11,10 +11,9 @@ import ( "errors" "math/bits" "net" + "net/netip" "sync" "unsafe" - - "golang.zx2c4.com/go118/netip" ) type parentIndirection struct { diff --git a/device/allowedips_rand_test.go b/device/allowedips_rand_test.go index ff56fe6..0d3eecb 100644 --- a/device/allowedips_rand_test.go +++ b/device/allowedips_rand_test.go @@ -8,10 +8,9 @@ package device import ( "math/rand" "net" + "net/netip" "sort" "testing" - - "golang.zx2c4.com/go118/netip" ) const ( diff --git a/device/allowedips_test.go b/device/allowedips_test.go index 68f382b..225c788 100644 --- a/device/allowedips_test.go +++ b/device/allowedips_test.go @@ -8,9 +8,8 @@ package device import ( "math/rand" "net" + "net/netip" "testing" - - "golang.zx2c4.com/go118/netip" ) type testPairCommonBits struct { diff --git a/device/device_test.go b/device/device_test.go index b484ca2..ab7236e 100644 --- a/device/device_test.go +++ b/device/device_test.go @@ -11,6 +11,7 @@ import ( "fmt" "io" "math/rand" + "net/netip" "runtime" "runtime/pprof" "sync" @@ -18,7 +19,6 @@ import ( "testing" "time" - "golang.zx2c4.com/go118/netip" "golang.zx2c4.com/wireguard/conn" "golang.zx2c4.com/wireguard/conn/bindtest" "golang.zx2c4.com/wireguard/tun/tuntest" diff --git a/device/endpoint_test.go b/device/endpoint_test.go index f1ae47e..b265be6 100644 --- a/device/endpoint_test.go +++ b/device/endpoint_test.go @@ -7,8 +7,7 @@ package device import ( "math/rand" - - "golang.zx2c4.com/go118/netip" + "net/netip" ) type DummyEndpoint struct { diff --git a/device/logger.go b/device/logger.go index c79c971..29073e9 100644 --- a/device/logger.go +++ b/device/logger.go @@ -16,8 +16,8 @@ import ( // They do not require a trailing newline in the format. // If nil, that level of logging will be silent. type Logger struct { - Verbosef func(format string, args ...interface{}) - Errorf func(format string, args ...interface{}) + Verbosef func(format string, args ...any) + Errorf func(format string, args ...any) } // Log levels for use with NewLogger. @@ -28,14 +28,14 @@ const ( ) // Function for use in Logger for discarding logged lines. -func DiscardLogf(format string, args ...interface{}) {} +func DiscardLogf(format string, args ...any) {} // NewLogger constructs a Logger that writes to stdout. // It logs at the specified log level and above. // It decorates log lines with the log level, date, time, and prepend. func NewLogger(level int, prepend string) *Logger { logger := &Logger{DiscardLogf, DiscardLogf} - logf := func(prefix string) func(string, ...interface{}) { + logf := func(prefix string) func(string, ...any) { return log.New(os.Stdout, prefix+": "+prepend, log.Ldate|log.Ltime).Printf } if level >= LogLevelVerbose { diff --git a/device/pools.go b/device/pools.go index f1d1fa0..f40477b 100644 --- a/device/pools.go +++ b/device/pools.go @@ -18,13 +18,13 @@ type WaitPool struct { max uint32 } -func NewWaitPool(max uint32, new func() interface{}) *WaitPool { +func NewWaitPool(max uint32, new func() any) *WaitPool { p := &WaitPool{pool: sync.Pool{New: new}, max: max} p.cond = sync.Cond{L: &p.lock} return p } -func (p *WaitPool) Get() interface{} { +func (p *WaitPool) Get() any { if p.max != 0 { p.lock.Lock() for atomic.LoadUint32(&p.count) >= p.max { @@ -36,7 +36,7 @@ func (p *WaitPool) Get() interface{} { return p.pool.Get() } -func (p *WaitPool) Put(x interface{}) { +func (p *WaitPool) Put(x any) { p.pool.Put(x) if p.max == 0 { return @@ -46,13 +46,13 @@ func (p *WaitPool) Put(x interface{}) { } func (device *Device) PopulatePools() { - device.pool.messageBuffers = NewWaitPool(PreallocatedBuffersPerPool, func() interface{} { + device.pool.messageBuffers = NewWaitPool(PreallocatedBuffersPerPool, func() any { return new([MaxMessageSize]byte) }) - device.pool.inboundElements = NewWaitPool(PreallocatedBuffersPerPool, func() interface{} { + device.pool.inboundElements = NewWaitPool(PreallocatedBuffersPerPool, func() any { return new(QueueInboundElement) }) - device.pool.outboundElements = NewWaitPool(PreallocatedBuffersPerPool, func() interface{} { + device.pool.outboundElements = NewWaitPool(PreallocatedBuffersPerPool, func() any { return new(QueueOutboundElement) }) } diff --git a/device/pools_test.go b/device/pools_test.go index b0840e1..17e2298 100644 --- a/device/pools_test.go +++ b/device/pools_test.go @@ -26,7 +26,7 @@ func TestWaitPool(t *testing.T) { if workers-4 <= 0 { t.Skip("Not enough cores") } - p := NewWaitPool(uint32(workers-4), func() interface{} { return make([]byte, 16) }) + p := NewWaitPool(uint32(workers-4), func() any { return make([]byte, 16) }) wg.Add(workers) max := uint32(0) updateMax := func() { @@ -71,7 +71,7 @@ func BenchmarkWaitPool(b *testing.B) { if workers-4 <= 0 { b.Skip("Not enough cores") } - p := NewWaitPool(uint32(workers-4), func() interface{} { return make([]byte, 16) }) + p := NewWaitPool(uint32(workers-4), func() any { return make([]byte, 16) }) wg.Add(workers) b.ResetTimer() for i := 0; i < workers; i++ { diff --git a/device/uapi.go b/device/uapi.go index 1994d46..30dd97e 100644 --- a/device/uapi.go +++ b/device/uapi.go @@ -12,13 +12,13 @@ import ( "fmt" "io" "net" + "net/netip" "strconv" "strings" "sync" "sync/atomic" "time" - "golang.zx2c4.com/go118/netip" "golang.zx2c4.com/wireguard/ipc" ) @@ -39,12 +39,12 @@ func (s IPCError) ErrorCode() int64 { return s.code } -func ipcErrorf(code int64, msg string, args ...interface{}) *IPCError { +func ipcErrorf(code int64, msg string, args ...any) *IPCError { return &IPCError{code: code, err: fmt.Errorf(msg, args...)} } var byteBufferPool = &sync.Pool{ - New: func() interface{} { return new(bytes.Buffer) }, + New: func() any { return new(bytes.Buffer) }, } // IpcGetOperation implements the WireGuard configuration protocol "get" operation. @@ -56,7 +56,7 @@ func (device *Device) IpcGetOperation(w io.Writer) error { buf := byteBufferPool.Get().(*bytes.Buffer) buf.Reset() defer byteBufferPool.Put(buf) - sendf := func(format string, args ...interface{}) { + sendf := func(format string, args ...any) { fmt.Fprintf(buf, format, args...) buf.WriteByte('\n') } @@ -161,12 +161,10 @@ func (device *Device) IpcSetOperation(r io.Reader) (err error) { peer.handlePostConfig() return nil } - parts := strings.Split(line, "=") - if len(parts) != 2 { - return ipcErrorf(ipc.IpcErrorProtocol, "failed to parse line %q, found %d =-separated parts, want 2", line, len(parts)) + key, value, ok := strings.Cut(line, "=") + if !ok { + return ipcErrorf(ipc.IpcErrorProtocol, "failed to parse line %q", line) } - key := parts[0] - value := parts[1] if key == "public_key" { if deviceConfig { @@ -1,11 +1,10 @@ module golang.zx2c4.com/wireguard -go 1.17 +go 1.18 require ( - golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa - golang.org/x/net v0.0.0-20211111083644-e5c967477495 - golang.org/x/sys v0.0.0-20211110154304-99a53858aa08 - golang.zx2c4.com/go118/netip v0.0.0-20211111135330-a4a02eeacf9d + golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd + golang.org/x/net v0.0.0-20220225172249-27dd8689420f + golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 ) @@ -1,19 +1,8 @@ -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211111083644-e5c967477495 h1:cjxxlQm6d4kYbhpZ2ghvmI8xnq0AG+jXmzrhzfkyu5A= -golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211110154304-99a53858aa08 h1:WecRHqgE09JBkh/584XIE6PMz5KKE/vER4izNUi30AQ= -golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.zx2c4.com/go118/netip v0.0.0-20211111135330-a4a02eeacf9d h1:9+v0G0naRhLPOJEeJOL6NuXTtAHHwmkyZlgQJ0XcQ8I= -golang.zx2c4.com/go118/netip v0.0.0-20211111135330-a4a02eeacf9d/go.mod h1:5yyfuiqVIJ7t+3MqrpTQ+QqRkMWiESiyDvPNvKYCecg= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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= diff --git a/ratelimiter/ratelimiter.go b/ratelimiter/ratelimiter.go index 8e78d5e..1e3c252 100644 --- a/ratelimiter/ratelimiter.go +++ b/ratelimiter/ratelimiter.go @@ -6,10 +6,9 @@ package ratelimiter import ( + "net/netip" "sync" "time" - - "golang.zx2c4.com/go118/netip" ) const ( diff --git a/ratelimiter/ratelimiter_test.go b/ratelimiter/ratelimiter_test.go index 3e06ff7..ca7db72 100644 --- a/ratelimiter/ratelimiter_test.go +++ b/ratelimiter/ratelimiter_test.go @@ -6,10 +6,9 @@ package ratelimiter import ( + "net/netip" "testing" "time" - - "golang.zx2c4.com/go118/netip" ) type result struct { diff --git a/tun/netstack/examples/http_client.go b/tun/netstack/examples/http_client.go index b39b453..352c1e4 100644 --- a/tun/netstack/examples/http_client.go +++ b/tun/netstack/examples/http_client.go @@ -12,8 +12,8 @@ import ( "io" "log" "net/http" + "net/netip" - "golang.zx2c4.com/go118/netip" "golang.zx2c4.com/wireguard/conn" "golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/tun/netstack" diff --git a/tun/netstack/examples/http_server.go b/tun/netstack/examples/http_server.go index 40f7804..0fdf4cd 100644 --- a/tun/netstack/examples/http_server.go +++ b/tun/netstack/examples/http_server.go @@ -13,8 +13,8 @@ import ( "log" "net" "net/http" + "net/netip" - "golang.zx2c4.com/go118/netip" "golang.zx2c4.com/wireguard/conn" "golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/tun/netstack" diff --git a/tun/netstack/examples/ping_client.go b/tun/netstack/examples/ping_client.go new file mode 100644 index 0000000..a1bc7f8 --- /dev/null +++ b/tun/netstack/examples/ping_client.go @@ -0,0 +1,76 @@ +//go:build ignore +// +build ignore + +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved. + */ + +package main + +import ( + "bytes" + "log" + "math/rand" + "net/netip" + "time" + + "golang.org/x/net/icmp" + "golang.org/x/net/ipv4" + + "golang.zx2c4.com/wireguard/conn" + "golang.zx2c4.com/wireguard/device" + "golang.zx2c4.com/wireguard/tun/netstack" +) + +func main() { + tun, tnet, err := netstack.CreateNetTUN( + []netip.Addr{netip.MustParseAddr("192.168.4.29")}, + []netip.Addr{netip.MustParseAddr("8.8.8.8")}, + 1420) + if err != nil { + log.Panic(err) + } + dev := device.NewDevice(tun, conn.NewDefaultBind(), device.NewLogger(device.LogLevelVerbose, "")) + dev.IpcSet(`private_key=a8dac1d8a70a751f0f699fb14ba1cff7b79cf4fbd8f09f44c6e6a90d0369604f +public_key=25123c5dcd3328ff645e4f2a3fce0d754400d3887a0cb7c56f0267e20fbf3c5b +endpoint=163.172.161.0:12912 +allowed_ip=0.0.0.0/0 +`) + err = dev.Up() + if err != nil { + log.Panic(err) + } + + socket, err := tnet.Dial("ping4", "zx2c4.com") + if err != nil { + log.Panic(err) + } + requestPing := icmp.Echo{ + Seq: rand.Intn(1 << 16), + Data: []byte("gopher burrow"), + } + icmpBytes, _ := (&icmp.Message{Type: ipv4.ICMPTypeEcho, Code: 0, Body: &requestPing}).Marshal(nil) + socket.SetReadDeadline(time.Now().Add(time.Second * 10)) + start := time.Now() + _, err = socket.Write(icmpBytes) + if err != nil { + log.Panic(err) + } + n, err := socket.Read(icmpBytes[:]) + if err != nil { + log.Panic(err) + } + replyPacket, err := icmp.ParseMessage(1, icmpBytes[:n]) + if err != nil { + log.Panic(err) + } + replyPing, ok := replyPacket.Body.(*icmp.Echo) + if !ok { + log.Panicf("invalid reply type: %v", replyPacket) + } + if !bytes.Equal(replyPing.Data, requestPing.Data) || replyPing.Seq != requestPing.Seq { + log.Panicf("invalid ping reply: %v", replyPing) + } + log.Printf("Ping latency: %v", time.Since(start)) +} diff --git a/tun/netstack/go.mod b/tun/netstack/go.mod index 46b57ba..18aa993 100644 --- a/tun/netstack/go.mod +++ b/tun/netstack/go.mod @@ -1,12 +1,17 @@ module golang.zx2c4.com/wireguard/tun/netstack -go 1.16 +go 1.18 require ( - golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 - golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 // indirect - golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect - golang.zx2c4.com/go118/netip v0.0.0-20211105124833-002a02cb0e53 - golang.zx2c4.com/wireguard v0.0.0-20210424170727-c9db4b7aaa22 + golang.org/x/net v0.0.0-20220225172249-27dd8689420f + golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24 gvisor.dev/gvisor v0.0.0-20211020211948-f76a604701b6 ) + +require ( + github.com/google/btree v1.0.1 // indirect + golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect + golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 // indirect + golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect + golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect +) diff --git a/tun/netstack/go.sum b/tun/netstack/go.sum index 01bfbc7..845c7e0 100644 --- a/tun/netstack/go.sum +++ b/tun/netstack/go.sum @@ -559,8 +559,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -638,8 +639,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 h1:0PC75Fz/kyMGhL0e1QnypqK2kQMqKt9csD1GnMJR+Zk= -golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -726,11 +727,9 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210314195730-07df6a141424/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 h1:iGu644GcxtEcrInvDsQRCwJjtCIOlT2V7IRt6ah2Whw= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -741,13 +740,11 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -805,12 +802,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.zx2c4.com/go118/netip v0.0.0-20211104120624-f0ae7a6e37c5 h1:mV4w4F7AtWXoDNkko9odoTdWpNwyDh8jx+S1fOZKDLg= -golang.zx2c4.com/go118/netip v0.0.0-20211104120624-f0ae7a6e37c5/go.mod h1:5yyfuiqVIJ7t+3MqrpTQ+QqRkMWiESiyDvPNvKYCecg= -golang.zx2c4.com/go118/netip v0.0.0-20211105124833-002a02cb0e53 h1:nFvpdzrHF9IPo9xPgayHWObCATpQYKky8VSSdt9lf9E= -golang.zx2c4.com/go118/netip v0.0.0-20211105124833-002a02cb0e53/go.mod h1:5yyfuiqVIJ7t+3MqrpTQ+QqRkMWiESiyDvPNvKYCecg= -golang.zx2c4.com/wireguard v0.0.0-20210424170727-c9db4b7aaa22 h1:ytS28bw9HtZVDRMDxviC6ryCJuccw+zXhh04u2IRWJw= -golang.zx2c4.com/wireguard v0.0.0-20210424170727-c9db4b7aaa22/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg= +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-20220316235147-5aff28b14c24 h1:KwsvzlnmErwMd3BXoBSEuL8qU72QxFM/uOUAgZmavRc= +golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= diff --git a/tun/netstack/tun.go b/tun/netstack/tun.go index fb7f07d..c26d8ed 100644 --- a/tun/netstack/tun.go +++ b/tun/netstack/tun.go @@ -13,12 +13,13 @@ import ( "fmt" "io" "net" + "net/netip" "os" + "regexp" "strconv" "strings" "time" - "golang.zx2c4.com/go118/netip" "golang.zx2c4.com/wireguard/tun" "golang.org/x/net/dns/dnsmessage" @@ -29,8 +30,10 @@ import ( "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" "gvisor.dev/gvisor/pkg/tcpip/network/ipv6" "gvisor.dev/gvisor/pkg/tcpip/stack" + "gvisor.dev/gvisor/pkg/tcpip/transport/icmp" "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" "gvisor.dev/gvisor/pkg/tcpip/transport/udp" + "gvisor.dev/gvisor/pkg/waiter" ) type netTun struct { @@ -101,7 +104,7 @@ func (e *endpoint) AddHeader(tcpip.LinkAddress, tcpip.LinkAddress, tcpip.Network func CreateNetTUN(localAddresses, dnsServers []netip.Addr, mtu int) (tun.Device, *Net, error) { opts := stack.Options{ NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol}, - TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol}, + TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol, icmp.NewProtocol6, icmp.NewProtocol4}, HandleLocal: true, } dev := &netTun{ @@ -227,7 +230,8 @@ func (net *Net) DialContextTCP(ctx context.Context, addr *net.TCPAddr) (*gonet.T if addr == nil { return net.DialContextTCPAddrPort(ctx, netip.AddrPort{}) } - return net.DialContextTCPAddrPort(ctx, netip.AddrPortFrom(netip.AddrFromSlice(addr.IP), uint16(addr.Port))) + ip, _ := netip.AddrFromSlice(addr.IP) + return net.DialContextTCPAddrPort(ctx, netip.AddrPortFrom(ip, uint16(addr.Port))) } func (net *Net) DialTCPAddrPort(addr netip.AddrPort) (*gonet.TCPConn, error) { @@ -239,7 +243,8 @@ func (net *Net) DialTCP(addr *net.TCPAddr) (*gonet.TCPConn, error) { if addr == nil { return net.DialTCPAddrPort(netip.AddrPort{}) } - return net.DialTCPAddrPort(netip.AddrPortFrom(netip.AddrFromSlice(addr.IP), uint16(addr.Port))) + ip, _ := netip.AddrFromSlice(addr.IP) + return net.DialTCPAddrPort(netip.AddrPortFrom(ip, uint16(addr.Port))) } func (net *Net) ListenTCPAddrPort(addr netip.AddrPort) (*gonet.TCPListener, error) { @@ -251,7 +256,8 @@ func (net *Net) ListenTCP(addr *net.TCPAddr) (*gonet.TCPListener, error) { if addr == nil { return net.ListenTCPAddrPort(netip.AddrPort{}) } - return net.ListenTCPAddrPort(netip.AddrPortFrom(netip.AddrFromSlice(addr.IP), uint16(addr.Port))) + ip, _ := netip.AddrFromSlice(addr.IP) + return net.ListenTCPAddrPort(netip.AddrPortFrom(ip, uint16(addr.Port))) } func (net *Net) DialUDPAddrPort(laddr, raddr netip.AddrPort) (*gonet.UDPConn, error) { @@ -270,17 +276,222 @@ func (net *Net) DialUDPAddrPort(laddr, raddr netip.AddrPort) (*gonet.UDPConn, er return gonet.DialUDP(net.stack, lfa, rfa, pn) } +func (net *Net) ListenUDPAddrPort(laddr netip.AddrPort) (*gonet.UDPConn, error) { + return net.DialUDPAddrPort(laddr, netip.AddrPort{}) +} + func (net *Net) DialUDP(laddr, raddr *net.UDPAddr) (*gonet.UDPConn, error) { var la, ra netip.AddrPort if laddr != nil { - la = netip.AddrPortFrom(netip.AddrFromSlice(laddr.IP), uint16(laddr.Port)) + ip, _ := netip.AddrFromSlice(laddr.IP) + la = netip.AddrPortFrom(ip, uint16(laddr.Port)) } if raddr != nil { - ra = netip.AddrPortFrom(netip.AddrFromSlice(raddr.IP), uint16(raddr.Port)) + ip, _ := netip.AddrFromSlice(raddr.IP) + ra = netip.AddrPortFrom(ip, uint16(raddr.Port)) } return net.DialUDPAddrPort(la, ra) } +func (net *Net) ListenUDP(laddr *net.UDPAddr) (*gonet.UDPConn, error) { + return net.DialUDP(laddr, nil) +} + +type PingConn struct { + laddr PingAddr + raddr PingAddr + wq waiter.Queue + ep tcpip.Endpoint + deadline *time.Timer +} + +type PingAddr struct{ addr netip.Addr } + +func (ia PingAddr) String() string { + return ia.addr.String() +} + +func (ia PingAddr) Network() string { + if ia.addr.Is4() { + return "ping4" + } else if ia.addr.Is6() { + return "ping6" + } + return "ping" +} + +func (ia PingAddr) Addr() netip.Addr { + return ia.addr +} + +func PingAddrFromAddr(addr netip.Addr) *PingAddr { + return &PingAddr{addr} +} + +func (net *Net) DialPingAddr(laddr, raddr netip.Addr) (*PingConn, error) { + if !laddr.IsValid() && !raddr.IsValid() { + return nil, errors.New("ping dial: invalid address") + } + v6 := laddr.Is6() || raddr.Is6() + bind := laddr.IsValid() + if !bind { + if v6 { + laddr = netip.IPv6Unspecified() + } else { + laddr = netip.IPv4Unspecified() + } + } + + tn := icmp.ProtocolNumber4 + pn := ipv4.ProtocolNumber + if v6 { + tn = icmp.ProtocolNumber6 + pn = ipv6.ProtocolNumber + } + + pc := &PingConn{ + laddr: PingAddr{laddr}, + deadline: time.NewTimer(time.Hour << 10), + } + pc.deadline.Stop() + + ep, tcpipErr := net.stack.NewEndpoint(tn, pn, &pc.wq) + if tcpipErr != nil { + return nil, fmt.Errorf("ping socket: endpoint: %s", tcpipErr) + } + pc.ep = ep + + if bind { + fa, _ := convertToFullAddr(netip.AddrPortFrom(laddr, 0)) + if tcpipErr = pc.ep.Bind(fa); tcpipErr != nil { + return nil, fmt.Errorf("ping bind: %s", tcpipErr) + } + } + + if raddr.IsValid() { + pc.raddr = PingAddr{raddr} + fa, _ := convertToFullAddr(netip.AddrPortFrom(raddr, 0)) + if tcpipErr = pc.ep.Connect(fa); tcpipErr != nil { + return nil, fmt.Errorf("ping connect: %s", tcpipErr) + } + } + + return pc, nil +} + +func (net *Net) ListenPingAddr(laddr netip.Addr) (*PingConn, error) { + return net.DialPingAddr(laddr, netip.Addr{}) +} + +func (net *Net) DialPing(laddr, raddr *PingAddr) (*PingConn, error) { + var la, ra netip.Addr + if laddr != nil { + la = laddr.addr + } + if raddr != nil { + ra = raddr.addr + } + return net.DialPingAddr(la, ra) +} + +func (net *Net) ListenPing(laddr *PingAddr) (*PingConn, error) { + var la netip.Addr + if laddr != nil { + la = laddr.addr + } + return net.ListenPingAddr(la) +} + +func (pc *PingConn) LocalAddr() net.Addr { + return pc.laddr +} + +func (pc *PingConn) RemoteAddr() net.Addr { + return pc.raddr +} + +func (pc *PingConn) Close() error { + pc.deadline.Reset(0) + pc.ep.Close() + return nil +} + +func (pc *PingConn) SetWriteDeadline(t time.Time) error { + return errors.New("not implemented") +} + +func (pc *PingConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { + var na netip.Addr + switch v := addr.(type) { + case *PingAddr: + na = v.addr + case *net.IPAddr: + na, _ = netip.AddrFromSlice(v.IP) + default: + return 0, fmt.Errorf("ping write: wrong net.Addr type") + } + if !((na.Is4() && pc.laddr.addr.Is4()) || (na.Is6() && pc.laddr.addr.Is6())) { + return 0, fmt.Errorf("ping write: mismatched protocols") + } + + buf := buffer.NewViewFromBytes(p) + rdr := buf.Reader() + rfa, _ := convertToFullAddr(netip.AddrPortFrom(na, 0)) + // won't block, no deadlines + n64, tcpipErr := pc.ep.Write(&rdr, tcpip.WriteOptions{ + To: &rfa, + }) + if tcpipErr != nil { + return int(n64), fmt.Errorf("ping write: %s", tcpipErr) + } + + return int(n64), nil +} + +func (pc *PingConn) Write(p []byte) (n int, err error) { + return pc.WriteTo(p, &pc.raddr) +} + +func (pc *PingConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { + e, notifyCh := waiter.NewChannelEntry(nil) + pc.wq.EventRegister(&e, waiter.EventIn) + defer pc.wq.EventUnregister(&e) + + select { + case <-pc.deadline.C: + return 0, nil, os.ErrDeadlineExceeded + case <-notifyCh: + } + + w := tcpip.SliceWriter(p) + + res, tcpipErr := pc.ep.Read(&w, tcpip.ReadOptions{ + NeedRemoteAddr: true, + }) + if tcpipErr != nil { + return 0, nil, fmt.Errorf("ping read: %s", tcpipErr) + } + + remoteAddr, _ := netip.AddrFromSlice([]byte(res.RemoteAddr.Addr)) + return res.Count, &PingAddr{remoteAddr}, nil +} + +func (pc *PingConn) Read(p []byte) (n int, err error) { + n, _, err = pc.ReadFrom(p) + return +} + +func (pc *PingConn) SetDeadline(t time.Time) error { + // pc.SetWriteDeadline is unimplemented + + return pc.SetReadDeadline(t) +} + +func (pc *PingConn) SetReadDeadline(t time.Time) error { + pc.deadline.Reset(t.Sub(time.Now())) + return nil +} + var ( errNoSuchHost = errors.New("no such host") errLameReferral = errors.New("lame referral") @@ -479,7 +690,10 @@ func (tnet *Net) exchange(ctx context.Context, server netip.Addr, q dnsmessage.Q return dnsmessage.Parser{}, dnsmessage.Header{}, err } if d, ok := ctx.Deadline(); ok && !d.IsZero() { - c.SetDeadline(d) + err := c.SetDeadline(d) + if err != nil { + return dnsmessage.Parser{}, dnsmessage.Header{}, err + } } var p dnsmessage.Parser var h dnsmessage.Header @@ -755,33 +969,38 @@ func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, er return now.Add(timeout), nil } +var protoSplitter = regexp.MustCompile(`^(tcp|udp|ping)(4|6)?$`) + func (tnet *Net) DialContext(ctx context.Context, network, address string) (net.Conn, error) { if ctx == nil { panic("nil context") } - var acceptV4, acceptV6, useUDP bool - if len(network) == 3 { + var acceptV4, acceptV6 bool + matches := protoSplitter.FindStringSubmatch(network) + if matches == nil { + return nil, &net.OpError{Op: "dial", Err: net.UnknownNetworkError(network)} + } else if len(matches[2]) == 0 { acceptV4 = true acceptV6 = true - } else if len(network) == 4 { - acceptV4 = network[3] == '4' - acceptV6 = network[3] == '6' - } - if !acceptV4 && !acceptV6 { - return nil, &net.OpError{Op: "dial", Err: net.UnknownNetworkError(network)} - } - if network[:3] == "udp" { - useUDP = true - } else if network[:3] != "tcp" { - return nil, &net.OpError{Op: "dial", Err: net.UnknownNetworkError(network)} - } - host, sport, err := net.SplitHostPort(address) - if err != nil { - return nil, &net.OpError{Op: "dial", Err: err} + } else { + acceptV4 = matches[2][0] == '4' + acceptV6 = !acceptV4 } - port, err := strconv.Atoi(sport) - if err != nil || port < 0 || port > 65535 { - return nil, &net.OpError{Op: "dial", Err: errNumericPort} + var host string + var port int + if matches[1] == "ping" { + host = address + } else { + var sport string + var err error + host, sport, err = net.SplitHostPort(address) + if err != nil { + return nil, &net.OpError{Op: "dial", Err: err} + } + port, err = strconv.Atoi(sport) + if err != nil || port < 0 || port > 65535 { + return nil, &net.OpError{Op: "dial", Err: errNumericPort} + } } allAddr, err := tnet.LookupContextHost(ctx, host) if err != nil { @@ -829,10 +1048,13 @@ func (tnet *Net) DialContext(ctx context.Context, network, address string) (net. } var c net.Conn - if useUDP { - c, err = tnet.DialUDPAddrPort(netip.AddrPort{}, addr) - } else { + switch matches[1] { + case "tcp": c, err = tnet.DialContextTCPAddrPort(dialCtx, addr) + case "udp": + c, err = tnet.DialUDPAddrPort(netip.AddrPort{}, addr) + case "ping": + c, err = tnet.DialPingAddr(netip.Addr{}, addr.Addr()) } if err == nil { return c, nil diff --git a/tun/tuntest/tuntest.go b/tun/tuntest/tuntest.go index bdf0467..8196c34 100644 --- a/tun/tuntest/tuntest.go +++ b/tun/tuntest/tuntest.go @@ -8,9 +8,9 @@ package tuntest import ( "encoding/binary" "io" + "net/netip" "os" - "golang.zx2c4.com/go118/netip" "golang.zx2c4.com/wireguard/tun" ) @@ -1,3 +1,3 @@ package main -const Version = "0.0.20211016" +const Version = "0.0.20220316" |