Skip to content

Commit 1ddf48b

Browse files
authored
Peformance improvements, bug fixes, and reverse port forwarding (#23)
* 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
1 parent 7d43619 commit 1ddf48b

22 files changed

+1234
-1321
lines changed

README.md

+55-11
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ In this diagram, the client has generated and installed WireGuard configuration
1616

1717
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)
1818
2. Run `./wiretap configure --port <port> --endpoint <socket> --routes <routes>` with the appropriate arguments
19-
3. Import the resulting `wiretap_relay.conf` and `wiretap_e2ee.conf` files into WireGuard on the client machine
19+
3. Import the resulting `wiretap.conf` and `wiretap_relay.conf` files into WireGuard on the client machine
2020
4. Copy and paste the server command output that best suits your target system into Wiretap on the server machine
2121
5. Add more servers and clients as needed with the `add` subcommand
2222

@@ -79,7 +79,7 @@ PublicKey = kMj7HwfYYFO/XEHNFK2kz9cBd7vTHk63fhygyuYLMzI=
7979
AllowedIPs = 172.17.0.0/24,fd:17::/48
8080
────────────────────────────────
8181
82-
config: wiretap_e2ee.conf
82+
config: wiretap.conf
8383
────────────────────────────────
8484
[Interface]
8585
PrivateKey = YCTRVwB4xOEcBtifVmhjMhRYL7+DOlDP5VdHZGclZGg=
@@ -105,12 +105,12 @@ Config File: ./wiretap serve -f wiretap_server.conf
105105
> **Note**
106106
> 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
107107
108-
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:
108+
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:
109109

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

113-
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`)
113+
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`)
114114

115115
### Deploy
116116

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

206-
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.
206+
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.
207207

208208
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.
209209

@@ -258,7 +258,7 @@ The `add client` subcommand can be used to share access to the Wiretap network w
258258
> **Note**
259259
> All servers must be deployed *before* adding additional clients
260260
261-
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:
261+
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:
262262

263263
```bash
264264
./wiretap add client --port 1337 --endpoint 1.3.3.8:1337
@@ -280,7 +280,7 @@ PublicKey = kMj7HwfYYFO/XEHNFK2kz9cBd7vTHk63fhygyuYLMzI=
280280
AllowedIPs = 172.17.0.0/24,fd:17::/48
281281
────────────────────────────────
282282
283-
config: wiretap_e2ee_1.conf
283+
config: wiretap_1.conf
284284
────────────────────────────────
285285
[Interface]
286286
PrivateKey = 8AhL1kDjwBn/IoY4KLd5mMP4GQsyMYNsqYm3aM/bHnE=
@@ -303,6 +303,46 @@ Endpoint = 172.17.0.3:51821
303303

304304
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.
305305

306+
### Port Forwarding
307+
308+
> **Warning**
309+
> Port forwarding exposes services on your local machine to the remote network, use with caution
310+
311+
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:
312+
313+
```
314+
./wiretap expose --local 80 --remote 8080
315+
```
316+
317+
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.
318+
To configure Wiretap to only use IPv4, use the `configure` subcommand's `--disable-ipv6` option.
319+
320+
To dynamically forward all ports using SOCKS5:
321+
322+
```
323+
./wiretap expose --dynamic --remote 8080
324+
```
325+
326+
All servers will spin up a SOCKS5 server on port 8080 and proxy traffic to your local machine and can be used like this:
327+
328+
```
329+
curl -x socks5://<server-ip>:8080 http://<any-ip>:1337
330+
```
331+
332+
The destination IP will be rewritten by the server so you can put any address.
333+
334+
#### List
335+
336+
Use `./wiretap expose list` to see all forwarding rules currently configured.
337+
338+
#### Remove
339+
340+
Use `./wiretap remove` with the same arguments used in `expose` to delete a rule. For example, to remove the SOCKS5 example above:
341+
342+
```
343+
./wiretap expose remove --dynamic --remote 8080
344+
```
345+
306346
## How It Works
307347

308348
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.
@@ -329,6 +369,7 @@ Usage:
329369
Available Commands:
330370
add Add peer to wiretap
331371
configure Build wireguard config
372+
expose Expose local services to servers
332373
help Help about any command
333374
ping Ping wiretap server API
334375
serve Listen and proxy traffic into target network
@@ -353,9 +394,12 @@ Use "wiretap [command] --help" for more information about a command.
353394
- TCP
354395
- Transparent connections
355396
- RST response when port is unreachable
397+
- Reverse Port Forward
398+
- Reverse Socks5 Support
356399
- UDP
357400
- Transparent "connections"
358401
- ICMP Destination Unreachable when port is unreachable
402+
- Reverse Port Forward
359403
* Application
360404
- API internal to Wiretap for dynamic configuration
361405
- Chain servers together to tunnel traffic through an arbitrary number of machines
@@ -460,7 +504,7 @@ Install the newly created WireGuard configs with:
460504

461505
```bash
462506
wg-quick up ./wiretap_relay.conf
463-
wg-quick up ./wiretap_e2ee.conf
507+
wg-quick up ./wiretap.conf
464508
```
465509

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

541585
```bash
542586
wg-quick down ./wiretap_relay.conf
543-
wg-quick down ./wiretap_e2ee.conf
587+
wg-quick down ./wiretap.conf
544588
```
545589

546590
## Experimental

demo.tape

+3-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
#
4444
# Run `socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"` before recording to enable clipboard operations
4545
# If using XQuartz, also run `xhost + localhost`
46+
#
47+
# Postprocess with `ffmpeg -an -i wiretap_demo.mp4 -vf "scale=1600:-1,fps=30" -c:v libx264 -preset slow -crf 28 output.mp4`
4648

