- 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
98 lines
2.2 KiB
Go
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)
|
|
}
|