# wg-connect
Bring a WireGuard tunnel up and down on BusyBox-based systems without
`wg-quick`, systemd, or bash.
## Requirements
- `wg` - WireGuard userspace tool
- `ip` - iproute2 or BusyBox `ip`
- `grep` - BusyBox grep (with `-E` support)
- POSIX `/bin/sh`
Root privileges are required (the script creates and configures network
interfaces).
## Installation
```sh
make install # to /usr/local
make install PREFIX=/usr # to /usr
make install DESTDIR=/tmp/pkg # for packaging
```
Or manually:
```sh
install -m 0755 wg-connect /usr/local/bin/wg-connect
install -m 0644 wg-connect.1 /usr/local/share/man/man1/wg-connect.1
```
## Usage
```sh
wg-connect up # bring a tunnel up
wg-connect down [name] # tear a tunnel down
```
**`up`** requires a config argument, resolved as follows:
| Argument | Resolves to |
|---|---|
| `myvpn` | `/etc/wireguard/myvpn.conf` |
| `myvpn.conf` | `./myvpn.conf`, then `/etc/wireguard/myvpn.conf` |
| `./foo.conf` | `./foo.conf` (path with `/` - used as-is) |
| `/any/path/c.conf` | `/any/path/c.conf` (absolute path) |
The interface name is derived from the config file's basename (minus
`.conf`). For example, `wg-connect up myvpn` creates interface `myvpn`,
and `wg-connect up /etc/wireguard/home.conf` creates interface `home`.
**`down`** accepts an optional name to tear down a specific tunnel.
Without a name it defaults to `wg0`.
## Config format
Standard WireGuard `[Interface]` + `[Peer]` sections. `wg-quick`
extensions (`Address`, `DNS`, etc.) are accepted. The script strips
them before passing the config to `wg setconf` and handles them itself.
```ini
[Interface]
Address = 10.0.0.2/24
PrivateKey = oBKGh1W0UeO7R2aV5pLkdMn8Xq3TcFyRbzJwZsPvCg=
DNS = 1.1.1.1
[Peer]
PublicKey = xTIBA5rboUvnH4htjbDs6TFeFHS4k0mrKV4xJCzO0H8=
PresharedKey = /pUcv4j6DZ1UGm0PwR7aBr9Lk2sFdXq3OcVy5Jh8Tg=
Endpoint = 203.0.113.45:51820
AllowedIPs = 0.0.0.0/0
```
Multiple `[Peer]` sections are supported; `AllowedIPs` and `Endpoint`
values are accumulated across all of them.
Note: if you run multiple tunnels, each must have a unique `ListenPort`
(or omit it entirely). The script detects port conflicts before
setting up the interface.
## What it does
**`up`**
1. Resolves the config path and derives the interface name.
2. Checks for port conflicts with any existing WireGuard interface.
3. Parses the config for `Address`, `DNS`, `Endpoint`, `AllowedIPs`,
and `ListenPort`.
4. Adds explicit routes for each peer endpoint through the current
default gateway, so encrypted UDP packets are not caught in the
tunnel's own routing.
5. Creates the WireGuard interface and applies the config.
6. Assigns the `Address` (appending `/32` if no CIDR is given).
7. Brings the interface up.
8. Installs routes for each `AllowedIPs` entry. `0.0.0.0/0` replaces
the default route.
9. If `DNS` is set, backs up `/etc/resolv.conf` and writes the VPN
nameserver.
10. Saves state to `/tmp/wg-connect..state` for teardown.
If any step fails, the trap handler rolls back everything created so
far (interface, endpoint routes, state file).
**`down`**
1. Reads `/tmp/wg-connect..state`.
2. Restores the original `/etc/resolv.conf`.
3. Removes the endpoint-specific routes.
4. Deletes the interface (which also removes its addresses and routes).
5. Restores the original default route if one was saved.
6. Removes the state file.
If the state file is missing but the interface still exists, `down`
falls back to cleaning up the leftover interface.
## Limitations
- IPv6 addresses and routes are skipped (BusyBox `ip` may lack `-6`
support).
- `DNS` supports a single nameserver only.
- PostUp / PostDown / PreUp / PreDown hooks are not executed.
- No firewall rules are added. If you need a kill switch, configure
`iptables` separately.
