github.com/tailscale/wireguard-go@v0.0.20201119-0.20210522003738-46b531feb08a/conn/conn.go (about) 1 /* SPDX-License-Identifier: MIT 2 * 3 * Copyright (C) 2017-2021 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" 13 "reflect" 14 "runtime" 15 "strings" 16 ) 17 18 // A ReceiveFunc receives a single inbound packet from the network. 19 // It writes the data into b. n is the length of the packet. 20 // ep is the remote endpoint. 21 type ReceiveFunc func(b []byte) (n int, ep Endpoint, err error) 22 23 // A Bind listens on a port for both IPv6 and IPv4 UDP traffic. 24 // 25 // A Bind interface may also be a PeekLookAtSocketFd or BindSocketToInterface, 26 // depending on the platform-specific implementation. 27 type Bind interface { 28 // Open puts the Bind into a listening state on a given port and reports the actual 29 // port that it bound to. Passing zero results in a random selection. 30 // fns is the set of functions that will be called to receive packets. 31 Open(port uint16) (fns []ReceiveFunc, actualPort uint16, err error) 32 33 // Close closes the Bind listener. 34 // All fns returned by Open must return net.ErrClosed after a call to Close. 35 Close() error 36 37 // SetMark sets the mark for each packet sent through this Bind. 38 // This mark is passed to the kernel as the socket option SO_MARK. 39 SetMark(mark uint32) error 40 41 // Send writes a packet b to address ep. 42 Send(b []byte, ep Endpoint) error 43 44 // ParseEndpoint creates a new endpoint from a string. 45 ParseEndpoint(s string) (Endpoint, error) 46 } 47 48 // BindSocketToInterface is implemented by Bind objects that support being 49 // tied to a single network interface. Used by wireguard-windows. 50 type BindSocketToInterface interface { 51 BindSocketToInterface4(interfaceIndex uint32, blackhole bool) error 52 BindSocketToInterface6(interfaceIndex uint32, blackhole bool) error 53 } 54 55 // PeekLookAtSocketFd is implemented by Bind objects that support having their 56 // file descriptor peeked at. Used by wireguard-android. 57 type PeekLookAtSocketFd interface { 58 PeekLookAtSocketFd4() (fd int, err error) 59 PeekLookAtSocketFd6() (fd int, err error) 60 } 61 62 // An Endpoint maintains the source/destination caching for a peer. 63 // 64 // dst: the remote address of a peer ("endpoint" in uapi terminology) 65 // src: the local address from which datagrams originate going to the peer 66 type Endpoint interface { 67 ClearSrc() // clears the source address 68 SrcToString() string // returns the local source address (ip:port) 69 DstToString() string // returns the destination address (ip:port) 70 DstToBytes() []byte // used for mac2 cookie calculations 71 DstIP() net.IP 72 SrcIP() net.IP 73 } 74 75 var ( 76 ErrBindAlreadyOpen = errors.New("bind is already open") 77 ErrWrongEndpointType = errors.New("endpoint type does not correspond with bind type") 78 ) 79 80 func (fn ReceiveFunc) PrettyName() string { 81 name := runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name() 82 // 0. cheese/taco.beansIPv6.func12.func21218-fm 83 name = strings.TrimSuffix(name, "-fm") 84 // 1. cheese/taco.beansIPv6.func12.func21218 85 if idx := strings.LastIndexByte(name, '/'); idx != -1 { 86 name = name[idx+1:] 87 // 2. taco.beansIPv6.func12.func21218 88 } 89 for { 90 var idx int 91 for idx = len(name) - 1; idx >= 0; idx-- { 92 if name[idx] < '0' || name[idx] > '9' { 93 break 94 } 95 } 96 if idx == len(name)-1 { 97 break 98 } 99 const dotFunc = ".func" 100 if !strings.HasSuffix(name[:idx+1], dotFunc) { 101 break 102 } 103 name = name[:idx+1-len(dotFunc)] 104 // 3. taco.beansIPv6.func12 105 // 4. taco.beansIPv6 106 } 107 if idx := strings.LastIndexByte(name, '.'); idx != -1 { 108 name = name[idx+1:] 109 // 5. beansIPv6 110 } 111 if name == "" { 112 return fmt.Sprintf("%p", fn) 113 } 114 if strings.HasSuffix(name, "IPv4") { 115 return "v4" 116 } 117 if strings.HasSuffix(name, "IPv6") { 118 return "v6" 119 } 120 return name 121 } 122 123 func parseEndpoint(s string) (*net.UDPAddr, error) { 124 // ensure that the host is an IP address 125 126 host, _, err := net.SplitHostPort(s) 127 if err != nil { 128 return nil, err 129 } 130 if i := strings.LastIndexByte(host, '%'); i > 0 && strings.IndexByte(host, ':') >= 0 { 131 // Remove the scope, if any. ResolveUDPAddr below will use it, but here we're just 132 // trying to make sure with a small sanity test that this is a real IP address and 133 // not something that's likely to incur DNS lookups. 134 host = host[:i] 135 } 136 if ip := net.ParseIP(host); ip == nil { 137 return nil, errors.New("Failed to parse IP address: " + host) 138 } 139 140 // parse address and port 141 142 addr, err := net.ResolveUDPAddr("udp", s) 143 if err != nil { 144 return nil, err 145 } 146 ip4 := addr.IP.To4() 147 if ip4 != nil { 148 addr.IP = ip4 149 } 150 return addr, err 151 }