diff --git a/docker/images/visor/install-preq.sh b/docker/images/visor/install-preq.sh index 8c8293c825..feb3838b5c 100755 --- a/docker/images/visor/install-preq.sh +++ b/docker/images/visor/install-preq.sh @@ -2,12 +2,12 @@ if type apt >/dev/null; then apt-get update && apt-get install -y --no-install-recommends \ - ca-certificates && + ca-certificates iptables && rm -rf /var/lib/apt/lists/* fi if type apk >/dev/null; then apk update - apk add --no-cache ca-certificates openssl iproute2 bash + apk add --no-cache ca-certificates openssl iproute2 bash iptables update-ca-certificates --fresh fi diff --git a/go.mod b/go.mod index bf7b33efa2..371f8705c6 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( golang.org/x/net v0.14.0 golang.org/x/sync v0.3.0 golang.org/x/sys v0.11.0 - golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 + golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675 ) require ( diff --git a/go.sum b/go.sum index 5307a88a02..a63dc333b3 100644 --- a/go.sum +++ b/go.sum @@ -451,6 +451,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= +golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675 h1:/J/RVnr7ng4fWPRH3xa4WtBJ1Jp+Auu4YNLmGiPv5QU= +golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675/go.mod h1:whfbyDBt09xhCYQWtO2+3UVjlaq6/9hDZrjg2ZE6SyA= golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 h1:EY138uSo1JYlDq+97u1FtcOUwPpIU6WL1Lkt7WpYjPA= golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1/go.mod h1:tqur9LnfstdR9ep2LaJT4lFUl0EjlHtge+gAjmsHUG4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= diff --git a/internal/vpn/tun_device_windows.go b/internal/vpn/tun_device_windows.go index c80d6b041b..bc49187e5c 100644 --- a/internal/vpn/tun_device_windows.go +++ b/internal/vpn/tun_device_windows.go @@ -34,13 +34,11 @@ func newTUNDevice() (TUNDevice, error) { } func (t *tunDevice) Read(buf []byte) (int, error) { - validBuf := [][]byte{buf} - return t.tun.Read(validBuf, []int{len(buf) + 1}, 0) + return t.tun.Read(buf, 0) } func (t *tunDevice) Write(buf []byte) (int, error) { - validBuf := [][]byte{buf} - return t.tun.Write(validBuf, 0) + return t.tun.Write(buf, 0) } func (t *tunDevice) Close() error { diff --git a/scripts/win_installer/Product.wxs b/scripts/win_installer/Product.wxs index df26c756ce..d501deb236 100644 --- a/scripts/win_installer/Product.wxs +++ b/scripts/win_installer/Product.wxs @@ -21,11 +21,9 @@ - - + = - NOT NEWERVERSIONDETECTED + NEWERVERSIONDETECTED diff --git a/vendor/golang.zx2c4.com/wireguard/conn/bind_std.go b/vendor/golang.zx2c4.com/wireguard/conn/bind_std.go deleted file mode 100644 index c701ef8724..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/bind_std.go +++ /dev/null @@ -1,408 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -import ( - "context" - "errors" - "net" - "net/netip" - "runtime" - "strconv" - "sync" - "syscall" - - "golang.org/x/net/ipv4" - "golang.org/x/net/ipv6" -) - -var ( - _ Bind = (*StdNetBind)(nil) -) - -// StdNetBind implements Bind for all platforms. While Windows has its own Bind -// (see bind_windows.go), it may fall back to StdNetBind. -// TODO: Remove usage of ipv{4,6}.PacketConn when net.UDPConn has comparable -// methods for sending and receiving multiple datagrams per-syscall. See the -// proposal in https://github.com/golang/go/issues/45886#issuecomment-1218301564. -type StdNetBind struct { - mu sync.Mutex // protects all fields except as specified - ipv4 *net.UDPConn - ipv6 *net.UDPConn - ipv4PC *ipv4.PacketConn // will be nil on non-Linux - ipv6PC *ipv6.PacketConn // will be nil on non-Linux - - // these three fields are not guarded by mu - udpAddrPool sync.Pool - ipv4MsgsPool sync.Pool - ipv6MsgsPool sync.Pool - - blackhole4 bool - blackhole6 bool -} - -func NewStdNetBind() Bind { - return &StdNetBind{ - udpAddrPool: sync.Pool{ - New: func() any { - return &net.UDPAddr{ - IP: make([]byte, 16), - } - }, - }, - - ipv4MsgsPool: sync.Pool{ - New: func() any { - msgs := make([]ipv4.Message, IdealBatchSize) - for i := range msgs { - msgs[i].Buffers = make(net.Buffers, 1) - msgs[i].OOB = make([]byte, srcControlSize) - } - return &msgs - }, - }, - - ipv6MsgsPool: sync.Pool{ - New: func() any { - msgs := make([]ipv6.Message, IdealBatchSize) - for i := range msgs { - msgs[i].Buffers = make(net.Buffers, 1) - msgs[i].OOB = make([]byte, srcControlSize) - } - return &msgs - }, - }, - } -} - -type StdNetEndpoint struct { - // AddrPort is the endpoint destination. - netip.AddrPort - // src is the current sticky source address and interface index, if - // supported. Typically this is a PKTINFO structure from/for control - // messages, see unix.PKTINFO for an example. - src []byte -} - -var ( - _ Bind = (*StdNetBind)(nil) - _ Endpoint = &StdNetEndpoint{} -) - -func (*StdNetBind) ParseEndpoint(s string) (Endpoint, error) { - e, err := netip.ParseAddrPort(s) - if err != nil { - return nil, err - } - return &StdNetEndpoint{ - AddrPort: e, - }, nil -} - -func (e *StdNetEndpoint) ClearSrc() { - if e.src != nil { - // Truncate src, no need to reallocate. - e.src = e.src[:0] - } -} - -func (e *StdNetEndpoint) DstIP() netip.Addr { - return e.AddrPort.Addr() -} - -// See sticky_default,linux, etc for implementations of SrcIP and SrcIfidx. - -func (e *StdNetEndpoint) DstToBytes() []byte { - b, _ := e.AddrPort.MarshalBinary() - return b -} - -func (e *StdNetEndpoint) DstToString() string { - return e.AddrPort.String() -} - -func listenNet(network string, port int) (*net.UDPConn, int, error) { - conn, err := listenConfig().ListenPacket(context.Background(), network, ":"+strconv.Itoa(port)) - if err != nil { - return nil, 0, err - } - - // Retrieve port. - laddr := conn.LocalAddr() - uaddr, err := net.ResolveUDPAddr( - laddr.Network(), - laddr.String(), - ) - if err != nil { - return nil, 0, err - } - return conn.(*net.UDPConn), uaddr.Port, nil -} - -func (s *StdNetBind) Open(uport uint16) ([]ReceiveFunc, uint16, error) { - s.mu.Lock() - defer s.mu.Unlock() - - var err error - var tries int - - if s.ipv4 != nil || s.ipv6 != nil { - return nil, 0, ErrBindAlreadyOpen - } - - // Attempt to open ipv4 and ipv6 listeners on the same port. - // If uport is 0, we can retry on failure. -again: - port := int(uport) - var v4conn, v6conn *net.UDPConn - var v4pc *ipv4.PacketConn - var v6pc *ipv6.PacketConn - - v4conn, port, err = listenNet("udp4", port) - if err != nil && !errors.Is(err, syscall.EAFNOSUPPORT) { - return nil, 0, err - } - - // Listen on the same port as we're using for ipv4. - v6conn, port, err = listenNet("udp6", port) - if uport == 0 && errors.Is(err, syscall.EADDRINUSE) && tries < 100 { - v4conn.Close() - tries++ - goto again - } - if err != nil && !errors.Is(err, syscall.EAFNOSUPPORT) { - v4conn.Close() - return nil, 0, err - } - var fns []ReceiveFunc - if v4conn != nil { - if runtime.GOOS == "linux" { - v4pc = ipv4.NewPacketConn(v4conn) - s.ipv4PC = v4pc - } - fns = append(fns, s.makeReceiveIPv4(v4pc, v4conn)) - s.ipv4 = v4conn - } - if v6conn != nil { - if runtime.GOOS == "linux" { - v6pc = ipv6.NewPacketConn(v6conn) - s.ipv6PC = v6pc - } - fns = append(fns, s.makeReceiveIPv6(v6pc, v6conn)) - s.ipv6 = v6conn - } - if len(fns) == 0 { - return nil, 0, syscall.EAFNOSUPPORT - } - - return fns, uint16(port), nil -} - -func (s *StdNetBind) makeReceiveIPv4(pc *ipv4.PacketConn, conn *net.UDPConn) ReceiveFunc { - return func(bufs [][]byte, sizes []int, eps []Endpoint) (n int, err error) { - msgs := s.ipv4MsgsPool.Get().(*[]ipv4.Message) - defer s.ipv4MsgsPool.Put(msgs) - for i := range bufs { - (*msgs)[i].Buffers[0] = bufs[i] - } - var numMsgs int - if runtime.GOOS == "linux" { - numMsgs, err = pc.ReadBatch(*msgs, 0) - if err != nil { - return 0, err - } - } else { - msg := &(*msgs)[0] - msg.N, msg.NN, _, msg.Addr, err = conn.ReadMsgUDP(msg.Buffers[0], msg.OOB) - if err != nil { - return 0, err - } - numMsgs = 1 - } - for i := 0; i < numMsgs; i++ { - msg := &(*msgs)[i] - sizes[i] = msg.N - addrPort := msg.Addr.(*net.UDPAddr).AddrPort() - ep := &StdNetEndpoint{AddrPort: addrPort} // TODO: remove allocation - getSrcFromControl(msg.OOB[:msg.NN], ep) - eps[i] = ep - } - return numMsgs, nil - } -} - -func (s *StdNetBind) makeReceiveIPv6(pc *ipv6.PacketConn, conn *net.UDPConn) ReceiveFunc { - return func(bufs [][]byte, sizes []int, eps []Endpoint) (n int, err error) { - msgs := s.ipv6MsgsPool.Get().(*[]ipv6.Message) - defer s.ipv6MsgsPool.Put(msgs) - for i := range bufs { - (*msgs)[i].Buffers[0] = bufs[i] - } - var numMsgs int - if runtime.GOOS == "linux" { - numMsgs, err = pc.ReadBatch(*msgs, 0) - if err != nil { - return 0, err - } - } else { - msg := &(*msgs)[0] - msg.N, msg.NN, _, msg.Addr, err = conn.ReadMsgUDP(msg.Buffers[0], msg.OOB) - if err != nil { - return 0, err - } - numMsgs = 1 - } - for i := 0; i < numMsgs; i++ { - msg := &(*msgs)[i] - sizes[i] = msg.N - addrPort := msg.Addr.(*net.UDPAddr).AddrPort() - ep := &StdNetEndpoint{AddrPort: addrPort} // TODO: remove allocation - getSrcFromControl(msg.OOB[:msg.NN], ep) - eps[i] = ep - } - return numMsgs, nil - } -} - -// TODO: When all Binds handle IdealBatchSize, remove this dynamic function and -// rename the IdealBatchSize constant to BatchSize. -func (s *StdNetBind) BatchSize() int { - if runtime.GOOS == "linux" { - return IdealBatchSize - } - return 1 -} - -func (s *StdNetBind) Close() error { - s.mu.Lock() - defer s.mu.Unlock() - - var err1, err2 error - if s.ipv4 != nil { - err1 = s.ipv4.Close() - s.ipv4 = nil - s.ipv4PC = nil - } - if s.ipv6 != nil { - err2 = s.ipv6.Close() - s.ipv6 = nil - s.ipv6PC = nil - } - s.blackhole4 = false - s.blackhole6 = false - if err1 != nil { - return err1 - } - return err2 -} - -func (s *StdNetBind) Send(bufs [][]byte, endpoint Endpoint) error { - s.mu.Lock() - blackhole := s.blackhole4 - conn := s.ipv4 - var ( - pc4 *ipv4.PacketConn - pc6 *ipv6.PacketConn - ) - is6 := false - if endpoint.DstIP().Is6() { - blackhole = s.blackhole6 - conn = s.ipv6 - pc6 = s.ipv6PC - is6 = true - } else { - pc4 = s.ipv4PC - } - s.mu.Unlock() - - if blackhole { - return nil - } - if conn == nil { - return syscall.EAFNOSUPPORT - } - if is6 { - return s.send6(conn, pc6, endpoint, bufs) - } else { - return s.send4(conn, pc4, endpoint, bufs) - } -} - -func (s *StdNetBind) send4(conn *net.UDPConn, pc *ipv4.PacketConn, ep Endpoint, bufs [][]byte) error { - ua := s.udpAddrPool.Get().(*net.UDPAddr) - as4 := ep.DstIP().As4() - copy(ua.IP, as4[:]) - ua.IP = ua.IP[:4] - ua.Port = int(ep.(*StdNetEndpoint).Port()) - msgs := s.ipv4MsgsPool.Get().(*[]ipv4.Message) - for i, buf := range bufs { - (*msgs)[i].Buffers[0] = buf - (*msgs)[i].Addr = ua - setSrcControl(&(*msgs)[i].OOB, ep.(*StdNetEndpoint)) - } - var ( - n int - err error - start int - ) - if runtime.GOOS == "linux" { - for { - n, err = pc.WriteBatch((*msgs)[start:len(bufs)], 0) - if err != nil || n == len((*msgs)[start:len(bufs)]) { - break - } - start += n - } - } else { - for i, buf := range bufs { - _, _, err = conn.WriteMsgUDP(buf, (*msgs)[i].OOB, ua) - if err != nil { - break - } - } - } - s.udpAddrPool.Put(ua) - s.ipv4MsgsPool.Put(msgs) - return err -} - -func (s *StdNetBind) send6(conn *net.UDPConn, pc *ipv6.PacketConn, ep Endpoint, bufs [][]byte) error { - ua := s.udpAddrPool.Get().(*net.UDPAddr) - as16 := ep.DstIP().As16() - copy(ua.IP, as16[:]) - ua.IP = ua.IP[:16] - ua.Port = int(ep.(*StdNetEndpoint).Port()) - msgs := s.ipv6MsgsPool.Get().(*[]ipv6.Message) - for i, buf := range bufs { - (*msgs)[i].Buffers[0] = buf - (*msgs)[i].Addr = ua - setSrcControl(&(*msgs)[i].OOB, ep.(*StdNetEndpoint)) - } - var ( - n int - err error - start int - ) - if runtime.GOOS == "linux" { - for { - n, err = pc.WriteBatch((*msgs)[start:len(bufs)], 0) - if err != nil || n == len((*msgs)[start:len(bufs)]) { - break - } - start += n - } - } else { - for i, buf := range bufs { - _, _, err = conn.WriteMsgUDP(buf, (*msgs)[i].OOB, ua) - if err != nil { - break - } - } - } - s.udpAddrPool.Put(ua) - s.ipv6MsgsPool.Put(msgs) - return err -} diff --git a/vendor/golang.zx2c4.com/wireguard/conn/bind_windows.go b/vendor/golang.zx2c4.com/wireguard/conn/bind_windows.go deleted file mode 100644 index d5095e004b..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/bind_windows.go +++ /dev/null @@ -1,601 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -import ( - "encoding/binary" - "io" - "net" - "net/netip" - "strconv" - "sync" - "sync/atomic" - "unsafe" - - "golang.org/x/sys/windows" - - "golang.zx2c4.com/wireguard/conn/winrio" -) - -const ( - packetsPerRing = 1024 - bytesPerPacket = 2048 - 32 - receiveSpins = 15 -) - -type ringPacket struct { - addr WinRingEndpoint - data [bytesPerPacket]byte -} - -type ringBuffer struct { - packets uintptr - head, tail uint32 - id winrio.BufferId - iocp windows.Handle - isFull bool - cq winrio.Cq - mu sync.Mutex - overlapped windows.Overlapped -} - -func (rb *ringBuffer) Push() *ringPacket { - for rb.isFull { - panic("ring is full") - } - ret := (*ringPacket)(unsafe.Pointer(rb.packets + (uintptr(rb.tail%packetsPerRing) * unsafe.Sizeof(ringPacket{})))) - rb.tail += 1 - if rb.tail%packetsPerRing == rb.head%packetsPerRing { - rb.isFull = true - } - return ret -} - -func (rb *ringBuffer) Return(count uint32) { - if rb.head%packetsPerRing == rb.tail%packetsPerRing && !rb.isFull { - return - } - rb.head += count - rb.isFull = false -} - -type afWinRingBind struct { - sock windows.Handle - rx, tx ringBuffer - rq winrio.Rq - mu sync.Mutex - blackhole bool -} - -// WinRingBind uses Windows registered I/O for fast ring buffered networking. -type WinRingBind struct { - v4, v6 afWinRingBind - mu sync.RWMutex - isOpen atomic.Uint32 // 0, 1, or 2 -} - -func NewDefaultBind() Bind { return NewWinRingBind() } - -func NewWinRingBind() Bind { - if !winrio.Initialize() { - return NewStdNetBind() - } - return new(WinRingBind) -} - -type WinRingEndpoint struct { - family uint16 - data [30]byte -} - -var ( - _ Bind = (*WinRingBind)(nil) - _ Endpoint = (*WinRingEndpoint)(nil) -) - -func (*WinRingBind) ParseEndpoint(s string) (Endpoint, error) { - host, port, err := net.SplitHostPort(s) - if err != nil { - return nil, err - } - host16, err := windows.UTF16PtrFromString(host) - if err != nil { - return nil, err - } - port16, err := windows.UTF16PtrFromString(port) - if err != nil { - return nil, err - } - hints := windows.AddrinfoW{ - Flags: windows.AI_NUMERICHOST, - Family: windows.AF_UNSPEC, - Socktype: windows.SOCK_DGRAM, - Protocol: windows.IPPROTO_UDP, - } - var addrinfo *windows.AddrinfoW - err = windows.GetAddrInfoW(host16, port16, &hints, &addrinfo) - if err != nil { - return nil, err - } - defer windows.FreeAddrInfoW(addrinfo) - if (addrinfo.Family != windows.AF_INET && addrinfo.Family != windows.AF_INET6) || addrinfo.Addrlen > unsafe.Sizeof(WinRingEndpoint{}) { - return nil, windows.ERROR_INVALID_ADDRESS - } - var dst [unsafe.Sizeof(WinRingEndpoint{})]byte - copy(dst[:], unsafe.Slice((*byte)(unsafe.Pointer(addrinfo.Addr)), addrinfo.Addrlen)) - return (*WinRingEndpoint)(unsafe.Pointer(&dst[0])), nil -} - -func (*WinRingEndpoint) ClearSrc() {} - -func (e *WinRingEndpoint) DstIP() netip.Addr { - switch e.family { - case windows.AF_INET: - return netip.AddrFrom4(*(*[4]byte)(e.data[2:6])) - case windows.AF_INET6: - return netip.AddrFrom16(*(*[16]byte)(e.data[6:22])) - } - return netip.Addr{} -} - -func (e *WinRingEndpoint) SrcIP() netip.Addr { - return netip.Addr{} // not supported -} - -func (e *WinRingEndpoint) DstToBytes() []byte { - switch e.family { - case windows.AF_INET: - b := make([]byte, 0, 6) - b = append(b, e.data[2:6]...) - b = append(b, e.data[1], e.data[0]) - return b - case windows.AF_INET6: - b := make([]byte, 0, 18) - b = append(b, e.data[6:22]...) - b = append(b, e.data[1], e.data[0]) - return b - } - return nil -} - -func (e *WinRingEndpoint) DstToString() string { - switch e.family { - case windows.AF_INET: - return netip.AddrPortFrom(netip.AddrFrom4(*(*[4]byte)(e.data[2:6])), binary.BigEndian.Uint16(e.data[0:2])).String() - case windows.AF_INET6: - var zone string - if scope := *(*uint32)(unsafe.Pointer(&e.data[22])); scope > 0 { - zone = strconv.FormatUint(uint64(scope), 10) - } - return netip.AddrPortFrom(netip.AddrFrom16(*(*[16]byte)(e.data[6:22])).WithZone(zone), binary.BigEndian.Uint16(e.data[0:2])).String() - } - return "" -} - -func (e *WinRingEndpoint) SrcToString() string { - return "" -} - -func (ring *ringBuffer) CloseAndZero() { - if ring.cq != 0 { - winrio.CloseCompletionQueue(ring.cq) - ring.cq = 0 - } - if ring.iocp != 0 { - windows.CloseHandle(ring.iocp) - ring.iocp = 0 - } - if ring.id != 0 { - winrio.DeregisterBuffer(ring.id) - ring.id = 0 - } - if ring.packets != 0 { - windows.VirtualFree(ring.packets, 0, windows.MEM_RELEASE) - ring.packets = 0 - } - ring.head = 0 - ring.tail = 0 - ring.isFull = false -} - -func (bind *afWinRingBind) CloseAndZero() { - bind.rx.CloseAndZero() - bind.tx.CloseAndZero() - if bind.sock != 0 { - windows.CloseHandle(bind.sock) - bind.sock = 0 - } - bind.blackhole = false -} - -func (bind *WinRingBind) closeAndZero() { - bind.isOpen.Store(0) - bind.v4.CloseAndZero() - bind.v6.CloseAndZero() -} - -func (ring *ringBuffer) Open() error { - var err error - packetsLen := unsafe.Sizeof(ringPacket{}) * packetsPerRing - ring.packets, err = windows.VirtualAlloc(0, packetsLen, windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE) - if err != nil { - return err - } - ring.id, err = winrio.RegisterPointer(unsafe.Pointer(ring.packets), uint32(packetsLen)) - if err != nil { - return err - } - ring.iocp, err = windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0) - if err != nil { - return err - } - ring.cq, err = winrio.CreateIOCPCompletionQueue(packetsPerRing, ring.iocp, 0, &ring.overlapped) - if err != nil { - return err - } - return nil -} - -func (bind *afWinRingBind) Open(family int32, sa windows.Sockaddr) (windows.Sockaddr, error) { - var err error - bind.sock, err = winrio.Socket(family, windows.SOCK_DGRAM, windows.IPPROTO_UDP) - if err != nil { - return nil, err - } - err = bind.rx.Open() - if err != nil { - return nil, err - } - err = bind.tx.Open() - if err != nil { - return nil, err - } - bind.rq, err = winrio.CreateRequestQueue(bind.sock, packetsPerRing, 1, packetsPerRing, 1, bind.rx.cq, bind.tx.cq, 0) - if err != nil { - return nil, err - } - err = windows.Bind(bind.sock, sa) - if err != nil { - return nil, err - } - sa, err = windows.Getsockname(bind.sock) - if err != nil { - return nil, err - } - return sa, nil -} - -func (bind *WinRingBind) Open(port uint16) (recvFns []ReceiveFunc, selectedPort uint16, err error) { - bind.mu.Lock() - defer bind.mu.Unlock() - defer func() { - if err != nil { - bind.closeAndZero() - } - }() - if bind.isOpen.Load() != 0 { - return nil, 0, ErrBindAlreadyOpen - } - var sa windows.Sockaddr - sa, err = bind.v4.Open(windows.AF_INET, &windows.SockaddrInet4{Port: int(port)}) - if err != nil { - return nil, 0, err - } - sa, err = bind.v6.Open(windows.AF_INET6, &windows.SockaddrInet6{Port: sa.(*windows.SockaddrInet4).Port}) - if err != nil { - return nil, 0, err - } - selectedPort = uint16(sa.(*windows.SockaddrInet6).Port) - for i := 0; i < packetsPerRing; i++ { - err = bind.v4.InsertReceiveRequest() - if err != nil { - return nil, 0, err - } - err = bind.v6.InsertReceiveRequest() - if err != nil { - return nil, 0, err - } - } - bind.isOpen.Store(1) - return []ReceiveFunc{bind.receiveIPv4, bind.receiveIPv6}, selectedPort, err -} - -func (bind *WinRingBind) Close() error { - bind.mu.RLock() - if bind.isOpen.Load() != 1 { - bind.mu.RUnlock() - return nil - } - bind.isOpen.Store(2) - windows.PostQueuedCompletionStatus(bind.v4.rx.iocp, 0, 0, nil) - windows.PostQueuedCompletionStatus(bind.v4.tx.iocp, 0, 0, nil) - windows.PostQueuedCompletionStatus(bind.v6.rx.iocp, 0, 0, nil) - windows.PostQueuedCompletionStatus(bind.v6.tx.iocp, 0, 0, nil) - bind.mu.RUnlock() - bind.mu.Lock() - defer bind.mu.Unlock() - bind.closeAndZero() - return nil -} - -// TODO: When all Binds handle IdealBatchSize, remove this dynamic function and -// rename the IdealBatchSize constant to BatchSize. -func (bind *WinRingBind) BatchSize() int { - // TODO: implement batching in and out of the ring - return 1 -} - -func (bind *WinRingBind) SetMark(mark uint32) error { - return nil -} - -func (bind *afWinRingBind) InsertReceiveRequest() error { - packet := bind.rx.Push() - dataBuffer := &winrio.Buffer{ - Id: bind.rx.id, - Offset: uint32(uintptr(unsafe.Pointer(&packet.data[0])) - bind.rx.packets), - Length: uint32(len(packet.data)), - } - addressBuffer := &winrio.Buffer{ - Id: bind.rx.id, - Offset: uint32(uintptr(unsafe.Pointer(&packet.addr)) - bind.rx.packets), - Length: uint32(unsafe.Sizeof(packet.addr)), - } - bind.mu.Lock() - defer bind.mu.Unlock() - return winrio.ReceiveEx(bind.rq, dataBuffer, 1, nil, addressBuffer, nil, nil, 0, uintptr(unsafe.Pointer(packet))) -} - -//go:linkname procyield runtime.procyield -func procyield(cycles uint32) - -func (bind *afWinRingBind) Receive(buf []byte, isOpen *atomic.Uint32) (int, Endpoint, error) { - if isOpen.Load() != 1 { - return 0, nil, net.ErrClosed - } - bind.rx.mu.Lock() - defer bind.rx.mu.Unlock() - - var err error - var count uint32 - var results [1]winrio.Result -retry: - count = 0 - for tries := 0; count == 0 && tries < receiveSpins; tries++ { - if tries > 0 { - if isOpen.Load() != 1 { - return 0, nil, net.ErrClosed - } - procyield(1) - } - count = winrio.DequeueCompletion(bind.rx.cq, results[:]) - } - if count == 0 { - err = winrio.Notify(bind.rx.cq) - if err != nil { - return 0, nil, err - } - var bytes uint32 - var key uintptr - var overlapped *windows.Overlapped - err = windows.GetQueuedCompletionStatus(bind.rx.iocp, &bytes, &key, &overlapped, windows.INFINITE) - if err != nil { - return 0, nil, err - } - if isOpen.Load() != 1 { - return 0, nil, net.ErrClosed - } - count = winrio.DequeueCompletion(bind.rx.cq, results[:]) - if count == 0 { - return 0, nil, io.ErrNoProgress - } - } - bind.rx.Return(1) - err = bind.InsertReceiveRequest() - if err != nil { - return 0, nil, err - } - // We limit the MTU well below the 65k max for practicality, but this means a remote host can still send us - // huge packets. Just try again when this happens. The infinite loop this could cause is still limited to - // attacker bandwidth, just like the rest of the receive path. - if windows.Errno(results[0].Status) == windows.WSAEMSGSIZE { - if isOpen.Load() != 1 { - return 0, nil, net.ErrClosed - } - goto retry - } - if results[0].Status != 0 { - return 0, nil, windows.Errno(results[0].Status) - } - packet := (*ringPacket)(unsafe.Pointer(uintptr(results[0].RequestContext))) - ep := packet.addr - n := copy(buf, packet.data[:results[0].BytesTransferred]) - return n, &ep, nil -} - -func (bind *WinRingBind) receiveIPv4(bufs [][]byte, sizes []int, eps []Endpoint) (int, error) { - bind.mu.RLock() - defer bind.mu.RUnlock() - n, ep, err := bind.v4.Receive(bufs[0], &bind.isOpen) - sizes[0] = n - eps[0] = ep - return 1, err -} - -func (bind *WinRingBind) receiveIPv6(bufs [][]byte, sizes []int, eps []Endpoint) (int, error) { - bind.mu.RLock() - defer bind.mu.RUnlock() - n, ep, err := bind.v6.Receive(bufs[0], &bind.isOpen) - sizes[0] = n - eps[0] = ep - return 1, err -} - -func (bind *afWinRingBind) Send(buf []byte, nend *WinRingEndpoint, isOpen *atomic.Uint32) error { - if isOpen.Load() != 1 { - return net.ErrClosed - } - if len(buf) > bytesPerPacket { - return io.ErrShortBuffer - } - bind.tx.mu.Lock() - defer bind.tx.mu.Unlock() - var results [packetsPerRing]winrio.Result - count := winrio.DequeueCompletion(bind.tx.cq, results[:]) - if count == 0 && bind.tx.isFull { - err := winrio.Notify(bind.tx.cq) - if err != nil { - return err - } - var bytes uint32 - var key uintptr - var overlapped *windows.Overlapped - err = windows.GetQueuedCompletionStatus(bind.tx.iocp, &bytes, &key, &overlapped, windows.INFINITE) - if err != nil { - return err - } - if isOpen.Load() != 1 { - return net.ErrClosed - } - count = winrio.DequeueCompletion(bind.tx.cq, results[:]) - if count == 0 { - return io.ErrNoProgress - } - } - if count > 0 { - bind.tx.Return(count) - } - packet := bind.tx.Push() - packet.addr = *nend - copy(packet.data[:], buf) - dataBuffer := &winrio.Buffer{ - Id: bind.tx.id, - Offset: uint32(uintptr(unsafe.Pointer(&packet.data[0])) - bind.tx.packets), - Length: uint32(len(buf)), - } - addressBuffer := &winrio.Buffer{ - Id: bind.tx.id, - Offset: uint32(uintptr(unsafe.Pointer(&packet.addr)) - bind.tx.packets), - Length: uint32(unsafe.Sizeof(packet.addr)), - } - bind.mu.Lock() - defer bind.mu.Unlock() - return winrio.SendEx(bind.rq, dataBuffer, 1, nil, addressBuffer, nil, nil, 0, 0) -} - -func (bind *WinRingBind) Send(bufs [][]byte, endpoint Endpoint) error { - nend, ok := endpoint.(*WinRingEndpoint) - if !ok { - return ErrWrongEndpointType - } - bind.mu.RLock() - defer bind.mu.RUnlock() - for _, buf := range bufs { - switch nend.family { - case windows.AF_INET: - if bind.v4.blackhole { - continue - } - if err := bind.v4.Send(buf, nend, &bind.isOpen); err != nil { - return err - } - case windows.AF_INET6: - if bind.v6.blackhole { - continue - } - if err := bind.v6.Send(buf, nend, &bind.isOpen); err != nil { - return err - } - } - } - return nil -} - -func (s *StdNetBind) BindSocketToInterface4(interfaceIndex uint32, blackhole bool) error { - s.mu.Lock() - defer s.mu.Unlock() - sysconn, err := s.ipv4.SyscallConn() - if err != nil { - return err - } - err2 := sysconn.Control(func(fd uintptr) { - err = bindSocketToInterface4(windows.Handle(fd), interfaceIndex) - }) - if err2 != nil { - return err2 - } - if err != nil { - return err - } - s.blackhole4 = blackhole - return nil -} - -func (s *StdNetBind) BindSocketToInterface6(interfaceIndex uint32, blackhole bool) error { - s.mu.Lock() - defer s.mu.Unlock() - sysconn, err := s.ipv6.SyscallConn() - if err != nil { - return err - } - err2 := sysconn.Control(func(fd uintptr) { - err = bindSocketToInterface6(windows.Handle(fd), interfaceIndex) - }) - if err2 != nil { - return err2 - } - if err != nil { - return err - } - s.blackhole6 = blackhole - return nil -} - -func (bind *WinRingBind) BindSocketToInterface4(interfaceIndex uint32, blackhole bool) error { - bind.mu.RLock() - defer bind.mu.RUnlock() - if bind.isOpen.Load() != 1 { - return net.ErrClosed - } - err := bindSocketToInterface4(bind.v4.sock, interfaceIndex) - if err != nil { - return err - } - bind.v4.blackhole = blackhole - return nil -} - -func (bind *WinRingBind) BindSocketToInterface6(interfaceIndex uint32, blackhole bool) error { - bind.mu.RLock() - defer bind.mu.RUnlock() - if bind.isOpen.Load() != 1 { - return net.ErrClosed - } - err := bindSocketToInterface6(bind.v6.sock, interfaceIndex) - if err != nil { - return err - } - bind.v6.blackhole = blackhole - return nil -} - -func bindSocketToInterface4(handle windows.Handle, interfaceIndex uint32) error { - const IP_UNICAST_IF = 31 - /* MSDN says for IPv4 this needs to be in net byte order, so that it's like an IP address with leading zeros. */ - var bytes [4]byte - binary.BigEndian.PutUint32(bytes[:], interfaceIndex) - interfaceIndex = *(*uint32)(unsafe.Pointer(&bytes[0])) - err := windows.SetsockoptInt(handle, windows.IPPROTO_IP, IP_UNICAST_IF, int(interfaceIndex)) - if err != nil { - return err - } - return nil -} - -func bindSocketToInterface6(handle windows.Handle, interfaceIndex uint32) error { - const IPV6_UNICAST_IF = 31 - return windows.SetsockoptInt(handle, windows.IPPROTO_IPV6, IPV6_UNICAST_IF, int(interfaceIndex)) -} diff --git a/vendor/golang.zx2c4.com/wireguard/conn/boundif_android.go b/vendor/golang.zx2c4.com/wireguard/conn/boundif_android.go deleted file mode 100644 index dd3ca5b076..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/boundif_android.go +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -func (s *StdNetBind) PeekLookAtSocketFd4() (fd int, err error) { - sysconn, err := s.ipv4.SyscallConn() - if err != nil { - return -1, err - } - err = sysconn.Control(func(f uintptr) { - fd = int(f) - }) - if err != nil { - return -1, err - } - return -} - -func (s *StdNetBind) PeekLookAtSocketFd6() (fd int, err error) { - sysconn, err := s.ipv6.SyscallConn() - if err != nil { - return -1, err - } - err = sysconn.Control(func(f uintptr) { - fd = int(f) - }) - if err != nil { - return -1, err - } - return -} diff --git a/vendor/golang.zx2c4.com/wireguard/conn/conn.go b/vendor/golang.zx2c4.com/wireguard/conn/conn.go deleted file mode 100644 index a1f57d2b1d..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/conn.go +++ /dev/null @@ -1,133 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -// Package conn implements WireGuard's network connections. -package conn - -import ( - "errors" - "fmt" - "net/netip" - "reflect" - "runtime" - "strings" -) - -const ( - IdealBatchSize = 128 // maximum number of packets handled per read and write -) - -// A ReceiveFunc receives at least one packet from the network and writes them -// into packets. On a successful read it returns the number of elements of -// sizes, packets, and endpoints that should be evaluated. Some elements of -// sizes may be zero, and callers should ignore them. Callers must pass a sizes -// and eps slice with a length greater than or equal to the length of packets. -// These lengths must not exceed the length of the associated Bind.BatchSize(). -type ReceiveFunc func(packets [][]byte, sizes []int, eps []Endpoint) (n int, err error) - -// A Bind listens on a port for both IPv6 and IPv4 UDP traffic. -// -// A Bind interface may also be a PeekLookAtSocketFd or BindSocketToInterface, -// depending on the platform-specific implementation. -type Bind interface { - // Open puts the Bind into a listening state on a given port and reports the actual - // port that it bound to. Passing zero results in a random selection. - // fns is the set of functions that will be called to receive packets. - Open(port uint16) (fns []ReceiveFunc, actualPort uint16, err error) - - // Close closes the Bind listener. - // All fns returned by Open must return net.ErrClosed after a call to Close. - Close() error - - // SetMark sets the mark for each packet sent through this Bind. - // This mark is passed to the kernel as the socket option SO_MARK. - SetMark(mark uint32) error - - // Send writes one or more packets in bufs to address ep. The length of - // bufs must not exceed BatchSize(). - Send(bufs [][]byte, ep Endpoint) error - - // ParseEndpoint creates a new endpoint from a string. - ParseEndpoint(s string) (Endpoint, error) - - // BatchSize is the number of buffers expected to be passed to - // the ReceiveFuncs, and the maximum expected to be passed to SendBatch. - BatchSize() int -} - -// BindSocketToInterface is implemented by Bind objects that support being -// tied to a single network interface. Used by wireguard-windows. -type BindSocketToInterface interface { - BindSocketToInterface4(interfaceIndex uint32, blackhole bool) error - BindSocketToInterface6(interfaceIndex uint32, blackhole bool) error -} - -// PeekLookAtSocketFd is implemented by Bind objects that support having their -// file descriptor peeked at. Used by wireguard-android. -type PeekLookAtSocketFd interface { - PeekLookAtSocketFd4() (fd int, err error) - PeekLookAtSocketFd6() (fd int, err error) -} - -// An Endpoint maintains the source/destination caching for a peer. -// -// dst: the remote address of a peer ("endpoint" in uapi terminology) -// src: the local address from which datagrams originate going to the peer -type Endpoint interface { - ClearSrc() // clears the source address - SrcToString() string // returns the local source address (ip:port) - DstToString() string // returns the destination address (ip:port) - DstToBytes() []byte // used for mac2 cookie calculations - DstIP() netip.Addr - SrcIP() netip.Addr -} - -var ( - ErrBindAlreadyOpen = errors.New("bind is already open") - ErrWrongEndpointType = errors.New("endpoint type does not correspond with bind type") -) - -func (fn ReceiveFunc) PrettyName() string { - name := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name() - // 0. cheese/taco.beansIPv6.func12.func21218-fm - name = strings.TrimSuffix(name, "-fm") - // 1. cheese/taco.beansIPv6.func12.func21218 - if idx := strings.LastIndexByte(name, '/'); idx != -1 { - name = name[idx+1:] - // 2. taco.beansIPv6.func12.func21218 - } - for { - var idx int - for idx = len(name) - 1; idx >= 0; idx-- { - if name[idx] < '0' || name[idx] > '9' { - break - } - } - if idx == len(name)-1 { - break - } - const dotFunc = ".func" - if !strings.HasSuffix(name[:idx+1], dotFunc) { - break - } - name = name[:idx+1-len(dotFunc)] - // 3. taco.beansIPv6.func12 - // 4. taco.beansIPv6 - } - if idx := strings.LastIndexByte(name, '.'); idx != -1 { - name = name[idx+1:] - // 5. beansIPv6 - } - if name == "" { - return fmt.Sprintf("%p", fn) - } - if strings.HasSuffix(name, "IPv4") { - return "v4" - } - if strings.HasSuffix(name, "IPv6") { - return "v6" - } - return name -} diff --git a/vendor/golang.zx2c4.com/wireguard/conn/controlfns.go b/vendor/golang.zx2c4.com/wireguard/conn/controlfns.go deleted file mode 100644 index 4f7d90fa10..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/controlfns.go +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -import ( - "net" - "syscall" -) - -// UDP socket read/write buffer size (7MB). The value of 7MB is chosen as it is -// the max supported by a default configuration of macOS. Some platforms will -// silently clamp the value to other maximums, such as linux clamping to -// net.core.{r,w}mem_max (see _linux.go for additional implementation that works -// around this limitation) -const socketBufferSize = 7 << 20 - -// controlFn is the callback function signature from net.ListenConfig.Control. -// It is used to apply platform specific configuration to the socket prior to -// bind. -type controlFn func(network, address string, c syscall.RawConn) error - -// controlFns is a list of functions that are called from the listen config -// that can apply socket options. -var controlFns = []controlFn{} - -// listenConfig returns a net.ListenConfig that applies the controlFns to the -// socket prior to bind. This is used to apply socket buffer sizing and packet -// information OOB configuration for sticky sockets. -func listenConfig() *net.ListenConfig { - return &net.ListenConfig{ - Control: func(network, address string, c syscall.RawConn) error { - for _, fn := range controlFns { - if err := fn(network, address, c); err != nil { - return err - } - } - return nil - }, - } -} diff --git a/vendor/golang.zx2c4.com/wireguard/conn/controlfns_linux.go b/vendor/golang.zx2c4.com/wireguard/conn/controlfns_linux.go deleted file mode 100644 index a2396fe899..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/controlfns_linux.go +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -import ( - "fmt" - "runtime" - "syscall" - - "golang.org/x/sys/unix" -) - -func init() { - controlFns = append(controlFns, - - // Attempt to set the socket buffer size beyond net.core.{r,w}mem_max by - // using SO_*BUFFORCE. This requires CAP_NET_ADMIN, and is allowed here to - // fail silently - the result of failure is lower performance on very fast - // links or high latency links. - func(network, address string, c syscall.RawConn) error { - return c.Control(func(fd uintptr) { - // Set up to *mem_max - _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, socketBufferSize) - _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, socketBufferSize) - // Set beyond *mem_max if CAP_NET_ADMIN - _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, socketBufferSize) - _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUFFORCE, socketBufferSize) - }) - }, - - // Enable receiving of the packet information (IP_PKTINFO for IPv4, - // IPV6_PKTINFO for IPv6) that is used to implement sticky socket support. - func(network, address string, c syscall.RawConn) error { - var err error - switch network { - case "udp4": - if runtime.GOOS != "android" { - c.Control(func(fd uintptr) { - err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_PKTINFO, 1) - }) - } - case "udp6": - c.Control(func(fd uintptr) { - if runtime.GOOS != "android" { - err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_RECVPKTINFO, 1) - if err != nil { - return - } - } - err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_V6ONLY, 1) - }) - default: - err = fmt.Errorf("unhandled network: %s: %w", network, unix.EINVAL) - } - return err - }, - ) -} diff --git a/vendor/golang.zx2c4.com/wireguard/conn/controlfns_unix.go b/vendor/golang.zx2c4.com/wireguard/conn/controlfns_unix.go deleted file mode 100644 index 91692c0a65..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/controlfns_unix.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build !windows && !linux && !wasm - -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -import ( - "syscall" - - "golang.org/x/sys/unix" -) - -func init() { - controlFns = append(controlFns, - func(network, address string, c syscall.RawConn) error { - return c.Control(func(fd uintptr) { - _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, socketBufferSize) - _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, socketBufferSize) - }) - }, - - func(network, address string, c syscall.RawConn) error { - var err error - if network == "udp6" { - c.Control(func(fd uintptr) { - err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_V6ONLY, 1) - }) - } - return err - }, - ) -} diff --git a/vendor/golang.zx2c4.com/wireguard/conn/controlfns_windows.go b/vendor/golang.zx2c4.com/wireguard/conn/controlfns_windows.go deleted file mode 100644 index c3bdf7d3a9..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/controlfns_windows.go +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -import ( - "syscall" - - "golang.org/x/sys/windows" -) - -func init() { - controlFns = append(controlFns, - func(network, address string, c syscall.RawConn) error { - return c.Control(func(fd uintptr) { - _ = windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_RCVBUF, socketBufferSize) - _ = windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_SNDBUF, socketBufferSize) - }) - }, - ) -} diff --git a/vendor/golang.zx2c4.com/wireguard/conn/default.go b/vendor/golang.zx2c4.com/wireguard/conn/default.go deleted file mode 100644 index b6f761b9ed..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/default.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !windows - -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -func NewDefaultBind() Bind { return NewStdNetBind() } diff --git a/vendor/golang.zx2c4.com/wireguard/conn/mark_default.go b/vendor/golang.zx2c4.com/wireguard/conn/mark_default.go deleted file mode 100644 index 31023844a2..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/mark_default.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:build !linux && !openbsd && !freebsd - -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -func (s *StdNetBind) SetMark(mark uint32) error { - return nil -} diff --git a/vendor/golang.zx2c4.com/wireguard/conn/mark_unix.go b/vendor/golang.zx2c4.com/wireguard/conn/mark_unix.go deleted file mode 100644 index d9e46eea7f..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/mark_unix.go +++ /dev/null @@ -1,65 +0,0 @@ -//go:build linux || openbsd || freebsd - -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -import ( - "runtime" - - "golang.org/x/sys/unix" -) - -var fwmarkIoctl int - -func init() { - switch runtime.GOOS { - case "linux", "android": - fwmarkIoctl = 36 /* unix.SO_MARK */ - case "freebsd": - fwmarkIoctl = 0x1015 /* unix.SO_USER_COOKIE */ - case "openbsd": - fwmarkIoctl = 0x1021 /* unix.SO_RTABLE */ - } -} - -func (s *StdNetBind) SetMark(mark uint32) error { - var operr error - if fwmarkIoctl == 0 { - return nil - } - if s.ipv4 != nil { - fd, err := s.ipv4.SyscallConn() - if err != nil { - return err - } - err = fd.Control(func(fd uintptr) { - operr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark)) - }) - if err == nil { - err = operr - } - if err != nil { - return err - } - } - if s.ipv6 != nil { - fd, err := s.ipv6.SyscallConn() - if err != nil { - return err - } - err = fd.Control(func(fd uintptr) { - operr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark)) - }) - if err == nil { - err = operr - } - if err != nil { - return err - } - } - return nil -} diff --git a/vendor/golang.zx2c4.com/wireguard/conn/sticky_default.go b/vendor/golang.zx2c4.com/wireguard/conn/sticky_default.go deleted file mode 100644 index 1fa8a0c4bb..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/sticky_default.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build !linux || android - -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -import "net/netip" - -func (e *StdNetEndpoint) SrcIP() netip.Addr { - return netip.Addr{} -} - -func (e *StdNetEndpoint) SrcIfidx() int32 { - return 0 -} - -func (e *StdNetEndpoint) SrcToString() string { - return "" -} - -// TODO: macOS, FreeBSD and other BSDs likely do support this feature set, but -// use alternatively named flags and need ports and require testing. - -// getSrcFromControl parses the control for PKTINFO and if found updates ep with -// the source information found. -func getSrcFromControl(control []byte, ep *StdNetEndpoint) { -} - -// setSrcControl parses the control for PKTINFO and if found updates ep with -// the source information found. -func setSrcControl(control *[]byte, ep *StdNetEndpoint) { -} - -// srcControlSize returns the recommended buffer size for pooling sticky control -// data. -const srcControlSize = 0 - -const StdNetSupportsStickySockets = false diff --git a/vendor/golang.zx2c4.com/wireguard/conn/sticky_linux.go b/vendor/golang.zx2c4.com/wireguard/conn/sticky_linux.go deleted file mode 100644 index a30ccc715c..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/sticky_linux.go +++ /dev/null @@ -1,110 +0,0 @@ -//go:build linux && !android - -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package conn - -import ( - "net/netip" - "unsafe" - - "golang.org/x/sys/unix" -) - -func (e *StdNetEndpoint) SrcIP() netip.Addr { - switch len(e.src) { - case unix.CmsgSpace(unix.SizeofInet4Pktinfo): - info := (*unix.Inet4Pktinfo)(unsafe.Pointer(&e.src[unix.CmsgLen(0)])) - return netip.AddrFrom4(info.Spec_dst) - case unix.CmsgSpace(unix.SizeofInet6Pktinfo): - info := (*unix.Inet6Pktinfo)(unsafe.Pointer(&e.src[unix.CmsgLen(0)])) - // TODO: set zone. in order to do so we need to check if the address is - // link local, and if it is perform a syscall to turn the ifindex into a - // zone string because netip uses string zones. - return netip.AddrFrom16(info.Addr) - } - return netip.Addr{} -} - -func (e *StdNetEndpoint) SrcIfidx() int32 { - switch len(e.src) { - case unix.CmsgSpace(unix.SizeofInet4Pktinfo): - info := (*unix.Inet4Pktinfo)(unsafe.Pointer(&e.src[unix.CmsgLen(0)])) - return info.Ifindex - case unix.CmsgSpace(unix.SizeofInet6Pktinfo): - info := (*unix.Inet6Pktinfo)(unsafe.Pointer(&e.src[unix.CmsgLen(0)])) - return int32(info.Ifindex) - } - return 0 -} - -func (e *StdNetEndpoint) SrcToString() string { - return e.SrcIP().String() -} - -// getSrcFromControl parses the control for PKTINFO and if found updates ep with -// the source information found. -func getSrcFromControl(control []byte, ep *StdNetEndpoint) { - ep.ClearSrc() - - var ( - hdr unix.Cmsghdr - data []byte - rem []byte = control - err error - ) - - for len(rem) > unix.SizeofCmsghdr { - hdr, data, rem, err = unix.ParseOneSocketControlMessage(rem) - if err != nil { - return - } - - if hdr.Level == unix.IPPROTO_IP && - hdr.Type == unix.IP_PKTINFO { - - if ep.src == nil || cap(ep.src) < unix.CmsgSpace(unix.SizeofInet4Pktinfo) { - ep.src = make([]byte, 0, unix.CmsgSpace(unix.SizeofInet4Pktinfo)) - } - ep.src = ep.src[:unix.CmsgSpace(unix.SizeofInet4Pktinfo)] - - hdrBuf := unsafe.Slice((*byte)(unsafe.Pointer(&hdr)), unix.SizeofCmsghdr) - copy(ep.src, hdrBuf) - copy(ep.src[unix.CmsgLen(0):], data) - return - } - - if hdr.Level == unix.IPPROTO_IPV6 && - hdr.Type == unix.IPV6_PKTINFO { - - if ep.src == nil || cap(ep.src) < unix.CmsgSpace(unix.SizeofInet6Pktinfo) { - ep.src = make([]byte, 0, unix.CmsgSpace(unix.SizeofInet6Pktinfo)) - } - - ep.src = ep.src[:unix.CmsgSpace(unix.SizeofInet6Pktinfo)] - - hdrBuf := unsafe.Slice((*byte)(unsafe.Pointer(&hdr)), unix.SizeofCmsghdr) - copy(ep.src, hdrBuf) - copy(ep.src[unix.CmsgLen(0):], data) - return - } - } -} - -// setSrcControl sets an IP{V6}_PKTINFO in control based on the source address -// and source ifindex found in ep. control's len will be set to 0 in the event -// that ep is a default value. -func setSrcControl(control *[]byte, ep *StdNetEndpoint) { - if cap(*control) < len(ep.src) { - return - } - *control = (*control)[:0] - *control = append(*control, ep.src...) -} - -var srcControlSize = unix.CmsgSpace(unix.SizeofInet6Pktinfo) - -const StdNetSupportsStickySockets = true diff --git a/vendor/golang.zx2c4.com/wireguard/conn/winrio/rio_windows.go b/vendor/golang.zx2c4.com/wireguard/conn/winrio/rio_windows.go deleted file mode 100644 index d1037bba90..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/conn/winrio/rio_windows.go +++ /dev/null @@ -1,254 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package winrio - -import ( - "log" - "sync" - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -const ( - MsgDontNotify = 1 - MsgDefer = 2 - MsgWaitAll = 4 - MsgCommitOnly = 8 - - MaxCqSize = 0x8000000 - - invalidBufferId = 0xFFFFFFFF - invalidCq = 0 - invalidRq = 0 - corruptCq = 0xFFFFFFFF -) - -var extensionFunctionTable struct { - cbSize uint32 - rioReceive uintptr - rioReceiveEx uintptr - rioSend uintptr - rioSendEx uintptr - rioCloseCompletionQueue uintptr - rioCreateCompletionQueue uintptr - rioCreateRequestQueue uintptr - rioDequeueCompletion uintptr - rioDeregisterBuffer uintptr - rioNotify uintptr - rioRegisterBuffer uintptr - rioResizeCompletionQueue uintptr - rioResizeRequestQueue uintptr -} - -type Cq uintptr - -type Rq uintptr - -type BufferId uintptr - -type Buffer struct { - Id BufferId - Offset uint32 - Length uint32 -} - -type Result struct { - Status int32 - BytesTransferred uint32 - SocketContext uint64 - RequestContext uint64 -} - -type notificationCompletionType uint32 - -const ( - eventCompletion notificationCompletionType = 1 - iocpCompletion notificationCompletionType = 2 -) - -type eventNotificationCompletion struct { - completionType notificationCompletionType - event windows.Handle - notifyReset uint32 -} - -type iocpNotificationCompletion struct { - completionType notificationCompletionType - iocp windows.Handle - key uintptr - overlapped *windows.Overlapped -} - -var ( - initialized sync.Once - available bool -) - -func Initialize() bool { - initialized.Do(func() { - var ( - err error - socket windows.Handle - cq Cq - ) - defer func() { - if err == nil { - return - } - if maj, _, _ := windows.RtlGetNtVersionNumbers(); maj <= 7 { - return - } - log.Printf("Registered I/O is unavailable: %v", err) - }() - socket, err = Socket(windows.AF_INET, windows.SOCK_DGRAM, windows.IPPROTO_UDP) - if err != nil { - return - } - defer windows.CloseHandle(socket) - WSAID_MULTIPLE_RIO := &windows.GUID{0x8509e081, 0x96dd, 0x4005, [8]byte{0xb1, 0x65, 0x9e, 0x2e, 0xe8, 0xc7, 0x9e, 0x3f}} - const SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER = 0xc8000024 - ob := uint32(0) - err = windows.WSAIoctl(socket, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, - (*byte)(unsafe.Pointer(WSAID_MULTIPLE_RIO)), uint32(unsafe.Sizeof(*WSAID_MULTIPLE_RIO)), - (*byte)(unsafe.Pointer(&extensionFunctionTable)), uint32(unsafe.Sizeof(extensionFunctionTable)), - &ob, nil, 0) - if err != nil { - return - } - - // While we should be able to stop here, after getting the function pointers, some anti-virus actually causes - // failures in RIOCreateRequestQueue, so keep going to be certain this is supported. - var iocp windows.Handle - iocp, err = windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0) - if err != nil { - return - } - defer windows.CloseHandle(iocp) - var overlapped windows.Overlapped - cq, err = CreateIOCPCompletionQueue(2, iocp, 0, &overlapped) - if err != nil { - return - } - defer CloseCompletionQueue(cq) - _, err = CreateRequestQueue(socket, 1, 1, 1, 1, cq, cq, 0) - if err != nil { - return - } - available = true - }) - return available -} - -func Socket(af, typ, proto int32) (windows.Handle, error) { - return windows.WSASocket(af, typ, proto, nil, 0, windows.WSA_FLAG_REGISTERED_IO) -} - -func CloseCompletionQueue(cq Cq) { - _, _, _ = syscall.Syscall(extensionFunctionTable.rioCloseCompletionQueue, 1, uintptr(cq), 0, 0) -} - -func CreateEventCompletionQueue(queueSize uint32, event windows.Handle, notifyReset bool) (Cq, error) { - notificationCompletion := &eventNotificationCompletion{ - completionType: eventCompletion, - event: event, - } - if notifyReset { - notificationCompletion.notifyReset = 1 - } - ret, _, err := syscall.Syscall(extensionFunctionTable.rioCreateCompletionQueue, 2, uintptr(queueSize), uintptr(unsafe.Pointer(notificationCompletion)), 0) - if ret == invalidCq { - return 0, err - } - return Cq(ret), nil -} - -func CreateIOCPCompletionQueue(queueSize uint32, iocp windows.Handle, key uintptr, overlapped *windows.Overlapped) (Cq, error) { - notificationCompletion := &iocpNotificationCompletion{ - completionType: iocpCompletion, - iocp: iocp, - key: key, - overlapped: overlapped, - } - ret, _, err := syscall.Syscall(extensionFunctionTable.rioCreateCompletionQueue, 2, uintptr(queueSize), uintptr(unsafe.Pointer(notificationCompletion)), 0) - if ret == invalidCq { - return 0, err - } - return Cq(ret), nil -} - -func CreatePolledCompletionQueue(queueSize uint32) (Cq, error) { - ret, _, err := syscall.Syscall(extensionFunctionTable.rioCreateCompletionQueue, 2, uintptr(queueSize), 0, 0) - if ret == invalidCq { - return 0, err - } - return Cq(ret), nil -} - -func CreateRequestQueue(socket windows.Handle, maxOutstandingReceive, maxReceiveDataBuffers, maxOutstandingSend, maxSendDataBuffers uint32, receiveCq, sendCq Cq, socketContext uintptr) (Rq, error) { - ret, _, err := syscall.Syscall9(extensionFunctionTable.rioCreateRequestQueue, 8, uintptr(socket), uintptr(maxOutstandingReceive), uintptr(maxReceiveDataBuffers), uintptr(maxOutstandingSend), uintptr(maxSendDataBuffers), uintptr(receiveCq), uintptr(sendCq), socketContext, 0) - if ret == invalidRq { - return 0, err - } - return Rq(ret), nil -} - -func DequeueCompletion(cq Cq, results []Result) uint32 { - var array uintptr - if len(results) > 0 { - array = uintptr(unsafe.Pointer(&results[0])) - } - ret, _, _ := syscall.Syscall(extensionFunctionTable.rioDequeueCompletion, 3, uintptr(cq), array, uintptr(len(results))) - if ret == corruptCq { - panic("cq is corrupt") - } - return uint32(ret) -} - -func DeregisterBuffer(id BufferId) { - _, _, _ = syscall.Syscall(extensionFunctionTable.rioDeregisterBuffer, 1, uintptr(id), 0, 0) -} - -func RegisterBuffer(buffer []byte) (BufferId, error) { - var buf unsafe.Pointer - if len(buffer) > 0 { - buf = unsafe.Pointer(&buffer[0]) - } - return RegisterPointer(buf, uint32(len(buffer))) -} - -func RegisterPointer(ptr unsafe.Pointer, size uint32) (BufferId, error) { - ret, _, err := syscall.Syscall(extensionFunctionTable.rioRegisterBuffer, 2, uintptr(ptr), uintptr(size), 0) - if ret == invalidBufferId { - return 0, err - } - return BufferId(ret), nil -} - -func SendEx(rq Rq, buf *Buffer, dataBufferCount uint32, localAddress, remoteAddress, controlContext, flags *Buffer, sflags uint32, requestContext uintptr) error { - ret, _, err := syscall.Syscall9(extensionFunctionTable.rioSendEx, 9, uintptr(rq), uintptr(unsafe.Pointer(buf)), uintptr(dataBufferCount), uintptr(unsafe.Pointer(localAddress)), uintptr(unsafe.Pointer(remoteAddress)), uintptr(unsafe.Pointer(controlContext)), uintptr(unsafe.Pointer(flags)), uintptr(sflags), requestContext) - if ret == 0 { - return err - } - return nil -} - -func ReceiveEx(rq Rq, buf *Buffer, dataBufferCount uint32, localAddress, remoteAddress, controlContext, flags *Buffer, sflags uint32, requestContext uintptr) error { - ret, _, err := syscall.Syscall9(extensionFunctionTable.rioReceiveEx, 9, uintptr(rq), uintptr(unsafe.Pointer(buf)), uintptr(dataBufferCount), uintptr(unsafe.Pointer(localAddress)), uintptr(unsafe.Pointer(remoteAddress)), uintptr(unsafe.Pointer(controlContext)), uintptr(unsafe.Pointer(flags)), uintptr(sflags), requestContext) - if ret == 0 { - return err - } - return nil -} - -func Notify(cq Cq) error { - ret, _, _ := syscall.Syscall(extensionFunctionTable.rioNotify, 1, uintptr(cq), 0, 0) - if ret != 0 { - return windows.Errno(ret) - } - return nil -} diff --git a/vendor/golang.zx2c4.com/wireguard/rwcancel/rwcancel.go b/vendor/golang.zx2c4.com/wireguard/rwcancel/rwcancel.go index e397c0e8ae..63e1510b10 100644 --- a/vendor/golang.zx2c4.com/wireguard/rwcancel/rwcancel.go +++ b/vendor/golang.zx2c4.com/wireguard/rwcancel/rwcancel.go @@ -1,4 +1,4 @@ -//go:build !windows && !wasm +//go:build !windows && !js /* SPDX-License-Identifier: MIT * diff --git a/vendor/golang.zx2c4.com/wireguard/rwcancel/rwcancel_stub.go b/vendor/golang.zx2c4.com/wireguard/rwcancel/rwcancel_stub.go index 2a98b2b4ad..182940b32e 100644 --- a/vendor/golang.zx2c4.com/wireguard/rwcancel/rwcancel_stub.go +++ b/vendor/golang.zx2c4.com/wireguard/rwcancel/rwcancel_stub.go @@ -1,4 +1,4 @@ -//go:build windows || wasm +//go:build windows || js // SPDX-License-Identifier: MIT diff --git a/vendor/golang.zx2c4.com/wireguard/tun/checksum.go b/vendor/golang.zx2c4.com/wireguard/tun/checksum.go deleted file mode 100644 index f4f847164a..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/tun/checksum.go +++ /dev/null @@ -1,42 +0,0 @@ -package tun - -import "encoding/binary" - -// TODO: Explore SIMD and/or other assembly optimizations. -func checksumNoFold(b []byte, initial uint64) uint64 { - ac := initial - i := 0 - n := len(b) - for n >= 4 { - ac += uint64(binary.BigEndian.Uint32(b[i : i+4])) - n -= 4 - i += 4 - } - for n >= 2 { - ac += uint64(binary.BigEndian.Uint16(b[i : i+2])) - n -= 2 - i += 2 - } - if n == 1 { - ac += uint64(b[i]) << 8 - } - return ac -} - -func checksum(b []byte, initial uint64) uint16 { - ac := checksumNoFold(b, initial) - ac = (ac >> 16) + (ac & 0xffff) - ac = (ac >> 16) + (ac & 0xffff) - ac = (ac >> 16) + (ac & 0xffff) - ac = (ac >> 16) + (ac & 0xffff) - return uint16(ac) -} - -func pseudoHeaderChecksumNoFold(protocol uint8, srcAddr, dstAddr []byte, totalLen uint16) uint64 { - sum := checksumNoFold(srcAddr, 0) - sum = checksumNoFold(dstAddr, sum) - sum = checksumNoFold([]byte{0, protocol}, sum) - tmp := make([]byte, 2) - binary.BigEndian.PutUint16(tmp, totalLen) - return checksumNoFold(tmp, sum) -} diff --git a/vendor/golang.zx2c4.com/wireguard/tun/errors.go b/vendor/golang.zx2c4.com/wireguard/tun/errors.go deleted file mode 100644 index 75ae3a434a..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/tun/errors.go +++ /dev/null @@ -1,12 +0,0 @@ -package tun - -import ( - "errors" -) - -var ( - // ErrTooManySegments is returned by Device.Read() when segmentation - // overflows the length of supplied buffers. This error should not cause - // reads to cease. - ErrTooManySegments = errors.New("too many segments") -) diff --git a/vendor/golang.zx2c4.com/wireguard/tun/tcp_offload_linux.go b/vendor/golang.zx2c4.com/wireguard/tun/tcp_offload_linux.go deleted file mode 100644 index 39a7180c5a..0000000000 --- a/vendor/golang.zx2c4.com/wireguard/tun/tcp_offload_linux.go +++ /dev/null @@ -1,627 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. - */ - -package tun - -import ( - "bytes" - "encoding/binary" - "errors" - "io" - "unsafe" - - "golang.org/x/sys/unix" - "golang.zx2c4.com/wireguard/conn" -) - -const tcpFlagsOffset = 13 - -const ( - tcpFlagFIN uint8 = 0x01 - tcpFlagPSH uint8 = 0x08 - tcpFlagACK uint8 = 0x10 -) - -// virtioNetHdr is defined in the kernel in include/uapi/linux/virtio_net.h. The -// kernel symbol is virtio_net_hdr. -type virtioNetHdr struct { - flags uint8 - gsoType uint8 - hdrLen uint16 - gsoSize uint16 - csumStart uint16 - csumOffset uint16 -} - -func (v *virtioNetHdr) decode(b []byte) error { - if len(b) < virtioNetHdrLen { - return io.ErrShortBuffer - } - copy(unsafe.Slice((*byte)(unsafe.Pointer(v)), virtioNetHdrLen), b[:virtioNetHdrLen]) - return nil -} - -func (v *virtioNetHdr) encode(b []byte) error { - if len(b) < virtioNetHdrLen { - return io.ErrShortBuffer - } - copy(b[:virtioNetHdrLen], unsafe.Slice((*byte)(unsafe.Pointer(v)), virtioNetHdrLen)) - return nil -} - -const ( - // virtioNetHdrLen is the length in bytes of virtioNetHdr. This matches the - // shape of the C ABI for its kernel counterpart -- sizeof(virtio_net_hdr). - virtioNetHdrLen = int(unsafe.Sizeof(virtioNetHdr{})) -) - -// flowKey represents the key for a flow. -type flowKey struct { - srcAddr, dstAddr [16]byte - srcPort, dstPort uint16 - rxAck uint32 // varying ack values should not be coalesced. Treat them as separate flows. -} - -// tcpGROTable holds flow and coalescing information for the purposes of GRO. -type tcpGROTable struct { - itemsByFlow map[flowKey][]tcpGROItem - itemsPool [][]tcpGROItem -} - -func newTCPGROTable() *tcpGROTable { - t := &tcpGROTable{ - itemsByFlow: make(map[flowKey][]tcpGROItem, conn.IdealBatchSize), - itemsPool: make([][]tcpGROItem, conn.IdealBatchSize), - } - for i := range t.itemsPool { - t.itemsPool[i] = make([]tcpGROItem, 0, conn.IdealBatchSize) - } - return t -} - -func newFlowKey(pkt []byte, srcAddr, dstAddr, tcphOffset int) flowKey { - key := flowKey{} - addrSize := dstAddr - srcAddr - copy(key.srcAddr[:], pkt[srcAddr:dstAddr]) - copy(key.dstAddr[:], pkt[dstAddr:dstAddr+addrSize]) - key.srcPort = binary.BigEndian.Uint16(pkt[tcphOffset:]) - key.dstPort = binary.BigEndian.Uint16(pkt[tcphOffset+2:]) - key.rxAck = binary.BigEndian.Uint32(pkt[tcphOffset+8:]) - return key -} - -// lookupOrInsert looks up a flow for the provided packet and metadata, -// returning the packets found for the flow, or inserting a new one if none -// is found. -func (t *tcpGROTable) lookupOrInsert(pkt []byte, srcAddrOffset, dstAddrOffset, tcphOffset, tcphLen, bufsIndex int) ([]tcpGROItem, bool) { - key := newFlowKey(pkt, srcAddrOffset, dstAddrOffset, tcphOffset) - items, ok := t.itemsByFlow[key] - if ok { - return items, ok - } - // TODO: insert() performs another map lookup. This could be rearranged to avoid. - t.insert(pkt, srcAddrOffset, dstAddrOffset, tcphOffset, tcphLen, bufsIndex) - return nil, false -} - -// insert an item in the table for the provided packet and packet metadata. -func (t *tcpGROTable) insert(pkt []byte, srcAddrOffset, dstAddrOffset, tcphOffset, tcphLen, bufsIndex int) { - key := newFlowKey(pkt, srcAddrOffset, dstAddrOffset, tcphOffset) - item := tcpGROItem{ - key: key, - bufsIndex: uint16(bufsIndex), - gsoSize: uint16(len(pkt[tcphOffset+tcphLen:])), - iphLen: uint8(tcphOffset), - tcphLen: uint8(tcphLen), - sentSeq: binary.BigEndian.Uint32(pkt[tcphOffset+4:]), - pshSet: pkt[tcphOffset+tcpFlagsOffset]&tcpFlagPSH != 0, - } - items, ok := t.itemsByFlow[key] - if !ok { - items = t.newItems() - } - items = append(items, item) - t.itemsByFlow[key] = items -} - -func (t *tcpGROTable) updateAt(item tcpGROItem, i int) { - items, _ := t.itemsByFlow[item.key] - items[i] = item -} - -func (t *tcpGROTable) deleteAt(key flowKey, i int) { - items, _ := t.itemsByFlow[key] - items = append(items[:i], items[i+1:]...) - t.itemsByFlow[key] = items -} - -// tcpGROItem represents bookkeeping data for a TCP packet during the lifetime -// of a GRO evaluation across a vector of packets. -type tcpGROItem struct { - key flowKey - sentSeq uint32 // the sequence number - bufsIndex uint16 // the index into the original bufs slice - numMerged uint16 // the number of packets merged into this item - gsoSize uint16 // payload size - iphLen uint8 // ip header len - tcphLen uint8 // tcp header len - pshSet bool // psh flag is set -} - -func (t *tcpGROTable) newItems() []tcpGROItem { - var items []tcpGROItem - items, t.itemsPool = t.itemsPool[len(t.itemsPool)-1], t.itemsPool[:len(t.itemsPool)-1] - return items -} - -func (t *tcpGROTable) reset() { - for k, items := range t.itemsByFlow { - items = items[:0] - t.itemsPool = append(t.itemsPool, items) - delete(t.itemsByFlow, k) - } -} - -// canCoalesce represents the outcome of checking if two TCP packets are -// candidates for coalescing. -type canCoalesce int - -const ( - coalescePrepend canCoalesce = -1 - coalesceUnavailable canCoalesce = 0 - coalesceAppend canCoalesce = 1 -) - -// tcpPacketsCanCoalesce evaluates if pkt can be coalesced with the packet -// described by item. This function makes considerations that match the kernel's -// GRO self tests, which can be found in tools/testing/selftests/net/gro.c. -func tcpPacketsCanCoalesce(pkt []byte, iphLen, tcphLen uint8, seq uint32, pshSet bool, gsoSize uint16, item tcpGROItem, bufs [][]byte, bufsOffset int) canCoalesce { - pktTarget := bufs[item.bufsIndex][bufsOffset:] - if tcphLen != item.tcphLen { - // cannot coalesce with unequal tcp options len - return coalesceUnavailable - } - if tcphLen > 20 { - if !bytes.Equal(pkt[iphLen+20:iphLen+tcphLen], pktTarget[item.iphLen+20:iphLen+tcphLen]) { - // cannot coalesce with unequal tcp options - return coalesceUnavailable - } - } - if pkt[0]>>4 == 6 { - if pkt[0] != pktTarget[0] || pkt[1]>>4 != pktTarget[1]>>4 { - // cannot coalesce with unequal Traffic class values - return coalesceUnavailable - } - if pkt[7] != pktTarget[7] { - // cannot coalesce with unequal Hop limit values - return coalesceUnavailable - } - } else { - if pkt[1] != pktTarget[1] { - // cannot coalesce with unequal ToS values - return coalesceUnavailable - } - if pkt[6]>>5 != pktTarget[6]>>5 { - // cannot coalesce with unequal DF or reserved bits. MF is checked - // further up the stack. - return coalesceUnavailable - } - if pkt[8] != pktTarget[8] { - // cannot coalesce with unequal TTL values - return coalesceUnavailable - } - } - // seq adjacency - lhsLen := item.gsoSize - lhsLen += item.numMerged * item.gsoSize - if seq == item.sentSeq+uint32(lhsLen) { // pkt aligns following item from a seq num perspective - if item.pshSet { - // We cannot append to a segment that has the PSH flag set, PSH - // can only be set on the final segment in a reassembled group. - return coalesceUnavailable - } - if len(pktTarget[iphLen+tcphLen:])%int(item.gsoSize) != 0 { - // A smaller than gsoSize packet has been appended previously. - // Nothing can come after a smaller packet on the end. - return coalesceUnavailable - } - if gsoSize > item.gsoSize { - // We cannot have a larger packet following a smaller one. - return coalesceUnavailable - } - return coalesceAppend - } else if seq+uint32(gsoSize) == item.sentSeq { // pkt aligns in front of item from a seq num perspective - if pshSet { - // We cannot prepend with a segment that has the PSH flag set, PSH - // can only be set on the final segment in a reassembled group. - return coalesceUnavailable - } - if gsoSize < item.gsoSize { - // We cannot have a larger packet following a smaller one. - return coalesceUnavailable - } - if gsoSize > item.gsoSize && item.numMerged > 0 { - // There's at least one previous merge, and we're larger than all - // previous. This would put multiple smaller packets on the end. - return coalesceUnavailable - } - return coalescePrepend - } - return coalesceUnavailable -} - -func tcpChecksumValid(pkt []byte, iphLen uint8, isV6 bool) bool { - srcAddrAt := ipv4SrcAddrOffset - addrSize := 4 - if isV6 { - srcAddrAt = ipv6SrcAddrOffset - addrSize = 16 - } - tcpTotalLen := uint16(len(pkt) - int(iphLen)) - tcpCSumNoFold := pseudoHeaderChecksumNoFold(unix.IPPROTO_TCP, pkt[srcAddrAt:srcAddrAt+addrSize], pkt[srcAddrAt+addrSize:srcAddrAt+addrSize*2], tcpTotalLen) - return ^checksum(pkt[iphLen:], tcpCSumNoFold) == 0 -} - -// coalesceResult represents the result of attempting to coalesce two TCP -// packets. -type coalesceResult int - -const ( - coalesceInsufficientCap coalesceResult = 0 - coalescePSHEnding coalesceResult = 1 - coalesceItemInvalidCSum coalesceResult = 2 - coalescePktInvalidCSum coalesceResult = 3 - coalesceSuccess coalesceResult = 4 -) - -// coalesceTCPPackets attempts to coalesce pkt with the packet described by -// item, returning the outcome. This function may swap bufs elements in the -// event of a prepend as item's bufs index is already being tracked for writing -// to a Device. -func coalesceTCPPackets(mode canCoalesce, pkt []byte, pktBuffsIndex int, gsoSize uint16, seq uint32, pshSet bool, item *tcpGROItem, bufs [][]byte, bufsOffset int, isV6 bool) coalesceResult { - var pktHead []byte // the packet that will end up at the front - headersLen := item.iphLen + item.tcphLen - coalescedLen := len(bufs[item.bufsIndex][bufsOffset:]) + len(pkt) - int(headersLen) - - // Copy data - if mode == coalescePrepend { - pktHead = pkt - if cap(pkt)-bufsOffset < coalescedLen { - // We don't want to allocate a new underlying array if capacity is - // too small. - return coalesceInsufficientCap - } - if pshSet { - return coalescePSHEnding - } - if item.numMerged == 0 { - if !tcpChecksumValid(bufs[item.bufsIndex][bufsOffset:], item.iphLen, isV6) { - return coalesceItemInvalidCSum - } - } - if !tcpChecksumValid(pkt, item.iphLen, isV6) { - return coalescePktInvalidCSum - } - item.sentSeq = seq - extendBy := coalescedLen - len(pktHead) - bufs[pktBuffsIndex] = append(bufs[pktBuffsIndex], make([]byte, extendBy)...) - copy(bufs[pktBuffsIndex][bufsOffset+len(pkt):], bufs[item.bufsIndex][bufsOffset+int(headersLen):]) - // Flip the slice headers in bufs as part of prepend. The index of item - // is already being tracked for writing. - bufs[item.bufsIndex], bufs[pktBuffsIndex] = bufs[pktBuffsIndex], bufs[item.bufsIndex] - } else { - pktHead = bufs[item.bufsIndex][bufsOffset:] - if cap(pktHead)-bufsOffset < coalescedLen { - // We don't want to allocate a new underlying array if capacity is - // too small. - return coalesceInsufficientCap - } - if item.numMerged == 0 { - if !tcpChecksumValid(bufs[item.bufsIndex][bufsOffset:], item.iphLen, isV6) { - return coalesceItemInvalidCSum - } - } - if !tcpChecksumValid(pkt, item.iphLen, isV6) { - return coalescePktInvalidCSum - } - if pshSet { - // We are appending a segment with PSH set. - item.pshSet = pshSet - pktHead[item.iphLen+tcpFlagsOffset] |= tcpFlagPSH - } - extendBy := len(pkt) - int(headersLen) - bufs[item.bufsIndex] = append(bufs[item.bufsIndex], make([]byte, extendBy)...) - copy(bufs[item.bufsIndex][bufsOffset+len(pktHead):], pkt[headersLen:]) - } - - if gsoSize > item.gsoSize { - item.gsoSize = gsoSize - } - hdr := virtioNetHdr{ - flags: unix.VIRTIO_NET_HDR_F_NEEDS_CSUM, // this turns into CHECKSUM_PARTIAL in the skb - hdrLen: uint16(headersLen), - gsoSize: uint16(item.gsoSize), - csumStart: uint16(item.iphLen), - csumOffset: 16, - } - - // Recalculate the total len (IPv4) or payload len (IPv6). Recalculate the - // (IPv4) header checksum. - if isV6 { - hdr.gsoType = unix.VIRTIO_NET_HDR_GSO_TCPV6 - binary.BigEndian.PutUint16(pktHead[4:], uint16(coalescedLen)-uint16(item.iphLen)) // set new payload len - } else { - hdr.gsoType = unix.VIRTIO_NET_HDR_GSO_TCPV4 - pktHead[10], pktHead[11] = 0, 0 // clear checksum field - binary.BigEndian.PutUint16(pktHead[2:], uint16(coalescedLen)) // set new total length - iphCSum := ^checksum(pktHead[:item.iphLen], 0) // compute checksum - binary.BigEndian.PutUint16(pktHead[10:], iphCSum) // set checksum field - } - hdr.encode(bufs[item.bufsIndex][bufsOffset-virtioNetHdrLen:]) - - // Calculate the pseudo header checksum and place it at the TCP checksum - // offset. Downstream checksum offloading will combine this with computation - // of the tcp header and payload checksum. - addrLen := 4 - addrOffset := ipv4SrcAddrOffset - if isV6 { - addrLen = 16 - addrOffset = ipv6SrcAddrOffset - } - srcAddrAt := bufsOffset + addrOffset - srcAddr := bufs[item.bufsIndex][srcAddrAt : srcAddrAt+addrLen] - dstAddr := bufs[item.bufsIndex][srcAddrAt+addrLen : srcAddrAt+addrLen*2] - psum := pseudoHeaderChecksumNoFold(unix.IPPROTO_TCP, srcAddr, dstAddr, uint16(coalescedLen-int(item.iphLen))) - binary.BigEndian.PutUint16(pktHead[hdr.csumStart+hdr.csumOffset:], checksum([]byte{}, psum)) - - item.numMerged++ - return coalesceSuccess -} - -const ( - ipv4FlagMoreFragments uint8 = 0x20 -) - -const ( - ipv4SrcAddrOffset = 12 - ipv6SrcAddrOffset = 8 - maxUint16 = 1<<16 - 1 -) - -// tcpGRO evaluates the TCP packet at pktI in bufs for coalescing with -// existing packets tracked in table. It will return false when pktI is not -// coalesced, otherwise true. This indicates to the caller if bufs[pktI] -// should be written to the Device. -func tcpGRO(bufs [][]byte, offset int, pktI int, table *tcpGROTable, isV6 bool) (pktCoalesced bool) { - pkt := bufs[pktI][offset:] - if len(pkt) > maxUint16 { - // A valid IPv4 or IPv6 packet will never exceed this. - return false - } - iphLen := int((pkt[0] & 0x0F) * 4) - if isV6 { - iphLen = 40 - ipv6HPayloadLen := int(binary.BigEndian.Uint16(pkt[4:])) - if ipv6HPayloadLen != len(pkt)-iphLen { - return false - } - } else { - totalLen := int(binary.BigEndian.Uint16(pkt[2:])) - if totalLen != len(pkt) { - return false - } - } - if len(pkt) < iphLen { - return false - } - tcphLen := int((pkt[iphLen+12] >> 4) * 4) - if tcphLen < 20 || tcphLen > 60 { - return false - } - if len(pkt) < iphLen+tcphLen { - return false - } - if !isV6 { - if pkt[6]&ipv4FlagMoreFragments != 0 || pkt[6]<<3 != 0 || pkt[7] != 0 { - // no GRO support for fragmented segments for now - return false - } - } - tcpFlags := pkt[iphLen+tcpFlagsOffset] - var pshSet bool - // not a candidate if any non-ACK flags (except PSH+ACK) are set - if tcpFlags != tcpFlagACK { - if pkt[iphLen+tcpFlagsOffset] != tcpFlagACK|tcpFlagPSH { - return false - } - pshSet = true - } - gsoSize := uint16(len(pkt) - tcphLen - iphLen) - // not a candidate if payload len is 0 - if gsoSize < 1 { - return false - } - seq := binary.BigEndian.Uint32(pkt[iphLen+4:]) - srcAddrOffset := ipv4SrcAddrOffset - addrLen := 4 - if isV6 { - srcAddrOffset = ipv6SrcAddrOffset - addrLen = 16 - } - items, existing := table.lookupOrInsert(pkt, srcAddrOffset, srcAddrOffset+addrLen, iphLen, tcphLen, pktI) - if !existing { - return false - } - for i := len(items) - 1; i >= 0; i-- { - // In the best case of packets arriving in order iterating in reverse is - // more efficient if there are multiple items for a given flow. This - // also enables a natural table.deleteAt() in the - // coalesceItemInvalidCSum case without the need for index tracking. - // This algorithm makes a best effort to coalesce in the event of - // unordered packets, where pkt may land anywhere in items from a - // sequence number perspective, however once an item is inserted into - // the table it is never compared across other items later. - item := items[i] - can := tcpPacketsCanCoalesce(pkt, uint8(iphLen), uint8(tcphLen), seq, pshSet, gsoSize, item, bufs, offset) - if can != coalesceUnavailable { - result := coalesceTCPPackets(can, pkt, pktI, gsoSize, seq, pshSet, &item, bufs, offset, isV6) - switch result { - case coalesceSuccess: - table.updateAt(item, i) - return true - case coalesceItemInvalidCSum: - // delete the item with an invalid csum - table.deleteAt(item.key, i) - case coalescePktInvalidCSum: - // no point in inserting an item that we can't coalesce - return false - default: - } - } - } - // failed to coalesce with any other packets; store the item in the flow - table.insert(pkt, srcAddrOffset, srcAddrOffset+addrLen, iphLen, tcphLen, pktI) - return false -} - -func isTCP4NoIPOptions(b []byte) bool { - if len(b) < 40 { - return false - } - if b[0]>>4 != 4 { - return false - } - if b[0]&0x0F != 5 { - return false - } - if b[9] != unix.IPPROTO_TCP { - return false - } - return true -} - -func isTCP6NoEH(b []byte) bool { - if len(b) < 60 { - return false - } - if b[0]>>4 != 6 { - return false - } - if b[6] != unix.IPPROTO_TCP { - return false - } - return true -} - -// handleGRO evaluates bufs for GRO, and writes the indices of the resulting -// packets into toWrite. toWrite, tcp4Table, and tcp6Table should initially be -// empty (but non-nil), and are passed in to save allocs as the caller may reset -// and recycle them across vectors of packets. -func handleGRO(bufs [][]byte, offset int, tcp4Table, tcp6Table *tcpGROTable, toWrite *[]int) error { - for i := range bufs { - if offset < virtioNetHdrLen || offset > len(bufs[i])-1 { - return errors.New("invalid offset") - } - var coalesced bool - switch { - case isTCP4NoIPOptions(bufs[i][offset:]): // ipv4 packets w/IP options do not coalesce - coalesced = tcpGRO(bufs, offset, i, tcp4Table, false) - case isTCP6NoEH(bufs[i][offset:]): // ipv6 packets w/extension headers do not coalesce - coalesced = tcpGRO(bufs, offset, i, tcp6Table, true) - } - if !coalesced { - hdr := virtioNetHdr{} - err := hdr.encode(bufs[i][offset-virtioNetHdrLen:]) - if err != nil { - return err - } - *toWrite = append(*toWrite, i) - } - } - return nil -} - -// tcpTSO splits packets from in into outBuffs, writing the size of each -// element into sizes. It returns the number of buffers populated, and/or an -// error. -func tcpTSO(in []byte, hdr virtioNetHdr, outBuffs [][]byte, sizes []int, outOffset int) (int, error) { - iphLen := int(hdr.csumStart) - srcAddrOffset := ipv6SrcAddrOffset - addrLen := 16 - if hdr.gsoType == unix.VIRTIO_NET_HDR_GSO_TCPV4 { - in[10], in[11] = 0, 0 // clear ipv4 header checksum - srcAddrOffset = ipv4SrcAddrOffset - addrLen = 4 - } - tcpCSumAt := int(hdr.csumStart + hdr.csumOffset) - in[tcpCSumAt], in[tcpCSumAt+1] = 0, 0 // clear tcp checksum - firstTCPSeqNum := binary.BigEndian.Uint32(in[hdr.csumStart+4:]) - nextSegmentDataAt := int(hdr.hdrLen) - i := 0 - for ; nextSegmentDataAt < len(in); i++ { - if i == len(outBuffs) { - return i - 1, ErrTooManySegments - } - nextSegmentEnd := nextSegmentDataAt + int(hdr.gsoSize) - if nextSegmentEnd > len(in) { - nextSegmentEnd = len(in) - } - segmentDataLen := nextSegmentEnd - nextSegmentDataAt - totalLen := int(hdr.hdrLen) + segmentDataLen - sizes[i] = totalLen - out := outBuffs[i][outOffset:] - - copy(out, in[:iphLen]) - if hdr.gsoType == unix.VIRTIO_NET_HDR_GSO_TCPV4 { - // For IPv4 we are responsible for incrementing the ID field, - // updating the total len field, and recalculating the header - // checksum. - if i > 0 { - id := binary.BigEndian.Uint16(out[4:]) - id += uint16(i) - binary.BigEndian.PutUint16(out[4:], id) - } - binary.BigEndian.PutUint16(out[2:], uint16(totalLen)) - ipv4CSum := ^checksum(out[:iphLen], 0) - binary.BigEndian.PutUint16(out[10:], ipv4CSum) - } else { - // For IPv6 we are responsible for updating the payload length field. - binary.BigEndian.PutUint16(out[4:], uint16(totalLen-iphLen)) - } - - // TCP header - copy(out[hdr.csumStart:hdr.hdrLen], in[hdr.csumStart:hdr.hdrLen]) - tcpSeq := firstTCPSeqNum + uint32(hdr.gsoSize*uint16(i)) - binary.BigEndian.PutUint32(out[hdr.csumStart+4:], tcpSeq) - if nextSegmentEnd != len(in) { - // FIN and PSH should only be set on last segment - clearFlags := tcpFlagFIN | tcpFlagPSH - out[hdr.csumStart+tcpFlagsOffset] &^= clearFlags - } - - // payload - copy(out[hdr.hdrLen:], in[nextSegmentDataAt:nextSegmentEnd]) - - // TCP checksum - tcpHLen := int(hdr.hdrLen - hdr.csumStart) - tcpLenForPseudo := uint16(tcpHLen + segmentDataLen) - tcpCSumNoFold := pseudoHeaderChecksumNoFold(unix.IPPROTO_TCP, in[srcAddrOffset:srcAddrOffset+addrLen], in[srcAddrOffset+addrLen:srcAddrOffset+addrLen*2], tcpLenForPseudo) - tcpCSum := ^checksum(out[hdr.csumStart:totalLen], tcpCSumNoFold) - binary.BigEndian.PutUint16(out[hdr.csumStart+hdr.csumOffset:], tcpCSum) - - nextSegmentDataAt += int(hdr.gsoSize) - } - return i, nil -} - -func gsoNoneChecksum(in []byte, cSumStart, cSumOffset uint16) error { - cSumAt := cSumStart + cSumOffset - // The initial value at the checksum offset should be summed with the - // checksum we compute. This is typically the pseudo-header checksum. - initial := binary.BigEndian.Uint16(in[cSumAt:]) - in[cSumAt], in[cSumAt+1] = 0, 0 - binary.BigEndian.PutUint16(in[cSumAt:], ^checksum(in[cSumStart:], uint64(initial))) - return nil -} diff --git a/vendor/golang.zx2c4.com/wireguard/tun/tun.go b/vendor/golang.zx2c4.com/wireguard/tun/tun.go index 0ae53d0733..01051b938e 100644 --- a/vendor/golang.zx2c4.com/wireguard/tun/tun.go +++ b/vendor/golang.zx2c4.com/wireguard/tun/tun.go @@ -18,36 +18,12 @@ const ( ) type Device interface { - // File returns the file descriptor of the device. - File() *os.File - - // Read one or more packets from the Device (without any additional headers). - // On a successful read it returns the number of packets read, and sets - // packet lengths within the sizes slice. len(sizes) must be >= len(bufs). - // A nonzero offset can be used to instruct the Device on where to begin - // reading into each element of the bufs slice. - Read(bufs [][]byte, sizes []int, offset int) (n int, err error) - - // Write one or more packets to the device (without any additional headers). - // On a successful write it returns the number of packets written. A nonzero - // offset can be used to instruct the Device on where to begin writing from - // each packet contained within the bufs slice. - Write(bufs [][]byte, offset int) (int, error) - - // MTU returns the MTU of the Device. - MTU() (int, error) - - // Name returns the current name of the Device. - Name() (string, error) - - // Events returns a channel of type Event, which is fed Device events. - Events() <-chan Event - - // Close stops the Device and closes the Event channel. - Close() error - - // BatchSize returns the preferred/max number of packets that can be read or - // written in a single read/write call. BatchSize must not change over the - // lifetime of a Device. - BatchSize() int + File() *os.File // returns the file descriptor of the device + Read([]byte, int) (int, error) // read a packet from the device (without any additional headers) + Write([]byte, int) (int, error) // writes a packet to the device (without any additional headers) + Flush() error // flush all previous writes to the device + MTU() (int, error) // returns the MTU of the device + Name() (string, error) // fetches and returns the current name + Events() <-chan Event // returns a constant channel of events related to the device + Close() error // stops the device and closes the event channel } diff --git a/vendor/golang.zx2c4.com/wireguard/tun/tun_darwin.go b/vendor/golang.zx2c4.com/wireguard/tun/tun_darwin.go index c9a6c0bc45..7411a69463 100644 --- a/vendor/golang.zx2c4.com/wireguard/tun/tun_darwin.go +++ b/vendor/golang.zx2c4.com/wireguard/tun/tun_darwin.go @@ -8,7 +8,6 @@ package tun import ( "errors" "fmt" - "io" "net" "os" "sync" @@ -16,6 +15,7 @@ import ( "time" "unsafe" + "golang.org/x/net/ipv6" "golang.org/x/sys/unix" ) @@ -33,7 +33,7 @@ type NativeTun struct { func retryInterfaceByIndex(index int) (iface *net.Interface, err error) { for i := 0; i < 20; i++ { iface, err = net.InterfaceByIndex(index) - if err != nil && errors.Is(err, unix.ENOMEM) { + if err != nil && errors.Is(err, syscall.ENOMEM) { time.Sleep(time.Duration(i) * time.Second / 3) continue } @@ -55,7 +55,7 @@ func (tun *NativeTun) routineRouteListener(tunIfindex int) { retry: n, err := unix.Read(tun.routeSocket, data) if err != nil { - if errno, ok := err.(unix.Errno); ok && errno == unix.EINTR { + if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINTR { goto retry } tun.errors <- err @@ -217,46 +217,45 @@ func (tun *NativeTun) Events() <-chan Event { return tun.events } -func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) { - // TODO: the BSDs look very similar in Read() and Write(). They should be - // collapsed, with platform-specific files containing the varying parts of - // their implementations. +func (tun *NativeTun) Read(buff []byte, offset int) (int, error) { select { case err := <-tun.errors: return 0, err default: - buf := bufs[0][offset-4:] - n, err := tun.tunFile.Read(buf[:]) + buff := buff[offset-4:] + n, err := tun.tunFile.Read(buff[:]) if n < 4 { return 0, err } - sizes[0] = n - 4 - return 1, err + return n - 4, err } } -func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) { - if offset < 4 { - return 0, io.ErrShortBuffer - } - for i, buf := range bufs { - buf = buf[offset-4:] - buf[0] = 0x00 - buf[1] = 0x00 - buf[2] = 0x00 - switch buf[4] >> 4 { - case 4: - buf[3] = unix.AF_INET - case 6: - buf[3] = unix.AF_INET6 - default: - return i, unix.EAFNOSUPPORT - } - if _, err := tun.tunFile.Write(buf); err != nil { - return i, err - } +func (tun *NativeTun) Write(buff []byte, offset int) (int, error) { + // reserve space for header + + buff = buff[offset-4:] + + // add packet information header + + buff[0] = 0x00 + buff[1] = 0x00 + buff[2] = 0x00 + + if buff[4]>>4 == ipv6.Version { + buff[3] = unix.AF_INET6 + } else { + buff[3] = unix.AF_INET } - return len(bufs), nil + + // write + + return tun.tunFile.Write(buff) +} + +func (tun *NativeTun) Flush() error { + // TODO: can flushing be implemented by buffering and using sendmmsg? + return nil } func (tun *NativeTun) Close() error { @@ -319,10 +318,6 @@ func (tun *NativeTun) MTU() (int, error) { return int(ifr.MTU), nil } -func (tun *NativeTun) BatchSize() int { - return 1 -} - func socketCloexec(family, sotype, proto int) (fd int, err error) { // See go/src/net/sys_cloexec.go for background. syscall.ForkLock.RLock() diff --git a/vendor/golang.zx2c4.com/wireguard/tun/tun_freebsd.go b/vendor/golang.zx2c4.com/wireguard/tun/tun_freebsd.go index 7c65fd9992..42431aa3ee 100644 --- a/vendor/golang.zx2c4.com/wireguard/tun/tun_freebsd.go +++ b/vendor/golang.zx2c4.com/wireguard/tun/tun_freebsd.go @@ -333,46 +333,45 @@ func (tun *NativeTun) Events() <-chan Event { return tun.events } -func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) { +func (tun *NativeTun) Read(buff []byte, offset int) (int, error) { select { case err := <-tun.errors: return 0, err default: - buf := bufs[0][offset-4:] - n, err := tun.tunFile.Read(buf[:]) + buff := buff[offset-4:] + n, err := tun.tunFile.Read(buff[:]) if n < 4 { return 0, err } - sizes[0] = n - 4 - return 1, err + return n - 4, err } } -func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) { +func (tun *NativeTun) Write(buf []byte, offset int) (int, error) { if offset < 4 { return 0, io.ErrShortBuffer } - for i, buf := range bufs { - buf = buf[offset-4:] - if len(buf) < 5 { - return i, io.ErrShortBuffer - } - buf[0] = 0x00 - buf[1] = 0x00 - buf[2] = 0x00 - switch buf[4] >> 4 { - case 4: - buf[3] = unix.AF_INET - case 6: - buf[3] = unix.AF_INET6 - default: - return i, unix.EAFNOSUPPORT - } - if _, err := tun.tunFile.Write(buf); err != nil { - return i, err - } + buf = buf[offset-4:] + if len(buf) < 5 { + return 0, io.ErrShortBuffer + } + buf[0] = 0x00 + buf[1] = 0x00 + buf[2] = 0x00 + switch buf[4] >> 4 { + case 4: + buf[3] = unix.AF_INET + case 6: + buf[3] = unix.AF_INET6 + default: + return 0, unix.EAFNOSUPPORT } - return len(bufs), nil + return tun.tunFile.Write(buf) +} + +func (tun *NativeTun) Flush() error { + // TODO: can flushing be implemented by buffering and using sendmmsg? + return nil } func (tun *NativeTun) Close() error { @@ -429,7 +428,3 @@ func (tun *NativeTun) MTU() (int, error) { } return int(*(*int32)(unsafe.Pointer(&ifr.MTU))), nil } - -func (tun *NativeTun) BatchSize() int { - return 1 -} diff --git a/vendor/golang.zx2c4.com/wireguard/tun/tun_linux.go b/vendor/golang.zx2c4.com/wireguard/tun/tun_linux.go index 12cd49f747..25dbc0749b 100644 --- a/vendor/golang.zx2c4.com/wireguard/tun/tun_linux.go +++ b/vendor/golang.zx2c4.com/wireguard/tun/tun_linux.go @@ -17,8 +17,9 @@ import ( "time" "unsafe" + "golang.org/x/net/ipv6" "golang.org/x/sys/unix" - "golang.zx2c4.com/wireguard/conn" + "golang.zx2c4.com/wireguard/rwcancel" ) @@ -32,25 +33,17 @@ type NativeTun struct { index int32 // if index errors chan error // async error handling events chan Event // device related events + nopi bool // the device was passed IFF_NO_PI netlinkSock int netlinkCancel *rwcancel.RWCancel hackListenerClosed sync.Mutex statusListenersShutdown chan struct{} - batchSize int - vnetHdr bool closeOnce sync.Once nameOnce sync.Once // guards calling initNameCache, which sets following fields nameCache string // name of interface nameErr error - - readOpMu sync.Mutex // readOpMu guards readBuff - readBuff [virtioNetHdrLen + 65535]byte // if vnetHdr every read() is prefixed by virtioNetHdr - - writeOpMu sync.Mutex // writeOpMu guards toWrite, tcp4GROTable, tcp6GROTable - toWrite []int - tcp4GROTable, tcp6GROTable *tcpGROTable } func (tun *NativeTun) File() *os.File { @@ -330,142 +323,57 @@ func (tun *NativeTun) nameSlow() (string, error) { return unix.ByteSliceToString(ifr[:]), nil } -func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) { - tun.writeOpMu.Lock() - defer func() { - tun.tcp4GROTable.reset() - tun.tcp6GROTable.reset() - tun.writeOpMu.Unlock() - }() - var ( - errs error - total int - ) - tun.toWrite = tun.toWrite[:0] - if tun.vnetHdr { - err := handleGRO(bufs, offset, tun.tcp4GROTable, tun.tcp6GROTable, &tun.toWrite) - if err != nil { - return 0, err - } - offset -= virtioNetHdrLen +func (tun *NativeTun) Write(buf []byte, offset int) (int, error) { + if tun.nopi { + buf = buf[offset:] } else { - for i := range bufs { - tun.toWrite = append(tun.toWrite, i) - } - } - for _, bufsI := range tun.toWrite { - n, err := tun.tunFile.Write(bufs[bufsI][offset:]) - if errors.Is(err, syscall.EBADFD) { - return total, os.ErrClosed - } - if err != nil { - errs = errors.Join(errs, err) + // reserve space for header + buf = buf[offset-4:] + + // add packet information header + buf[0] = 0x00 + buf[1] = 0x00 + if buf[4]>>4 == ipv6.Version { + buf[2] = 0x86 + buf[3] = 0xdd } else { - total += n + buf[2] = 0x08 + buf[3] = 0x00 } } - return total, errs -} -// handleVirtioRead splits in into bufs, leaving offset bytes at the front of -// each buffer. It mutates sizes to reflect the size of each element of bufs, -// and returns the number of packets read. -func handleVirtioRead(in []byte, bufs [][]byte, sizes []int, offset int) (int, error) { - var hdr virtioNetHdr - err := hdr.decode(in) - if err != nil { - return 0, err - } - in = in[virtioNetHdrLen:] - if hdr.gsoType == unix.VIRTIO_NET_HDR_GSO_NONE { - if hdr.flags&unix.VIRTIO_NET_HDR_F_NEEDS_CSUM != 0 { - // This means CHECKSUM_PARTIAL in skb context. We are responsible - // for computing the checksum starting at hdr.csumStart and placing - // at hdr.csumOffset. - err = gsoNoneChecksum(in, hdr.csumStart, hdr.csumOffset) - if err != nil { - return 0, err - } - } - if len(in) > len(bufs[0][offset:]) { - return 0, fmt.Errorf("read len %d overflows bufs element len %d", len(in), len(bufs[0][offset:])) - } - n := copy(bufs[0][offset:], in) - sizes[0] = n - return 1, nil - } - if hdr.gsoType != unix.VIRTIO_NET_HDR_GSO_TCPV4 && hdr.gsoType != unix.VIRTIO_NET_HDR_GSO_TCPV6 { - return 0, fmt.Errorf("unsupported virtio GSO type: %d", hdr.gsoType) - } - - ipVersion := in[0] >> 4 - switch ipVersion { - case 4: - if hdr.gsoType != unix.VIRTIO_NET_HDR_GSO_TCPV4 { - return 0, fmt.Errorf("ip header version: %d, GSO type: %d", ipVersion, hdr.gsoType) - } - case 6: - if hdr.gsoType != unix.VIRTIO_NET_HDR_GSO_TCPV6 { - return 0, fmt.Errorf("ip header version: %d, GSO type: %d", ipVersion, hdr.gsoType) - } - default: - return 0, fmt.Errorf("invalid ip header version: %d", ipVersion) - } - - if len(in) <= int(hdr.csumStart+12) { - return 0, errors.New("packet is too short") - } - // Don't trust hdr.hdrLen from the kernel as it can be equal to the length - // of the entire first packet when the kernel is handling it as part of a - // FORWARD path. Instead, parse the TCP header length and add it onto - // csumStart, which is synonymous for IP header length. - tcpHLen := uint16(in[hdr.csumStart+12] >> 4 * 4) - if tcpHLen < 20 || tcpHLen > 60 { - // A TCP header must be between 20 and 60 bytes in length. - return 0, fmt.Errorf("tcp header len is invalid: %d", tcpHLen) - } - hdr.hdrLen = hdr.csumStart + tcpHLen - - if len(in) < int(hdr.hdrLen) { - return 0, fmt.Errorf("length of packet (%d) < virtioNetHdr.hdrLen (%d)", len(in), hdr.hdrLen) - } - - if hdr.hdrLen < hdr.csumStart { - return 0, fmt.Errorf("virtioNetHdr.hdrLen (%d) < virtioNetHdr.csumStart (%d)", hdr.hdrLen, hdr.csumStart) - } - cSumAt := int(hdr.csumStart + hdr.csumOffset) - if cSumAt+1 >= len(in) { - return 0, fmt.Errorf("end of checksum offset (%d) exceeds packet length (%d)", cSumAt+1, len(in)) + n, err := tun.tunFile.Write(buf) + if errors.Is(err, syscall.EBADFD) { + err = os.ErrClosed } + return n, err +} - return tcpTSO(in, hdr, bufs, sizes, offset) +func (tun *NativeTun) Flush() error { + // TODO: can flushing be implemented by buffering and using sendmmsg? + return nil } -func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) { - tun.readOpMu.Lock() - defer tun.readOpMu.Unlock() +func (tun *NativeTun) Read(buf []byte, offset int) (n int, err error) { select { - case err := <-tun.errors: - return 0, err + case err = <-tun.errors: default: - readInto := bufs[0][offset:] - if tun.vnetHdr { - readInto = tun.readBuff[:] - } - n, err := tun.tunFile.Read(readInto) - if errors.Is(err, syscall.EBADFD) { - err = os.ErrClosed - } - if err != nil { - return 0, err - } - if tun.vnetHdr { - return handleVirtioRead(readInto[:n], bufs, sizes, offset) + if tun.nopi { + n, err = tun.tunFile.Read(buf[offset:]) } else { - sizes[0] = n - return 1, nil + buff := buf[offset-4:] + n, err = tun.tunFile.Read(buff[:]) + if errors.Is(err, syscall.EBADFD) { + err = os.ErrClosed + } + if n < 4 { + n = 0 + } else { + n -= 4 + } } } + return } func (tun *NativeTun) Events() <-chan Event { @@ -491,50 +399,6 @@ func (tun *NativeTun) Close() error { return err2 } -func (tun *NativeTun) BatchSize() int { - return tun.batchSize -} - -const ( - // TODO: support TSO with ECN bits - tunOffloads = unix.TUN_F_CSUM | unix.TUN_F_TSO4 | unix.TUN_F_TSO6 -) - -func (tun *NativeTun) initFromFlags(name string) error { - sc, err := tun.tunFile.SyscallConn() - if err != nil { - return err - } - if e := sc.Control(func(fd uintptr) { - var ( - ifr *unix.Ifreq - ) - ifr, err = unix.NewIfreq(name) - if err != nil { - return - } - err = unix.IoctlIfreq(int(fd), unix.TUNGETIFF, ifr) - if err != nil { - return - } - got := ifr.Uint16() - if got&unix.IFF_VNET_HDR != 0 { - err = unix.IoctlSetInt(int(fd), unix.TUNSETOFFLOAD, tunOffloads) - if err != nil { - return - } - tun.vnetHdr = true - tun.batchSize = conn.IdealBatchSize - } else { - tun.batchSize = 1 - } - }); e != nil { - return e - } - return err -} - -// CreateTUN creates a Device with the provided name and MTU. func CreateTUN(name string, mtu int) (Device, error) { nfd, err := unix.Open(cloneDevicePath, unix.O_RDWR|unix.O_CLOEXEC, 0) if err != nil { @@ -544,16 +408,25 @@ func CreateTUN(name string, mtu int) (Device, error) { return nil, err } - ifr, err := unix.NewIfreq(name) - if err != nil { - return nil, err + var ifr [ifReqSize]byte + var flags uint16 = unix.IFF_TUN // | unix.IFF_NO_PI (disabled for TUN status hack) + nameBytes := []byte(name) + if len(nameBytes) >= unix.IFNAMSIZ { + unix.Close(nfd) + return nil, fmt.Errorf("interface name too long: %w", unix.ENAMETOOLONG) } - // IFF_VNET_HDR enables the "tun status hack" via routineHackListener() - // where a null write will return EINVAL indicating the TUN is up. - ifr.SetUint16(unix.IFF_TUN | unix.IFF_NO_PI | unix.IFF_VNET_HDR) - err = unix.IoctlIfreq(nfd, unix.TUNSETIFF, ifr) - if err != nil { - return nil, err + copy(ifr[:], nameBytes) + *(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = flags + + _, _, errno := unix.Syscall( + unix.SYS_IOCTL, + uintptr(nfd), + uintptr(unix.TUNSETIFF), + uintptr(unsafe.Pointer(&ifr[0])), + ) + if errno != 0 { + unix.Close(nfd) + return nil, errno } err = unix.SetNonblock(nfd, true) @@ -568,16 +441,13 @@ func CreateTUN(name string, mtu int) (Device, error) { return CreateTUNFromFile(fd, mtu) } -// CreateTUNFromFile creates a Device from an os.File with the provided MTU. func CreateTUNFromFile(file *os.File, mtu int) (Device, error) { tun := &NativeTun{ tunFile: file, events: make(chan Event, 5), errors: make(chan error, 5), statusListenersShutdown: make(chan struct{}), - tcp4GROTable: newTCPGROTable(), - tcp6GROTable: newTCPGROTable(), - toWrite: make([]int, 0, conn.IdealBatchSize), + nopi: false, } name, err := tun.Name() @@ -585,12 +455,8 @@ func CreateTUNFromFile(file *os.File, mtu int) (Device, error) { return nil, err } - err = tun.initFromFlags(name) - if err != nil { - return nil, err - } - // start event listener + tun.index, err = getIFIndex(name) if err != nil { return nil, err @@ -619,8 +485,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (Device, error) { return tun, nil } -// CreateUnmonitoredTUNFromFD creates a Device from the provided file -// descriptor. func CreateUnmonitoredTUNFromFD(fd int) (Device, string, error) { err := unix.SetNonblock(fd, true) if err != nil { @@ -628,20 +492,14 @@ func CreateUnmonitoredTUNFromFD(fd int) (Device, string, error) { } file := os.NewFile(uintptr(fd), "/dev/tun") tun := &NativeTun{ - tunFile: file, - events: make(chan Event, 5), - errors: make(chan error, 5), - tcp4GROTable: newTCPGROTable(), - tcp6GROTable: newTCPGROTable(), - toWrite: make([]int, 0, conn.IdealBatchSize), + tunFile: file, + events: make(chan Event, 5), + errors: make(chan error, 5), + nopi: true, } name, err := tun.Name() if err != nil { return nil, "", err } - err = tun.initFromFlags(name) - if err != nil { - return nil, "", err - } - return tun, name, err + return tun, name, nil } diff --git a/vendor/golang.zx2c4.com/wireguard/tun/tun_openbsd.go b/vendor/golang.zx2c4.com/wireguard/tun/tun_openbsd.go index ae571b90c3..e7fd79c5b0 100644 --- a/vendor/golang.zx2c4.com/wireguard/tun/tun_openbsd.go +++ b/vendor/golang.zx2c4.com/wireguard/tun/tun_openbsd.go @@ -8,13 +8,13 @@ package tun import ( "errors" "fmt" - "io" "net" "os" "sync" "syscall" "unsafe" + "golang.org/x/net/ipv6" "golang.org/x/sys/unix" ) @@ -204,43 +204,45 @@ func (tun *NativeTun) Events() <-chan Event { return tun.events } -func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) { +func (tun *NativeTun) Read(buff []byte, offset int) (int, error) { select { case err := <-tun.errors: return 0, err default: - buf := bufs[0][offset-4:] - n, err := tun.tunFile.Read(buf[:]) + buff := buff[offset-4:] + n, err := tun.tunFile.Read(buff[:]) if n < 4 { return 0, err } - sizes[0] = n - 4 - return 1, err + return n - 4, err } } -func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) { - if offset < 4 { - return 0, io.ErrShortBuffer - } - for i, buf := range bufs { - buf = buf[offset-4:] - buf[0] = 0x00 - buf[1] = 0x00 - buf[2] = 0x00 - switch buf[4] >> 4 { - case 4: - buf[3] = unix.AF_INET - case 6: - buf[3] = unix.AF_INET6 - default: - return i, unix.EAFNOSUPPORT - } - if _, err := tun.tunFile.Write(buf); err != nil { - return i, err - } +func (tun *NativeTun) Write(buff []byte, offset int) (int, error) { + // reserve space for header + + buff = buff[offset-4:] + + // add packet information header + + buff[0] = 0x00 + buff[1] = 0x00 + buff[2] = 0x00 + + if buff[4]>>4 == ipv6.Version { + buff[3] = unix.AF_INET6 + } else { + buff[3] = unix.AF_INET } - return len(bufs), nil + + // write + + return tun.tunFile.Write(buff) +} + +func (tun *NativeTun) Flush() error { + // TODO: can flushing be implemented by buffering and using sendmmsg? + return nil } func (tun *NativeTun) Close() error { @@ -327,7 +329,3 @@ func (tun *NativeTun) MTU() (int, error) { return int(*(*int32)(unsafe.Pointer(&ifr.MTU))), nil } - -func (tun *NativeTun) BatchSize() int { - return 1 -} diff --git a/vendor/golang.zx2c4.com/wireguard/tun/tun_windows.go b/vendor/golang.zx2c4.com/wireguard/tun/tun_windows.go index 0cb4ce1925..d5abb14898 100644 --- a/vendor/golang.zx2c4.com/wireguard/tun/tun_windows.go +++ b/vendor/golang.zx2c4.com/wireguard/tun/tun_windows.go @@ -15,6 +15,7 @@ import ( _ "unsafe" "golang.org/x/sys/windows" + "golang.zx2c4.com/wintun" ) @@ -43,7 +44,6 @@ type NativeTun struct { closeOnce sync.Once close atomic.Bool forcedMTU int - outSizes []int } var ( @@ -134,14 +134,9 @@ func (tun *NativeTun) ForceMTU(mtu int) { } } -func (tun *NativeTun) BatchSize() int { - // TODO: implement batching with wintun - return 1 -} - // Note: Read() and Write() assume the caller comes only from a single thread; there's no locking. -func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) { +func (tun *NativeTun) Read(buff []byte, offset int) (int, error) { tun.running.Add(1) defer tun.running.Done() retry: @@ -158,11 +153,10 @@ retry: switch err { case nil: packetSize := len(packet) - copy(bufs[0][offset:], packet) - sizes[0] = packetSize + copy(buff[offset:], packet) tun.session.ReleaseReceivePacket(packet) tun.rate.update(uint64(packetSize)) - return 1, nil + return packetSize, nil case windows.ERROR_NO_MORE_ITEMS: if !shouldSpin || uint64(nanotime()-start) >= spinloopDuration { windows.WaitForSingleObject(tun.readWait, windows.INFINITE) @@ -179,33 +173,33 @@ retry: } } -func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) { +func (tun *NativeTun) Flush() error { + return nil +} + +func (tun *NativeTun) Write(buff []byte, offset int) (int, error) { tun.running.Add(1) defer tun.running.Done() if tun.close.Load() { return 0, os.ErrClosed } - for i, buf := range bufs { - packetSize := len(buf) - offset - tun.rate.update(uint64(packetSize)) + packetSize := len(buff) - offset + tun.rate.update(uint64(packetSize)) - packet, err := tun.session.AllocateSendPacket(packetSize) - switch err { - case nil: - // TODO: Explore options to eliminate this copy. - copy(packet, buf[offset:]) - tun.session.SendPacket(packet) - continue - case windows.ERROR_HANDLE_EOF: - return i, os.ErrClosed - case windows.ERROR_BUFFER_OVERFLOW: - continue // Dropping when ring is full. - default: - return i, fmt.Errorf("Write failed: %w", err) - } + packet, err := tun.session.AllocateSendPacket(packetSize) + if err == nil { + copy(packet, buff[offset:]) + tun.session.SendPacket(packet) + return packetSize, nil + } + switch err { + case windows.ERROR_HANDLE_EOF: + return 0, os.ErrClosed + case windows.ERROR_BUFFER_OVERFLOW: + return 0, nil // Dropping when ring is full. } - return len(bufs), nil + return 0, fmt.Errorf("Write failed: %w", err) } // LUID returns Windows interface instance ID. diff --git a/vendor/modules.txt b/vendor/modules.txt index 52dc5b2726..feb2d3d1b9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -551,10 +551,8 @@ golang.org/x/tools/internal/typesinternal # golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 ## explicit; go 1.17 golang.zx2c4.com/wintun -# golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 -## explicit; go 1.20 -golang.zx2c4.com/wireguard/conn -golang.zx2c4.com/wireguard/conn/winrio +# golang.zx2c4.com/wireguard v0.0.0-20230223181233-21636207a675 +## explicit; go 1.19 golang.zx2c4.com/wireguard/rwcancel golang.zx2c4.com/wireguard/tun # google.golang.org/protobuf v1.31.0