Skip to content

Commit 54d3df4

Browse files
DennyDailuker983
andauthored
Add --config-file to serve (#7)
* Add --config-file to `serve` * use viper to support env var and config file * properly integrate viper with cobra * add viper * slightly better error message * set default option for --server-config-output * show config file option in configure output * add powershell command to the output * Tidy go.mod * Update docs and demo for new env arguments --------- Co-authored-by: Luke Rindels <lrindels@pm.me>
1 parent 8b5787b commit 54d3df4

File tree

11 files changed

+689
-92
lines changed

11 files changed

+689
-92
lines changed

README.md

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ In this diagram, the client has generated and installed a WireGuard configuratio
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
1919
3. Import the resulting `wiretap.conf` file into WireGuard on the client machine
20-
4. Copy and paste the arguments output from the configure command into Wiretap on the server machine
20+
4. Copy and paste the server command output that best suits your target system into Wiretap on the server machine
2121

2222
## Requirements
2323

@@ -62,20 +62,25 @@ Following the example in the diagram:
6262
Configuration successfully generated.
6363
Import the config into WireGuard locally and pass the arguments below to Wiretap on the remote machine.
6464
65-
config: wiretap.conf
65+
client config: wiretap.conf
6666
────────────────────────────────
6767
[Interface]
68-
PrivateKey = qCvx4DBXqemoO8B7eRI2H9Em8zJn++rIBKO+F+ufQWE=
68+
PrivateKey = 0PjJSe+uFvCGolet/WJN7EBXauB9jjUfNhdwk9i4Q2Q=
6969
Address = 192.168.0.2/32
7070
Address = fd::2/128
7171
ListenPort = 1337
7272
7373
[Peer]
74-
PublicKey = 6NxBlwJHujEFr5n9qvFAUyinj0l7Wadd/ZDQMCqTJAA=
74+
PublicKey = +xi5lM2V7nPwJ/02mF7CpK4pzgrtof2h1ykClkQqgnQ=
7575
AllowedIPs = 10.0.0.0/24,a::/128
7676
────────────────────────────────
7777
78-
args: serve --private qGrU0juci5PLJ1ydSufE/UwlErL/bqfcz6uWil705UU= --public ZhRIAcGVwT7l9dhEXv7cvYKwLxOZJR4bgU4zePZaT04= --endpoint 1.3.3.7:1337
78+
server config: wiretap_server.conf
79+
80+
server command:
81+
POSIX Shell: WIRETAP_INTERFACE_PRIVATEKEY=8O7ul6vWcdlcy515RD2kNwU2TRvEoe0UwCl1XjnFQ2Q= WIRETAP_PEER_PUBLICKEY=7QorkqrYFfSUpg+kw6ipFMee9d8r5BGmJprceluUzX8= WIRETAP_PEER_ENDPOINT=1.3.3.7:1337 ./wiretap serve
82+
PowerShell: $env:WIRETAP_INTERFACE_PRIVATEKEY="8O7ul6vWcdlcy515RD2kNwU2TRvEoe0UwCl1XjnFQ2Q="; $env:WIRETAP_PEER_PUBLICKEY="7QorkqrYFfSUpg+kw6ipFMee9d8r5BGmJprceluUzX8="; $env:WIRETAP_PEER_ENDPOINT="1.3.3.7:1337"; .\wiretap.exe serve
83+
Config File: ./wiretap serve -f wiretap_server.conf
7984
8085
```
8186

@@ -89,9 +94,13 @@ Don't forget to disable or remove the tunnel when you're done (e.g., `sudo wg-qu
8994
### Deploy
9095

9196
On the remote machine, upload the binary and then copy the command with the private and public keys to start Wiretap in server mode:
97+
```powershell
98+
$env:WIRETAP_INTERFACE_PRIVATEKEY="8O7ul6vWcdlcy515RD2kNwU2TRvEoe0UwCl1XjnFQ2Q="; $env:WIRETAP_PEER_PUBLICKEY="7QorkqrYFfSUpg+kw6ipFMee9d8r5BGmJprceluUzX8="; $env:WIRETAP_PEER_ENDPOINT="1.3.3.7:1337"; .\wiretap.exe serve
9299
```
93-
.\wiretap.exe serve --private qGrU0juci5PLJ1ydSufE/UwlErL/bqfcz6uWil705UU= --public ZhRIAcGVwT7l9dhEXv7cvYKwLxOZJR4bgU4zePZaT04= --endpoint 1.3.3.7:1337
94-
```
100+
101+
There are two other ways to pass arguments to the server:
102+
1. With a config file: `-f wiretap_server.conf`
103+
2. The legacy method of passing command line arguments (`--endpoint 1.3.3.7:1337 ...`). Be aware that this method exposes arguments to other users on the system. Compromising the private key could allow someone to connect to the client as a peer and/or decrypt traffic
95104

96105
Confirm that the client and server have successfully completed the handshake. The client should see a successful handshake in whatever WireGuard interface is running. If using the command-line tools, check with `wg show`.
97106

@@ -274,7 +283,7 @@ Configure Wiretap from the client machine. Remember, `--endpoint` is how the ser
274283
* `--routes` needs to be the subnet of the target network: `10.2.0.0/16`. But there is also an IPv6 subnet, so we should also put `fd:2::/64`. If you just wanted to route traffic to the target host, you could put `10.2.0.4/32` here instead
275284

276285
```bash
277-
./wiretap_linux_amd64 configure --endpoint 10.1.0.2:51820 --routes 10.2.0.0/16,fd:2::/64
286+
./wiretap configure --endpoint 10.1.0.2:51820 --routes 10.2.0.0/16,fd:2::/64
278287
```
279288

280289
Install the newly created WireGuard config with:
@@ -286,7 +295,7 @@ wg-quick up ./wiretap.conf
286295
Copy and paste the Wiretap arguments printed by the configure command into the server machine prompt. It should look like this:
287296

288297
```bash
289-
./wiretap_linux_amd64 serve --private <key> --public <key> --endpoint 10.1.0.2:51820
298+
WIRETAP_INTERFACE_PRIVATEKEY=<key> WIRETAP_PEER_PUBLICKEY=<key> WIRETAP_PEER_ENDPOINT=10.1.0.2:51820 ./wiretap serve
290299
```
291300

292301
#### Test
@@ -360,7 +369,7 @@ In this example, we're forwarding 51821/udp on the server to 51820 on the client
360369

361370
Finally, run Wiretap with the forwarded local port as your endpoint on the server system:
362371
```bash
363-
./wiretap serve --private <key> --public <key> --endpoint localhost:51821
372+
WIRETAP_INTERFACE_PRIVATEKEY=<key> WIRETAP_PEER_PUBLICKEY=<key> WIRETAP_PEER_ENDPOINT=localhost:51821 ./wiretap serve
364373
```
365374

366375
### Nested Tunnels

demo.tape

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
# Show Show the subsequent commands in the output
4343
#
4444
# Run `socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"` before recording to enable clipboard operations
45+
# If using XQuartz, also run `xhost + localhost`
4546

4647
Output media/wiretap_demo.mp4
4748

@@ -100,7 +101,7 @@ Sleep 2s
100101

101102
# show curl doesn't work, then configure wiretap
102103
Type "curl http://10.2.0.4 --connect-timeout 3" Sleep 1s Enter Sleep 6s
103-
Type "./wiretap_linux_arm64 configure --endpoint 10.1.0.2:51820 --routes 10.2.0.0/16,fd:2::/64 -c" Sleep 1s Enter Sleep 4s
104+
Type "./wiretap configure --endpoint 10.1.0.2:51820 --routes 10.2.0.0/16,fd:2::/64 -c" Sleep 1s Enter Sleep 4s
104105
Type "wg-quick up ./wiretap.conf" Sleep 1s Enter Sleep 2s
105106

106107
Ctrl+b
@@ -109,9 +110,8 @@ Sleep 2s
109110

110111
# args are in clipboard now
111112
# this is bash magic, ESC+Ctrl+E will expand the current line
112-
# type ./wiretap_linux_arm64 $(xsel)
113+
# type $(xsel)
113114
# run expansion to make command line look like it was pasted
114-
Type "./wiretap_linux_arm64 " Sleep 1s
115115
Hide
116116
Type "$(xsel)"
117117
Escape

media/wiretap_demo.mp4

24 KB
Binary file not shown.

src/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ else
2828
EXT=
2929
endif
3030

31+
OUTPUT=$(BIN)/$@_$(OS)_$(ARCH)$(EXT)## Output location
32+
3133
# ld flags
3234
LDFLAGS=-s -w
3335
LDFLAGS+=-X wiretap/cmd.Version=$(VERSION)
@@ -37,7 +39,7 @@ LDFLAGS+=-X wiretap/cmd.Version=$(VERSION)
3739

3840
## wiretap: Build binary for the specified OS and architecture
3941
wiretap:
40-
$(ENV) $(GOBUILD) $(NOARGFLAGS) -o $(BIN)/$@_$(OS)_$(ARCH)$(EXT) -ldflags "$(LDFLAGS)" *.go
42+
$(ENV) $(GOBUILD) $(NOARGFLAGS) -o $(OUTPUT) -ldflags "$(LDFLAGS)" *.go
4143

4244
## all: Build binaries for every OS/ARCH pair listed in the Makefile
4345
all:

src/cmd/configure.go

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type configureCmdConfig struct {
1717
endpoint string
1818
port int
1919
configFile string
20+
serverConfigFile string
2021
writeToClipboard bool
2122
addr4 string
2223
addr6 string
@@ -31,13 +32,31 @@ var configureCmd = configureCmdConfig{
3132
endpoint: Endpoint,
3233
port: Port,
3334
configFile: Config,
35+
serverConfigFile: ServerConfig,
3436
writeToClipboard: false,
3537
addr4: Subnet4.Addr().Next().Next().String() + "/32",
3638
addr6: Subnet6.Addr().Next().Next().String() + "/128",
3739
apiAddr: ApiAddr.String(),
3840
disableApi: false,
3941
}
4042

43+
// Check if file exists, add number suffix if it does.
44+
func getUniqueFilename(filename string) string {
45+
var err error
46+
count := 1
47+
ext := filepath.Ext(filename)
48+
basename := strings.TrimSuffix(filename, ext)
49+
for {
50+
_, err = os.Stat(filename)
51+
if os.IsNotExist(err) {
52+
break
53+
}
54+
filename = fmt.Sprintf("%s_%d%s", basename, count, ext)
55+
count += 1
56+
}
57+
return filename
58+
}
59+
4160
// Add command and set flags.
4261
func init() {
4362
// Usage info.
@@ -56,6 +75,7 @@ func init() {
5675
cmd.Flags().StringVarP(&configureCmd.endpoint, "endpoint", "e", configureCmd.endpoint, "socket address of wireguard listener that server will connect to (example \"1.2.3.4:51820\")")
5776
cmd.Flags().IntVarP(&configureCmd.port, "port", "p", configureCmd.port, "port of local wireguard listener")
5877
cmd.Flags().StringVarP(&configureCmd.configFile, "output", "o", configureCmd.configFile, "wireguard config output filename")
78+
cmd.Flags().StringVarP(&configureCmd.serverConfigFile, "server-config-output", "s", configureCmd.serverConfigFile, "wiretap server config output filename")
5979
cmd.Flags().BoolVarP(&configureCmd.writeToClipboard, "clipboard", "c", configureCmd.writeToClipboard, "copy configuration args to clipboard")
6080

6181
cmd.Flags().StringVarP(&configureCmd.addr4, "ipv4", "4", configureCmd.addr4, "virtual wireguard interface ipv4 address")
@@ -104,41 +124,29 @@ func (c configureCmdConfig) Run() {
104124
config, err := peer.GetConfig(configArgs)
105125
check("failed to generate config", err)
106126

107-
// Add number to filename if it already exists.
108-
count := 1
109-
ext := filepath.Ext(c.configFile)
110-
basename := strings.TrimSuffix(c.configFile, ext)
111-
for {
112-
_, err = os.Stat(c.configFile)
113-
if os.IsNotExist(err) {
114-
break
115-
}
116-
c.configFile = fmt.Sprintf("%s_%d%s", basename, count, ext)
117-
count += 1
118-
}
119-
120127
// Write config file and get status string.
128+
c.configFile = getUniqueFilename(c.configFile)
121129
var fileStatus string
122130
err = os.WriteFile(c.configFile, []byte(config.AsFile()), 0600)
123131
if err != nil {
124-
fileStatus = fmt.Sprintf("%s %s", RedBold("config:"), Red(fmt.Sprintf("error writing config file: %v", err)))
132+
fileStatus = fmt.Sprintf("%s %s", RedBold("client config:"), Red(fmt.Sprintf("error writing config file: %v", err)))
125133
} else {
126-
fileStatus = fmt.Sprintf("%s %s", GreenBold("config:"), Green(c.configFile))
134+
fileStatus = fmt.Sprintf("%s %s", GreenBold("client config:"), Green(c.configFile))
127135
}
128136

129-
// Generate argument string.
130-
argString := fmt.Sprintf("serve --private %s --public %s",
131-
config.GetPeerPrivateKey(0),
132-
config.GetPublicKey(),
133-
)
134-
135-
if len(config.GetPeerEndpoint(0)) > 0 {
136-
argString = fmt.Sprintf("%s --endpoint %s", argString, config.GetPeerEndpoint(0))
137+
// Write server config file and get status string.
138+
c.serverConfigFile = getUniqueFilename(c.serverConfigFile)
139+
var serverFileStatus string
140+
err = os.WriteFile(c.serverConfigFile, []byte(config.AsServerFile()), 0600)
141+
if err != nil {
142+
serverFileStatus = fmt.Sprintf("%s %s", RedBold("server config:"), Red(fmt.Sprintf("error writing config file: %v", err)))
143+
} else {
144+
serverFileStatus = fmt.Sprintf("%s %s", GreenBold("server config:"), Green(c.serverConfigFile))
137145
}
138146

139147
var clipboardStatus string
140148
if c.writeToClipboard {
141-
err = clipboard.WriteAll(argString)
149+
err = clipboard.WriteAll(config.AsServerCommand("POSIX"))
142150
if err != nil {
143151
clipboardStatus = fmt.Sprintf("%s %s", RedBold("clipboard:"), Red(fmt.Sprintf("error copying to clipboard: %v", err)))
144152
} else {
@@ -156,7 +164,12 @@ func (c configureCmdConfig) Run() {
156164
fmt.Fprint(color.Output, WhiteBold(config.AsFile()))
157165
fmt.Fprintln(color.Output, Green(strings.Repeat("─", 32)))
158166
fmt.Fprintln(color.Output)
159-
fmt.Fprintln(color.Output, GreenBold("args:"), Green(argString))
167+
fmt.Fprintln(color.Output, serverFileStatus)
168+
fmt.Fprintln(color.Output)
169+
fmt.Fprintln(color.Output, GreenBold("server command:"))
170+
fmt.Fprintln(color.Output, Cyan("POSIX Shell: "), Green(config.AsServerCommand("POSIX")))
171+
fmt.Fprintln(color.Output, Cyan(" PowerShell: "), Green(config.AsServerCommand("POWERSHELL")))
172+
fmt.Fprintln(color.Output, Cyan("Config File: "), Green("./wiretap serve -f " + c.serverConfigFile))
160173
fmt.Fprintln(color.Output)
161174
if c.writeToClipboard {
162175
fmt.Fprintln(color.Output, clipboardStatus)

src/cmd/root.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@ import (
1313

1414
// Defaults shared by multiple commands.
1515
var (
16-
Version = "v0.0.0"
17-
Endpoint = ""
18-
Port = 51820
19-
Config = "wiretap.conf"
20-
Keepalive = 25
21-
ShowHidden = false
22-
ApiAddr = netip.MustParsePrefix("a::/128")
23-
ApiPort = 80
24-
Subnet4 = netip.MustParsePrefix("192.168.0.0/24")
25-
Subnet6 = netip.MustParsePrefix("fd::/64")
16+
Version = "v0.0.0"
17+
Endpoint = ""
18+
Port = 51820
19+
Config = "wiretap.conf"
20+
ServerConfig = "wiretap_server.conf"
21+
Keepalive = 25
22+
ShowHidden = false
23+
ApiAddr = netip.MustParsePrefix("a::/128")
24+
ApiPort = 80
25+
Subnet4 = netip.MustParsePrefix("192.168.0.0/24")
26+
Subnet6 = netip.MustParsePrefix("fd::/64")
2627
)
2728

2829
// Define colors.

0 commit comments

Comments
 (0)