4749
Output media/wiretap_demo.mp4
4850

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

108110
Ctrl+b
109111
Left

docker-compose.yml

+2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ services:
5555
depends_on:
5656
- client
5757
image: wiretap:latest
58+
ports:
59+
- "6060:6060"
5860
networks:
5961
exposed:
6062
ipv4_address: 10.1.0.3

media/wiretap_demo.mp4

-38.5 KB
Binary file not shown.

src/api/api.go

+71
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,74 @@ func AddAllowedIPs(apiAddr netip.AddrPort, pubKey wgtypes.Key, allowedIPs []net.
155155

156156
return err
157157
}
158+
159+
func Expose(apiAddr netip.AddrPort, localPort uint, remotePort uint, protocol string, dynamic bool) error {
160+
req := serverapi.ExposeRequest{
161+
Action: serverapi.ExposeActionExpose,
162+
LocalPort: localPort,
163+
RemotePort: remotePort,
164+
Protocol: protocol,
165+
Dynamic: dynamic,
166+
}
167+
168+
body, err := json.Marshal(req)
169+
if err != nil {
170+
return err
171+
}
172+
173+
_, err = makeRequest(request{
174+
URL: makeUrl(apiAddr, "expose", []string{}),
175+
Method: "POST",
176+
Body: body,
177+
})
178+
179+
return err
180+
}
181+
182+
func ExposeList(apiAddr netip.AddrPort) ([]serverapi.ExposeTuple, error) {
183+
req := serverapi.ExposeRequest{
184+
Action: serverapi.ExposeActionList,
185+
}
186+
187+
body, err := json.Marshal(req)
188+
if err != nil {
189+
return nil, err
190+
}
191+
192+
body, err = makeRequest(request{
193+
URL: makeUrl(apiAddr, "expose", []string{}),
194+
Method: "POST",
195+
Body: body,
196+
})
197+
if err != nil {
198+
return nil, err
199+
}
200+
201+
var tuples []serverapi.ExposeTuple
202+
err = json.Unmarshal(body, &tuples)
203+
204+
return tuples, err
205+
}
206+
207+
func ExposeDelete(apiAddr netip.AddrPort, localPort uint, remotePort uint, protocol string, dynamic bool) error {
208+
req := serverapi.ExposeRequest{
209+
Action: serverapi.ExposeActionDelete,
210+
LocalPort: localPort,
211+
RemotePort: remotePort,
212+
Protocol: protocol,
213+
Dynamic: dynamic,
214+
}
215+
216+
body, err := json.Marshal(req)
217+
if err != nil {
218+
return err
219+
}
220+
221+
_, err = makeRequest(request{
222+
URL: makeUrl(apiAddr, "expose", []string{}),
223+
Method: "POST",
224+
Body: body,
225+
})
226+
227+
return err
228+
}

src/cmd/add_client.go

+16-2
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,29 @@ func (c addClientCmdConfig) Run() {
7070
addresses, err := api.AllocateClientNode(apiAddrPort)
7171
check("failed to retrieve address allocation from server", err)
7272

73+
disableV6 := false
74+
if len(baseConfigE2EE.GetPeers()[0].GetAllowedIPs()) < 3 {
75+
disableV6 = true
76+
}
77+
7378
// Make new configs for client.
79+
relayAddrs := []string{addresses.NextClientRelayAddr4.String() + "/32"}
80+
if !disableV6 {
81+
relayAddrs = append(relayAddrs, addresses.NextClientRelayAddr6.String()+"/128")
82+
}
7483
clientConfigRelay, err := peer.GetConfig(peer.ConfigArgs{
7584
ListenPort: addCmdArgs.port,
76-
Addresses: []string{addresses.NextClientRelayAddr4.String() + "/32", addresses.NextClientRelayAddr6.String() + "/128"},
85+
Addresses: relayAddrs,
7786
})
7887
check("failed to generate client relay config", err)
88+
89+
e2eeAddrs := []string{addresses.NextClientE2EEAddr4.String() + "/32"}
90+
if !disableV6 {
91+
e2eeAddrs = append(e2eeAddrs, addresses.NextClientE2EEAddr6.String()+"/128")
92+
}
7993
clientConfigE2EE, err := peer.GetConfig(peer.ConfigArgs{
8094
ListenPort: E2EEPort,
81-
Addresses: []string{addresses.NextClientE2EEAddr4.String() + "/32", addresses.NextClientE2EEAddr6.String() + "/128"},
95+
Addresses: e2eeAddrs,
8296
MTU: c.mtu - 80,
8397
})
8498
check("failed to generate relay e2ee config", err)

0 commit comments

Comments
 (0)