Загрузка данных
//go:build illumios || solaris
package tun
import (
"fmt"
"os"
"os/exec"
wgtun "golang.zx2c4.com/wireguard/tun"
)
const (
tunDevicePath = "/dev/tun"
)
// IllumiosTun реализует актуальный интерфейс wgtun.Device
type IllumiosTun struct {
file *os.File
name string
mtu int
events chan wgtun.Event
}
func (t *IllumiosTun) File() *os.File {
return t.file
}
// BatchSize возвращает размер батча (1 для стандартного интерфейса illumios)
func (t *IllumiosTun) BatchSize() int {
return 1
}
// Read считывает один пакет в первый буфер слайса
func (t *IllumiosTun) Read(packets [][]byte, sizes []int, offset int) (int, error) {
if len(packets) == 0 || len(sizes) == 0 {
return 0, nil
}
n, err := t.file.Read(packets[0][offset:])
if err != nil {
return 0, err
}
sizes[0] = n
return 1, nil
}
// Write записывает пакеты в TUN устройство
func (t *IllumiosTun) Write(packets [][]byte, offset int) (int, error) {
count := 0
for _, pkt := range packets {
if len(pkt) <= offset {
continue
}
_, err := t.file.Write(pkt[offset:])
if err != nil {
return count, err
}
count++
}
return count, nil
}
// Flush сбрасывает буферизированные данные
func (t *IllumiosTun) Flush() error {
return nil
}
func (t *IllumiosTun) Close() error {
if t.events != nil {
close(t.events)
}
return t.file.Close()
}
func (t *IllumiosTun) Name() (string, error) {
return t.name, nil
}
func (t *IllumiosTun) Events() <-chan wgtun.Event {
return t.events
}
func (t *IllumiosTun) MTU() (int, error) {
return t.mtu, nil
}
func (t *IllumiosTun) SetMTU(mtu int) error {
t.mtu = mtu
return nil
}
func createIllumiosTUN(ifname string, mtu uint64) (wgtun.Device, error) {
file, err := os.OpenFile(tunDevicePath, os.O_RDWR, 0)
if err != nil {
return nil, fmt.Errorf("failed to open %s: %w", tunDevicePath, err)
}
ev := make(chan wgtun.Event, 1)
ev <- wgtun.EventUp
return &IllumiosTun{
file: file,
name: ifname,
mtu: int(mtu),
events: ev,
}, nil
}
// setup инициализирует TUN адаптер
func (tun *TunAdapter) setup(ifname string, addr string, mtu uint64) error {
iface, err := createIllumiosTUN(ifname, mtu)
if err != nil {
return fmt.Errorf("failed to create illumios TUN: %w", err)
}
tun.iface = iface
if m, err := iface.MTU(); err == nil {
tun.mtu = getSupportedMTU(uint64(m))
} else {
tun.mtu = 0
}
if addr != "" {
return tun.setupAddress(addr)
}
return nil
}
// setupFD настраивает адаптер из существующего дескриптора
func (tun *TunAdapter) setupFD(fd int32, addr string, mtu uint64) error {
file := os.NewFile(uintptr(fd), "tun")
if file == nil {
return fmt.Errorf("invalid file descriptor")
}
ev := make(chan wgtun.Event, 1)
ev <- wgtun.EventUp
tun.iface = &IllumiosTun{
file: file,
name: "tun-fd",
mtu: int(mtu),
events: ev,
}
tun.mtu = getSupportedMTU(mtu)
if addr != "" {
return tun.setupAddress(addr)
}
return nil
}
// setupAddress настраивает IPv6 адрес интерфейса через ifconfig
func (tun *TunAdapter) setupAddress(addr string) error {
name := tun.Name()
if name == "" {
name = "tun0"
}
// Назначение IPv6 адреса в illumios/Solaris
cmd := exec.Command("ifconfig", name, "inet6", "add", addr+"/128", "up")
if out, err := cmd.CombinedOutput(); err != nil {
tun.log.Warnf("Warning: ifconfig failed (%v): %s. You may need to configure %s manually to %s", err, string(out), name, addr)
} else {
tun.log.Infof("Configured address %s on %s", addr, name)
}
return nil
}