summaryrefslogtreecommitdiffhomepage
path: root/tunnel/tools
diff options
context:
space:
mode:
authorMikael Magnusson <mikma@users.sourceforge.net>2023-02-11 22:24:31 +0100
committerMikael Magnusson <mikma@users.sourceforge.net>2023-07-05 21:41:01 +0200
commite67511cbb2d37f38b54e3c917b26a69bd0737bca (patch)
tree88a041397e936845aa2ef0e0bc1f20094a1ae169 /tunnel/tools
parente430fd583fff78056f1af79b17684a2ea3025d0f (diff)
tunnel: request DHCPv6 leases
Diffstat (limited to 'tunnel/tools')
-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.go192
-rw-r--r--tunnel/tools/libwg-go/jni.c6
-rw-r--r--tunnel/tools/libwg-go/service.go63
5 files changed, 283 insertions, 2 deletions
diff --git a/tunnel/tools/libwg-go/Makefile b/tunnel/tools/libwg-go/Makefile
index 9bec6fdc..5ae4548d 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 -buildid=" -v -trimpath -buildvcs=false -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 484a89b0..943ba628 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
@@ -143,10 +144,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
new file mode 100644
index 00000000..b7919151
--- /dev/null
+++ b/tunnel/tools/libwg-go/dhcp.go
@@ -0,0 +1,192 @@
+package main
+
+import (
+ "context"
+ "net"
+ "net/netip"
+ "time"
+
+ "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 = true
+)
+
+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 {
+ iaid := []byte{0, 0, 0, 3}
+ ident := []byte{255} // Type IAID+DUID
+ ident = append(ident, iaid...) // IAID
+ ident = append(ident, duid.ToBytes()...) // DUID
+ return dhcpv4.OptClientIdentifier(ident)
+}
+
+func getDuid(hwAddr net.HardwareAddr) dhcpv6.DUID {
+ duid := &dhcpv6.DUIDLLT{
+ HWType: iana.HWTypeEthernet,
+ Time: uint32(time.Now().Unix()),
+ LinkLayerAddr: hwAddr,
+ }
+
+ return duid
+}
+
+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
+ }
+
+ relay, err := d.client.SendAndReadRelay(ctx, &d.serverAddr, packet, match)
+ if err != nil {
+ return nil, err
+ }
+
+ inner, err := relay.GetInnerMessage()
+ if err != nil {
+ return nil, err
+ }
+
+ return inner, nil
+}
+
+// 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
+ }
+ for _, mt := range tt {
+ if inner.Type() == mt {
+ return true
+ }
+ }
+ return false
+ }
+}
+
+// func New() *dhcp {
+// }
+
+func RunDhcp(ctx context.Context, laddr, raddr netip.Addr) ([]*gen.Lease, error) {
+ d := &dhcp{}
+
+ d.linkAddr = net.ParseIP("fe80::101")
+ d.peerAddr = net.ParseIP("::1")
+
+ // TODO generate hostname and hwAddr from public key
+ hostName := "foobar"
+ d.fqdn = hostName + ".m7n.se"
+ d.hwAddr = []byte{41, 42, 43, 44, 45, 46}
+
+
+ src := net.UDPAddr{IP: laddr.AsSlice(),
+ Port: 0, // Use non-restrict UDP source port
+ }
+
+
+ d.serverAddr = net.UDPAddr{IP: raddr.AsSlice(),
+ Port: 547,
+ }
+
+ err := d.Start(&src)
+ if err != nil {
+ return nil, err
+ }
+
+ defer d.Close()
+
+ reply, err := d.ObtainLease(ctx) // Use reply
+ if err != nil {
+ return nil, err
+ }
+
+ return getAddressesFromReply(reply), nil
+}
+
+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
+}
+
+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
+}
+
+func (d *dhcp) Close() error {
+ err := d.client.Close()
+
+ d.client = nil
+ return err
+}
+
+func (d *dhcp) ObtainLease(ctx context.Context) (*dhcpv6.Message, error){
+ duidOpt := dhcpv6.WithClientID(getDuid(d.hwAddr))
+ fqdnOpt := dhcpv6.WithFQDN(0x1, d.fqdn)
+
+ solicit, err := dhcpv6.NewSolicit(d.hwAddr, duidOpt, fqdnOpt, dhcpv6.WithRapidCommit)
+ if err != nil {
+ return nil, err
+ }
+
+ msg, err := d.encapSendAndRead(ctx, solicit, isRelayMessageType(dhcpv6.MessageTypeReply, dhcpv6.MessageTypeAdvertise))
+ if err != nil {
+ return nil, err
+ }
+
+ 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 d.encapSendAndRead(ctx, req, nil)
+}
diff --git a/tunnel/tools/libwg-go/jni.c b/tunnel/tools/libwg-go/jni.c
index b386579c..443848e8 100644
--- a/tunnel/tools/libwg-go/jni.c
+++ b/tunnel/tools/libwg-go/jni.c
@@ -16,6 +16,7 @@ extern char *wgGetConfig(int handle);
extern char *wgVersion();
extern int wgSetConfig(int handle, struct go_string settings);
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)
{
@@ -95,3 +96,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 72916a8e..30fe650b 100644
--- a/tunnel/tools/libwg-go/service.go
+++ b/tunnel/tools/libwg-go/service.go
@@ -5,6 +5,7 @@ import (
"fmt"
"io"
"net"
+ "net/netip"
"net/url"
"os"
@@ -224,3 +225,65 @@ func (e *LibwgServiceImpl) Reverse(stream gen.Libwg_ReverseServer) error {
e.logger.Verbosef("Reverse returns")
return nil
}
+
+func (e *LibwgServiceImpl) Dhcp(ctx context.Context, req *gen.DhcpRequest) (*gen.DhcpResponse, error) {
+ var relayAddr netip.Addr
+ var sourceAddr netip.Addr
+
+ source := req.GetSource()
+ if source != nil {
+ sourceAddr, _ = netip.AddrFromSlice(source.GetAddress())
+ }
+
+ if !sourceAddr.IsValid() || !sourceAddr.Is6() {
+ r := &gen.DhcpResponse{
+ Error: &gen.Error{
+ Message: fmt.Sprintf("DHCPv6 source address missing"),
+ },
+ }
+ return r, nil
+ }
+
+ relay := req.GetRelay()
+ if relay != nil {
+ relayAddr, _ = netip.AddrFromSlice(relay.GetAddress())
+ } else {
+ // Construct relay address from source prefix
+ relayRaw := source.GetAddress()[:8]
+ relayRaw = append(relayRaw, 0)
+ relayRaw = append(relayRaw, 0)
+ relayRaw = append(relayRaw, 0)
+ relayRaw = append(relayRaw, 0)
+ relayRaw = append(relayRaw, 0)
+ relayRaw = append(relayRaw, 0)
+ relayRaw = append(relayRaw, 0)
+ relayRaw = append(relayRaw, 1)
+ relayAddr, _ = netip.AddrFromSlice(relayRaw)
+ }
+
+ if !relayAddr.IsValid() || !relayAddr.Is6() {
+ r := &gen.DhcpResponse{
+ Error: &gen.Error{
+ Message: fmt.Sprintf("DHCPv6 relay address calculation failed"),
+ },
+ }
+ return r, nil
+ }
+
+ e.logger.Verbosef("RunDhcp %v %v", sourceAddr, relayAddr)
+
+ leases, err := RunDhcp(ctx, sourceAddr, relayAddr)
+ 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
+}