2021-10-21 15:24:11 -06:00
|
|
|
//go:build !android && !e2e_testing
|
|
|
|
// +build !android,!e2e_testing
|
2020-07-01 09:20:52 -06:00
|
|
|
|
2021-11-11 15:37:29 -07:00
|
|
|
package overlay
|
2019-11-19 10:00:20 -07:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"unsafe"
|
|
|
|
|
2021-03-26 08:46:30 -06:00
|
|
|
"github.com/sirupsen/logrus"
|
2019-11-19 10:00:20 -07:00
|
|
|
"github.com/vishvananda/netlink"
|
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Tun struct {
|
|
|
|
io.ReadWriteCloser
|
2019-12-12 09:34:17 -07:00
|
|
|
fd int
|
|
|
|
Device string
|
|
|
|
Cidr *net.IPNet
|
|
|
|
MaxMTU int
|
|
|
|
DefaultMTU int
|
|
|
|
TXQueueLen int
|
2021-11-11 15:37:29 -07:00
|
|
|
Routes []Route
|
|
|
|
UnsafeRoutes []Route
|
2021-03-26 08:46:30 -06:00
|
|
|
l *logrus.Logger
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
type ifReq struct {
|
|
|
|
Name [16]byte
|
|
|
|
Flags uint16
|
|
|
|
pad [8]byte
|
|
|
|
}
|
|
|
|
|
|
|
|
func ioctl(a1, a2, a3 uintptr) error {
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
_, _, errno := unix.Syscall(unix.SYS_IOCTL, a1, a2, a3)
|
2019-11-19 10:00:20 -07:00
|
|
|
if errno != 0 {
|
|
|
|
return errno
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
func ipv4(addr string) (o [4]byte, err error) {
|
|
|
|
ip := net.ParseIP(addr).To4()
|
|
|
|
if ip == nil {
|
|
|
|
err = fmt.Errorf("failed to parse addr %s", addr)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for i, b := range ip {
|
|
|
|
o[i] = b
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
const (
|
2021-02-25 13:01:14 -07:00
|
|
|
cIFF_TUN = 0x0001
|
|
|
|
cIFF_NO_PI = 0x1000
|
|
|
|
cIFF_MULTI_QUEUE = 0x0100
|
2019-11-19 10:00:20 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
type ifreqAddr struct {
|
|
|
|
Name [16]byte
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
Addr unix.RawSockaddrInet4
|
2019-11-19 10:00:20 -07:00
|
|
|
pad [8]byte
|
|
|
|
}
|
|
|
|
|
|
|
|
type ifreqMTU struct {
|
|
|
|
Name [16]byte
|
2019-11-25 12:21:48 -07:00
|
|
|
MTU int32
|
2019-11-19 10:00:20 -07:00
|
|
|
pad [8]byte
|
|
|
|
}
|
|
|
|
|
|
|
|
type ifreqQLEN struct {
|
|
|
|
Name [16]byte
|
2019-12-11 13:02:57 -07:00
|
|
|
Value int32
|
2019-11-19 10:00:20 -07:00
|
|
|
pad [8]byte
|
|
|
|
}
|
|
|
|
|
2021-11-11 15:37:29 -07:00
|
|
|
func newTunFromFd(l *logrus.Logger, deviceFd int, cidr *net.IPNet, defaultMTU int, routes []Route, unsafeRoutes []Route, txQueueLen int) (ifce *Tun, err error) {
|
2020-06-30 12:48:58 -06:00
|
|
|
|
|
|
|
file := os.NewFile(uintptr(deviceFd), "/dev/net/tun")
|
|
|
|
|
|
|
|
ifce = &Tun{
|
|
|
|
ReadWriteCloser: file,
|
|
|
|
fd: int(file.Fd()),
|
|
|
|
Device: "tun0",
|
|
|
|
Cidr: cidr,
|
|
|
|
DefaultMTU: defaultMTU,
|
|
|
|
TXQueueLen: txQueueLen,
|
|
|
|
Routes: routes,
|
|
|
|
UnsafeRoutes: unsafeRoutes,
|
2021-03-26 08:46:30 -06:00
|
|
|
l: l,
|
2020-06-30 12:48:58 -06:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-11-11 15:37:29 -07:00
|
|
|
func newTun(l *logrus.Logger, deviceName string, cidr *net.IPNet, defaultMTU int, routes []Route, unsafeRoutes []Route, txQueueLen int, multiqueue bool) (ifce *Tun, err error) {
|
2019-11-19 10:00:20 -07:00
|
|
|
fd, err := unix.Open("/dev/net/tun", os.O_RDWR, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var req ifReq
|
|
|
|
req.Flags = uint16(cIFF_TUN | cIFF_NO_PI)
|
2021-02-25 13:01:14 -07:00
|
|
|
if multiqueue {
|
|
|
|
req.Flags |= cIFF_MULTI_QUEUE
|
|
|
|
}
|
2019-11-19 10:00:20 -07:00
|
|
|
copy(req.Name[:], deviceName)
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
if err = ioctl(uintptr(fd), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&req))); err != nil {
|
2021-02-25 13:01:14 -07:00
|
|
|
return nil, err
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
name := strings.Trim(string(req.Name[:]), "\x00")
|
|
|
|
|
|
|
|
file := os.NewFile(uintptr(fd), "/dev/net/tun")
|
|
|
|
|
|
|
|
maxMTU := defaultMTU
|
|
|
|
for _, r := range routes {
|
2021-11-11 15:37:29 -07:00
|
|
|
if r.MTU > maxMTU {
|
|
|
|
maxMTU = r.MTU
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ifce = &Tun{
|
|
|
|
ReadWriteCloser: file,
|
|
|
|
fd: int(file.Fd()),
|
|
|
|
Device: name,
|
|
|
|
Cidr: cidr,
|
|
|
|
MaxMTU: maxMTU,
|
|
|
|
DefaultMTU: defaultMTU,
|
|
|
|
TXQueueLen: txQueueLen,
|
|
|
|
Routes: routes,
|
2019-12-12 09:34:17 -07:00
|
|
|
UnsafeRoutes: unsafeRoutes,
|
2021-03-26 08:46:30 -06:00
|
|
|
l: l,
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-02-25 13:01:14 -07:00
|
|
|
func (c *Tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
|
|
|
|
fd, err := unix.Open("/dev/net/tun", os.O_RDWR, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var req ifReq
|
|
|
|
req.Flags = uint16(cIFF_TUN | cIFF_NO_PI | cIFF_MULTI_QUEUE)
|
|
|
|
copy(req.Name[:], c.Device)
|
|
|
|
if err = ioctl(uintptr(fd), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&req))); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
file := os.NewFile(uintptr(fd), "/dev/net/tun")
|
|
|
|
|
|
|
|
return file, nil
|
|
|
|
}
|
|
|
|
|
2019-11-19 10:00:20 -07:00
|
|
|
func (c *Tun) WriteRaw(b []byte) error {
|
|
|
|
var nn int
|
|
|
|
for {
|
|
|
|
max := len(b)
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
n, err := unix.Write(c.fd, b[nn:max])
|
2019-11-19 10:00:20 -07:00
|
|
|
if n > 0 {
|
|
|
|
nn += n
|
|
|
|
}
|
|
|
|
if nn == len(b) {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if n == 0 {
|
|
|
|
return io.ErrUnexpectedEOF
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-25 13:01:14 -07:00
|
|
|
func (c *Tun) Write(b []byte) (int, error) {
|
|
|
|
return len(b), c.WriteRaw(b)
|
|
|
|
}
|
|
|
|
|
2019-11-19 10:00:20 -07:00
|
|
|
func (c Tun) deviceBytes() (o [16]byte) {
|
|
|
|
for i, c := range c.Device {
|
|
|
|
o[i] = byte(c)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c Tun) Activate() error {
|
|
|
|
devName := c.deviceBytes()
|
|
|
|
|
|
|
|
var addr, mask [4]byte
|
|
|
|
|
|
|
|
copy(addr[:], c.Cidr.IP.To4())
|
|
|
|
copy(mask[:], c.Cidr.Mask)
|
|
|
|
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
s, err := unix.Socket(
|
|
|
|
unix.AF_INET,
|
|
|
|
unix.SOCK_DGRAM,
|
|
|
|
unix.IPPROTO_IP,
|
2019-11-19 10:00:20 -07:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
fd := uintptr(s)
|
|
|
|
|
|
|
|
ifra := ifreqAddr{
|
|
|
|
Name: devName,
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
Addr: unix.RawSockaddrInet4{
|
|
|
|
Family: unix.AF_INET,
|
2019-11-19 10:00:20 -07:00
|
|
|
Addr: addr,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the device ip address
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
if err = ioctl(fd, unix.SIOCSIFADDR, uintptr(unsafe.Pointer(&ifra))); err != nil {
|
2019-11-24 00:18:03 -07:00
|
|
|
return fmt.Errorf("failed to set tun address: %s", err)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set the device network
|
|
|
|
ifra.Addr.Addr = mask
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
if err = ioctl(fd, unix.SIOCSIFNETMASK, uintptr(unsafe.Pointer(&ifra))); err != nil {
|
2019-11-24 00:18:03 -07:00
|
|
|
return fmt.Errorf("failed to set tun netmask: %s", err)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set the device name
|
|
|
|
ifrf := ifReq{Name: devName}
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
if err = ioctl(fd, unix.SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {
|
2019-11-24 00:18:03 -07:00
|
|
|
return fmt.Errorf("failed to set tun device name: %s", err)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set the MTU on the device
|
2019-11-25 12:21:48 -07:00
|
|
|
ifm := ifreqMTU{Name: devName, MTU: int32(c.MaxMTU)}
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
if err = ioctl(fd, unix.SIOCSIFMTU, uintptr(unsafe.Pointer(&ifm))); err != nil {
|
2019-12-18 17:49:46 -07:00
|
|
|
// This is currently a non fatal condition because the route table must have the MTU set appropriately as well
|
2021-03-26 08:46:30 -06:00
|
|
|
c.l.WithError(err).Error("Failed to set tun mtu")
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set the transmit queue length
|
2019-12-11 13:02:57 -07:00
|
|
|
ifrq := ifreqQLEN{Name: devName, Value: int32(c.TXQueueLen)}
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
if err = ioctl(fd, unix.SIOCSIFTXQLEN, uintptr(unsafe.Pointer(&ifrq))); err != nil {
|
2019-12-20 10:10:26 -07:00
|
|
|
// If we can't set the queue length nebula will still work but it may lead to packet loss
|
2021-03-26 08:46:30 -06:00
|
|
|
c.l.WithError(err).Error("Failed to set tun tx queue length")
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bring up the interface
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
ifrf.Flags = ifrf.Flags | unix.IFF_UP
|
|
|
|
if err = ioctl(fd, unix.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {
|
2019-11-24 00:18:03 -07:00
|
|
|
return fmt.Errorf("failed to bring the tun device up: %s", err)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set the routes
|
|
|
|
link, err := netlink.LinkByName(c.Device)
|
|
|
|
if err != nil {
|
2019-11-24 00:18:03 -07:00
|
|
|
return fmt.Errorf("failed to get tun device link: %s", err)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Default route
|
|
|
|
dr := &net.IPNet{IP: c.Cidr.IP.Mask(c.Cidr.Mask), Mask: c.Cidr.Mask}
|
|
|
|
nr := netlink.Route{
|
|
|
|
LinkIndex: link.Attrs().Index,
|
|
|
|
Dst: dr,
|
|
|
|
MTU: c.DefaultMTU,
|
2021-11-11 15:37:29 -07:00
|
|
|
AdvMSS: c.advMSS(Route{}),
|
2019-11-19 10:00:20 -07:00
|
|
|
Scope: unix.RT_SCOPE_LINK,
|
|
|
|
Src: c.Cidr.IP,
|
|
|
|
Protocol: unix.RTPROT_KERNEL,
|
|
|
|
Table: unix.RT_TABLE_MAIN,
|
|
|
|
Type: unix.RTN_UNICAST,
|
|
|
|
}
|
|
|
|
err = netlink.RouteReplace(&nr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to set mtu %v on the default route %v; %v", c.DefaultMTU, dr, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Path routes
|
|
|
|
for _, r := range c.Routes {
|
|
|
|
nr := netlink.Route{
|
|
|
|
LinkIndex: link.Attrs().Index,
|
2021-11-11 15:37:29 -07:00
|
|
|
Dst: r.Cidr,
|
|
|
|
MTU: r.MTU,
|
2020-06-26 11:47:21 -06:00
|
|
|
AdvMSS: c.advMSS(r),
|
2019-11-19 10:00:20 -07:00
|
|
|
Scope: unix.RT_SCOPE_LINK,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = netlink.RouteAdd(&nr)
|
|
|
|
if err != nil {
|
2021-11-11 15:37:29 -07:00
|
|
|
return fmt.Errorf("failed to set mtu %v on route %v; %v", r.MTU, r.Cidr, err)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-12 09:34:17 -07:00
|
|
|
// Unsafe path routes
|
|
|
|
for _, r := range c.UnsafeRoutes {
|
|
|
|
nr := netlink.Route{
|
|
|
|
LinkIndex: link.Attrs().Index,
|
2021-11-11 15:37:29 -07:00
|
|
|
Dst: r.Cidr,
|
|
|
|
MTU: r.MTU,
|
|
|
|
Priority: r.Metric,
|
2020-06-26 11:47:21 -06:00
|
|
|
AdvMSS: c.advMSS(r),
|
2019-12-12 09:34:17 -07:00
|
|
|
Scope: unix.RT_SCOPE_LINK,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = netlink.RouteAdd(&nr)
|
|
|
|
if err != nil {
|
2021-11-11 15:37:29 -07:00
|
|
|
return fmt.Errorf("failed to set mtu %v on route %v; %v", r.MTU, r.Cidr, err)
|
2019-12-12 09:34:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-19 10:00:20 -07:00
|
|
|
// Run the interface
|
Add linux-386, linux-ppc64le targets (#56)
* Use golang.org/x/sys/unix for _linux.go sources
To support builds on GOARCH=386 and possibly elsewhere, it's necessary
to use the x/sys/unix package instead of the syscall package. This is
because the syscall package is frozen and does not support
SYS_GETSOCKNAME, SYS_RECVFROM, nor SYS_SENDTO for GOARCH=386.
This commit alone doesn't add support for 386 builds, just gets things
onto x/sys/unix so that it's possible.
The remaining uses of the syscall package relate to signals, which
cannot be switched to the x/sys/unix package at this time. Windows
support breaks, so they can either continue using the syscall package
(it's frozen, this is safe for Go 1.x at minimum), or something can be
written to just use both windows- and unix-compatible signals.
* Add linux-386, ppc64le targets to Makefile
Because 'linux' is linux-amd64 already, just add linux-386 and
linux-ppc64le targets to distinguish them. Would rename the linux
target but that might break existing uses.
2019-12-11 18:51:55 -07:00
|
|
|
ifrf.Flags = ifrf.Flags | unix.IFF_UP | unix.IFF_RUNNING
|
|
|
|
if err = ioctl(fd, unix.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifrf))); err != nil {
|
2019-11-24 00:18:03 -07:00
|
|
|
return fmt.Errorf("failed to run tun device: %s", err)
|
2019-11-19 10:00:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2020-06-26 11:47:21 -06:00
|
|
|
|
2020-07-28 06:53:16 -06:00
|
|
|
func (c *Tun) CidrNet() *net.IPNet {
|
|
|
|
return c.Cidr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Tun) DeviceName() string {
|
|
|
|
return c.Device
|
|
|
|
}
|
|
|
|
|
2021-11-11 15:37:29 -07:00
|
|
|
func (c Tun) advMSS(r Route) int {
|
|
|
|
mtu := r.MTU
|
|
|
|
if r.MTU == 0 {
|
2020-06-26 11:47:21 -06:00
|
|
|
mtu = c.DefaultMTU
|
|
|
|
}
|
|
|
|
|
|
|
|
// We only need to set advmss if the route MTU does not match the device MTU
|
|
|
|
if mtu != c.MaxMTU {
|
|
|
|
return mtu - 40
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|