chore: make wireguard work over webrtc

This commit is contained in:
braginini
2021-11-16 14:36:24 +01:00
parent f0a0888046
commit b35dcd21df
8 changed files with 113 additions and 80 deletions

View File

@@ -1,3 +1,3 @@
run:
GOOS=js GOARCH=wasm go build -o assets/tun.wasm ./wasm/
GOOS=js GOARCH=wasm go build -o assets/client.wasm ./client/
go run main.go

View File

@@ -4,7 +4,7 @@
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("tun.wasm"), go.importObject).then((result) => {
WebAssembly.instantiateStreaming(fetch("client.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});
</script>
@@ -14,16 +14,16 @@
<input type=button value="Generate Public Key" onclick='generateWireguardKey()'>
</p>
<label for="wgPrivateKey">Wireguard private key:</label>
<input id="wgPrivateKey" type=input size="50" value="">
<input id="wgPrivateKey" type=input size="50" value="qJi7zSrgdokeoXE27fbca2hvMlgg1NQIW6KbrTJhhmc=">
</p>
<label for="publicKey">Wireguard Public Key:</label>
<input id="publicKey" type=input size="50" value="">
<input id="publicKey" type=input size="50" value="6M9O7PRhKMEOiboBp9cX6rNrLBevtHX7H0O2FMXUkFI=">
<p/>
<label for="wgIp">Wireguard private IP:</label>
<input id="wgIp" type=input size="50" value="10.0.0.2/24">
<p/>
<label for="peerKey">Wireguard Peer Public key:</label>
<input id="peerKey" type=input size="50" value="aaWf6mtEgamDgCmSCt2/6Y7aV8j6p6a0nw2GOUbBKwY=">
<input id="peerKey" type=input size="50" value="RFuT84MDhIvmgQndwMkxQPjG195poq713EMJZv1XPEw=">
<p/>
<label for="peerAllowedIPs">Wireguard Peer AllowedIPs:</label>
<input id="peerAllowedIPs" type=input size="50" value="Paste other peer AllowedIPs">

Binary file not shown.

View File

@@ -9,10 +9,8 @@ import (
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun/netstack"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"io"
"log"
"net"
"net/http"
"syscall/js"
"time"
)
@@ -32,15 +30,15 @@ func main() {
defer cancel()
connectToSignal := func(key wgtypes.Key, remoteKey wgtypes.Key) {
signalClient, err := client.NewWebsocketClient(ctx, "ws://apitest.wiretrustee.com:80/signal", key)
signalClient, err := client.NewWebsocketClient(ctx, "ws://localhost:80/signal", key)
if err != nil {
return
}
time.Sleep(5 * time.Second)
tun, tnet, err := netstack.CreateNetTUN(
[]net.IP{net.ParseIP("10.100.0.2")},
tun, _, err := netstack.CreateNetTUN(
[]net.IP{net.ParseIP("10.100.0.1")},
[]net.IP{net.ParseIP("8.8.8.8")},
1420)
@@ -63,12 +61,13 @@ func main() {
log.Printf("device started")
client := http.Client{
/*client := http.Client{
Transport: &http.Transport{
DialContext: tnet.DialContext,
},
}
req, _ := http.NewRequest("GET", "http://apitest.wiretrustee.com:9090/", nil)
time.Sleep(2 * time.Second)
req, _ := http.NewRequest("GET", "https://httpbin.org/ip", nil)
req.Header.Set("js.fetch:mode", "no-cors")
resp, err := client.Do(req)
if err != nil {
@@ -78,7 +77,8 @@ func main() {
if err != nil {
log.Panic(err)
}
log.Println(string(body))
log.Printf(string(body))
log.Printf(resp.Status)*/
select {}
}

View File

@@ -14,6 +14,8 @@ import (
"time"
)
const initDataChannelName = "wiretrustee-init"
func (*WebRTCBind) makeReceive(dcConn net.Conn) conn.ReceiveFunc {
return func(buff []byte) (int, conn.Endpoint, error) {
log.Printf("receiving from endpoint %s", dcConn.RemoteAddr().String())
@@ -21,8 +23,8 @@ func (*WebRTCBind) makeReceive(dcConn net.Conn) conn.ReceiveFunc {
if err != nil {
return 0, nil, err
}
addr := dcConn.RemoteAddr().(*DataChannelAddr)
return n, (*WebRTCEndpoint)(addr), err
//addr := dcConn.RemoteAddr().(DataChannelAddr)
return n, &WebRTCEndpoint{}, err
}
}
@@ -59,6 +61,9 @@ func NewWebRTCBind(id string, signal signal.Client, pubKey string, remotePubKey
// blocks until channel was successfully opened
func (bind *WebRTCBind) acceptDC() (stream net.Conn, err error) {
for dc := range bind.incoming {
if dc.Label() == initDataChannelName {
continue
}
stream, err := WrapDataChannel(dc)
if err != nil {
dc.Close()
@@ -125,13 +130,14 @@ func (bind *WebRTCBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort ui
})
bind.pc.OnDataChannel(func(dc *webrtc.DataChannel) {
log.Printf("received channel %s %v", dc.Label(), dc)
bind.incoming <- dc
})
controlling := bind.key < bind.remoteKey
// decision who is creating an offer
if controlling {
_, err = bind.pc.CreateDataChannel(bind.id, nil)
_, err = bind.pc.CreateDataChannel(initDataChannelName, nil)
if err != nil {
return nil, 0, err
}
@@ -152,7 +158,6 @@ func (bind *WebRTCBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort ui
case <-bind.closeCond.C:
return nil, 0, fmt.Errorf("closed while waiting for WebRTC candidates")
}
log.Printf("candidates gathered")
err = bind.signal.Send(&proto.Message{
@@ -236,7 +241,7 @@ func (bind *WebRTCBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort ui
}
select {
case <-time.After(30 * time.Second):
case <-time.After(10 * time.Second):
return nil, 0, fmt.Errorf("failed to connect in time: %w", err)
case <-connected.C:
}
@@ -257,7 +262,7 @@ func (bind *WebRTCBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort ui
}
bind.conn = dcConn
fns = append(fns, bind.makeReceive(bind.conn))
return fns, 38676, nil
return fns, 0, nil
}
@@ -303,10 +308,11 @@ func (*WebRTCBind) SetMark(mark uint32) error {
}
func (bind *WebRTCBind) Send(b []byte, ep conn.Endpoint) error {
_, err := bind.conn.Write(b)
n, err := bind.conn.Write(b)
if err != nil {
return err
}
log.Printf("wrote %d bytes", n)
return nil
}

View File

@@ -7,6 +7,7 @@ import (
"errors"
"github.com/pion/webrtc/v3"
"io"
"log"
"net"
"time"
)
@@ -56,6 +57,7 @@ func WrapDataChannel(rtcDataChannel *webrtc.DataChannel) (*DataChannelConn, erro
conn.openCond.Signal()
})
conn.dc.OnMessage(func(msg webrtc.DataChannelMessage) {
log.Printf("received message from data channel %d", len(msg.Data))
if rw != nil {
_, err := rw.Write(msg.Data)
if err != nil {
@@ -84,6 +86,7 @@ func (dc *DataChannelConn) Read(b []byte) (n int, err error) {
func (dc *DataChannelConn) Write(b []byte) (n int, err error) {
err = dc.dc.Send(b)
log.Printf("writing to channel %s %v", dc.dc.Label(), dc.dc)
if err != nil {
return 0, err
}
@@ -165,6 +168,7 @@ func (cr ContextReadCloser) SetReadDeadline(t time.Time) error {
}
func (cr ContextReadCloser) Read(p []byte) (n int, err error) {
log.Printf("reading bytes ro buf of len %d", len(p))
done := make(chan struct{})
go func() {
n, err = cr.ReadCloser.Read(p)

View File

@@ -1,60 +0,0 @@
package main
import (
"encoding/hex"
"fmt"
"io"
"log"
"net"
"net/http"
"time"
"golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun/netstack"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
func main() {
tun, tnet, err := netstack.CreateNetTUN(
[]net.IP{net.ParseIP("10.100.0.2")},
[]net.IP{net.ParseIP("8.8.8.8")},
1420)
if err != nil {
log.Panic(err)
}
clientKey,_ := wgtypes.ParseKey("WI+uoQD9jGi+nyifmFwmswQu5r0uWFH31WeSmfU0snI=")
serverKey,_ := wgtypes.ParseKey("kLpbgt+g2+g8x556VmsLYyhTh77WmKfaFB0x+LcVyWY=")
publicServerkey := serverKey.PublicKey()
dev := device.NewDevice(tun, conn.NewDefaultBind(), device.NewLogger(device.LogLevelVerbose, ""))
err = dev.IpcSet(fmt.Sprintf("private_key=%s\npublic_key=%s\npersistent_keepalive_interval=5\nendpoint=65.108.52.126:50000\nallowed_ip=0.0.0.0/0",
hex.EncodeToString(clientKey[:]),
hex.EncodeToString(publicServerkey[:]),
))
if err != nil {
log.Panic(err)
}
err = dev.Up()
if err != nil {
log.Panic(err)
}
client := http.Client{
Transport: &http.Transport{
DialContext: tnet.DialContext,
},
}
resp, err := client.Get("https://www.zx2c4.com/ip")
if err != nil {
log.Panic(err)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Panic(err)
}
log.Println(string(body))
time.Sleep(30 * time.Second)
}

83
browser/server/server.go Normal file
View File

@@ -0,0 +1,83 @@
package main
import (
"context"
"encoding/hex"
"flag"
"fmt"
"github.com/wiretrustee/wiretrustee/browser/conn"
"github.com/wiretrustee/wiretrustee/signal/client"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun/netstack"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"io"
"log"
"net"
"net/http"
"time"
)
//my private key qJi7zSrgdokeoXE27fbca2hvMlgg1NQIW6KbrTJhhmc=
//remote private key KLuBc6tM/NRV1071bfPiNUxZmMhGBCXfxoDg+A+J7ns=
func main() {
keyFlag := flag.String("key", "", "a Wireguard private key")
remoteKeyFlag := flag.String("remote-key", "", "a Wireguard remote peer public key")
signalEndpoint := flag.String("signal-endpoint", "ws://apitest.wiretrustee.com:80/signal", "a Signal service Websocket endpoint")
flag.Parse()
key, err := wgtypes.ParseKey(*keyFlag)
if err != nil {
panic(err)
}
log.Printf("my public key: %s", key.PublicKey().String())
remoteKey, err := wgtypes.ParseKey(*remoteKeyFlag)
if err != nil {
panic(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
time.Sleep(5 * time.Second)
signal, err := client.NewWebsocketClient(ctx, *signalEndpoint, key)
tun, tnet, err := netstack.CreateNetTUN(
[]net.IP{net.ParseIP("10.100.0.2")},
[]net.IP{net.ParseIP("8.8.8.8")},
1420)
b := conn.NewWebRTCBind("chann-1", signal, key.PublicKey().String(), remoteKey.String())
dev := device.NewDevice(tun, b, device.NewLogger(device.LogLevelVerbose, ""))
err = dev.IpcSet(fmt.Sprintf("private_key=%s\npublic_key=%s\npersistent_keepalive_interval=10\nendpoint=webrtc://datachannel\nallowed_ip=0.0.0.0/0",
hex.EncodeToString(key[:]),
hex.EncodeToString(remoteKey[:]),
))
dev.Up()
if err != nil {
panic(err)
}
listener, err := tnet.ListenTCP(&net.TCPAddr{Port: 80})
if err != nil {
log.Panicln(err)
}
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
log.Printf("> %s - %s - %s", request.RemoteAddr, request.URL.String(), request.UserAgent())
io.WriteString(writer, "Hello from userspace TCP!")
})
err = http.Serve(listener, nil)
if err != nil {
log.Panicln(err)
}
select {}
}