aboutsummaryrefslogtreecommitdiffstats
path: root/conn/conn.go
diff options
context:
space:
mode:
Diffstat (limited to 'conn/conn.go')
-rw-r--r--conn/conn.go133
1 files changed, 133 insertions, 0 deletions
diff --git a/conn/conn.go b/conn/conn.go
new file mode 100644
index 0000000..1304657
--- /dev/null
+++ b/conn/conn.go
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2017-2025 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
+}