This tool can be used to automatically create wireguard tunnels. Using rpcd a new wireguard interface is created on the server where the client can connect to. Wiregurad server automatically installs a user and associated ACL to use the wireguard-installer-server features. The user is called wginstaller and so is the password. Get Usage: wg-client-installer get_usage --ip 127.0.0.1 --user wginstaller --password wginstaller Register Interface: wg-client-installer register --ip 127.0.0.1 --user wginstaller --password wginstaller --bandwidth 10 --mtu 1400 Signed-off-by: Nick Hainke <vincent@systemli.org>lilik-openwrt-22.03
@ -0,0 +1,69 @@ | |||
include $(TOPDIR)/rules.mk | |||
PKG_NAME:=wg-installer | |||
PKG_RELEASE:=$(AUTORELEASE) | |||
PKG_MAINTAINER:=Nick Hainke <vincent@systemli.org> | |||
include $(INCLUDE_DIR)/package.mk | |||
Build/Compile= | |||
define Package/wg-installer/Default | |||
SECTION:=net | |||
CATEGORY:=Network | |||
TITLE:=WireGuard Installer | |||
URL:=https://github.com/Freifunk-Spalter/ | |||
PKGARCH:=all | |||
DEPENDS:=+kmod-wireguard +owipcalc | |||
endef | |||
define Package/wg-installer-server | |||
$(call Package/wg-installer/Default) | |||
TITLE+= (server) | |||
DEPENDS:=+rpcd +uhttpd +uhttpd-mod-ubus +owipcalc | |||
endef | |||
define Package/wg-installer-server/install | |||
$(INSTALL_DIR) $(1)/usr/share/wginstaller/ | |||
$(INSTALL_BIN) ./wg-server/lib/install_wginstaller_user.sh $(1)/usr/share/wginstaller/install_wginstaller_user.sh | |||
$(INSTALL_BIN) ./wg-server/lib/wg_functions.sh $(1)/usr/share/wginstaller/wg_functions.sh | |||
$(INSTALL_BIN) ./common/wg.sh $(1)/usr/share/wginstaller/wg.sh | |||
$(INSTALL_DIR) $(1)/usr/libexec/rpcd/ | |||
$(INSTALL_BIN) ./wg-server/wginstaller.sh $(1)/usr/libexec/rpcd/wginstaller | |||
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d | |||
$(CP) ./wg-server/config/wginstaller.json $(1)/usr/share/rpcd/acl.d/ | |||
$(INSTALL_DIR) $(1)/etc/config | |||
$(INSTALL_CONF) ./wg-server/config/wgserver.conf $(1)/etc/config/wgserver | |||
endef | |||
define Package/wg-installer-server/postinst | |||
#!/bin/sh | |||
if [ -z $${IPKG_INSTROOT} ] ; then | |||
. /usr/share/wginstaller/install_wginstaller_user.sh | |||
fi | |||
endef | |||
define Package/wg-installer-client | |||
$(call Package/wg-installer/Default) | |||
TITLE+= (client) | |||
DEPENDS:=+curl +wireguard-tools | |||
endef | |||
define Package/wg-installer-client/install | |||
$(INSTALL_DIR) $(1)/usr/share/wginstaller/ | |||
$(INSTALL_BIN) ./wg-client/lib/rpcd_ubus.sh $(1)/usr/share/wginstaller/rpcd_ubus.sh | |||
$(INSTALL_BIN) ./common/wg.sh $(1)/usr/share/wginstaller/wg.sh | |||
$(INSTALL_DIR) $(1)/usr/bin | |||
$(INSTALL_BIN) ./wg-client/wg-client-installer.sh $(1)/usr/bin/wg-client-installer | |||
$(INSTALL_DIR) $(1)/etc/config | |||
$(INSTALL_CONF) ./wg-client/config/wgclient.conf $(1)/etc/config/wgclient | |||
endef | |||
$(eval $(call BuildPackage,wg-installer-server)) | |||
$(eval $(call BuildPackage,wg-installer-client)) |
@ -0,0 +1,26 @@ | |||
## Wireguard Installer | |||
This tool can be used to automatically create wireguard tunnels. Using rpcd a new wireguard interface is created on the server where the client can connect to. | |||
## Installation | |||
For Server | |||
opkg install wireguard-installer-server | |||
For Client | |||
opkg install wireguard-installer-client | |||
Wiregurad server automatically installs a user and associated ACL to use the wireguard-installer-server features. | |||
The user is called wginstaller and so is the password. | |||
## Usage | |||
Get Usage Statistics | |||
wg-client-installer get_usage --ip 127.0.0.1 --user wginstaller --password wginstaller | |||
Register Tunnel Interface | |||
wg-client-installer register --ip 127.0.0.1 --user wginstaller --password wginstaller --bandwidth 10 |
@ -0,0 +1,13 @@ | |||
next_port () { | |||
local port_start=$1 | |||
local port_end=$2 | |||
ports=$(wg show all listen-port | awk '{print $2}') | |||
for i in $(seq $port_start $port_end); do | |||
if ! echo $ports | grep -q "$i"; then | |||
echo $i | |||
return | |||
fi | |||
done | |||
} |
@ -0,0 +1,8 @@ | |||
config client | |||
option wg_key '/root/wg.key' | |||
option wg_pub '/root/wg.pub' | |||
option base_prefix '2000::/64' | |||
option port_start '51820' | |||
option port_end '52820' | |||
option try_insecure '1' | |||
option try_http '1' |
@ -0,0 +1,134 @@ | |||
. /usr/share/libubox/jshn.sh | |||
query_gw () { | |||
local ip=$1 | |||
local req=$2 | |||
# first try https | |||
ret=$(curl https://$ip/ubus -d "$req") 2>/dev/null | |||
if [ $? -eq 0 ]; then | |||
echo $ret | |||
return 0 | |||
fi | |||
# try with --insecure | |||
if [ $(uci get wgclient.@client[0].try_insecure) == '1' ]; then | |||
ret=$(curl --insecure https://$ip/ubus -d "$req") 2>/dev/null | |||
if [ $? -eq 0 ]; then | |||
echo $ret | |||
return 0 | |||
fi | |||
fi | |||
# try with http | |||
if [ $(uci get wgclient.@client[0].try_http) == '1' ]; then | |||
ret=$(curl http://$ip/ubus -d "$req") 2>/dev/null | |||
if [ $? -eq 0 ]; then | |||
echo $ret | |||
return 0 | |||
fi | |||
fi | |||
return 1 | |||
} | |||
request_token () { | |||
local ip=$1 | |||
local user=$2 | |||
local password=$3 | |||
json_init | |||
json_add_string "jsonrpc" "2.0" | |||
json_add_int "id" "1" | |||
json_add_string "method" "call" | |||
json_add_array "params" | |||
json_add_string "" "00000000000000000000000000000000" | |||
json_add_string "" "session" | |||
json_add_string "" "login" | |||
json_add_object | |||
json_add_string "username" $user | |||
json_add_string "password" $password | |||
json_close_object | |||
json_close_array | |||
req=$(json_dump) | |||
ret=$(query_gw $ip "$req") 2>/dev/null | |||
if [ $? != 0 ]; then | |||
return 1 | |||
fi | |||
json_load "$ret" | |||
json_get_vars result result | |||
json_select result | |||
json_select 2 | |||
json_get_var ubus_rpc_session ubus_rpc_session | |||
echo $ubus_rpc_session | |||
} | |||
wg_rpcd_get_usage () { | |||
local token=$1 | |||
local ip=$2 | |||
local secret=$3 | |||
json_init | |||
json_add_string "jsonrpc" "2.0" | |||
json_add_int "id" "1" | |||
json_add_string "method" "call" | |||
json_add_array "params" | |||
json_add_string "" $token | |||
json_add_string "" "wginstaller" | |||
json_add_string "" "get_usage" | |||
json_add_object | |||
json_close_object | |||
json_close_array | |||
req=$(json_dump) | |||
ret=$(query_gw $ip "$req") 2>/dev/null | |||
if [ $? != 0 ]; then | |||
return 1 | |||
fi | |||
# return values | |||
json_load "$ret" | |||
json_get_vars result result | |||
json_select result | |||
json_select 2 | |||
json_get_var num_interfaces num_interfaces | |||
echo "num_interfaces: ${num_interfaces}" | |||
} | |||
wg_rpcd_register () { | |||
local token=$1 | |||
local ip=$2 | |||
local uplink_bw=$3 | |||
local mtu=$4 | |||
local public_key=$5 | |||
json_init | |||
json_add_string "jsonrpc" "2.0" | |||
json_add_int "id" "1" | |||
json_add_string "method" "call" | |||
json_add_array "params" | |||
json_add_string "" $token | |||
json_add_string "" "wginstaller" | |||
json_add_string "" "register" | |||
json_add_object | |||
json_add_int "uplink_bw" $uplink_bw | |||
json_add_int "mtu" $mtu | |||
json_add_string "public_key" $public_key | |||
json_close_object | |||
json_close_array | |||
req=$(json_dump) | |||
ret=$(query_gw $ip "$req") 2>/dev/null | |||
if [ $? != 0 ]; then | |||
return 1 | |||
fi | |||
json_load "$ret" | |||
json_get_vars result result | |||
json_select result | |||
json_select 2 | |||
json_get_var pubkey pubkey | |||
json_get_var gw_ip gw_ip | |||
json_get_var port port | |||
echo "pubkey: ${pubkey}" | |||
echo "gw_ip: ${gw_ip}" | |||
echo "port: ${port}" | |||
} |
@ -0,0 +1,119 @@ | |||
#!/bin/sh | |||
. /usr/share/wginstaller/rpcd_ubus.sh | |||
. /usr/share/wginstaller/wg.sh | |||
CMD=$1 | |||
shift | |||
while true; do | |||
case "$1" in | |||
-h | --help) | |||
echo "help" | |||
shift 1 | |||
;; | |||
-i | --ip) | |||
IP=$2 | |||
shift 2 | |||
;; | |||
--user) | |||
USER=$2 | |||
shift 2 | |||
;; | |||
--password) | |||
PASSWORD=$2 | |||
shift 2 | |||
;; | |||
--bandwidth) | |||
BANDWIDTH=$2 | |||
shift 2 | |||
;; | |||
--mtu) | |||
WG_MTU=$2 | |||
shift 2 | |||
;; | |||
'') | |||
break | |||
;; | |||
*) | |||
break | |||
;; | |||
esac | |||
done | |||
escape_ip () { | |||
local gw_ip=$1 | |||
# ipv4 processing | |||
ret_ip=$(echo $gw_ip | tr '.' '_') | |||
# ipv6 processing | |||
ret_ip=$(echo $ret_ip | tr ':' '_') | |||
ret_ip=$(echo $ret_ip | cut -d '[' -f 2) | |||
ret_ip=$(echo $ret_ip | cut -d ']' -f 1) | |||
echo $ret_ip | |||
} | |||
register_client_interface () { | |||
local pubkey=$1 | |||
local gw_ip=$2 | |||
local gw_port=$3 | |||
local endpoint=$4 | |||
local mtu_client=$5 | |||
gw_key=$(uci get wgclient.@client[0].wg_key) | |||
interface_name="gw_$(escape_ip $endpoint)" | |||
port_start=$(uci get wgclient.@client[0].port_start) | |||
port_end=$(uci get wgclient.@client[0].port_end) | |||
base_prefix=$(uci get wgclient.@client[0].base_prefix) | |||
port=$(next_port $port_start $port_end) | |||
ifname="wg_$port" | |||
offset=$(($port - $port_start)) | |||
client_ip=$(owipcalc $base_prefix add $offset next 128) | |||
client_ip_assign="${client_ip}/128" | |||
echo "Installing Interface With:" | |||
echo "Endpoint ${endpoint}" | |||
echo "Client IP ${client_ip}" | |||
echo "Port ${port}" | |||
echo "Pubkey ${pubkey}" | |||
ip link add dev $ifname type wireguard | |||
ip -6 a a dev $ifname $client_ip | |||
wg set $ifname listen-port $port private-key $gw_key peer $pubkey allowed-ips ::/0 endpoint "${endpoint}:${gw_port}" | |||
ip link set up dev $ifname | |||
ip link set mtu $mtu_client dev $ifname # configure mtu here! | |||
} | |||
# rpc login | |||
token="$(request_token $IP $USER $PASSWORD)" | |||
if [ $? != 0 ]; then | |||
echo "failed to register token" | |||
exit 1 | |||
fi | |||
# now call procedure | |||
case $CMD in | |||
"get_usage") | |||
wg_rpcd_get_usage $token $IP | |||
;; | |||
"register") | |||
gw_pub=$(uci get wgclient.@client[0].wg_pub) | |||
gw_pub_string=$(cat $gw_pub) | |||
register_output=$(wg_rpcd_register $token $IP $BANDWIDTH $WG_MTU $gw_pub_string) | |||
if [ $? != 0 ]; then | |||
echo "Failed to Register!" | |||
exit 1 | |||
fi | |||
pubkey=$(echo $register_output | awk '{print $2}') | |||
ip_addr=$(echo $register_output | awk '{print $4}') | |||
port=$(echo $register_output | awk '{print $6}') | |||
client_ip=$(echo $register_output | awk '{print $8}') | |||
register_client_interface $pubkey $ip_addr $port $IP $WG_MTU | |||
;; | |||
*) echo "Usage: wg-client-installer [cmd] --ip [2001::1] --user wginstaller --password wginstaller" ;; | |||
esac |
@ -0,0 +1,19 @@ | |||
{ | |||
"wginstaller": { | |||
"description": "WireGuard Installer", | |||
"read": { | |||
"ubus": { | |||
"wginstaller": [ "*" ], | |||
"session": [ | |||
"access", | |||
"login" | |||
] | |||
} | |||
}, | |||
"write": { | |||
"ubus": { | |||
"wginstaller": [ "*" ] | |||
} | |||
} | |||
} | |||
} |
@ -0,0 +1,6 @@ | |||
config server | |||
option port_start '51820' | |||
option port_end '52820' | |||
option base_prefix '2002::/64' | |||
option wg_key '/root/wg.key' | |||
option wg_pub '/root/wg.pub' |
@ -0,0 +1,22 @@ | |||
#!/bin/sh | |||
# do not override already existing user!!! | |||
[ "$(uci show rpcd | grep wginstaller)" ] && exit 0 | |||
# install wginstaller user with standard credentials | |||
# user: wginstaller | |||
# password: wginstaller | |||
uci add rpcd login | |||
uci set rpcd.@login[-1].username='wginstaller' | |||
password=$(uhttpd -m wginstaller) | |||
uci set rpcd.@login[-1].password=$password | |||
uci add_list rpcd.@login[-1].read='wginstaller' | |||
uci add_list rpcd.@login[-1].write='wginstaller' | |||
uci commit rpcd | |||
# restart rpcd | |||
/etc/init.d/rpcd restart | |||
# restart uhttpd | |||
/etc/init.d/uhttpd restart |
@ -0,0 +1,46 @@ | |||
. /usr/share/libubox/jshn.sh | |||
. /usr/share/wginstaller/wg.sh | |||
wg_get_usage () { | |||
num_interfaces = $(wg show interfaces | wc -w) | |||
json_init | |||
json_add_int "num_interfaces" $num_interfaces | |||
echo $(json_dump) | |||
} | |||
wg_register () { | |||
local uplink_bw=$1 | |||
local mtu=$2 | |||
local public_key=$3 | |||
base_prefix=$(uci get wgserver.@server[0].base_prefix) | |||
port_start=$(uci get wgserver.@server[0].port_start) | |||
port_end=$(uci get wgserver.@server[0].port_end) | |||
port=$(next_port $port_start $port_end) | |||
ifname="wg_$port" | |||
offset=$(($port - $port_start)) | |||
gw_ip=$(owipcalc $base_prefix add $offset next 128) # gateway ip | |||
gw_ip_assign="${gw_ip}/128" | |||
gw_key=$(uci get wgserver.@server[0].wg_key) | |||
gw_pub=$(uci get wgserver.@server[0].wg_pub) | |||
wg_server_pubkey=$(cat $gw_pub) | |||
# create wg tunnel | |||
ip link add dev $ifname type wireguard | |||
wg set $ifname listen-port $port private-key $gw_key peer $public_key allowed-ips ::0/0 | |||
ip -6 a a $gw_ip_assign dev $ifname | |||
ip -6 a a fe80::1/64 dev $ifname | |||
ip link set up dev $ifname | |||
ip link set mtu $mtu dev $ifname | |||
# craft return address | |||
json_init | |||
json_add_string "pubkey" $wg_server_pubkey | |||
json_add_string "gw_ip" $gw_ip_assign | |||
json_add_int "port" $port | |||
echo $(json_dump) | |||
} |
@ -0,0 +1,32 @@ | |||
#!/bin/sh | |||
. /usr/share/libubox/jshn.sh | |||
. /usr/share/wginstaller/wg_functions.sh | |||
case "$1" in | |||
list) | |||
cmd='{ "get_usage": {},' | |||
cmd=$(echo $cmd ' "register": {"uplink_bw":"10", "mtu":"1400", "public_key": "xyz"} }') | |||
echo $cmd | |||
;; | |||
call) | |||
case "$2" in | |||
get_usage) | |||
read input | |||
logger -t "wginstaller" "call" "$2" "$input" | |||
wg_get_usage | |||
;; | |||
register) | |||
read input | |||
logger -t "wginstaller" "call" "$2" "$input" | |||
json_load "$input" | |||
json_get_var uplink_bw uplink_bw | |||
json_get_var mtu mtu | |||
json_get_var public_key public_key | |||
wg_register $uplink_bw $mtu $public_key | |||
;; | |||
esac | |||
;; | |||
esac |