0

Generate WireGuard peer configuration

Free lines Bash 1 revisions 102 2 months ago 2 months ago
#!/bin/bash

umask 077

# version of https://stackoverflow.com/a/43196141/2164304
generate_ip() {
	LAST_IP=`grep -F "AllowedIPs" $LOCAL_PEER_CONFIG | cut -d '=' '-f2-' | cut -d '/' -f1 | xargs -n1 | sort -nrt . -k 3,3 -k 4,4 | head -n1`
    IP_HEX=$(printf '%.2X%.2X%.2X%.2X\n' `echo $LAST_IP | sed -e 's/\./ /g'`)
    NEXT_IP_HEX=$(printf %.8X `echo $(( 0x$IP_HEX + 1 ))`)
    NEXT_IP=$(printf '%d.%d.%d.%d\n' `echo $NEXT_IP_HEX | sed -r 's/(..)/0x\1 /g'`)
    echo "$NEXT_IP"
}

HELP="Usage:

mkwg [args] client-name

-h / --help:                                              Show this thing
-c / --config    [/etc/wireguard/wg0.conf]:               Specify local peer configuration
-p / --publickey [read from /etc/wireguard/publickey]:    Specify local peer public key
-o / --output    [./<client-name>]:                       Specify directory to output config
-w / --write     [false]:                                 Write to local peer config
"

# CLI args
REMOTE_PEER_NAME=""
OUTPUT_DIR=""
LOCAL_PEER_CONFIG="/etc/wireguard/wg0.conf"
WRITE_LOCAL_PEER_CONFIG=0

# Things to figure out
LOCAL_PEER_PUBLIC_IP=""
LOCAL_PEER_PUBLIC_KEY=""
LOCAL_PEER_PORT=""
REMOTE_PEER_WIREGUARD_IP=""

# Parse CLI args
POSITIONAL=()

while [[ $# -gt 0 ]]
do
key="$1"

case $key in
    -c|--config)
		LOCAL_PEER_CONFIG="$2"
		shift # past argument
		shift # past value
    ;;
    -h|--help)
		echo "$HELP"
		exit
    ;;
    -p|--publickey)
		LOCAL_PEER_PUBLIC_KEY="$2"
		shift # past argument
		shift # past value
    ;;
    -o|--output)
		OUTPUT_DIR="$2"
		shift # past argument
		shift # past value
    ;;
    -w|--write)
		WRITE_LOCAL_PEER_CONFIG=1
		shift # past argument
		shift # past value
    ;;
    *)    # unknown option
		POSITIONAL+=("$1") # save it in an array for later
		shift # past argument
    ;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters

REMOTE_PEER_NAME="$POSITIONAL"

# Verify input & skim down some data

if [ -z "$REMOTE_PEER_NAME" ]; then
	>&2 echo "$HELP"
	exit 1
fi

if [ -z "$OUTPUT_DIR" ]; then
	OUTPUT_DIR="./$REMOTE_PEER_NAME"
fi

if [ ! -r "$LOCAL_PEER_CONFIG" ]; then
	>&2 echo "Local peer's configuration cannot be read at '$LOCAL_PEER_CONFIG'"
	exit 1
fi

LOCAL_PEER_PUBLIC_IP=`curl -s https://ipinfo.io/ip`

if [ -z "$LOCAL_PEER_PUBLIC_IP" ]; then
	>&2 echo "Local peer's public IP could not be fetched"
	exit 1
fi

LOCAL_PEER_PORT=`grep -m1 -F "ListenPort" "$LOCAL_PEER_CONFIG" | cut -d '=' '-f2-' | xargs`

if [ -z "$LOCAL_PEER_PUBLIC_KEY" ]; then
	if [ ! -r "/etc/wireguard/publickey" ]; then
		>&2 echo "Local peer public key could not be read at /etc/wireguard/publickey"
		exit 1
	fi

	LOCAL_PEER_PUBLIC_KEY=`cat /etc/wireguard/publickey`

	# Just makin' sure
	if [ -z "$LOCAL_PEER_PUBLIC_KEY" ]; then
		>&2 echo "Local peer public key could not be found at /etc/wireguard/publickey"
		exit 1
	fi
fi

if [[ "$WRITE_LOCAL_PEER_CONFIG" -eq "1" && ! -w "$LOCAL_PEER_CONFIG" ]]; then
	>&2 echo "Local peer configuration is not writable"
	exit 1
fi

REMOTE_PEER_WIREGUARD_IP=`generate_ip`

# Actual work heheheheh

if [ -d "$OUTPUT_DIR" ]; then
	>&2 echo "Directory '$OUTPUT_DIR' exists."
	exit 1
fi

# Create a directory for the client
mkdir "$OUTPUT_DIR"

# Generate pub/priv keys, and a preshared key
wg genkey | tee "$OUTPUT_DIR/privatekey" | wg pubkey > "$OUTPUT_DIR/publickey"
wg genkey > "$OUTPUT_DIR/preshared"

# Write configuration

cat <<EOT >> "$OUTPUT_DIR/config.conf"
[Interface]
Address = $REMOTE_PEER_WIREGUARD_IP/32
DNS = 1.1.1.1,1.0.0.1
MTU=1280
PrivateKey = `cat "$OUTPUT_DIR/privatekey"`

[Peer]
PublicKey = $LOCAL_PEER_PUBLIC_KEY
PresharedKey = `cat "$OUTPUT_DIR/preshared"`
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = $LOCAL_PEER_PUBLIC_IP:$LOCAL_PEER_PORT
EOT

# Set permissions

chmod 700 "$OUTPUT_DIR"
chmod 600 "$OUTPUT_DIR/privatekey"
chmod 600 "$OUTPUT_DIR/publickey"
chmod 600 "$OUTPUT_DIR/preshared"

REMOTE_PEER_CONFIG="
[Peer]
PublicKey = `cat "$OUTPUT_DIR/publickey"`
PresharedKey = `cat "$OUTPUT_DIR/preshared"`
AllowedIPs = $REMOTE_PEER_WIREGUARD_IP/32
"

if [ "$WRITE_LOCAL_PEER_CONFIG" -eq "1" ]; then
	echo -e "\n\n$REMOTE_PEER_CONFIG" >> $LOCAL_PEER_CONFIG
else
	echo -e "Copy the following configuration to local peer's config (like /etc/wireguard/wg0.conf):\n"
	echo "$REMOTE_PEER_CONFIG"
fi

if [ -x "$(command -v qrencode)" ]; then
	echo -e "QR code of new peer's config:\n"
	qrencode -t ansi "$REMOTE_PEER_CONFIG"
	echo -e "\nRemote peer's configuration is also available at $OUTPUT_DIR/config.conf"
else
	echo -e "QR code could not be generated because 'qrencode' is not installed."
	echo -e "Copy remote peer's configuration from $OUTPUT_DIR/config.conf"
fi

echo ">> Configuration finished. Make sure to restart WireGuard."

A bash script to generate a WireGuard peer configuration.

Usage:

mkwg [args] client-name

-h / --help:                                              Show this thing
-c / --config    [/etc/wireguard/wg0.conf]:               Specify local peer configuration
-p / --publickey [read from /etc/wireguard/publickey]:    Specify local peer public key
-o / --output    [./<client-name>]:                       Specify directory to output config
-w / --write     [false]:                                 Write to local peer config