summaryrefslogtreecommitdiffhomepage
path: root/tunnel/tools/libwg-go
diff options
context:
space:
mode:
Diffstat (limited to 'tunnel/tools/libwg-go')
-rw-r--r--tunnel/tools/libwg-go/Makefile2
-rw-r--r--tunnel/tools/libwg-go/api-android.go22
-rw-r--r--tunnel/tools/libwg-go/dhcp.go338
-rw-r--r--tunnel/tools/libwg-go/go.mod3
-rw-r--r--tunnel/tools/libwg-go/jni.c6
-rw-r--r--tunnel/tools/libwg-go/service.go17
6 files changed, 192 insertions, 196 deletions
diff --git a/tunnel/tools/libwg-go/Makefile b/tunnel/tools/libwg-go/Makefile
index ba3ab19e..9ed24e1c 100644
--- a/tunnel/tools/libwg-go/Makefile
+++ b/tunnel/tools/libwg-go/Makefile
@@ -71,7 +71,7 @@ gen/%_grpc.pb.go: $(PROTODIR)/%.proto $(BUILDDIR)/go-$(GO_VERSION)/.prepared $(P
$(PROTOC) -I $(PROTODIR) -I $(PROTO_INCLUDEDIR) --go-grpc_out=./gen --go-grpc_opt=paths=source_relative $<
$(DESTDIR)/libwg-go.so: export PATH := $(BUILDDIR)/go-$(GO_VERSION)/bin/:$(PATH)
-$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(GO_VERSION)/.prepared go.mod api-android.go http-proxy.go service.go gen/libwg.pb.go gen/libwg_grpc.pb.go jni.c
+$(DESTDIR)/libwg-go.so: $(BUILDDIR)/go-$(GO_VERSION)/.prepared go.mod api-android.go dhcp.go http-proxy.go service.go gen/libwg.pb.go gen/libwg_grpc.pb.go jni.c
go build -tags linux -ldflags="-X golang.zx2c4.com/wireguard/ipc.socketDirectory=/data/data/$(ANDROID_PACKAGE_NAME)/cache/wireguard" -v -trimpath -o "$@" -buildmode c-shared
.DELETE_ON_ERROR:
diff --git a/tunnel/tools/libwg-go/api-android.go b/tunnel/tools/libwg-go/api-android.go
index 0ab80be9..78ee7f54 100644
--- a/tunnel/tools/libwg-go/api-android.go
+++ b/tunnel/tools/libwg-go/api-android.go
@@ -49,6 +49,7 @@ type TunnelHandle struct {
device *device.Device
uapi net.Listener
logger *device.Logger
+ tun *tun.NativeTun
}
var tunnelHandles map[int32]TunnelHandle
@@ -148,10 +149,29 @@ func wgTurnOn(interfaceName string, tunFd int32, settings string) int32 {
device.Close()
return -1
}
- tunnelHandles[i] = TunnelHandle{device: device, uapi: uapi}
+ tunnelHandles[i] = TunnelHandle{device: device, uapi: uapi, tun: tun}
return i
}
+//export wgSetFd
+func wgSetFd(tunnelHandle int32, tunFd int32) {
+ tag := cstring(fmt.Sprintf("WireGuard/GoBackend/%x", tunnelHandle))
+ logger := &device.Logger{
+ Verbosef: AndroidLogger{level: C.ANDROID_LOG_DEBUG, tag: tag}.Printf,
+ Errorf: AndroidLogger{level: C.ANDROID_LOG_ERROR, tag: tag}.Printf,
+ }
+
+ handle, ok := tunnelHandles[tunnelHandle]
+ if !ok {
+ unix.Close(int(tunFd))
+ logger.Errorf("Tunnel not found")
+ return
+ }
+
+ handle.tun.SetFd(int(tunFd))
+ logger.Verbosef("wgSetFd: %v", tunFd)
+}
+
//export wgTurnOff
func wgTurnOff(tunnelHandle int32) {
handle, ok := tunnelHandles[tunnelHandle]
diff --git a/tunnel/tools/libwg-go/dhcp.go b/tunnel/tools/libwg-go/dhcp.go
index 70a95f27..aaeb2e38 100644
--- a/tunnel/tools/libwg-go/dhcp.go
+++ b/tunnel/tools/libwg-go/dhcp.go
@@ -1,73 +1,30 @@
package main
import (
- "context"
- "fmt"
- "log"
- "net"
- "net/netip"
-
- "github.com/insomniacslk/dhcp/dhcpv4"
- "github.com/insomniacslk/dhcp/dhcpv6"
- "github.com/insomniacslk/dhcp/dhcpv6/nclient6"
- "github.com/insomniacslk/dhcp/iana"
+ "context"
+ "net"
+ "net/netip"
+
+ "github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/insomniacslk/dhcp/dhcpv6"
+ "github.com/insomniacslk/dhcp/dhcpv6/nclient6"
+ "github.com/insomniacslk/dhcp/iana"
+
+ gen "golang.zx2c4.com/wireguard/android/gen"
)
const (
- ENABLE_PD = false
- //ENABLE_PD = true
- ENABLE_TA = false
- //ENABLE_TA = true
- //ENABLE_4O6 = false
- ENABLE_4O6 = true
+ ENABLE_PD = true
)
-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))
-
- for _, mod := range modifiers {
- mod(msg)
- }
- return msg, nil
-}
-
-// type DHCPv4o6Client struct {
-// nclient4.Client
-// }
-
-func dhcpv4Query(ctx context.Context, client *nclient6.Client, dest *net.UDPAddr, msg *dhcpv4.DHCPv4) (*dhcpv4.DHCPv4, error) {
- query, err := newDHCPv4Query(0x800000, withDHCPv4Msg(msg))
- if err != nil {
- return nil, err
- }
-
- resp, err := client.SendAndRead(ctx, dest, query, nil)
- if err != nil {
- return nil, err
- }
-
- msgOpt := resp.GetOneOption(dhcpv6.OptionDHCPv4Msg)
- if msgOpt == nil {
- return nil, fmt.Errorf("Missing DHCPv4Msg option in response")
- }
-
- offer := msgOpt.(*dhcpv6.OptDHCPv4Msg).Msg
- return offer, nil
+type dhcp struct {
+ fqdn string
+ hwAddr net.HardwareAddr
+ conn *net.UDPConn
+ serverAddr net.UDPAddr
+ client *nclient6.Client
+ linkAddr net.IP
+ peerAddr net.IP
}
func newClientIDOpt(duid *dhcpv6.Duid) dhcpv4.Option {
@@ -78,171 +35,164 @@ func newClientIDOpt(duid *dhcpv6.Duid) dhcpv4.Option {
return dhcpv4.OptClientIdentifier(ident)
}
-func runDhcp4o6(ctx context.Context, client *nclient6.Client, v4o6 *dhcpv6.OptDHCP4oDHCP6Server, duid *dhcpv6.Duid, hwAddr net.HardwareAddr, hostName string) (*netip.Prefix, error) {
- serverAddr := nclient6.AllDHCPRelayAgentsAndServers
- if len(v4o6.DHCP4oDHCP6Servers) > 0 {
- // TODO use all servers
- serverAddr = &net.UDPAddr{
- IP: v4o6.DHCP4oDHCP6Servers[0],
- Port: dhcpv6.DefaultServerPort,
- }
- }
-
- modHostName := dhcpv4.WithGeneric(dhcpv4.OptionHostName, []byte(hostName))
- disc, err := dhcpv4.NewDiscovery(hwAddr, dhcpv4.WithOption(newClientIDOpt(duid)), modHostName)
- if err != nil {
- return nil, err
- }
- offer, err := dhcpv4Query(ctx, client, serverAddr, disc)
- if err != nil {
- return nil, err
- }
- req, err := dhcpv4.NewRequestFromOffer(offer, modHostName)
- if err != nil {
- return nil, err
- }
- ack, err := dhcpv4Query(ctx, client, serverAddr, req)
- if err != nil {
- return nil, err
- }
-
- // client.Close()
- fmt.Println("doClient end", ack.YourIPAddr, ack.SubnetMask())
- if ip4 := ack.YourIPAddr.To4(); ip4 == nil {
- return nil, fmt.Errorf("Not IPv4! %v", ack.YourIPAddr)
- } else {
- log.Println("IPv4", ip4)
+func getDuid(hwAddr net.HardwareAddr) dhcpv6.Duid {
+ duid := dhcpv6.Duid{
+ Type: dhcpv6.DUID_LL,
+ HwType: iana.HWTypeEthernet,
+ LinkLayerAddr: hwAddr,
}
- addr, _ := netip.AddrFromSlice(ack.YourIPAddr)
- prefix := netip.PrefixFrom(addr, 32) // TODO use SubnetMask
- log.Printf("Append %v", prefix)
- return &prefix, nil
+ return duid
}
-func RunDhcp(ctx context.Context, conn *net.UDPConn, hwAddr net.HardwareAddr) ([]netip.Prefix, error) {
- client, err := nclient6.NewWithConn(conn, hwAddr, nclient6.WithDebugLogger())
+func (d *dhcp) encapSendAndRead(ctx context.Context, msg *dhcpv6.Message, match nclient6.Matcher) (*dhcpv6.Message, error) {
+ packet, err := dhcpv6.EncapsulateRelay(msg, dhcpv6.MessageTypeRelayForward, d.linkAddr, d.peerAddr)
if err != nil {
return nil, err
}
- duid := dhcpv6.Duid{
- Type: dhcpv6.DUID_LL,
- HwType: iana.HWTypeEthernet,
- LinkLayerAddr: hwAddr,
+ relay, err := d.client.SendAndReadRelay(ctx, &d.serverAddr, packet, match)
+ if err != nil {
+ return nil, err
}
- hostName := "gvisor"
- fqdn := hostName + ".m7n.se"
- fqdnOpt := dhcpv6.WithFQDN(0x1, fqdn)
+ inner, err := relay.GetInnerMessage()
+ if err != nil {
+ return nil, err
+ }
- solicitMods := []dhcpv6.Modifier{}
+ return inner, nil
+}
- if ENABLE_PD {
- _, iaIPNet, err := net.ParseCIDR("::/64")
- if err != nil {
- return nil, err
+// isRelayMessageType returns a matcher that checks for the message type.
+func isRelayMessageType(t dhcpv6.MessageType, tt ...dhcpv6.MessageType) nclient6.Matcher {
+ return func(p dhcpv6.DHCPv6) bool {
+ inner, err := p.GetInnerMessage()
+ if err != nil {
+ return false
+ }
+ if inner.Type() == t {
+ return true
}
- iaPrefix := dhcpv6.OptIAPrefix{
- 0, 0, iaIPNet, dhcpv6.PrefixOptions{},
+ for _, mt := range tt {
+ if inner.Type() == mt {
+ return true
+ }
}
- solicitMods = append(solicitMods, dhcpv6.WithIAPD([4]byte{0, 0, 0, 1}, &iaPrefix))
+ return false
}
+}
- if ENABLE_TA {
- solicitMods = append(solicitMods, dhcpv6.WithIATA([4]byte{0, 0, 0, 1}))
- }
-
- oro := dhcpv6.WithRequestedOptions(dhcpv6.OptionDHCP4oDHCP6Server, dhcpv6.OptionFQDN)
+// func New() *dhcp {
+// }
- solicitMods = append(solicitMods, dhcpv6.WithIAID([4]byte{0, 0, 0, 1}))
- solicitMods = append(solicitMods, fqdnOpt)
- solicitMods = append(solicitMods, dhcpv6.WithClientID(duid))
- solicitMods = append(solicitMods, oro)
+func RunDhcp(ctx context.Context) ([]*gen.Lease, error) {
+ d := &dhcp{}
+
+ d.linkAddr = net.ParseIP("fe80::101")
+ d.peerAddr = net.ParseIP("::1")
- adv, err := client.Solicit(ctx, solicitMods...)
- if err != nil {
- return nil, err
- }
+ hostName := "foobar"
+ d.fqdn = hostName + ".m7n.se"
+ d.hwAddr = []byte{41, 42, 43, 44, 45, 46}
- requestMods := []dhcpv6.Modifier{}
- requestMods = append(requestMods, fqdnOpt)
- requestMods = append(requestMods, oro)
+ laddr, err := netip.ParseAddr("fd1c:a56b:a0d7:1260::101")
+ if err != nil {
+ return nil, err
+ }
- if ENABLE_TA {
- // Add IA_TA from advertise which is not added by default.
- withIaTa := func(req dhcpv6.DHCPv6) {
- if iaTa := adv.GetOneOption(dhcpv6.OptionIATA); iaTa != nil {
- req.AddOption(iaTa)
- }
- }
- requestMods = append(requestMods, withIaTa)
- }
+ src := net.UDPAddr{IP: laddr.AsSlice(),
+ Port: 0, // Use non-restrict UDP source port
+ }
- msg, err := client.Request(ctx, adv, requestMods...)
- if err != nil {
- return nil, err
- }
+ raddr, err := netip.ParseAddr("fd1c:a56b:a0d7:1260::1")
+ if err != nil {
+ return nil, err
+ }
- iana := msg.GetOneOption(dhcpv6.OptionIANA).(*dhcpv6.OptIANA)
- ianaOpts := iana.Options.Get(dhcpv6.OptionIAAddr)
+ d.serverAddr = net.UDPAddr{IP: raddr.AsSlice(),
+ Port: 547,
+ }
- var iapdOpts []dhcpv6.Option
+ err = d.Start(&src)
+ if err != nil {
+ return nil, err
+ }
- if ENABLE_PD {
- iapd := msg.GetOneOption(dhcpv6.OptionIAPD).(*dhcpv6.OptIAPD)
- iapdOpts = iapd.Options.Get(dhcpv6.OptionIAPrefix)
- }
+ defer d.Close()
- addrs := make([]netip.Prefix, 0, len(ianaOpts)+len(iapdOpts)+1)
+ reply, err := d.ObtainLease(ctx) // Use reply
+ if err != nil {
+ return nil, err
+ }
- opt4o6 := msg.GetOneOption(dhcpv6.OptionDHCP4oDHCP6Server)
- if ENABLE_4O6 && opt4o6 != nil {
- v4o6 := opt4o6.(*dhcpv6.OptDHCP4oDHCP6Server)
- log.Println("dhcp4o6: ", v4o6)
+ return getAddressesFromReply(reply), nil
+}
- prefix, err := runDhcp4o6(ctx, client, v4o6, &duid, hwAddr, hostName)
- if err == nil {
- addrs = append(addrs, *prefix)
- } else {
- return nil, err
- }
- }
+func getAddressesFromReply(reply *dhcpv6.Message) []*gen.Lease{
+ var leases []*gen.Lease = make([]*gen.Lease, 0, 4)
+
+ if opt := reply.GetOneOption(dhcpv6.OptionIANA); opt != nil {
+ iana := opt.(*dhcpv6.OptIANA)
+ ianaOpts := iana.Options.Get(dhcpv6.OptionIAAddr)
+
+ for _, opt := range ianaOpts {
+ addr :=opt.(*dhcpv6.OptIAAddress).IPv6Addr
+ lease := &gen.Lease{
+ Address: &gen.InetAddress{
+ Address: addr,
+ },
+ // PreferredLifetime: ,
+ // ValidLifetime: ,
+ }
+ leases = append(leases, lease)
+ }
+ }
+
+ return leases
+}
- for _, addr := range ianaOpts {
- prefix := netip.PrefixFrom(netip.IPv6Unspecified(), 128)
- ip, ok := netip.AddrFromSlice(addr.(*dhcpv6.OptIAAddress).IPv6Addr)
- if ok {
- prefix = netip.PrefixFrom(ip, 128)
- }
+func (d *dhcp) Start(localAddr *net.UDPAddr) error {
+ conn, err := net.ListenUDP("udp6", localAddr)
+ if err != nil {
+ return err
+ }
+
+ d.client, err = nclient6.NewWithConn(conn, d.hwAddr, nclient6.WithDebugLogger())
+ return err
+}
- log.Printf("IANA %v", prefix)
- addrs = append(addrs, prefix)
- }
+func (d *dhcp) Close() error {
+ err := d.client.Close()
- for _, addr := range iapdOpts {
- ipnet := addr.(*dhcpv6.OptIAPrefix).Prefix
- addr, _ := netip.AddrFromSlice(ipnet.IP) // TODO use ok
- prefixlen, _ := ipnet.Mask.Size()
- prefix := netip.PrefixFrom(addr, prefixlen)
+ d.client = nil
+ return err
+}
- log.Printf("IAPD %v", prefix)
- addrs = append(addrs, prefix)
- }
+func (d *dhcp) ObtainLease(ctx context.Context) (*dhcpv6.Message, error){
+ duidOpt := dhcpv6.WithClientID(getDuid(d.hwAddr))
+ fqdnOpt := dhcpv6.WithFQDN(0x1, d.fqdn)
- opt := msg.GetOneOption(dhcpv6.OptionIATA)
- if opt != nil {
- iata := opt.(*dhcpv6.OptIATA)
- taOpts := iata.Options.Get(dhcpv6.OptionIAAddr)
+ solicit, err := dhcpv6.NewSolicit(d.hwAddr, duidOpt, fqdnOpt, dhcpv6.WithRapidCommit)
+ if err != nil {
+ return nil, err
+ }
- for _, addr := range taOpts {
- ip := addr.(*dhcpv6.OptIAAddress).IPv6Addr
- addr, _ := netip.AddrFromSlice(ip) // TODO use ok
- prefix := netip.PrefixFrom(addr, 128)
+ msg, err := d.encapSendAndRead(ctx, solicit, isRelayMessageType(dhcpv6.MessageTypeReply, dhcpv6.MessageTypeAdvertise))
+ if err != nil {
+ return nil, err
+ }
- log.Printf("IATA %v", prefix)
- }
- }
+ if msg.Type() == dhcpv6.MessageTypeReply {
+ // We got RapidCommitted.
+ return msg, nil
+ }
+
+ // We didn't get RapidCommitted. Request regular lease.
+ req, err := dhcpv6.NewRequestFromAdvertise(msg, fqdnOpt)
+ if err != nil {
+ return nil, err
+ }
- return addrs, nil
+ return d.encapSendAndRead(ctx, req, nil)
}
diff --git a/tunnel/tools/libwg-go/go.mod b/tunnel/tools/libwg-go/go.mod
index 19ee576f..e92d2cc0 100644
--- a/tunnel/tools/libwg-go/go.mod
+++ b/tunnel/tools/libwg-go/go.mod
@@ -22,3 +22,6 @@ require (
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
)
+
+replace github.com/insomniacslk/dhcp => /src/insomniacslk-dhcp
+replace golang.zx2c4.com/wireguard => /src/wireguard-go
diff --git a/tunnel/tools/libwg-go/jni.c b/tunnel/tools/libwg-go/jni.c
index 121729a7..20bfb332 100644
--- a/tunnel/tools/libwg-go/jni.c
+++ b/tunnel/tools/libwg-go/jni.c
@@ -15,6 +15,7 @@ extern int wgGetSocketV6(int handle);
extern char *wgGetConfig(int handle);
extern char *wgVersion();
extern int wgStartGrpc();
+extern int wgSetFd(int handle, int tun_fd);
JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgTurnOn(JNIEnv *env, jclass c, jstring ifname, jint tun_fd, jstring settings)
{
@@ -82,3 +83,8 @@ JNIEXPORT jint JNICALL Java_com_wireguard_android_backend_GoBackend_wgStartGrpc(
(*env)->ReleaseStringUTFChars(env, sockname, sockname_str);
return res;
}
+
+JNIEXPORT void JNICALL Java_com_wireguard_android_backend_GoBackend_wgSetFd(JNIEnv *env, jclass c, jint handle, jint tun_fd)
+{
+ wgSetFd(handle, tun_fd);
+}
diff --git a/tunnel/tools/libwg-go/service.go b/tunnel/tools/libwg-go/service.go
index 1f2e629c..66bdd5ef 100644
--- a/tunnel/tools/libwg-go/service.go
+++ b/tunnel/tools/libwg-go/service.go
@@ -244,3 +244,20 @@ func (e *LibwgServiceImpl) IpcSet(ctx context.Context, req *gen.IpcSetRequest) (
return r, nil
}
+
+func (e *LibwgServiceImpl) Dhcp(ctx context.Context, req *gen.DhcpRequest) (*gen.DhcpResponse, error) {
+ leases, err := RunDhcp(ctx)
+ if err != nil {
+ r := &gen.DhcpResponse{
+ Error: &gen.Error{
+ Message: fmt.Sprintf("RunDhcp failed: %v", err),
+ },
+ }
+ return r, nil
+ }
+
+ r := &gen.DhcpResponse{
+ Leases: leases,
+ }
+ return r, nil
+}