# Fetch type
my $type = $Wireguard::peers{$key}[1];
- my @remote_subnets = &Wireguard::decode_subnets($Wireguard::peers{$key}[6]);
- my @local_subnets = &Wireguard::decode_subnets($Wireguard::peers{$key}[8]);
+ my @remote_subnets = &Wireguard::decode_subnets($Wireguard::peers{$key}[8]);
+ my @local_subnets = &Wireguard::decode_subnets($Wireguard::peers{$key}[10]);
# Flush CGI parameters & load configuration
%cgiparams = (
"TYPE" => $Wireguard::peers{$key}[1],
"NAME" => $Wireguard::peers{$key}[2],
"PUBLIC_KEY" => $Wireguard::peers{$key}[3],
- "ENDPOINT_ADDRESS" => $Wireguard::peers{$key}[4],
- "ENDPOINT_PORT" => $Wireguard::peers{$key}[5],
+ "PRIVATE_KEY" => $Wireguard::peers{$key}[4],
+ "PORT" => $Wireguard::peers{$key}[5],
+ "ENDPOINT_ADDRESS" => $Wireguard::peers{$key}[6],
+ "ENDPOINT_PORT" => $Wireguard::peers{$key}[7],
"REMOTE_SUBNETS" => join(", ", @remote_subnets),
- "REMARKS" => &MIME::Base64::decode_base64($Wireguard::peers{$key}[7]),
+ "REMARKS" => &MIME::Base64::decode_base64($Wireguard::peers{$key}[9]),
"LOCAL_SUBNETS" => join(", ", @local_subnets),
- "PSK" => $Wireguard::peers{$key}[9],
- "KEEPALIVE" => $Wireguard::peers{$key}[10],
+ "PSK" => $Wireguard::peers{$key}[11],
+ "KEEPALIVE" => $Wireguard::peers{$key}[12],
);
# Jump to the editor
push(@errormessages, $Lang::tr{'wg invalid public key'});
}
+ # Check private key
+ #if ($cgiparams{'PRIVATE_KEY'} eq '') {
+ # # The private key may be empty
+ #} elsif (!&Wireguard::key_is_valid($cgiparams{'PRIVATE_KEY'})) {
+ # push(@errormessages, $Lang::tr{'wg invalid private key'});
+ #}
+
# Check PSK
if ($cgiparams{'PSK'} eq '') {
# The PSK may be empty
push(@errormessages, $Lang::tr{'wg invalid psk'});
}
+ # Check port
+ #unless (&General::validport($cgiparams{'PORT'})) {
+ # push(@errormessages, $LANG::tr{'invalid port'});
+ #}
+
# Check the endpoint address
if ($cgiparams{'ENDPOINT_ADDRESS'} eq '') {
# The endpoint address may be empty
"net",
# 2 = Name
$cgiparams{"NAME"},
- # 3 = Pubkey
+ # 3 = Public Key
$cgiparams{"PUBLIC_KEY"},
- # 4 = Endpoint Address
+ # 4 = Private Key
+ $cgiparams{"PRIVATE_KEY"},
+ # 5 = Port
+ $cgiparams{"PORT"},
+ # 6 = Endpoint Address
$cgiparams{"ENDPOINT_ADDRESS"},
- # 5 = Endpoint Port
+ # 7 = Endpoint Port
$cgiparams{"ENDPOINT_PORT"},
- # 6 = Remote Subnets
+ # 8 = Remote Subnets
&Wireguard::encode_subnets(@remote_subnets),
- # 7 = Remark
+ # 9 = Remark
&Wireguard::encode_remarks($cgiparams{"REMARKS"}),
- # 8 = Local Subnets
+ # 10 = Local Subnets
&Wireguard::encode_subnets(@local_subnets),
- # 9 = PSK
+ # 11 = PSK
$cgiparams{"PSK"} || "",
- # 10 = Keepalive
+ # 12 = Keepalive
$cgiparams{"KEEPALIVE"} || 0,
];
# Fetch some configuration parts
} else {
$cgiparams{"PUBLIC_KEY"} = $Wireguard::peers{$key}[3];
- $cgiparams{'CLIENT_ADDRESS'} = $Wireguard::peers{$key}[6];
- $cgiparams{"PSK"} = $Wireguard::peers{$key}[9];
+ $cgiparams{'CLIENT_ADDRESS'} = $Wireguard::peers{$key}[8];
+ $cgiparams{"PSK"} = $Wireguard::peers{$key}[11];
}
# Save the connection
"host",
# 2 = Name
$cgiparams{"NAME"},
- # 3 = Pubkey
+ # 3 = Public Key
$cgiparams{"PUBLIC_KEY"},
- # 4 = Endpoint Address
+ # 4 = Private Key
"",
- # 5 = Endpoint Port
+ # 5 = Port
"",
- # 6 = Remote Subnets
+ # 6 = Endpoint Address
+ "",
+ # 7 = Endpoint Port
+ "",
+ # 8 = Remote Subnets
$cgiparams{'CLIENT_ADDRESS'},
- # 7 = Remark
+ # 9 = Remark
&Wireguard::encode_remarks($cgiparams{"REMARKS"}),
- # 8 = Local Subnets
+ # 10 = Local Subnets
&Wireguard::encode_subnets(@local_subnets),
- # 9 = PSK
+ # 11 = PSK
$cgiparams{"PSK"},
- # 10 = Keepalive
+ # 12 = Keepalive
0,
];
my $type = $Wireguard::peers{$key}[1];
my $name = $Wireguard::peers{$key}[2];
my $pubkey = $Wireguard::peers{$key}[3];
- my $endpoint = $Wireguard::peers{$key}[4];
- my $port = $Wireguard::peers{$key}[5];
- my $routes = $Wireguard::peers{$key}[6];
- my $remarks = &Wireguard::decode_remarks($Wireguard::peers{$key}[7]);
+ #my $privkey = $Wireguard::peers{$key}[4]
+ #my $port = $Wireguard::peers{$key}[5];
+ my $endpoint = $Wireguard::peers{$key}[6];
+ #my $endpport = $Wireguard::peers{$key}[7];
+ my $routes = $Wireguard::peers{$key}[8];
+ my $remarks = &Wireguard::decode_remarks($Wireguard::peers{$key}[9]);
my $connected = $Lang::tr{'capsclosed'};
my $country = "ZZ";
<input type="hidden" name="ACTION" value="SAVE-PEER-NET">
<input type="hidden" name="KEY" value="$cgiparams{'KEY'}">
+ <input type="hidden" name="PRIVATE_KEY" value="$cgiparams{'PRIVATE_KEY'}">
+
<table class="form">
<tr>
<td>
my %peer = (
"NAME" => $Wireguard::peers{$key}[2],
"PUBLIC_KEY" => $Wireguard::peers{$key}[3],
- "CLIENT_ADDRESS" => $Wireguard::peers{$key}[6],
- "LOCAL_SUBNETS" => &Wireguard::decode_subnets($Wireguard::peers{$key}[8]),
- "PSK" => $Wireguard::peers{$key}[9],
+ "CLIENT_ADDRESS" => $Wireguard::peers{$key}[8],
+ "LOCAL_SUBNETS" => &Wireguard::decode_subnets($Wireguard::peers{$key}[10]),
+ "PSK" => $Wireguard::peers{$key}[11],
# Other stuff
"PRIVATE_KEY" => $private_key,
. ${rc_functions}
. /etc/rc.d/init.d/networking/functions.network
-INTF="wg0"
-
eval $(/usr/local/bin/readhash /var/ipfire/wireguard/settings)
-generate_config() {
- echo "[Interface]"
- echo "PrivateKey = ${PRIVATE_KEY}"
+interfaces() {
+ local id
+ local enabled
+ local type
+ local _rest
+
+ local IFS=','
+
+ # wg0 will always be created for roadwarrior
+ echo "wg0"
+
+ while read -r id enabled type _rest; do
+ # Skip peers that are not enabled
+ [ "${enabled}" = "on" ] || continue
+
+ # Skip anything that isn't a net-to-net connection
+ [ "${type}" = "net" ] || continue
+
+ echo "wg${id}"
+ done < /var/ipfire/wireguard/peers
+
+ return 0
+}
+
+interface_is_rw() {
+ local intf="${1}"
+
+ [ "${intf}" = "wg0" ]
+}
+
+setup_interface() {
+ local intf="${1}"
+
+ # Create the interface if it does not exist
+ if [ ! -d "/sys/class/net/${intf}" ]; then
+ ip link add "${intf}" type wireguard || return $?
+ fi
- # Optionally set the port
- if [ -n "${PORT}" ]; then
- echo "ListenPort = ${PORT}"
+ # Set up the interface
+ ip link set "${intf}" up
+
+ # Set the MTU
+ if [ -n "${MTU}" ]; then
+ ip link set "${intf}" mtu "${MTU}" || return $?
fi
+ # Load the configuration into the kernel
+ wg syncconf "${intf}" <(generate_config "${intf}") || return $?
+
+ return 0
+}
+
+cleanup_interfaces() {
+ local interfaces=( "$(interfaces)" )
+
+ local intf
+ for intf in /sys/class/net/wg[0-9]*; do
+ [ -d "${intf}" ] || continue
+
+ # Remove the path
+ intf="${intf##*/}"
+
+ local found=0
+ local i
+
+ for i in ${interfaces[@]}; do
+ if [ "${intf}" = "${i}" ]; then
+ found=1
+ break
+ fi
+ done
+
+ if [ "${found}" -eq 0 ]; then
+ ip link del "${intf}"
+ fi
+ done
+
+ return 0
+}
+
+generate_config() {
+ local intf="${1}"
+
+ # Flush all previously set routes
+ ip route flush dev "${intf}"
+
local IFS=','
local id
local type
local name
local pubkey
- local endpoint
+ local privkey
local port
+ local endpoint_addr
+ local endpoint_port
local remote_subnets
local remarks
local local_subnets
local keepalive
local _rest
- local local_subnet
- local remote_subnet
+ # Handles the special case of the RW interface
+ if interface_is_rw "${intf}"; then
+ echo "[Interface]"
+ echo "PrivateKey = ${PRIVATE_KEY}"
- # Flush firewall rules
- iptables -F WGBLOCK
+ # Optionally set the port
+ if [ -n "${PORT}" ]; then
+ echo "ListenPort = ${PORT}"
+ fi
- # Flush all previously set routes
- ip route flush dev "${INTF}"
+ # Add the client pool
+ if [ -n "${CLIENT_POOL}" ]; then
+ ip route add "${CLIENT_POOL}" dev "${intf}"
+ fi
+
+ while read -r id enabled type name pubkey privkey port endpoint_addr endpoint_port \
+ remote_subnets remarks local_subnets psk keepalive _rest; do
+ # Skip peers that are not hosts or not enabled
+ [ "${type}" = "host" ] || continue
+ [ "${enabled}" = "on" ] || continue
+
+ echo "[Peer]"
+ echo "PublicKey = ${pubkey}"
+
+ # Set PSK (if set)
+ if [ -n "${psk}" ]; then
+ echo "PresharedKey = ${psk}"
+ fi
+
+ # Set routes
+ if [ -n "${remote_subnets}" ]; then
+ echo "AllowedIPs = ${remote_subnets//|/, }"
+ fi
+
+ echo # newline
+ done < /var/ipfire/wireguard/peers
- # Add the client pool
- if [ -n "${CLIENT_POOL}" ]; then
- ip route add "${CLIENT_POOL}" dev "${INTF}"
+ return 0
fi
- local args
- local src
+ local local_subnet
+ local remote_subnet
+
+ while read -r id enabled type name pubkey privkey port endpoint_addr endpoint_port \
+ remote_subnets remarks local_subnets psk keepalive _rest; do
+ # Check for the matching connection
+ [ "${type}" = "net" ] || continue
+ [ "${intf}" = "wg${id}" ] || continue
- while read -r id enabled type name pubkey endpoint port remote_subnets \
- remarks local_subnets psk keepalive _rest; do
# Skip peers that are not enabled
[ "${enabled}" = "on" ] || continue
+ echo "[Interface]"
+
+ if [ -n "${privkey}" ]; then
+ echo "PrivateKey = ${privkey}"
+ fi
+
+ # Optionally set the port
+ if [ -n "${port}" ]; then
+ echo "ListenPort = ${port}"
+
+ # Open the port
+ iptables -A WGINPUT -p udp --dport "${port}" -j ACCEPT
+ fi
+
echo "[Peer]"
echo "PublicKey = ${pubkey}"
# Set PSK (if set)
if [ -n "${psk}" ]; then
- echo "PresharedKey= ${psk}"
+ echo "PresharedKey = ${psk}"
fi
# Set endpoint
- if [ -n "${endpoint}" ]; then
- echo "Endpoint = ${endpoint}${port:+:}${port}"
+ if [ -n "${endpoint_addr}" ]; then
+ echo "Endpoint = ${endpoint_addr}${endpoint_port:+:}${endpoint_port}"
fi
# Set routes
echo "AllowedIPs = ${remote_subnets//|/, }"
# Apply the routes
- if [ "${type}" = "net" ]; then
- local_subnets=( "${local_subnets//|/,}" )
+ local_subnets=( "${local_subnets//|/,}" )
- # Find an IP address of the firewall that is inside the routed subnet
- src="$(ipfire_address_in_networks "${local_subnets[@]}")"
+ # Find an IP address of the firewall that is inside the routed subnet
+ local src="$(ipfire_address_in_networks "${local_subnets[@]}")"
- for remote_subnet in ${remote_subnets//|/,}; do
- args=(
- "${remote_subnet}" "dev" "${INTF}"
- )
+ for remote_subnet in ${remote_subnets//|/,}; do
+ local args=(
+ "${remote_subnet}" "dev" "${intf}"
+ )
- # Add the preferred source if we found one
- if [ -n "${src}" ]; then
- args+=( "src" "${src}" )
- fi
+ # Add the preferred source if we found one
+ if [ -n "${src}" ]; then
+ args+=( "src" "${src}" )
+ fi
- ip route add "${args[@]}"
- done
- fi
+ ip route add "${args[@]}"
+ done
fi
# Set keepalive
# Set blocking rules
for local_subnet in ${local_subnets//|/ }; do
for remote_subnet in ${remote_subnets//|/ }; do
- iptables -A WGBLOCK \
+ iptables -I WGBLOCK \
-s "${remote_subnet}" -d "${local_subnet}" -j RETURN
done
done
- done < /var/ipfire/wireguard/peers
- # Block all other traffic
- iptables -A WGBLOCK -j REJECT --reject-with icmp-admin-prohibited
+ # There will only be one match, so we can break as soon we get here
+ break
+ done < /var/ipfire/wireguard/peers
}
reload_firewall() {
if [ "${ENABLED}" = "on" ]; then
iptables -A WGINPUT -p udp --dport "${PORT}" -j ACCEPT
fi
+
+ iptables -F WGBLOCK
+
+ # Block all other traffic
+ iptables -A WGBLOCK -j REJECT --reject-with icmp-admin-prohibited
}
wg_start() {
- # Reload the firewall
- reload_firewall
+ local failed=0
+ local intf
- # Create the interface if it does not exist
- if [ ! -d "/sys/class/net/${INTF}" ]; then
- ip link add "${INTF}" type wireguard || return $?
- fi
+ # Find all interfaces
+ local interfaces=( "$(interfaces)" )
- # Set up the interface
- ip link set "${INTF}" up
+ # Shut down any unwanted interfaces
+ cleanup_interfaces
- # Set the MTU
- if [ -n "${MTU}" ]; then
- ip link set "${INTF}" mtu "${MTU}" || return $?
- fi
+ # Reload the firewall
+ reload_firewall
- # Load the configuration into the kernel
- wg syncconf "${INTF}" <(generate_config) || return $?
+ # Setup all interfaces
+ for intf in ${interfaces[@]}; do
+ setup_interface "${intf}" || failed=1
+ done
- return 0
+ return ${failed}
}
wg_stop() {
+ local intf
+
# Reload the firewall
ENABLED=off reload_firewall
- if [ -d "/sys/class/net/${INTF}" ]; then
- ip link del "${INTF}" || return $?
- fi
+ for intf in /sys/class/net/wg[0-9]*; do
+ ip link del "${intf##*/}"
+ done
+
+ return 0
}
case "${1}" in