diff options
Diffstat (limited to 'tunnel/tools/libwg-go/api-android.go')
-rw-r--r-- | tunnel/tools/libwg-go/api-android.go | 246 |
1 files changed, 242 insertions, 4 deletions
diff --git a/tunnel/tools/libwg-go/api-android.go b/tunnel/tools/libwg-go/api-android.go index 6d0802ff..f90d7ef3 100644 --- a/tunnel/tools/libwg-go/api-android.go +++ b/tunnel/tools/libwg-go/api-android.go @@ -10,6 +10,7 @@ package main import "C" import ( + "context" "fmt" "math" "net" @@ -20,11 +21,28 @@ import ( "strings" "unsafe" + "github.com/insomniacslk/dhcp/dhcpv4" + "github.com/insomniacslk/dhcp/dhcpv6" + "github.com/insomniacslk/dhcp/dhcpv6/nclient6" + "github.com/insomniacslk/dhcp/iana" + + "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/link/fdbased" + "gvisor.dev/gvisor/pkg/tcpip/link/rawfile" + "gvisor.dev/gvisor/pkg/tcpip/link/sniffer" + tunlink "gvisor.dev/gvisor/pkg/tcpip/link/tun" + "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" + "gvisor.dev/gvisor/pkg/tcpip/network/ipv6" + "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" + "gvisor.dev/gvisor/pkg/tcpip/transport/udp" + "gvisor.dev/gvisor/pkg/tcpip/stack" + "golang.org/x/sys/unix" "golang.zx2c4.com/wireguard/conn" "golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/ipc" "golang.zx2c4.com/wireguard/tun" + "golang.zx2c4.com/wireguard/tun/netstack" ) type AndroidLogger struct { @@ -48,6 +66,9 @@ func (l AndroidLogger) Printf(format string, args ...interface{}) { type TunnelHandle struct { device *device.Device uapi net.Listener + stack *stack.Stack + tnet *netstack.Net + logger *device.Logger } var tunnelHandles map[int32]TunnelHandle @@ -80,13 +101,13 @@ func wgTurnOn(interfaceName string, tunFd int32, settings string) int32 { Errorf: AndroidLogger{level: C.ANDROID_LOG_ERROR, tag: tag}.Printf, } - tun, name, err := tun.CreateUnmonitoredTUNFromFD(int(tunFd)) + handle, tun, err := newTunnel(logger) if err != nil { - unix.Close(int(tunFd)) - logger.Errorf("CreateUnmonitoredTUNFromFD: %v", err) + logger.Errorf("newTunnel: %v", err) return -1 } + name := "foobar" logger.Verbosef("Attaching to interface %v", name) device := device.NewDevice(tun, conn.NewStdNetBind(), logger) @@ -142,7 +163,12 @@ func wgTurnOn(interfaceName string, tunFd int32, settings string) int32 { device.Close() return -1 } - tunnelHandles[i] = TunnelHandle{device: device, uapi: uapi} + handle.device = device + handle.uapi = uapi + tunnelHandles[i] = handle + + go handle.startDHCPv6() + return i } @@ -224,4 +250,216 @@ func wgVersion() *C.char { return C.CString("unknown") } +func withDHCPv4Msg(msg *dhcpv4.DHCPv4) dhcpv6.Modifier { + return func(d dhcpv6.DHCPv6) { + opt := dhcpv6.OptDHCPv4Msg{ + Msg: msg, + } + d.UpdateOption(&opt) + } +} + +func NewDHCPv4Query(flags uint32, modifiers ...dhcpv6.Modifier) (*dhcpv6.Message, error) { + msg, err := dhcpv6.NewMessage() + if err != nil { + return nil, err + } + msg.MessageType = dhcpv6.MessageTypeDHCPv4Query + msg.TransactionID = dhcpv6.TransactionID{byte(flags >> 16), byte(flags >> 8), byte(flags)} + //msg.AddOption(dhcpv6.OptElapsedTime(0)) + //modifiers = append([]dhcpv6.Modifier{dhcpv6.WithRequestedOptions(dhcpv6.OptionDHCP4oDHCP6Server)}, modifiers...) + + for _, mod := range modifiers { + mod(msg) + } + return msg, nil +} + +func newTunnel(logger *device.Logger) (TunnelHandle, tun.Device, error) { + // TODO: Configurable local address + localAddresses := []net.IP{net.ParseIP("fe80::104")} + dnsServers := []net.IP{net.ParseIP("8.8.8.8"), net.ParseIP("8.8.4.4")} + mtu := 1420 + + opts := stack.Options{ + NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol}, + TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol}, + HandleLocal: true, + } + stack := stack.New(opts) + + tun, tnet, err := netstack.CreateNetTUNWithStack(stack, 1, localAddresses, dnsServers, mtu) + if err != nil { + // TODO: Release stack? + return TunnelHandle{}, nil, err + } + + handle := TunnelHandle{stack: stack, tnet: tnet, logger: logger} + return handle, tun, nil +} + +func (handle *TunnelHandle) startDHCPv6() { + // TODO: Configurable address + src, err := net.ResolveUDPAddr("udp6", "[fe80::104%1]:546"); if err != nil { + handle.logger.Errorf("ResolveUDPAddr: %v", err) + return + } + + var dst *net.UDPAddr + dst = nil + + conn, err := handle.tnet.DialUDP(src, dst); if err != nil { + handle.logger.Errorf("DialUDP: %v (%v -> %v)", src, dst, err) + return + } + + hwaddr := []byte("ABCDEF") + client, err := nclient6.NewWithConn(conn, hwaddr, nclient6.WithDebugLogger()); if err != nil { + handle.logger.Errorf("NewWithConn: %v", err) + return + } + + duid := dhcpv6.Duid{ + Type: dhcpv6.DUID_LL, + HwType: iana.HWTypeEthernet, + LinkLayerAddr: hwaddr, + } + + hostName := "gvisor" + fqdn := hostName + ".m7n.se" + fqdnOpt := dhcpv6.WithFQDN(0x1, fqdn) + + _, iaIPNet, err := net.ParseCIDR("::/64"); if err != nil { + handle.logger.Errorf("ParseCIDR: %v", err) + return + } + iaPrefix := dhcpv6.OptIAPrefix{ + 0, 0, iaIPNet, dhcpv6.PrefixOptions{}, + } + + iaid := []byte{0, 0, 0, 3} + ident := []byte{255} // Type IAID+DUID + ident = append(ident, iaid...) // IAID + ident = append(ident, duid.ToBytes()...) // DUID + clientIDOpt := dhcpv4.OptClientIdentifier(ident) + + adv, err := client.Solicit(context.Background(), + dhcpv6.WithIAPD([4]byte{0, 0, 0, 1}, &iaPrefix), + dhcpv6.WithIAID([4]byte{0, 0, 0, 2}), + fqdnOpt, + dhcpv6.WithClientID(duid), + dhcpv6.WithRequestedOptions(dhcpv6.OptionDHCP4oDHCP6Server), + dhcpv6.WithDHCP4oDHCP6Server(net.ParseIP("fe80::1")), + ); if err != nil { + handle.logger.Errorf("Solicit: %v", err) + return + } + + msg, err := client.Request(context.Background(), adv, fqdnOpt); if err != nil { + handle.logger.Errorf("Request: %v", err) + return + } + + modHostName := dhcpv4.WithGeneric(dhcpv4.OptionHostName, []byte(hostName)) + disc, err := dhcpv4.NewDiscovery(hwaddr, dhcpv4.WithOption(clientIDOpt), modHostName); if err != nil { + handle.logger.Errorf("NewDiscovery: %v", err) + return + } + disc_query, err := NewDHCPv4Query(0x800000, withDHCPv4Msg(disc)); if err != nil { + handle.logger.Errorf("NewDHCPv4Query: %v", err) + return + } + + serverAddr := nclient6.AllDHCPRelayAgentsAndServers + disc_resp, err := client.SendAndRead(context.Background(), serverAddr, disc_query, nil); if err != nil { + handle.logger.Errorf("SendAndRead: %v", err) + return + } + + msgOpt := disc_resp.GetOneOption(dhcpv6.OptionDHCPv4Msg); if msgOpt == nil { + handle.logger.Errorf("Missing DHCPv4Msg option in discovery") + return + } + + offer := msgOpt.(*dhcpv6.OptDHCPv4Msg).Msg + req, err := dhcpv4.NewRequestFromOffer(offer, modHostName); if err != nil { + handle.logger.Errorf("NewRequestFromOffer: %v", err) + return + } + + req_query, err := NewDHCPv4Query(0x800000, withDHCPv4Msg(req)); if err != nil { + handle.logger.Errorf("NewDHCPv4Query: %v", err) + return + } + req_resp, err := client.SendAndRead(context.Background(), serverAddr, req_query, nil); if err != nil { + handle.logger.Errorf("Serveraddr: %v", err) + return + } + + msgOpt = req_resp.GetOneOption(dhcpv6.OptionDHCPv4Msg); if msgOpt == nil { + handle.logger.Errorf("Missing DHCPv4Msg option in ack") + return + } + ack := msgOpt.(*dhcpv6.OptDHCPv4Msg).Msg + + // TODO: Close clients? + // client.Close() + handle.logger.Verbosef("doClient end %v %v", ack.YourIPAddr, ack.SubnetMask()) + if ip4 := ack.YourIPAddr.To4(); ip4 == nil { + handle.logger.Errorf("Not IPv4! %v", ack.YourIPAddr) + return + } + + // tcperr := tnet.AddAddress(ack.YourIPAddr); if tcperr != nil { + // log.Fatal(tcperr) + // } + + iana := msg.GetOneOption(dhcpv6.OptionIANA).(*dhcpv6.OptIANA) + for _, addr := range iana.Options.Get(dhcpv6.OptionIAAddr) { + ip := addr.(*dhcpv6.OptIAAddress).IPv6Addr + str := ip.String() + "/128" + handle.logger.Verbosef("Addr %v", str) + + // err := tnet.AddAddress(ip); if err != nil { + // log.Fatal(err) + // } + } + + handle.logger.Verbosef("DHCP done") +} + +func (handle *TunnelHandle) newTun(id tcpip.NICID, tunName string) { + mtu, err := rawfile.GetMTU(tunName) + if err != nil { + handle.logger.Errorf("GetMTU: %v", err) + return + } + + fd, err := tunlink.Open(tunName) + if err != nil { + handle.logger.Errorf("Open: %v", err) + return + } + + linkEP, err := fdbased.New(&fdbased.Options{FDs: []int{fd}, MTU: mtu}) + if err != nil { + handle.logger.Errorf("fdbased.New: %v", err) + return + } + if err := handle.stack.CreateNIC(id, sniffer.New(linkEP)); err != nil { + handle.logger.Errorf("CreateNIC: %v", err) + return + } +} + +func (handle *TunnelHandle) createNetTUNFromFD(tunFd int) { + // newTun(2, "tun0") + // tun, name, err := handle.createNetTUNFromFD(int(tunFd)) + // if err != nil { + // unix.Close(int(tunFd)) + // logger.Errorf("createNetTUNFromFD: %v", err) + // return -1 + // } +} + func main() {} |