Загрузка данных


//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
}