Skip to content

Commit

Permalink
Add --config-file to serve (#7)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
DennyDai and luker983 authored Mar 23, 2023
1 parent 8b5787b commit 54d3df4
Show file tree
Hide file tree
Showing 11 changed files with 689 additions and 92 deletions.
29 changes: 19 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ In this diagram, the client has generated and installed a WireGuard configuratio
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.conf` file into WireGuard on the client machine
4. Copy and paste the arguments output from the configure command into Wiretap on the server machine
4. Copy and paste the server command output that best suits your target system into Wiretap on the server machine

## Requirements

Expand Down Expand Up @@ -62,20 +62,25 @@ Following the example in the diagram:
Configuration successfully generated.
Import the config into WireGuard locally and pass the arguments below to Wiretap on the remote machine.
config: wiretap.conf
client config: wiretap.conf
────────────────────────────────
[Interface]
PrivateKey = qCvx4DBXqemoO8B7eRI2H9Em8zJn++rIBKO+F+ufQWE=
PrivateKey = 0PjJSe+uFvCGolet/WJN7EBXauB9jjUfNhdwk9i4Q2Q=
Address = 192.168.0.2/32
Address = fd::2/128
ListenPort = 1337
[Peer]
PublicKey = 6NxBlwJHujEFr5n9qvFAUyinj0l7Wadd/ZDQMCqTJAA=
PublicKey = +xi5lM2V7nPwJ/02mF7CpK4pzgrtof2h1ykClkQqgnQ=
AllowedIPs = 10.0.0.0/24,a::/128
────────────────────────────────
args: serve --private qGrU0juci5PLJ1ydSufE/UwlErL/bqfcz6uWil705UU= --public ZhRIAcGVwT7l9dhEXv7cvYKwLxOZJR4bgU4zePZaT04= --endpoint 1.3.3.7:1337
server config: wiretap_server.conf
server command:
POSIX Shell: WIRETAP_INTERFACE_PRIVATEKEY=8O7ul6vWcdlcy515RD2kNwU2TRvEoe0UwCl1XjnFQ2Q= WIRETAP_PEER_PUBLICKEY=7QorkqrYFfSUpg+kw6ipFMee9d8r5BGmJprceluUzX8= WIRETAP_PEER_ENDPOINT=1.3.3.7:1337 ./wiretap serve
PowerShell: $env:WIRETAP_INTERFACE_PRIVATEKEY="8O7ul6vWcdlcy515RD2kNwU2TRvEoe0UwCl1XjnFQ2Q="; $env:WIRETAP_PEER_PUBLICKEY="7QorkqrYFfSUpg+kw6ipFMee9d8r5BGmJprceluUzX8="; $env:WIRETAP_PEER_ENDPOINT="1.3.3.7:1337"; .\wiretap.exe serve
Config File: ./wiretap serve -f wiretap_server.conf
```

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

On the remote machine, upload the binary and then copy the command with the private and public keys to start Wiretap in server mode:
```powershell
$env:WIRETAP_INTERFACE_PRIVATEKEY="8O7ul6vWcdlcy515RD2kNwU2TRvEoe0UwCl1XjnFQ2Q="; $env:WIRETAP_PEER_PUBLICKEY="7QorkqrYFfSUpg+kw6ipFMee9d8r5BGmJprceluUzX8="; $env:WIRETAP_PEER_ENDPOINT="1.3.3.7:1337"; .\wiretap.exe serve
```
.\wiretap.exe serve --private qGrU0juci5PLJ1ydSufE/UwlErL/bqfcz6uWil705UU= --public ZhRIAcGVwT7l9dhEXv7cvYKwLxOZJR4bgU4zePZaT04= --endpoint 1.3.3.7:1337
```

There are two other ways to pass arguments to the server:
1. With a config file: `-f wiretap_server.conf`
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

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`.

Expand Down Expand Up @@ -274,7 +283,7 @@ Configure Wiretap from the client machine. Remember, `--endpoint` is how the ser
* `--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

```bash
./wiretap_linux_amd64 configure --endpoint 10.1.0.2:51820 --routes 10.2.0.0/16,fd:2::/64
./wiretap configure --endpoint 10.1.0.2:51820 --routes 10.2.0.0/16,fd:2::/64
```

Install the newly created WireGuard config with:
Expand All @@ -286,7 +295,7 @@ 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:

```bash
./wiretap_linux_amd64 serve --private <key> --public <key> --endpoint 10.1.0.2:51820
WIRETAP_INTERFACE_PRIVATEKEY=<key> WIRETAP_PEER_PUBLICKEY=<key> WIRETAP_PEER_ENDPOINT=10.1.0.2:51820 ./wiretap serve
```

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

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

### Nested Tunnels
Expand Down
6 changes: 3 additions & 3 deletions demo.tape
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
# Show Show the subsequent commands in the output
#
# Run `socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"` before recording to enable clipboard operations
# If using XQuartz, also run `xhost + localhost`

Output media/wiretap_demo.mp4

Expand Down Expand Up @@ -100,7 +101,7 @@ Sleep 2s

# show curl doesn't work, then configure wiretap
Type "curl http://10.2.0.4 --connect-timeout 3" Sleep 1s Enter Sleep 6s
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
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.conf" Sleep 1s Enter Sleep 2s

Ctrl+b
Expand All @@ -109,9 +110,8 @@ Sleep 2s

# args are in clipboard now
# this is bash magic, ESC+Ctrl+E will expand the current line
# type ./wiretap_linux_arm64 $(xsel)
# type $(xsel)
# run expansion to make command line look like it was pasted
Type "./wiretap_linux_arm64 " Sleep 1s
Hide
Type "$(xsel)"
Escape
Expand Down
Binary file modified media/wiretap_demo.mp4
Binary file not shown.
4 changes: 3 additions & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ else
EXT=
endif

OUTPUT=$(BIN)/$@_$(OS)_$(ARCH)$(EXT)## Output location

# ld flags
LDFLAGS=-s -w
LDFLAGS+=-X wiretap/cmd.Version=$(VERSION)
Expand All @@ -37,7 +39,7 @@ LDFLAGS+=-X wiretap/cmd.Version=$(VERSION)

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

## all: Build binaries for every OS/ARCH pair listed in the Makefile
all:
Expand Down
63 changes: 38 additions & 25 deletions src/cmd/configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type configureCmdConfig struct {
endpoint string
port int
configFile string
serverConfigFile string
writeToClipboard bool
addr4 string
addr6 string
Expand All @@ -31,13 +32,31 @@ var configureCmd = configureCmdConfig{
endpoint: Endpoint,
port: Port,
configFile: Config,
serverConfigFile: ServerConfig,
writeToClipboard: false,
addr4: Subnet4.Addr().Next().Next().String() + "/32",
addr6: Subnet6.Addr().Next().Next().String() + "/128",
apiAddr: ApiAddr.String(),
disableApi: false,
}

// Check if file exists, add number suffix if it does.
func getUniqueFilename(filename string) string {
var err error
count := 1
ext := filepath.Ext(filename)
basename := strings.TrimSuffix(filename, ext)
for {
_, err = os.Stat(filename)
if os.IsNotExist(err) {
break
}
filename = fmt.Sprintf("%s_%d%s", basename, count, ext)
count += 1
}
return filename
}

// Add command and set flags.
func init() {
// Usage info.
Expand All @@ -56,6 +75,7 @@ func init() {
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\")")
cmd.Flags().IntVarP(&configureCmd.port, "port", "p", configureCmd.port, "port of local wireguard listener")
cmd.Flags().StringVarP(&configureCmd.configFile, "output", "o", configureCmd.configFile, "wireguard config output filename")
cmd.Flags().StringVarP(&configureCmd.serverConfigFile, "server-config-output", "s", configureCmd.serverConfigFile, "wiretap server config output filename")
cmd.Flags().BoolVarP(&configureCmd.writeToClipboard, "clipboard", "c", configureCmd.writeToClipboard, "copy configuration args to clipboard")

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

// Add number to filename if it already exists.
count := 1
ext := filepath.Ext(c.configFile)
basename := strings.TrimSuffix(c.configFile, ext)
for {
_, err = os.Stat(c.configFile)
if os.IsNotExist(err) {
break
}
c.configFile = fmt.Sprintf("%s_%d%s", basename, count, ext)
count += 1
}

// Write config file and get status string.
c.configFile = getUniqueFilename(c.configFile)
var fileStatus string
err = os.WriteFile(c.configFile, []byte(config.AsFile()), 0600)
if err != nil {
fileStatus = fmt.Sprintf("%s %s", RedBold("config:"), Red(fmt.Sprintf("error writing config file: %v", err)))
fileStatus = fmt.Sprintf("%s %s", RedBold("client config:"), Red(fmt.Sprintf("error writing config file: %v", err)))
} else {
fileStatus = fmt.Sprintf("%s %s", GreenBold("config:"), Green(c.configFile))
fileStatus = fmt.Sprintf("%s %s", GreenBold("client config:"), Green(c.configFile))
}

// Generate argument string.
argString := fmt.Sprintf("serve --private %s --public %s",
config.GetPeerPrivateKey(0),
config.GetPublicKey(),
)

if len(config.GetPeerEndpoint(0)) > 0 {
argString = fmt.Sprintf("%s --endpoint %s", argString, config.GetPeerEndpoint(0))
// Write server config file and get status string.
c.serverConfigFile = getUniqueFilename(c.serverConfigFile)
var serverFileStatus string
err = os.WriteFile(c.serverConfigFile, []byte(config.AsServerFile()), 0600)
if err != nil {
serverFileStatus = fmt.Sprintf("%s %s", RedBold("server config:"), Red(fmt.Sprintf("error writing config file: %v", err)))
} else {
serverFileStatus = fmt.Sprintf("%s %s", GreenBold("server config:"), Green(c.serverConfigFile))
}

var clipboardStatus string
if c.writeToClipboard {
err = clipboard.WriteAll(argString)
err = clipboard.WriteAll(config.AsServerCommand("POSIX"))
if err != nil {
clipboardStatus = fmt.Sprintf("%s %s", RedBold("clipboard:"), Red(fmt.Sprintf("error copying to clipboard: %v", err)))
} else {
Expand All @@ -156,7 +164,12 @@ func (c configureCmdConfig) Run() {
fmt.Fprint(color.Output, WhiteBold(config.AsFile()))
fmt.Fprintln(color.Output, Green(strings.Repeat("─", 32)))
fmt.Fprintln(color.Output)
fmt.Fprintln(color.Output, GreenBold("args:"), Green(argString))
fmt.Fprintln(color.Output, serverFileStatus)
fmt.Fprintln(color.Output)
fmt.Fprintln(color.Output, GreenBold("server command:"))
fmt.Fprintln(color.Output, Cyan("POSIX Shell: "), Green(config.AsServerCommand("POSIX")))
fmt.Fprintln(color.Output, Cyan(" PowerShell: "), Green(config.AsServerCommand("POWERSHELL")))
fmt.Fprintln(color.Output, Cyan("Config File: "), Green("./wiretap serve -f " + c.serverConfigFile))
fmt.Fprintln(color.Output)
if c.writeToClipboard {
fmt.Fprintln(color.Output, clipboardStatus)
Expand Down
21 changes: 11 additions & 10 deletions src/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ import (

// Defaults shared by multiple commands.
var (
Version = "v0.0.0"
Endpoint = ""
Port = 51820
Config = "wiretap.conf"
Keepalive = 25
ShowHidden = false
ApiAddr = netip.MustParsePrefix("a::/128")
ApiPort = 80
Subnet4 = netip.MustParsePrefix("192.168.0.0/24")
Subnet6 = netip.MustParsePrefix("fd::/64")
Version = "v0.0.0"
Endpoint = ""
Port = 51820
Config = "wiretap.conf"
ServerConfig = "wiretap_server.conf"
Keepalive = 25
ShowHidden = false
ApiAddr = netip.MustParsePrefix("a::/128")
ApiPort = 80
Subnet4 = netip.MustParsePrefix("192.168.0.0/24")
Subnet6 = netip.MustParsePrefix("fd::/64")
)

// Define colors.
Expand Down
Loading

0 comments on commit 54d3df4

Please sign in to comment.