Skip to content

Commit

Permalink
Peformance improvements, bug fixes, and reverse port forwarding (#23)
Browse files Browse the repository at this point in the history
* Replace DNAT with TCP Forwarder

* Use transport forwarders in place of DNAT

* Add option to disable ipv6

* Remove magic number check

* Fix flags

* Implement basic port forwarding

* Add basic reverse socks support

* Update README.md
  • Loading branch information
luker983 authored Jul 18, 2023
1 parent 7d43619 commit 1ddf48b
Show file tree
Hide file tree
Showing 22 changed files with 1,234 additions and 1,321 deletions.
66 changes: 55 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ In this diagram, the client has generated and installed WireGuard configuration

1. Download binaries from the [releases](https://github.com/sandialabs/wiretap/releases) page, one for your client machine and one for your server (if different os/arch)
2. Run `./wiretap configure --port <port> --endpoint <socket> --routes <routes>` with the appropriate arguments
3. Import the resulting `wiretap_relay.conf` and `wiretap_e2ee.conf` files into WireGuard on the client machine
3. Import the resulting `wiretap.conf` and `wiretap_relay.conf` files into WireGuard on the client machine
4. Copy and paste the server command output that best suits your target system into Wiretap on the server machine
5. Add more servers and clients as needed with the `add` subcommand

Expand Down Expand Up @@ -79,7 +79,7 @@ PublicKey = kMj7HwfYYFO/XEHNFK2kz9cBd7vTHk63fhygyuYLMzI=
AllowedIPs = 172.17.0.0/24,fd:17::/48
────────────────────────────────
config: wiretap_e2ee.conf
config: wiretap.conf
────────────────────────────────
[Interface]
PrivateKey = YCTRVwB4xOEcBtifVmhjMhRYL7+DOlDP5VdHZGclZGg=
Expand All @@ -105,12 +105,12 @@ Config File: ./wiretap serve -f wiretap_server.conf
> **Note**
> Wiretap uses 2 WireGuard interfaces per node in order to safely and scalably chain together servers. This means your client will bind to more than one port, but only the Relay Interface port needs to be accessible by the Server. See the [How It Works](#how-it-works) section for details. Use `--simple` if your setup requires a single interface on the client
Install the resulting config either by copying and pasting the output or by importing the new `wiretap_relay.conf` and `wiretap_e2ee.conf` files into WireGuard:
Install the resulting config either by copying and pasting the output or by importing the new `wiretap.conf` and `wiretap_relay.conf` files into WireGuard:

* If using a GUI, select the menu option similar to *Import Tunnel(s) From File*
* If you have `wg-quick` installed, `sudo wg-quick up ./wiretap_relay.conf` and `sudo wg-quick up ./wiretap_e2ee.conf`
* If you have `wg-quick` installed, `sudo wg-quick up ./wiretap.conf` and `sudo wg-quick up ./wiretap_relay.conf`

Don't forget to disable or remove the tunnels when you're done (e.g., `sudo wg-quick down ./wiretap_relay.conf` and `sudo wg-quick down ./wiretap_e2ee.conf`)
Don't forget to disable or remove the tunnels when you're done (e.g., `sudo wg-quick down ./wiretap.conf` and `sudo wg-quick down ./wiretap_relay.conf`)

### Deploy

Expand Down Expand Up @@ -176,7 +176,7 @@ If you plan to attach a server directly to the client, the status command just c
Configurations successfully generated.
Import the updated config(s) into WireGuard locally and pass the arguments below to Wiretap on the new remote server.
config: wiretap_e2ee.conf
config: wiretap.conf
────────────────────────────────
[Interface]
PrivateKey = YCTRVwB4xOEcBtifVmhjMhRYL7+DOlDP5VdHZGclZGg=
Expand All @@ -203,7 +203,7 @@ POSIX Shell: WIRETAP_RELAY_INTERFACE_PRIVATEKEY=sLERnxT2+VdwwcJOTUHK5fa5sIN7oJ1
Config File: ./wiretap serve -f wiretap_server_1.conf
```

The client's E2EE configuration will be modified, so you need to reimport it. For example, `wg-quick down ./wiretap_e2ee.conf` and `wg-quick up ./wiretap_e2ee.conf`. If you are attaching a server directly to the client, the Relay interface will also need to be refreshed.
The client's E2EE configuration will be modified, so you need to reimport it. For example, `wg-quick down ./wiretap.conf` and `wg-quick up ./wiretap.conf`. If you are attaching a server directly to the client, the Relay interface will also need to be refreshed.

Now you can use any of the server command options to deploy Wiretap to the new server. It will then connect to the already existing server.

Expand Down Expand Up @@ -258,7 +258,7 @@ The `add client` subcommand can be used to share access to the Wiretap network w
> **Note**
> All servers must be deployed *before* adding additional clients
Adding a client is very similar to the other commands. It will generate a `wiretap_relay.conf` and `wiretap_e2ee.conf` for sharing. Make sure that all of the first-hop servers (any server directly attached to the original client) can reach or be reached by the new client. Once you get the endpoint information from whoever will be running the new client run:
Adding a client is very similar to the other commands. It will generate a `wiretap.conf` and `wiretap_relay.conf` for sharing. Make sure that all of the first-hop servers (any server directly attached to the original client) can reach or be reached by the new client. Once you get the endpoint information from whoever will be running the new client run:

```bash
./wiretap add client --port 1337 --endpoint 1.3.3.8:1337
Expand All @@ -280,7 +280,7 @@ PublicKey = kMj7HwfYYFO/XEHNFK2kz9cBd7vTHk63fhygyuYLMzI=
AllowedIPs = 172.17.0.0/24,fd:17::/48
────────────────────────────────
config: wiretap_e2ee_1.conf
config: wiretap_1.conf
────────────────────────────────
[Interface]
PrivateKey = 8AhL1kDjwBn/IoY4KLd5mMP4GQsyMYNsqYm3aM/bHnE=
Expand All @@ -303,6 +303,46 @@ Endpoint = 172.17.0.3:51821

Send these files and have the recipient import them into WireGuard to have access to everything in the Wiretap network! By default the routes (AllowedIPs) are copied over, but can be modified by the recipient as needed.

### Port Forwarding

> **Warning**
> Port forwarding exposes services on your local machine to the remote network, use with caution
You can expose a service on the client by using the `expose` subcommand. For example, to allow remote systems to access port 80/tcp on your local machine, you could run:

```
./wiretap expose --local 80 --remote 8080
```

Now all Wiretap servers will be bound to port 8080/tcp and proxy connections to your services on port 80/tcp. By default this uses IPv6, so make sure any listening services support IPv6 as well.
To configure Wiretap to only use IPv4, use the `configure` subcommand's `--disable-ipv6` option.

To dynamically forward all ports using SOCKS5:

```
./wiretap expose --dynamic --remote 8080
```

All servers will spin up a SOCKS5 server on port 8080 and proxy traffic to your local machine and can be used like this:

```
curl -x socks5://<server-ip>:8080 http://<any-ip>:1337
```

The destination IP will be rewritten by the server so you can put any address.

#### List

Use `./wiretap expose list` to see all forwarding rules currently configured.

#### Remove

Use `./wiretap remove` with the same arguments used in `expose` to delete a rule. For example, to remove the SOCKS5 example above:

```
./wiretap expose remove --dynamic --remote 8080
```

## How It Works

A traditional VPN can't be installed by unprivileged users because VPNs rely on dangerous operations like changing network routes and working with raw packets.
Expand All @@ -329,6 +369,7 @@ Usage:
Available Commands:
add Add peer to wiretap
configure Build wireguard config
expose Expose local services to servers
help Help about any command
ping Ping wiretap server API
serve Listen and proxy traffic into target network
Expand All @@ -353,9 +394,12 @@ Use "wiretap [command] --help" for more information about a command.
- TCP
- Transparent connections
- RST response when port is unreachable
- Reverse Port Forward
- Reverse Socks5 Support
- UDP
- Transparent "connections"
- ICMP Destination Unreachable when port is unreachable
- Reverse Port Forward
* Application
- API internal to Wiretap for dynamic configuration
- Chain servers together to tunnel traffic through an arbitrary number of machines
Expand Down Expand Up @@ -460,7 +504,7 @@ Install the newly created WireGuard configs with:

```bash
wg-quick up ./wiretap_relay.conf
wg-quick up ./wiretap_e2ee.conf
wg-quick up ./wiretap.conf
```

Copy and paste the Wiretap arguments printed by the configure command into the server machine prompt. It should look like this:
Expand Down Expand Up @@ -540,7 +584,7 @@ To bring down the WireGuard interfaces on the client machine, run:

```bash
wg-quick down ./wiretap_relay.conf
wg-quick down ./wiretap_e2ee.conf
wg-quick down ./wiretap.conf
```

## Experimental
Expand Down
4 changes: 3 additions & 1 deletion demo.tape
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
#
# Run `socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"` before recording to enable clipboard operations
# If using XQuartz, also run `xhost + localhost`
#
# Postprocess with `ffmpeg -an -i wiretap_demo.mp4 -vf "scale=1600:-1,fps=30" -c:v libx264 -preset slow -crf 28 output.mp4`

Output media/wiretap_demo.mp4

Expand Down Expand Up @@ -103,7 +105,7 @@ Sleep 2s
Type "curl http://10.2.0.4 --connect-timeout 3" Sleep 1s Enter Sleep 6s
Type "./wiretap configure --endpoint 10.1.0.2:51820 --routes 10.2.0.0/16,fd:2::/64 -c" Sleep 1s Enter Sleep 4s
Type "wg-quick up ./wiretap_relay.conf" Sleep 1s Enter Sleep 2s
Type "wg-quick up ./wiretap_e2ee.conf" Sleep 1s Enter Sleep 2s
Type "wg-quick up ./wiretap.conf" Sleep 1s Enter Sleep 2s

Ctrl+b
Left
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ services:
depends_on:
- client
image: wiretap:latest
ports:
- "6060:6060"
networks:
exposed:
ipv4_address: 10.1.0.3
Expand Down
Binary file modified media/wiretap_demo.mp4
Binary file not shown.
71 changes: 71 additions & 0 deletions src/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,74 @@ func AddAllowedIPs(apiAddr netip.AddrPort, pubKey wgtypes.Key, allowedIPs []net.

return err
}

func Expose(apiAddr netip.AddrPort, localPort uint, remotePort uint, protocol string, dynamic bool) error {
req := serverapi.ExposeRequest{
Action: serverapi.ExposeActionExpose,
LocalPort: localPort,
RemotePort: remotePort,
Protocol: protocol,
Dynamic: dynamic,
}

body, err := json.Marshal(req)
if err != nil {
return err
}

_, err = makeRequest(request{
URL: makeUrl(apiAddr, "expose", []string{}),
Method: "POST",
Body: body,
})

return err
}

func ExposeList(apiAddr netip.AddrPort) ([]serverapi.ExposeTuple, error) {
req := serverapi.ExposeRequest{
Action: serverapi.ExposeActionList,
}

body, err := json.Marshal(req)
if err != nil {
return nil, err
}

body, err = makeRequest(request{
URL: makeUrl(apiAddr, "expose", []string{}),
Method: "POST",
Body: body,
})
if err != nil {
return nil, err
}

var tuples []serverapi.ExposeTuple
err = json.Unmarshal(body, &tuples)

return tuples, err
}

func ExposeDelete(apiAddr netip.AddrPort, localPort uint, remotePort uint, protocol string, dynamic bool) error {
req := serverapi.ExposeRequest{
Action: serverapi.ExposeActionDelete,
LocalPort: localPort,
RemotePort: remotePort,
Protocol: protocol,
Dynamic: dynamic,
}

body, err := json.Marshal(req)
if err != nil {
return err
}

_, err = makeRequest(request{
URL: makeUrl(apiAddr, "expose", []string{}),
Method: "POST",
Body: body,
})

return err
}
18 changes: 16 additions & 2 deletions src/cmd/add_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,29 @@ func (c addClientCmdConfig) Run() {
addresses, err := api.AllocateClientNode(apiAddrPort)
check("failed to retrieve address allocation from server", err)

disableV6 := false
if len(baseConfigE2EE.GetPeers()[0].GetAllowedIPs()) < 3 {
disableV6 = true
}

// Make new configs for client.
relayAddrs := []string{addresses.NextClientRelayAddr4.String() + "/32"}
if !disableV6 {
relayAddrs = append(relayAddrs, addresses.NextClientRelayAddr6.String()+"/128")
}
clientConfigRelay, err := peer.GetConfig(peer.ConfigArgs{
ListenPort: addCmdArgs.port,
Addresses: []string{addresses.NextClientRelayAddr4.String() + "/32", addresses.NextClientRelayAddr6.String() + "/128"},
Addresses: relayAddrs,
})
check("failed to generate client relay config", err)

e2eeAddrs := []string{addresses.NextClientE2EEAddr4.String() + "/32"}
if !disableV6 {
e2eeAddrs = append(e2eeAddrs, addresses.NextClientE2EEAddr6.String()+"/128")
}
clientConfigE2EE, err := peer.GetConfig(peer.ConfigArgs{
ListenPort: E2EEPort,
Addresses: []string{addresses.NextClientE2EEAddr4.String() + "/32", addresses.NextClientE2EEAddr6.String() + "/128"},
Addresses: e2eeAddrs,
MTU: c.mtu - 80,
})
check("failed to generate relay e2ee config", err)
Expand Down
Loading

0 comments on commit 1ddf48b

Please sign in to comment.