github.com/koomox/wireguard-go@v0.0.0-20230722134753-17a50b2f22a3/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 60 // BindSocketToInterface is implemented by Bind objects that support being 61 // tied to a single network interface. Used by wireguard-windows. 62 type BindSocketToInterface interface { 63 BindSocketToInterface4(interfaceIndex uint32, blackhole bool) error 64 BindSocketToInterface6(interfaceIndex uint32, blackhole bool) error 65 } 66 67 // PeekLookAtSocketFd is implemented by Bind objects that support having their 68 // file descriptor peeked at. Used by wireguard-android. 69 type PeekLookAtSocketFd interface { 70 PeekLookAtSocketFd4() (fd int, err error) 71 PeekLookAtSocketFd6() (fd int, err error) 72 } 73 74 // An Endpoint maintains the source/destination caching for a peer. 75 // 76 // dst: the remote address of a peer ("endpoint" in uapi terminology) 77 // src: the local address from which datagrams originate going to the peer 78 type Endpoint interface { 79 ClearSrc() // clears the source address 80 SrcToString() string // returns the local source address (ip:port) 81 DstToString() string // returns the destination address (ip:port) 82 DstToBytes() []byte // used for mac2 cookie calculations 83 DstIP() netip.Addr 84 SrcIP() netip.Addr 85 } 86 87 var ( 88 ErrBindAlreadyOpen = errors.New("bind is already open") 89 ErrWrongEndpointType = errors.New("endpoint type does not correspond with bind type") 90 ) 91 92 func (fn ReceiveFunc) PrettyName() string { 93 name := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name() 94 // 0. cheese/taco.beansIPv6.func12.func21218-fm 95 name = strings.TrimSuffix(name, "-fm") 96 // 1. cheese/taco.beansIPv6.func12.func21218 97 if idx := strings.LastIndexByte(name, '/'); idx != -1 { 98 name = name[idx+1:] 99 // 2. taco.beansIPv6.func12.func21218 100 } 101 for { 102 var idx int 103 for idx = len(name) - 1; idx >= 0; idx-- { 104 if name[idx] < '0' || name[idx] > '9' { 105 break 106 } 107 } 108 if idx == len(name)-1 { 109 break 110 } 111 const dotFunc = ".func" 112 if !strings.HasSuffix(name[:idx+1], dotFunc) { 113 break 114 } 115 name = name[:idx+1-len(dotFunc)] 116 // 3. taco.beansIPv6.func12 117 // 4. taco.beansIPv6 118 } 119 if idx := strings.LastIndexByte(name, '.'); idx != -1 { 120 name = name[idx+1:] 121 // 5. beansIPv6 122 } 123 if name == "" { 124 return fmt.Sprintf("%p", fn) 125 } 126 if strings.HasSuffix(name, "IPv4") { 127 return "v4" 128 } 129 if strings.HasSuffix(name, "IPv6") { 130 return "v6" 131 } 132 return name 133 }