github.com/sagernet/wireguard-go@v0.0.0-20231215174105-89dec3b2f3e8/conn/conn.go (about) 1 /* SPDX-License-Identifier: MIT 2 * 3 * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. 4 */ 5 6 // Package conn implements WireGuard's network connections. 7 package conn 8 9 import ( 10 "errors" 11 "fmt" 12 "net/netip" 13 "reflect" 14 "runtime" 15 "strings" 16 ) 17 18 const ( 19 IdealBatchSize = 128 // maximum number of packets handled per read and write 20 ) 21 22 // A ReceiveFunc receives at least one packet from the network and writes them 23 // into packets. On a successful read it returns the number of elements of 24 // sizes, packets, and endpoints that should be evaluated. Some elements of 25 // sizes may be zero, and callers should ignore them. Callers must pass a sizes 26 // and eps slice with a length greater than or equal to the length of packets. 27 // These lengths must not exceed the length of the associated Bind.BatchSize(). 28 type ReceiveFunc func(packets [][]byte, sizes []int, eps []Endpoint) (n int, err error) 29 30 // A Bind listens on a port for both IPv6 and IPv4 UDP traffic. 31 // 32 // A Bind interface may also be a PeekLookAtSocketFd or BindSocketToInterface, 33 // depending on the platform-specific implementation. 34 type Bind interface { 35 // Open puts the Bind into a listening state on a given port and reports the actual 36 // port that it bound to. Passing zero results in a random selection. 37 // fns is the set of functions that will be called to receive packets. 38 Open(port uint16) (fns []ReceiveFunc, actualPort uint16, err error) 39 40 // Close closes the Bind listener. 41 // All fns returned by Open must return net.ErrClosed after a call to Close. 42 Close() error 43 44 // SetMark sets the mark for each packet sent through this Bind. 45 // This mark is passed to the kernel as the socket option SO_MARK. 46 SetMark(mark uint32) error 47 48 // Send writes one or more packets in bufs to address ep. The length of 49 // bufs must not exceed BatchSize(). 50 Send(bufs [][]byte, ep Endpoint) error 51 52 // ParseEndpoint creates a new endpoint from a string. 53 ParseEndpoint(s string) (Endpoint, error) 54 55 // BatchSize is the number of buffers expected to be passed to 56 // the ReceiveFuncs, and the maximum expected to be passed to SendBatch. 57 BatchSize() int 58 59 SetReservedForEndpoint(destination netip.AddrPort, reserved [3]byte) 60 } 61 62 // BindSocketToInterface is implemented by Bind objects that support being 63 // tied to a single network interface. Used by wireguard-windows. 64 type BindSocketToInterface interface { 65 BindSocketToInterface4(interfaceIndex uint32, blackhole bool) error 66 BindSocketToInterface6(interfaceIndex uint32, blackhole bool) error 67 } 68 69 // PeekLookAtSocketFd is implemented by Bind objects that support having their 70 // file descriptor peeked at. Used by wireguard-android. 71 type PeekLookAtSocketFd interface { 72 PeekLookAtSocketFd4() (fd int, err error) 73 PeekLookAtSocketFd6() (fd int, err error) 74 } 75 76 // An Endpoint maintains the source/destination caching for a peer. 77 // 78 // dst: the remote address of a peer ("endpoint" in uapi terminology) 79 // src: the local address from which datagrams originate going to the peer 80 type Endpoint interface { 81 ClearSrc() // clears the source address 82 SrcToString() string // returns the local source address (ip:port) 83 DstToString() string // returns the destination address (ip:port) 84 DstToBytes() []byte // used for mac2 cookie calculations 85 DstIP() netip.Addr 86 SrcIP() netip.Addr 87 } 88 89 var ( 90 ErrBindAlreadyOpen = errors.New("bind is already open") 91 ErrWrongEndpointType = errors.New("endpoint type does not correspond with bind type") 92 ) 93 94 func (fn ReceiveFunc) PrettyName() string { 95 name := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name() 96 // 0. cheese/taco.beansIPv6.func12.func21218-fm 97 name = strings.TrimSuffix(name, "-fm") 98 // 1. cheese/taco.beansIPv6.func12.func21218 99 if idx := strings.LastIndexByte(name, '/'); idx != -1 { 100 name = name[idx+1:] 101 // 2. taco.beansIPv6.func12.func21218 102 } 103 for { 104 var idx int 105 for idx = len(name) - 1; idx >= 0; idx-- { 106 if name[idx] < '0' || name[idx] > '9' { 107 break 108 } 109 } 110 if idx == len(name)-1 { 111 break 112 } 113 const dotFunc = ".func" 114 if !strings.HasSuffix(name[:idx+1], dotFunc) { 115 break 116 } 117 name = name[:idx+1-len(dotFunc)] 118 // 3. taco.beansIPv6.func12 119 // 4. taco.beansIPv6 120 } 121 if idx := strings.LastIndexByte(name, '.'); idx != -1 { 122 name = name[idx+1:] 123 // 5. beansIPv6 124 } 125 if name == "" { 126 return fmt.Sprintf("%p", fn) 127 } 128 if strings.HasSuffix(name, "IPv4") { 129 return "v4" 130 } 131 if strings.HasSuffix(name, "IPv6") { 132 return "v6" 133 } 134 return name 135 }