lux/host/lux_netif.go

231 lines
4.2 KiB
Go

package host
import (
"lux/proto"
"net"
"net/netip"
"strconv"
"strings"
)
// Option containing all network interfaces of host (excluding loopbacks)
// IPv6 GUA
// IPv6 ULA
// IPv6 LL
// IPv4
type LuxNetAddrType int
const (
LuxNetAddrType4 = 0
LuxNetAddrType6LL = 1
LuxNetAddrType6ULA = 2
LuxNetAddrType6GUA = 3
)
func (addrType LuxNetAddrType) String() string {
switch addrType {
case LuxNetAddrType4:
return "ip4"
case LuxNetAddrType6LL:
return "ip6ll"
case LuxNetAddrType6ULA:
return "ip6ula"
case LuxNetAddrType6GUA:
return "ip6gua"
default:
return strconv.Itoa(int(addrType))
}
}
type LuxNetAddr struct {
Type LuxNetAddrType
Addr netip.Addr
}
func (addr *LuxNetAddr) Read(rd *proto.LuxBuffer) error {
addrType, err := rd.ReadUint16()
if err != nil {
return err
}
addr.Type = LuxNetAddrType(addrType)
ipAddr, err := rd.ReadIP()
if err != nil {
return err
}
addr.Addr = ipAddr
return nil
}
func (addr *LuxNetAddr) Write(wd *proto.LuxBuffer) {
wd.WriteUint16(uint16(addr.Type))
wd.WriteIP(addr.Addr)
}
type LuxNetInterface struct {
Name string
Index int
Addrs []LuxNetAddr
}
func NewLuxNetInterface() LuxNetInterface {
return LuxNetInterface{
Addrs: make([]LuxNetAddr, 0),
}
}
func parseNetlinkIp(addr string) string {
if strings.ContainsRune(addr, '/') {
return strings.Split(addr, "/")[0]
}
return addr
}
func (luxNet *LuxNetInterface) FromNetlink(netif *net.Interface) error {
luxNet.Name = netif.Name
luxNet.Index = netif.Index
// enumerate interface ips
addrs, err := netif.Addrs()
if err != nil {
return err
}
for _, addr := range addrs {
ip := net.ParseIP(parseNetlinkIp(addr.String()))
if ip == nil {
return err
}
luxAddr := LuxNetAddr{}
if ip.IsLoopback() {
continue // loopbacks are useless to LUX
} else if ip.To4() == nil {
// got IPv6
if ip.IsLinkLocalUnicast() {
luxAddr.Type = LuxNetAddrType6LL
} else if ip[0] == 0xFD || ip[0] == 0xFC {
// ULA - fc00::/7 with L = 1 -> fd00::/8,
// tho fc L 0 is not defined we still gonna assume its ULA
luxAddr.Type = LuxNetAddrType6ULA
} else {
// anything else is global unicast
luxAddr.Type = LuxNetAddrType6GUA
}
} else {
// got IPv4
luxAddr.Type = LuxNetAddrType4
}
luxAddr.Addr = proto.LuxProtoIPToAddr(ip)
luxNet.Addrs = append(luxNet.Addrs, luxAddr)
}
return nil
}
func (netif *LuxNetInterface) Read(rd *proto.LuxBuffer) error {
name, err := rd.ReadString()
if err != nil {
return err
}
netif.Name = name
idx, err := rd.ReadUint16()
if err != nil {
return err
}
netif.Index = int(idx)
addrNum, err := rd.ReadUint16()
if err != nil {
return err
}
for i := 0; i < int(addrNum); i++ {
addr := LuxNetAddr{}
if addr.Read(rd) != nil {
return err
}
netif.Addrs = append(netif.Addrs, addr)
}
return nil
}
func (netif *LuxNetInterface) Write(wd *proto.LuxBuffer) {
wd.WriteString(netif.Name)
wd.WriteUint16(uint16(netif.Index))
wd.WriteUint16(uint16(len(netif.Addrs)))
for _, addr := range netif.Addrs {
addr.Write(wd)
}
}
type LuxOptionNetIf struct {
Interfaces map[string]*LuxNetInterface
}
func NewLuxOptionNetIf() LuxOptionNetIf {
return LuxOptionNetIf{
Interfaces: make(map[string]*LuxNetInterface),
}
}
func (opt *LuxOptionNetIf) EnumerateNetlink() error {
ifaces, err := net.Interfaces()
if err != nil {
return err
}
for _, iface := range ifaces {
netif := NewLuxNetInterface()
if err := netif.FromNetlink(&iface); err != nil {
return nil
}
if len(netif.Addrs) > 0 {
// only add if we got atleast 1 ip, since we might want to skip
// netif loopback that has no IP because we skip one in FromNetlink
opt.Interfaces[netif.Name] = &netif
}
}
return nil
}
func (opt *LuxOptionNetIf) Read(rd *proto.LuxBuffer) error {
ifNum, err := rd.ReadUint16()
if err != nil {
return err
}
for i := 0; i < int(ifNum); i++ {
netif := NewLuxNetInterface()
if err := netif.Read(rd); err != nil {
return err
}
opt.Interfaces[netif.Name] = &netif
}
return nil
}
func (opt *LuxOptionNetIf) Write(wd *proto.LuxBuffer) {
wd.WriteUint16(uint16(len(opt.Interfaces)))
for _, netif := range opt.Interfaces {
netif.Write(wd)
}
}
func (*LuxOptionNetIf) Type() LuxOptionType {
return LuxOptionTypeNetIf
}