Skip to content

Commit ccda107

Browse files
authored
Fix ioctl(2) code for OpenBSD (#1175)
This cleans up the mess to configure an IP address on a tun(4) device. Handrolling a hardcoded ioctl(2) request is far from perfect, but Go (golang.org/sys/unix) is to blame here. Tested on OpenBSD 7.6 -current where yggdrasil now drives the interface would use of ifconfig or other helpers.
1 parent 6d5243b commit ccda107

File tree

2 files changed

+124
-2
lines changed

2 files changed

+124
-2
lines changed

src/tun/tun_bsd.go renamed to src/tun/tun_freebsd.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
//go:build openbsd || freebsd
2-
// +build openbsd freebsd
1+
//go:build freebsd
2+
// +build freebsd
33

44
package tun
55

src/tun/tun_openbsd.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
//go:build openbsd
2+
// +build openbsd
3+
4+
package tun
5+
6+
import (
7+
"fmt"
8+
"net"
9+
"syscall"
10+
"unsafe"
11+
12+
"golang.org/x/sys/unix"
13+
14+
wgtun "golang.zx2c4.com/wireguard/tun"
15+
)
16+
17+
const (
18+
SIOCAIFADDR_IN6 = 0x8080691a
19+
ND6_INFINITE_LIFETIME = 0xffffffff
20+
)
21+
22+
type in6_addrlifetime struct {
23+
ia6t_expire int64
24+
ia6t_preferred int64
25+
ia6t_vltime uint32
26+
ia6t_pltime uint32
27+
}
28+
29+
// Match types from the net package, effectively being [16]byte for IPv6 addresses.
30+
type in6_addr [16]uint8
31+
32+
type sockaddr_in6 struct {
33+
sin6_len uint8
34+
sin6_family uint8
35+
sin6_port uint16
36+
sin6_flowinfo uint32
37+
sin6_addr in6_addr
38+
sin6_scope_id uint32
39+
}
40+
41+
func (sa6 *sockaddr_in6) setSockaddr(addr [/*16*/]byte /* net.IP or net.IPMask */) {
42+
sa6.sin6_len = uint8(unsafe.Sizeof(*sa6))
43+
sa6.sin6_family = unix.AF_INET6
44+
45+
for i := range sa6.sin6_addr {
46+
sa6.sin6_addr[i] = addr[i]
47+
}
48+
}
49+
50+
type in6_aliasreq struct {
51+
ifra_name [syscall.IFNAMSIZ]byte
52+
ifra_addr sockaddr_in6
53+
ifra_dstaddr sockaddr_in6
54+
ifra_prefixmask sockaddr_in6
55+
ifra_flags int32
56+
ifra_lifetime in6_addrlifetime
57+
}
58+
59+
// Configures the TUN adapter with the correct IPv6 address and MTU.
60+
func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
61+
iface, err := wgtun.CreateTUN(ifname, int(mtu))
62+
if err != nil {
63+
return fmt.Errorf("failed to create TUN: %w", err)
64+
}
65+
tun.iface = iface
66+
if mtu, err := iface.MTU(); err == nil {
67+
tun.mtu = getSupportedMTU(uint64(mtu))
68+
} else {
69+
tun.mtu = 0
70+
}
71+
if addr != "" {
72+
return tun.setupAddress(addr)
73+
}
74+
return nil
75+
}
76+
77+
// Configures the "utun" adapter from an existing file descriptor.
78+
func (tun *TunAdapter) setupFD(fd int32, addr string, mtu uint64) error {
79+
return fmt.Errorf("setup via FD not supported on this platform")
80+
}
81+
82+
func (tun *TunAdapter) setupAddress(addr string) error {
83+
var sfd int
84+
var err error
85+
86+
ip, prefix, err := net.ParseCIDR(addr)
87+
if err != nil {
88+
tun.log.Errorf("Error in ParseCIDR: %v", err)
89+
return err
90+
}
91+
92+
// Create system socket
93+
if sfd, err = unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0); err != nil {
94+
tun.log.Printf("Create AF_INET6 socket failed: %v", err)
95+
return err
96+
}
97+
98+
// Friendly output
99+
tun.log.Infof("Interface name: %s", tun.Name())
100+
tun.log.Infof("Interface IPv6: %s", addr)
101+
tun.log.Infof("Interface MTU: %d", tun.mtu)
102+
103+
// Create the address request
104+
var ar in6_aliasreq
105+
copy(ar.ifra_name[:], tun.Name())
106+
107+
ar.ifra_addr.setSockaddr(ip)
108+
109+
prefixmask := net.CIDRMask(prefix.Mask.Size())
110+
ar.ifra_prefixmask.setSockaddr(prefixmask)
111+
112+
ar.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME
113+
ar.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME
114+
115+
// Set the interface address
116+
if err = unix.IoctlSetInt(sfd, SIOCAIFADDR_IN6, int(uintptr(unsafe.Pointer(&ar)))); err != nil {
117+
tun.log.Errorf("Error in SIOCAIFADDR_IN6: %v", err)
118+
return err
119+
}
120+
121+
return nil
122+
}

0 commit comments

Comments
 (0)