diff options
Diffstat (limited to 'pkg/tcpip/sample/wg_tunnel')
-rw-r--r-- | pkg/tcpip/sample/wg_tunnel/main.go | 601 |
1 files changed, 50 insertions, 551 deletions
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 |