aboutsummaryrefslogtreecommitdiffstats
path: root/conn/conn.go
diff options
context:
space:
mode:
Diffstat (limited to 'conn/conn.go')
-rw-r--r--conn/conn.go132
1 files changed, 77 insertions, 55 deletions
diff --git a/conn/conn.go b/conn/conn.go
index ad91d2d..1304657 100644
--- a/conn/conn.go
+++ b/conn/conn.go
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: MIT
*
- * Copyright (C) 2017-2020 WireGuard LLC. All Rights Reserved.
+ * Copyright (C) 2017-2025 WireGuard LLC. All Rights Reserved.
*/
// Package conn implements WireGuard's network connections.
@@ -8,49 +8,53 @@ package conn
import (
"errors"
- "net"
+ "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 {
- // LastMark reports the last mark set for this Bind.
- LastMark() uint32
+ // 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
- // ReceiveIPv6 reads an IPv6 UDP packet into b.
- //
- // It reports the number of bytes read, n,
- // the packet source address ep,
- // and any error.
- ReceiveIPv6(buff []byte) (n int, ep Endpoint, err error)
-
- // ReceiveIPv4 reads an IPv4 UDP packet into b.
- //
- // It reports the number of bytes read, n,
- // the packet source address ep,
- // and any error.
- ReceiveIPv4(b []byte) (n int, ep Endpoint, err error)
-
- // Send writes a packet b to address ep.
- Send(b []byte, ep Endpoint) 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
- // Close closes the Bind connection.
- Close() error
-}
+ // ParseEndpoint creates a new endpoint from a string.
+ ParseEndpoint(s string) (Endpoint, error)
-// CreateBind creates a Bind bound to a port.
-//
-// The value actualPort reports the actual port number the Bind
-// object gets bound to.
-func CreateBind(port uint16) (b Bind, actualPort uint16, err error) {
- return createBind(port)
+ // 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
@@ -69,43 +73,61 @@ type PeekLookAtSocketFd interface {
// 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
+// 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() net.IP
- SrcIP() net.IP
+ DstIP() netip.Addr
+ SrcIP() netip.Addr
}
-func parseEndpoint(s string) (*net.UDPAddr, error) {
- // ensure that the host is an IP address
+var (
+ ErrBindAlreadyOpen = errors.New("bind is already open")
+ ErrWrongEndpointType = errors.New("endpoint type does not correspond with bind type")
+)
- host, _, err := net.SplitHostPort(s)
- if err != nil {
- return nil, err
+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
}
- if i := strings.LastIndexByte(host, '%'); i > 0 && strings.IndexByte(host, ':') >= 0 {
- // Remove the scope, if any. ResolveUDPAddr below will use it, but here we're just
- // trying to make sure with a small sanity test that this is a real IP address and
- // not something that's likely to incur DNS lookups.
- host = host[:i]
+ 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 ip := net.ParseIP(host); ip == nil {
- return nil, errors.New("Failed to parse IP address: " + host)
+ if idx := strings.LastIndexByte(name, '.'); idx != -1 {
+ name = name[idx+1:]
+ // 5. beansIPv6
}
-
- // parse address and port
-
- addr, err := net.ResolveUDPAddr("udp", s)
- if err != nil {
- return nil, err
+ if name == "" {
+ return fmt.Sprintf("%p", fn)
+ }
+ if strings.HasSuffix(name, "IPv4") {
+ return "v4"
}
- ip4 := addr.IP.To4()
- if ip4 != nil {
- addr.IP = ip4
+ if strings.HasSuffix(name, "IPv6") {
+ return "v6"
}
- return addr, err
+ return name
}