summaryrefslogtreecommitdiffhomepage
path: root/tunnel/tools/libwg-go/api-android.go
diff options
context:
space:
mode:
authorMikael Magnusson <mikma@users.sourceforge.net>2021-02-03 17:37:42 +0100
committerMikael Magnusson <mikma@users.sourceforge.net>2021-03-11 23:52:20 +0000
commit4d6c8340bcf0a6fc9026166f95f4a00b5b3c64cc (patch)
treeb52c47186bb6e4b7176559d1b7eacfe995a10b24 /tunnel/tools/libwg-go/api-android.go
parent66bbf038f1b9edf2a4463498a3aa45f78a01dfab (diff)
dhcp 4o6 working
Diffstat (limited to 'tunnel/tools/libwg-go/api-android.go')
-rw-r--r--tunnel/tools/libwg-go/api-android.go246
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() {}