hysteria/extras/network/tun.go
Niko Marmeladkov da8366eb8a
feat: L3 VPN tunnel, FileMask noise, Hysteria outbound
- Network: Layer 3 IP tunnel over QUIC with TUN interfaces and IP pool
- FileMask: new noise/obfuscation layer masking traffic as encrypted file downloads
- Hysteria outbound: chain Hysteria servers via pluggable outbound
2026-06-16 16:07:55 +03:00

98 lines
2.2 KiB
Go

package network
import (
"fmt"
"os"
"os/exec"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
const (
TUNSETIFF = 0x400454ca
TUNSETOFFLOAD = 0x400454d0
IFF_TUN = 0x0001
IFF_NO_PI = 0x1000
)
type ifReq struct {
Name [16]byte
Flags uint16
pad [22]byte
}
type TUNInterface struct {
Name string
Address string
MTU int
fd int
}
func OpenTUN(name string, address string, mtu int) (*TUNInterface, error) {
exec.Command("modprobe", "tun").Run()
if _, err := os.Stat("/dev/net/tun"); err != nil {
return nil, fmt.Errorf("TUN not available: %w", err)
}
fd, err := unix.Open("/dev/net/tun", unix.O_RDWR, 0)
if err != nil {
return nil, fmt.Errorf("open /dev/net/tun: %w", err)
}
var req ifReq
req.Flags = IFF_TUN | IFF_NO_PI
copy(req.Name[:], name)
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(TUNSETIFF), uintptr(unsafe.Pointer(&req)))
if errno != 0 {
unix.Close(fd)
return nil, fmt.Errorf("TUNSETIFF: %w", errno)
}
offload := 0
syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(TUNSETOFFLOAD), uintptr(unsafe.Pointer(&offload)))
ifName := string(req.Name[:])
ifName = ifName[:len(name)]
t := &TUNInterface{
Name: ifName,
MTU: mtu,
fd: fd,
}
if err := t.configure(address); err != nil {
t.Close()
return nil, fmt.Errorf("configure TUN: %w", err)
}
return t, nil
}
func (t *TUNInterface) configure(address string) error {
if err := exec.Command("ip", "link", "set", "dev", t.Name, "mtu", fmt.Sprintf("%d", t.MTU), "up").Run(); err != nil {
return fmt.Errorf("set link up: %w", err)
}
if address != "" {
if err := exec.Command("ip", "addr", "add", address, "dev", t.Name).Run(); err != nil {
return fmt.Errorf("set addr: %w", err)
}
}
return nil
}
func (t *TUNInterface) Route(cidr string) error {
return exec.Command("ip", "route", "replace", cidr, "dev", t.Name).Run()
}
func (t *TUNInterface) Read() ([]byte, error) {
buf := make([]byte, t.MTU*2)
n, err := unix.Read(t.fd, buf)
if err != nil {
return nil, err
}
return buf[:n], nil
}
func (t *TUNInterface) Write(pkt []byte) error {
_, err := unix.Write(t.fd, pkt)
return err
}
func (t *TUNInterface) Close() error {
return unix.Close(t.fd)
}