diff options
author | Mikael Magnusson <mikma@users.sourceforge.net> | 2020-03-18 21:33:35 +0100 |
---|---|---|
committer | Mikael Magnusson <mikma@users.sourceforge.net> | 2020-03-18 21:33:35 +0100 |
commit | 1d171254911cfcd62926f43938edde2ad20e64fc (patch) | |
tree | 77599760f09df953ca2793fe37e7b5131d7d696d | |
parent | 9ff81925ffcb1833871a409c4bc004144062ae22 (diff) |
WIP move config to separate package
-rw-r--r-- | pkg/tcpip/config/config.go | 526 | ||||
-rw-r--r-- | pkg/tcpip/sample/wg_tunnel/main.go | 601 |
2 files changed, 576 insertions, 551 deletions
diff --git a/pkg/tcpip/config/config.go b/pkg/tcpip/config/config.go new file mode 100644 index 000000000..3c1f91ecc --- /dev/null +++ b/pkg/tcpip/config/config.go @@ -0,0 +1,526 @@ +package config + +import ( + "bufio" + "encoding/base64" + "encoding/hex" + "fmt" + "log" + "net" + "os" + "runtime" + "strconv" + "strings" + + "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/link/channel" + "gvisor.dev/gvisor/pkg/tcpip/link/fdbased" + "gvisor.dev/gvisor/pkg/tcpip/link/loopback" + "gvisor.dev/gvisor/pkg/tcpip/link/rawfile" + "gvisor.dev/gvisor/pkg/tcpip/link/tun" + "gvisor.dev/gvisor/pkg/tcpip/link/wireguard" + "gvisor.dev/gvisor/pkg/tcpip/network/arp" + "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" + "gvisor.dev/gvisor/pkg/tcpip/network/ipv6" + "gvisor.dev/gvisor/pkg/tcpip/stack" + + "golang.zx2c4.com/wireguard/device" + "golang.zx2c4.com/wireguard/ipc" +// wg_tun "golang.zx2c4.com/wireguard/tun" + + "gopkg.in/yaml.v3" +) + +type Route struct { + To string `yaml:"to"` + Via string `yaml:"via"` + Metric int `yaml:"metric"` + Mark uint32 `yaml:"mask"` + Markmask uint32 `yaml:"markmask"` +} + +type Common struct { + Match struct { + Name string `yaml:"name"` + } `yaml:"match"` + Addresses []string `yaml:"addresses"` + Nameservers struct { + Addresses []string `yaml:"addresses"` + } `yaml:"nameservers"` + Macaddress string `yaml:"macaddress"` + Routes []Route `yaml:"routes"` + Mtu uint32 `yaml:"mtu"` +} + +type Ethernet struct { + Common `yaml:",inline"` +} + +type Tuntap struct { + Common `yaml:",inline"` + Mode string `yaml:"mode"` + Name string `yaml:"name"` +} + +type WireguardKey []byte + +type Routes []tcpip.Route + +func (wgKey *WireguardKey) UnmarshalYAML(value *yaml.Node) error{ + key, err := base64.StdEncoding.DecodeString(value.Value) + fmt.Println("UnmarshalYAML", key, err) + *wgKey = key + return err +} + +type WireguardPeer struct { + PublicKey WireguardKey `yaml:"public_key"` + Endpoint string `yaml:"endpoint"` + AllowedIPs []string `yaml:"allowed_ips"` + PersistentKeepalive int `yaml:"persistent_keepalive"` +} + +func (peer WireguardPeer) String() string{ + return fmt.Sprintf("{PublicKey=%v, Endpoint=%v, AllowedIPs=%v, PersistentKeepalive=%v}", peer.PublicKey, peer.Endpoint, peer.AllowedIPs, peer.PersistentKeepalive) +} + +type Wireguard struct { + Common `yaml:",inline"` + Name string `yaml:"name"` + ListenPort uint16 `yaml:"listen_port"` + PrivateKey WireguardKey `yaml:"private_key"` + Peers []*WireguardPeer `yaml:"peers"` +} + +type Tunnel struct { + Common `yaml:",inline"` + Mode string `yaml:"mode"` + Local string `yaml:"local"` + Remote string `yaml:"remote"` + + Conn *net.UDPConn + Sd *os.File +} + +type Netplan struct { + Network struct { + Version int `yaml:"version"` + Renderer string `yaml:"renderer"` + Ethernets map[string] *Ethernet `yaml:"ethernets"` + Tuntaps map[string] *Tuntap `yaml:"tuntaps"` + Wireguards map[string] *Wireguard `yaml:"wireguards"` + Tunnels map[string] *Tunnel `yaml:"tunnels"` + } `yaml:"network"` +} + +func CheckError(err error) { + if err != nil { + log.Fatal("Error: " , err) + } +} + +func addTunLink(s *stack.Stack, nic tcpip.NICID, id string, tap bool, addr tcpip.LinkAddress, tuntap *Tuntap) { + var err error + + mtu := tuntap.Mtu + tunName := tuntap.Name + + if mtu == 0 { + mtu, err = rawfile.GetMTU(tunName) + if err != nil { + log.Fatal("GetMTU", err) + } + } + + var fd int + if tap { + fd, err = tun.OpenTAP(tunName) + } else { + fd, err = tun.Open(tunName) + } + if err != nil { + log.Fatalf("Open %s %b %s", err, tap, tunName) + } + + linkEP, err := fdbased.New(&fdbased.Options{ + FDs: []int{fd}, + MTU: mtu, + EthernetHeader: tap, + Address: addr, + }) + if err := s.CreateNICWithOptions(nic, linkEP, stack.NICOptions{Name: id, Disabled: true}); err != nil { + log.Fatal("CreateNIC", err) + } + + if tap { + if err := s.AddAddress(nic, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { + log.Fatal("AddAddress", err) + } + } +} + +func addRouterLink(s *stack.Stack, nic tcpip.NICID, id string, addr tcpip.LinkAddress, + tun *Tunnel) { + + ServerAddr,err := net.ResolveUDPAddr("udp", tun.Remote) + CheckError(err) + + LocalAddr, err := net.ResolveUDPAddr("udp", tun.Local) + CheckError(err) + + conn, err := net.DialUDP("udp", LocalAddr, ServerAddr) + CheckError(err) + + tun.Conn = conn + + fmt.Println("Tunnel ", conn) + + sd, err := conn.File() + CheckError(err) + + tun.Sd = sd + + conn.Close() + + var fd int + fd = int(sd.Fd()) + //TestFinialize(&tun.Conn) + runtime.GC() + linkEP, err := fdbased.New(&fdbased.Options{ + FDs: []int{fd}, + MTU: tun.Mtu, + EthernetHeader: true, +// EthernetHeader: false, + Address: addr, + }) + CheckError(err) + + fmt.Println("addRouterLink MTU ", tun.Mtu, tun.Conn) + //channelSize := 128 + // linkEP := channel.New(channelSize, mtu, addr) + if err := s.CreateNICWithOptions(nic, linkEP, stack.NICOptions{Name: id, Disabled: true}); err != nil { + log.Fatal("CreateNIC ", id, err) + } + + if err := s.AddAddress(nic, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { + log.Fatal("AddAddress", err) + } + +// client(linkEP.C) + fmt.Println("Tunnel ", tun.Conn) +} + +func addWgLink(s *stack.Stack, nic tcpip.NICID, interfaceName string, addr tcpip.LinkAddress) *device.Device { + loglevel := device.LogLevelDebug + + chanSize := 1024 + var chanMtu uint32 = 1420 + ep := channel.New(chanSize, chanMtu, addr) + + logger := device.NewLogger(loglevel, "(wg_tunnel) ") + + //mtu := 1500 + // tun, err := wg_tun.CreateTUN(interfaceName, mtu) + tun, err := wireguard.CreateWgTun(s, ep) + if err != nil { + log.Fatal("CreateWgTun", err) + } + + + fileUAPI, err := func() (*os.File, error) { + ENV_WG_UAPI_FD := "WG_UAPI_FD" + uapiFdStr := os.Getenv(ENV_WG_UAPI_FD) + if uapiFdStr == "" { + return ipc.UAPIOpen(interfaceName) + } + + // use supplied fd + + fd, err := strconv.ParseUint(uapiFdStr, 10, 32) + if err != nil { + return nil, err + } + + return os.NewFile(uintptr(fd), ""), nil + }() + + if err != nil { + logger.Error.Println("UAPI listen error:", err) + log.Fatal("Setup failed") + } + // daemonize the process + + device := device.NewDevice(tun, logger) + + errs := make(chan error) + + uapi, err := ipc.UAPIListen(interfaceName, fileUAPI) + if err != nil { + logger.Error.Println("Failed to listen on uapi socket:", err) + log.Fatal("Setup failed") + } + + go func() { + for { + conn, err := uapi.Accept() + if err != nil { + errs <- err + return + } + go device.IpcHandle(conn) + } + }() + + logger.Info.Println("UAPI listener started") + fmt.Println("Device ", device) + + if err := s.CreateNICWithOptions(nic, ep, stack.NICOptions{Name: interfaceName, Disabled: true}); err != nil { + log.Fatal("CreateNIC", err) + } + + return device +} + +func parseAddress(addrName string) (tcpip.Address, tcpip.NetworkProtocolNumber) { + ip := net.ParseIP(addrName) + + if ip.To4() != nil { + return tcpip.Address(ip.To4()), ipv4.ProtocolNumber + } else { + return tcpip.Address(ip.To16()), ipv6.ProtocolNumber + } +} + +func ParseSubnet(subnetName string) (tcpip.Address, tcpip.Subnet, tcpip.NetworkProtocolNumber) { + parsedAddr, parsedNet, err := net.ParseCIDR(subnetName) + if err != nil { + log.Fatalf("Bad IP/CIDR address: %v", subnetName) + } + + var addr tcpip.Address + var net tcpip.Address + var proto tcpip.NetworkProtocolNumber + + if parsedAddr.To4() != nil { + addr = tcpip.Address(parsedAddr.To4()) + net = tcpip.Address(parsedNet.IP.To4()) + proto = ipv4.ProtocolNumber + } else { + addr = tcpip.Address(parsedAddr.To16()) + net = tcpip.Address(parsedNet.IP.To16()) + proto = ipv6.ProtocolNumber + } + + // ones, zeros := parsedNet.Mask.Size() + + mask, err := hex.DecodeString(parsedNet.Mask.String()) + if err != nil { + log.Fatalf("Bad mask", err) + } + + subnet, err := tcpip.NewSubnet(net, tcpip.AddressMask(mask)) + if err != nil { + log.Fatalf("Bad subnet", err, net, parsedNet.Mask.String()) + } + + return addr, subnet, proto +} + +func (routes *Routes) AddAddress(s *stack.Stack, nic tcpip.NICID, addrName string) tcpip.NetworkProtocolNumber { + // // Parse the IP address. Support both ipv4 and ipv6. + addr, subnet, proto := ParseSubnet(addrName) + + if false { + if err := s.AddAddress(nic, proto, addr); err != nil { + log.Fatal("AddAddress", err) + } + } else { + addr := tcpip.ProtocolAddress{ + Protocol: proto, + AddressWithPrefix: tcpip.AddressWithPrefix{ + Address: addr, + PrefixLen: subnet.Prefix(), + }} + + fmt.Println("Added address ", addr) + + if err := s.AddProtocolAddress(nic, addr); err != nil { + log.Fatalf("AddProtocolAddress", err, nic) + } + + route := tcpip.Route{ + Destination: addr.AddressWithPrefix.Subnet(), + NIC: nic, + } + + *routes = append(*routes, route) + } + + // subnet, err := tcpip.NewSubnet(tcpip.Address(parsedNet.IP), + // tcpip.AddressMask(parsedNet.Mask)) + // if err != nil { + // log.Fatal(err) + // } + + return proto +} + +func (routes *Routes) addRoute(nic tcpip.NICID, routeCfg Route){ + _, dest, _ := ParseSubnet(routeCfg.To) + via, _ := parseAddress(routeCfg.Via) + + route := tcpip.Route{ + Destination: dest, + Gateway: via, + NIC: nic, + Mark: routeCfg.Mark, + Markmask: routeCfg.Markmask, + } + + *routes = append(*routes, route) +} + +func (routes *Routes) setupCommon(s *stack.Stack, nic tcpip.NICID, id string, cfg Common) { + for _, addr := range cfg.Addresses { + routes.AddAddress(s, nic, addr) + } + + for _, route := range cfg.Routes { + fmt.Println("Add Route:", route) + routes.addRoute(nic, route) + } + + for _, route := range *routes { + fmt.Println("Added Route:", route) + } + + // TODO check after enabling the NICs + // if !s.CheckNIC(nic) { + // log.Fatal("not usable ", id) + // } +} + +func (routes *Routes) setupLoopback(s *stack.Stack, nic tcpip.NICID, id string, eth *Ethernet) { + fmt.Println("Ethernet", id, nic, eth) + + linkEP := loopback.New() + if err := s.CreateNICWithOptions(nic, linkEP, stack.NICOptions{Name: id, Disabled: true}); err != nil { + log.Fatal("CreateNIC", err) + } + + routes.setupCommon(s, nic, id, eth.Common) +} + +func (routes *Routes) setupTunnel(s *stack.Stack, nic tcpip.NICID, id string, tun *Tunnel) { + fmt.Println("TUN", id, nic, tun) + + maddr, err := net.ParseMAC(tun.Macaddress) + if err != nil { + log.Fatalf("Bad MAC address: %v", tun.Macaddress) + } + + addRouterLink(s, nic, id, tcpip.LinkAddress(maddr), tun) + fmt.Println("Tunnel 20", tun.Conn) + routes.setupCommon(s, nic, id, tun.Common) + fmt.Println("Tunnel 21", tun.Conn) +} + +func (routes *Routes) setupTuntap(s *stack.Stack, nic tcpip.NICID, id string, tun *Tuntap) { + fmt.Println("Tuntap", id, nic, tun) + + maddr, err := net.ParseMAC(tun.Macaddress) + if err != nil { + log.Fatalf("Bad MAC address: %v", tun.Macaddress) + } + + var tap bool + switch tun.Mode { + case "tun": + tap = false + case "tap": + tap = true + default: + log.Fatalf("Bad mode: %v", tun.Mode) + } + + addTunLink(s, nic, id, tap, tcpip.LinkAddress(maddr), tun) + routes.setupCommon(s, nic, id, tun.Common) +} + +func (routes *Routes) setupWG(s *stack.Stack, nic tcpip.NICID, id string, wg *Wireguard) { + fmt.Println("WG", id, nic, wg.ListenPort, wg) + fmt.Printf("Peers %v\n", wg.Peers) + + maddr, err := net.ParseMAC(wg.Macaddress) + if err != nil { + log.Fatalf("Bad MAC address: %v", wg.Macaddress) + } + + //addTunLink(s, tunNic, tunName, tcpip.LinkAddress(tapMaddr)) + device := addWgLink(s, nic, wg.Name, tcpip.LinkAddress(maddr)) + + var wgCmd strings.Builder + fmt.Fprintf(&wgCmd, "private_key=%s\nlisten_port=%d\nreplace_peers=true\n", + hex.EncodeToString(wg.PrivateKey), wg.ListenPort) + for _, peer := range wg.Peers { + fmt.Fprintf(&wgCmd, "public_key=%s\nendpoint=%s\npersistent_keepalive_interval=%d\nreplace_allowed_ips=true\n", + hex.EncodeToString(peer.PublicKey), peer.Endpoint, peer.PersistentKeepalive) + for _, allowedIp := range peer.AllowedIPs { + fmt.Fprintf(&wgCmd, "allowed_ip=%s\n", allowedIp) + } + wgCmd.WriteString("\n") + } + str := wgCmd.String() + fmt.Println("IpcSetOperation", str) + device.IpcSetOperation(bufio.NewReader(strings.NewReader(str))) + + routes.setupCommon(s, nic, id, wg.Common) + + go func() { + fmt.Println("Starting ", nic) + + select { + // case <-term: + // case <-errs: + case <-device.Wait(): + } + + fmt.Println("Finnished ", nic) + }() +} + +func (routes *Routes) Setup(s *stack.Stack, np *Netplan) { + s.SetForwarding(true) + + var nic tcpip.NICID = -1 +// var wg2Nic tcpip.NICID = -1 + + for id, tun := range np.Network.Ethernets { + nic = nic + 1 + routes.setupLoopback(s, nic, id, tun) + } + + for id, tun := range np.Network.Tuntaps { + nic = nic + 1 + routes.setupTuntap(s, nic, id, tun) + } + + for id, wg := range np.Network.Wireguards { + nic = nic + 1 + // if id == "wg2" { + // wg2Nic = nic + // } + routes.setupWG(s, nic, id, wg) + } + + for id, tun := range np.Network.Tunnels { + nic = nic + 1 + routes.setupTunnel(s, nic, id, tun) + } + + nicCount := nic + + for nic = 0; nic < nicCount; nic++ { + s.EnableNIC(nic) + } +} diff --git a/pkg/tcpip/sample/wg_tunnel/main.go b/pkg/tcpip/sample/wg_tunnel/main.go index 1c87a09c2..066216dfb 100644 --- a/pkg/tcpip/sample/wg_tunnel/main.go +++ b/pkg/tcpip/sample/wg_tunnel/main.go @@ -20,10 +20,7 @@ package main import ( - "bufio" "context" - "encoding/base64" - "encoding/hex" "flag" "fmt" "io/ioutil" @@ -34,17 +31,11 @@ import ( "runtime" "sort" "strconv" - "strings" "time" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" - "gvisor.dev/gvisor/pkg/tcpip/link/channel" - "gvisor.dev/gvisor/pkg/tcpip/link/fdbased" - "gvisor.dev/gvisor/pkg/tcpip/link/loopback" - "gvisor.dev/gvisor/pkg/tcpip/link/rawfile" - "gvisor.dev/gvisor/pkg/tcpip/link/tun" - "gvisor.dev/gvisor/pkg/tcpip/link/wireguard" + "gvisor.dev/gvisor/pkg/tcpip/config" "gvisor.dev/gvisor/pkg/tcpip/network/arp" "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" "gvisor.dev/gvisor/pkg/tcpip/network/ipv6" @@ -54,9 +45,6 @@ import ( "gvisor.dev/gvisor/pkg/tcpip/transport/udp" "gvisor.dev/gvisor/pkg/waiter" - "golang.zx2c4.com/wireguard/device" - "golang.zx2c4.com/wireguard/ipc" -// wg_tun "golang.zx2c4.com/wireguard/tun" "gopkg.in/yaml.v3" @@ -66,86 +54,6 @@ import ( "github.com/insomniacslk/dhcp/iana" ) -type Route struct { - To string `yaml:"to"` - Via string `yaml:"via"` - Metric int `yaml:"metric"` - Mark uint32 `yaml:"mask"` - Markmask uint32 `yaml:"markmask"` -} - -type Common struct { - Match struct { - Name string `yaml:"name"` - } `yaml:"match"` - Addresses []string `yaml:"addresses"` - Nameservers struct { - Addresses []string `yaml:"addresses"` - } `yaml:"nameservers"` - Macaddress string `yaml:"macaddress"` - Routes []Route `yaml:"routes"` - Mtu uint32 `yaml:"mtu"` -} - -type Ethernet struct { - Common `yaml:",inline"` -} - -type Tuntap struct { - Common `yaml:",inline"` - Mode string `yaml:"mode"` - Name string `yaml:"name"` -} - -type WireguardKey []byte - -func (wgKey *WireguardKey) UnmarshalYAML(value *yaml.Node) error{ - key, err := base64.StdEncoding.DecodeString(value.Value) - fmt.Println("UnmarshalYAML", key, err) - *wgKey = key - return err -} - -type WireguardPeer struct { - PublicKey WireguardKey `yaml:"public_key"` - Endpoint string `yaml:"endpoint"` - AllowedIPs []string `yaml:"allowed_ips"` - PersistentKeepalive int `yaml:"persistent_keepalive"` -} - -func (peer WireguardPeer) String() string{ - return fmt.Sprintf("{PublicKey=%v, Endpoint=%v, AllowedIPs=%v, PersistentKeepalive=%v}", peer.PublicKey, peer.Endpoint, peer.AllowedIPs, peer.PersistentKeepalive) -} - -type Wireguard struct { - Common `yaml:",inline"` - Name string `yaml:"name"` - ListenPort uint16 `yaml:"listen_port"` - PrivateKey WireguardKey `yaml:"private_key"` - Peers []*WireguardPeer `yaml:"peers"` -} - -type Tunnel struct { - Common `yaml:",inline"` - Mode string `yaml:"mode"` - Local string `yaml:"local"` - Remote string `yaml:"remote"` - - Conn *net.UDPConn - Sd *os.File -} - -type Netplan struct { - Network struct { - Version int `yaml:"version"` - Renderer string `yaml:"renderer"` - Ethernets map[string] *Ethernet `yaml:"ethernets"` - Tuntaps map[string] *Tuntap `yaml:"tuntaps"` - Wireguards map[string] *Wireguard `yaml:"wireguards"` - Tunnels map[string] *Tunnel `yaml:"tunnels"` - } `yaml:"network"` -} - func echo(wq *waiter.Queue, ep tcpip.Endpoint) { defer ep.Close() @@ -170,52 +78,6 @@ func echo(wq *waiter.Queue, ep tcpip.Endpoint) { } } -func addTunLink(s *stack.Stack, nic tcpip.NICID, id string, tap bool, addr tcpip.LinkAddress, tuntap *Tuntap) { - var err error - - mtu := tuntap.Mtu - tunName := tuntap.Name - - if mtu == 0 { - mtu, err = rawfile.GetMTU(tunName) - if err != nil { - log.Fatal("GetMTU", err) - } - } - - var fd int - if tap { - fd, err = tun.OpenTAP(tunName) - } else { - fd, err = tun.Open(tunName) - } - if err != nil { - log.Fatalf("Open %s %b %s", err, tap, tunName) - } - - linkEP, err := fdbased.New(&fdbased.Options{ - FDs: []int{fd}, - MTU: mtu, - EthernetHeader: tap, - Address: addr, - }) - if err := s.CreateNICWithOptions(nic, linkEP, stack.NICOptions{Name: id, Disabled: true}); err != nil { - log.Fatal("CreateNIC", err) - } - - if tap { - if err := s.AddAddress(nic, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { - log.Fatal("AddAddress", err) - } - } -} - -func CheckError(err error) { - if err != nil { - log.Fatal("Error: " , err) - } -} - func TestFinialize(conn *net.UDPConn) { event := make(chan string) @@ -234,275 +96,51 @@ func TestFinialize(conn *net.UDPConn) { } } -func addRouterLink(s *stack.Stack, nic tcpip.NICID, id string, addr tcpip.LinkAddress, - tun *Tunnel) { - - ServerAddr,err := net.ResolveUDPAddr("udp", tun.Remote) - CheckError(err) - - LocalAddr, err := net.ResolveUDPAddr("udp", tun.Local) - CheckError(err) - - conn, err := net.DialUDP("udp", LocalAddr, ServerAddr) - CheckError(err) - - tun.Conn = conn - - fmt.Println("Tunnel ", conn) - - sd, err := conn.File() - CheckError(err) - - tun.Sd = sd - - conn.Close() - - var fd int - fd = int(sd.Fd()) - //TestFinialize(&tun.Conn) - runtime.GC() - linkEP, err := fdbased.New(&fdbased.Options{ - FDs: []int{fd}, - MTU: tun.Mtu, - EthernetHeader: true, -// EthernetHeader: false, - Address: addr, - }) - CheckError(err) - - fmt.Println("addRouterLink MTU ", tun.Mtu, tun.Conn) - //channelSize := 128 - // linkEP := channel.New(channelSize, mtu, addr) - if err := s.CreateNICWithOptions(nic, linkEP, stack.NICOptions{Name: id, Disabled: true}); err != nil { - log.Fatal("CreateNIC ", id, err) - } - - if err := s.AddAddress(nic, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { - log.Fatal("AddAddress", err) - } - -// client(linkEP.C) - fmt.Println("Tunnel ", tun.Conn) -} - -func addWgLink(s *stack.Stack, nic tcpip.NICID, interfaceName string, addr tcpip.LinkAddress) *device.Device { - loglevel := device.LogLevelDebug - - chanSize := 1024 - var chanMtu uint32 = 1420 - ep := channel.New(chanSize, chanMtu, addr) - - logger := device.NewLogger(loglevel, "(wg_tunnel) ") - - //mtu := 1500 - // tun, err := wg_tun.CreateTUN(interfaceName, mtu) - tun, err := wireguard.CreateWgTun(s, ep) - if err != nil { - log.Fatal("CreateWgTun", err) - } - - - fileUAPI, err := func() (*os.File, error) { - ENV_WG_UAPI_FD := "WG_UAPI_FD" - uapiFdStr := os.Getenv(ENV_WG_UAPI_FD) - if uapiFdStr == "" { - return ipc.UAPIOpen(interfaceName) - } - - // use supplied fd - - fd, err := strconv.ParseUint(uapiFdStr, 10, 32) - if err != nil { - return nil, err - } - - return os.NewFile(uintptr(fd), ""), nil - }() - - if err != nil { - logger.Error.Println("UAPI listen error:", err) - log.Fatal("Setup failed") - } - // daemonize the process - - device := device.NewDevice(tun, logger) - - errs := make(chan error) - - uapi, err := ipc.UAPIListen(interfaceName, fileUAPI) - if err != nil { - logger.Error.Println("Failed to listen on uapi socket:", err) - log.Fatal("Setup failed") - } - - go func() { - for { - conn, err := uapi.Accept() - if err != nil { - errs <- err - return - } - go device.IpcHandle(conn) - } - }() - - logger.Info.Println("UAPI listener started") - fmt.Println("Device ", device) - - if err := s.CreateNICWithOptions(nic, ep, stack.NICOptions{Name: interfaceName, Disabled: true}); err != nil { - log.Fatal("CreateNIC", err) - } - - return device -} - -func parseAddress(addrName string) (tcpip.Address, tcpip.NetworkProtocolNumber) { - ip := net.ParseIP(addrName) - - if ip.To4() != nil { - return tcpip.Address(ip.To4()), ipv4.ProtocolNumber - } else { - return tcpip.Address(ip.To16()), ipv6.ProtocolNumber - } -} - -func parseSubnet(subnetName string) (tcpip.Address, tcpip.Subnet, tcpip.NetworkProtocolNumber) { - parsedAddr, parsedNet, err := net.ParseCIDR(subnetName) - if err != nil { - log.Fatalf("Bad IP/CIDR address: %v", subnetName) - } - - var addr tcpip.Address - var net tcpip.Address - var proto tcpip.NetworkProtocolNumber - - if parsedAddr.To4() != nil { - addr = tcpip.Address(parsedAddr.To4()) - net = tcpip.Address(parsedNet.IP.To4()) - proto = ipv4.ProtocolNumber - } else { - addr = tcpip.Address(parsedAddr.To16()) - net = tcpip.Address(parsedNet.IP.To16()) - proto = ipv6.ProtocolNumber - } - - // ones, zeros := parsedNet.Mask.Size() - - mask, err := hex.DecodeString(parsedNet.Mask.String()) - if err != nil { - log.Fatalf("Bad mask", err) - } - - subnet, err := tcpip.NewSubnet(net, tcpip.AddressMask(mask)) - if err != nil { - log.Fatalf("Bad subnet", err, net, parsedNet.Mask.String()) - } - - return addr, subnet, proto -} - -func (routes *Routes) addAddress(s *stack.Stack, nic tcpip.NICID, addrName string) tcpip.NetworkProtocolNumber { - // // Parse the IP address. Support both ipv4 and ipv6. - addr, subnet, proto := parseSubnet(addrName) - - if false { - if err := s.AddAddress(nic, proto, addr); err != nil { - log.Fatal("AddAddress", err) - } - } else { - addr := tcpip.ProtocolAddress{ - Protocol: proto, - AddressWithPrefix: tcpip.AddressWithPrefix{ - Address: addr, - PrefixLen: subnet.Prefix(), - }} - - fmt.Println("Added address ", addr) - - if err := s.AddProtocolAddress(nic, addr); err != nil { - log.Fatalf("AddProtocolAddress", err, nic) - } - - route := tcpip.Route{ - Destination: addr.AddressWithPrefix.Subnet(), - NIC: nic, - } +// func (routes *Routes) OnDuplicateAddressDetectionStatus(nicID tcpip.NICID, addr tcpip.Address, resolved bool, err *tcpip.Error) { +// fmt.Println("OnDuplicateAddressDetectionStatus ", addr) +// } - *routes = append(*routes, route) - } +// func (routes *Routes) OnDefaultRouterDiscovered(nicID tcpip.NICID, addr tcpip.Address) bool { +// fmt.Println("OnDefaultRouterDiscovered") +// return true +// } - // subnet, err := tcpip.NewSubnet(tcpip.Address(parsedNet.IP), - // tcpip.AddressMask(parsedNet.Mask)) - // if err != nil { - // log.Fatal(err) - // } +// func (routes *Routes) OnDefaultRouterInvalidated(nicID tcpip.NICID, addr tcpip.Address) { +// } - return proto -} - -type Routes []tcpip.Route +// func (routes *Routes) OnOnLinkPrefixDiscovered(nicID tcpip.NICID, prefix tcpip.Subnet) bool { +// fmt.Println("OnOnLinkPrefixDiscovered ", prefix) +// return true +// } +// func (routes *Routes) OnOnLinkPrefixInvalidated(nicID tcpip.NICID, prefix tcpip.Subnet) { +// } -func (routes *Routes) OnDuplicateAddressDetectionStatus(nicID tcpip.NICID, addr tcpip.Address, resolved bool, err *tcpip.Error) { - fmt.Println("OnDuplicateAddressDetectionStatus ", addr) -} +// func (routes *Routes) OnAutoGenAddress(tcpip.NICID, tcpip.AddressWithPrefix) bool { +// return true +// } -func (routes *Routes) OnDefaultRouterDiscovered(nicID tcpip.NICID, addr tcpip.Address) bool { - fmt.Println("OnDefaultRouterDiscovered") - return true -} +// func (routes *Routes) OnAutoGenAddressDeprecated(tcpip.NICID, tcpip.AddressWithPrefix) { +// } -func (routes *Routes) OnDefaultRouterInvalidated(nicID tcpip.NICID, addr tcpip.Address) { -} +// func (routes *Routes) OnAutoGenAddressInvalidated(tcpip.NICID, tcpip.AddressWithPrefix) { +// } -func (routes *Routes) OnOnLinkPrefixDiscovered(nicID tcpip.NICID, prefix tcpip.Subnet) bool { - fmt.Println("OnOnLinkPrefixDiscovered ", prefix) - return true -} +// func (routes *Routes) OnRecursiveDNSServerOption(nicID tcpip.NICID, addrs []tcpip.Address, lifetime time.Duration) { +// fmt.Println("OnRecursiveDNSServerOption ", addrs) +// } -func (routes *Routes) OnOnLinkPrefixInvalidated(nicID tcpip.NICID, prefix tcpip.Subnet) { -} - -func (routes *Routes) OnAutoGenAddress(tcpip.NICID, tcpip.AddressWithPrefix) bool { - return true -} - -func (routes *Routes) OnAutoGenAddressDeprecated(tcpip.NICID, tcpip.AddressWithPrefix) { -} - -func (routes *Routes) OnAutoGenAddressInvalidated(tcpip.NICID, tcpip.AddressWithPrefix) { -} - -func (routes *Routes) OnRecursiveDNSServerOption(nicID tcpip.NICID, addrs []tcpip.Address, lifetime time.Duration) { - fmt.Println("OnRecursiveDNSServerOption ", addrs) -} - -func (routes *Routes) OnDHCPv6Configuration(nicID tcpip.NICID, config stack.DHCPv6ConfigurationFromNDPRA) { - str := "undefined" - switch config { - case stack.DHCPv6NoConfiguration: str = "no config" - case stack.DHCPv6ManagedAddress: str = "managed" - case stack.DHCPv6OtherConfigurations: str = "other" - } +// func (routes *Routes) OnDHCPv6Configuration(nicID tcpip.NICID, config stack.DHCPv6ConfigurationFromNDPRA) { +// str := "undefined" +// switch config { +// case stack.DHCPv6NoConfiguration: str = "no config" +// case stack.DHCPv6ManagedAddress: str = "managed" +// case stack.DHCPv6OtherConfigurations: str = "other" +// } - fmt.Println("OnDHCPv6Configuration ", str) -} - +// fmt.Println("OnDHCPv6Configuration ", str) +// } -func (routes *Routes) addRoute(nic tcpip.NICID, routeCfg Route){ - _, dest, _ := parseSubnet(routeCfg.To) - via, _ := parseAddress(routeCfg.Via) - - route := tcpip.Route{ - Destination: dest, - Gateway: via, - NIC: nic, - Mark: routeCfg.Mark, - Markmask: routeCfg.Markmask, - } - - *routes = append(*routes, route) -} func protocolToString(proto tcpip.NetworkProtocolNumber) string { switch proto { @@ -533,120 +171,11 @@ func dumpRoutes(s *stack.Stack) { } } -func (routes *Routes) setupCommon(s *stack.Stack, nic tcpip.NICID, id string, cfg Common) { - for _, addr := range cfg.Addresses { - routes.addAddress(s, nic, addr) - } - - for _, route := range cfg.Routes { - fmt.Println("Add Route:", route) - routes.addRoute(nic, route) - } - - for _, route := range *routes { - fmt.Println("Added Route:", route) - } - - // TODO check after enabling the NICs - // if !s.CheckNIC(nic) { - // log.Fatal("not usable ", id) - // } -} - -func (routes *Routes) setupLoopback(s *stack.Stack, nic tcpip.NICID, id string, eth *Ethernet) { - fmt.Println("Ethernet", id, nic, eth) - - linkEP := loopback.New() - if err := s.CreateNICWithOptions(nic, linkEP, stack.NICOptions{Name: id, Disabled: true}); err != nil { - log.Fatal("CreateNIC", err) - } - - routes.setupCommon(s, nic, id, eth.Common) -} - -func (routes *Routes) setupTunnel(s *stack.Stack, nic tcpip.NICID, id string, tun *Tunnel) { - fmt.Println("TUN", id, nic, tun) - - maddr, err := net.ParseMAC(tun.Macaddress) - if err != nil { - log.Fatalf("Bad MAC address: %v", tun.Macaddress) - } - - addRouterLink(s, nic, id, tcpip.LinkAddress(maddr), tun) - fmt.Println("Tunnel 20", tun.Conn) - routes.setupCommon(s, nic, id, tun.Common) - fmt.Println("Tunnel 21", tun.Conn) -} - -func (routes *Routes) setupTuntap(s *stack.Stack, nic tcpip.NICID, id string, tun *Tuntap) { - fmt.Println("Tuntap", id, nic, tun) - - maddr, err := net.ParseMAC(tun.Macaddress) - if err != nil { - log.Fatalf("Bad MAC address: %v", tun.Macaddress) - } - - var tap bool - switch tun.Mode { - case "tun": - tap = false - case "tap": - tap = true - default: - log.Fatalf("Bad mode: %v", tun.Mode) - } - - addTunLink(s, nic, id, tap, tcpip.LinkAddress(maddr), tun) - routes.setupCommon(s, nic, id, tun.Common) -} - -func (routes *Routes) setupWG(s *stack.Stack, nic tcpip.NICID, id string, wg *Wireguard) { - fmt.Println("WG", id, nic, wg.ListenPort, wg) - fmt.Printf("Peers %v\n", wg.Peers) - - maddr, err := net.ParseMAC(wg.Macaddress) - if err != nil { - log.Fatalf("Bad MAC address: %v", wg.Macaddress) - } - - //addTunLink(s, tunNic, tunName, tcpip.LinkAddress(tapMaddr)) - device := addWgLink(s, nic, wg.Name, tcpip.LinkAddress(maddr)) - - var wgCmd strings.Builder - fmt.Fprintf(&wgCmd, "private_key=%s\nlisten_port=%d\nreplace_peers=true\n", - hex.EncodeToString(wg.PrivateKey), wg.ListenPort) - for _, peer := range wg.Peers { - fmt.Fprintf(&wgCmd, "public_key=%s\nendpoint=%s\npersistent_keepalive_interval=%d\nreplace_allowed_ips=true\n", - hex.EncodeToString(peer.PublicKey), peer.Endpoint, peer.PersistentKeepalive) - for _, allowedIp := range peer.AllowedIPs { - fmt.Fprintf(&wgCmd, "allowed_ip=%s\n", allowedIp) - } - wgCmd.WriteString("\n") - } - str := wgCmd.String() - fmt.Println("IpcSetOperation", str) - device.IpcSetOperation(bufio.NewReader(strings.NewReader(str))) - - routes.setupCommon(s, nic, id, wg.Common) - - go func() { - fmt.Println("Starting ", nic) - - select { - // case <-term: - // case <-errs: - case <-device.Wait(): - } - - fmt.Println("Finnished ", nic) - }() -} - -func KeepAliveTunnel(np *Netplan) { +func KeepAliveTunnel(np *config.Netplan) { KeepAliveTunnelEx(np, true) } -func KeepAliveTunnelEx(np *Netplan, debug bool) { +func KeepAliveTunnelEx(np *config.Netplan, debug bool) { for _, tun := range np.Network.Tunnels { if debug { fmt.Println("Tunnel ", tun.Mode, tun.Local, tun.Remote, tun.Conn, tun.Sd) @@ -719,7 +248,7 @@ func NewDHCPv4Query(flags uint32, modifiers ...dhcpv6.Modifier) (*dhcpv6.Message return msg, nil } -func (routes *Routes) doClient(s *stack.Stack, nic tcpip.NICID) { +func doClient(s *stack.Stack, routes *config.Routes, nic tcpip.NICID) { fmt.Println("doClient start") // TODO use link local address @@ -832,14 +361,14 @@ func (routes *Routes) doClient(s *stack.Stack, nic tcpip.NICID) { // client.Close() fmt.Println("doClient end", ack.YourIPAddr, ack.SubnetMask()) ip := net.IPNet{IP: ack.YourIPAddr, Mask:ack.SubnetMask()} - routes.addAddress(s, nic, ip.String()) + routes.AddAddress(s, nic, ip.String()) iana := msg.GetOneOption(dhcpv6.OptionIANA).(*dhcpv6.OptIANA) for _, addr := range iana.Options.Get(dhcpv6.OptionIAAddr) { str := addr.(*dhcpv6.OptIAAddress).IPv6Addr.String() + "/128" - routes.addAddress(s, nic, str) + routes.AddAddress(s, nic, str) - _, dest, _ := parseSubnet(addr.(*dhcpv6.OptIAAddress).IPv6Addr.String() + "/64") + _, dest, _ := config.ParseSubnet(addr.(*dhcpv6.OptIAAddress).IPv6Addr.String() + "/64") route := tcpip.Route{ Destination: dest, NIC: nic, @@ -853,7 +382,7 @@ func (routes *Routes) doClient(s *stack.Stack, nic tcpip.NICID) { for _, opt := range iapd.Options.Get(dhcpv6.OptionIAPrefix) { prefix := opt.(*dhcpv6.OptIAPrefix) str := prefix.Prefix.IP.String()+"1"+"/128" - routes.addAddress(s, loNic, str) + routes.AddAddress(s, loNic, str) } dumpAddresses(s) @@ -912,7 +441,7 @@ func main() { log.Fatalf("File reading error", err) } - var np Netplan + var np config.Netplan err = yaml.Unmarshal(data, &np) fmt.Println("err", err) fmt.Println("res", np) @@ -926,7 +455,7 @@ func main() { log.Fatalf("Unable to convert port %v: %v", portName, err) } - routes := Routes{} + routes := config.Routes{} // Create the stack with ip and tcp protocols, then add a tun-based // NIC and address. @@ -942,40 +471,8 @@ func main() { }) // FIXME enable - s.SetForwarding(true) - - var nic tcpip.NICID = -1 - var wg2Nic tcpip.NICID = -1 - - for id, tun := range np.Network.Ethernets { - nic = nic + 1 - routes.setupLoopback(s, nic, id, tun) - } - - for id, tun := range np.Network.Tuntaps { - nic = nic + 1 - routes.setupTuntap(s, nic, id, tun) - } - - for id, wg := range np.Network.Wireguards { - nic = nic + 1 - if id == "wg2" { - wg2Nic = nic - } - routes.setupWG(s, nic, id, wg) - } - - for id, tun := range np.Network.Tunnels { - nic = nic + 1 - routes.setupTunnel(s, nic, id, tun) - } - - nicCount := nic - - for nic = 0; nic < nicCount; nic++ { - s.EnableNIC(nic) - } - + routes.Setup(s, &np) + KeepAliveTunnel(&np) // Sort route table for longest prefix match @@ -986,8 +483,10 @@ func main() { s.SetRouteTable(routes) // FIXME disabled for now, to test startSolicitingRouters - if true { - routes.doClient(s, wg2Nic) + if false { + // FIXME + var wg2Nic tcpip.NICID = -1 + doClient(s, &routes, wg2Nic) } // Sort route table for longest prefix match |