sing/common/tun/tun_linux.go
2022-05-04 19:34:55 +08:00

171 lines
3.5 KiB
Go

package tun
/*
import (
"bytes"
"net"
"syscall"
"unsafe"
E "github.com/sagernet/sing/common/exceptions"
"golang.org/x/sys/unix"
)
const ifReqSize = unix.IFNAMSIZ + 64
func (t *Interface) Name() (string, error) {
if t.tunName != "" {
return t.tunName, nil
}
var ifr [ifReqSize]byte
_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(t.tunFd), uintptr(unix.TUNGETIFF), uintptr(unsafe.Pointer(&ifr[0])))
if errno != 0 {
return "", errno
}
name := ifr[:]
if i := bytes.IndexByte(name, 0); i != -1 {
name = name[:i]
}
t.tunName = string(name)
return t.tunName, nil
}
func (t *Interface) MTU() (int, error) {
name, err := t.Name()
if err != nil {
return 0, err
}
fd, err := unix.Socket(
unix.AF_INET,
unix.SOCK_DGRAM,
0,
)
if err != nil {
return 0, err
}
defer unix.Close(fd)
var ifr [ifReqSize]byte
copy(ifr[:], name)
_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(unix.SIOCGIFMTU), uintptr(unsafe.Pointer(&ifr[0])))
if errno != 0 {
return 0, errno
}
return int(*(*int32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ]))), nil
}
func (t *Interface) SetMTU(mtu int) error {
name, err := t.Name()
if err != nil {
return err
}
fd, err := unix.Socket(
unix.AF_INET,
unix.SOCK_DGRAM,
0,
)
if err != nil {
return err
}
defer unix.Close(fd)
var ifr [ifReqSize]byte
copy(ifr[:], name)
*(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(mtu)
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
uintptr(fd),
uintptr(unix.SIOCSIFMTU),
uintptr(unsafe.Pointer(&ifr[0])),
)
if errno != 0 {
return errno
}
return nil
}
func (t *Interface) SetAddress() error {
name, err := t.Name()
if err != nil {
return err
}
fd, err := unix.Socket(
unix.AF_INET,
unix.SOCK_DGRAM,
0,
)
if err != nil {
return err
}
defer unix.Close(fd)
ifreq, err := unix.NewIfreq(name)
if err != nil {
return E.Cause(err, "failed to create ifreq for name ", name)
}
ifreq.SetInet4Addr(t.inetAddress.Addr().AsSlice())
err = unix.IoctlIfreq(fd, syscall.SIOCSIFADDR, ifreq)
if err == nil {
ifreq, _ = unix.NewIfreq(name)
ifreq.SetInet4Addr(net.CIDRMask(t.inetAddress.Bits(), 32))
err = unix.IoctlIfreq(fd, syscall.SIOCSIFNETMASK, ifreq)
}
if err != nil {
return E.Cause(err, "failed to set ipv4 address on ", name)
}
if t.inet6Address.IsValid() {
ifreq, _ = unix.NewIfreq(name)
err = unix.IoctlIfreq(fd, syscall.SIOCGIFINDEX, ifreq)
if err != nil {
return E.Cause(err, "failed to get interface index for ", name)
}
ifreq6 := in6_ifreq{
ifr6_addr: in6_addr{
addr: t.inet6Address.Addr().As16(),
},
ifr6_prefixlen: uint32(t.inet6Address.Bits()),
ifr6_ifindex: ifreq.Uint32(),
}
fd6, err := unix.Socket(
unix.AF_INET6,
unix.SOCK_DGRAM,
0,
)
if err != nil {
return err
}
defer unix.Close(fd6)
if _, _, errno := syscall.Syscall(
syscall.SYS_IOCTL,
uintptr(fd6),
uintptr(syscall.SIOCSIFADDR),
uintptr(unsafe.Pointer(&ifreq6)),
); errno != 0 {
return E.Cause(errno, "failed to set ipv6 address on ", name)
}
}
ifreq, _ = unix.NewIfreq(name)
err = unix.IoctlIfreq(fd, syscall.SIOCGIFFLAGS, ifreq)
if err == nil {
ifreq.SetUint16(ifreq.Uint16() | syscall.IFF_UP | syscall.IFF_RUNNING)
err = unix.IoctlIfreq(fd, syscall.SIOCSIFFLAGS, ifreq)
}
if err != nil {
return E.Cause(err, "failed to bring tun device up")
}
return nil
}
type in6_addr struct {
addr [16]byte
}
type in6_ifreq struct {
ifr6_addr in6_addr
ifr6_prefixlen uint32
ifr6_ifindex uint32
}
*/