b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | #!/bin/sh |
| 2 | # Copyright 2016-2017 Dan Luedtke <mail@danrl.com> |
| 3 | # Licensed to the public under the Apache License 2.0. |
| 4 | |
| 5 | WG=/usr/bin/wg |
| 6 | if [ ! -x $WG ]; then |
| 7 | logger -t "wireguard" "error: missing wireguard-tools (${WG})" |
| 8 | exit 0 |
| 9 | fi |
| 10 | |
| 11 | [ -n "$INCLUDE_ONLY" ] || { |
| 12 | . /lib/functions.sh |
| 13 | . ../netifd-proto.sh |
| 14 | init_proto "$@" |
| 15 | } |
| 16 | |
| 17 | proto_wireguard_init_config() { |
| 18 | proto_config_add_string "private_key" |
| 19 | proto_config_add_int "listen_port" |
| 20 | proto_config_add_int "mtu" |
| 21 | proto_config_add_string "fwmark" |
| 22 | available=1 |
| 23 | no_proto_task=1 |
| 24 | } |
| 25 | |
| 26 | proto_wireguard_setup_peer() { |
| 27 | local peer_config="$1" |
| 28 | |
| 29 | local disabled |
| 30 | local public_key |
| 31 | local preshared_key |
| 32 | local allowed_ips |
| 33 | local route_allowed_ips |
| 34 | local endpoint_host |
| 35 | local endpoint_port |
| 36 | local persistent_keepalive |
| 37 | |
| 38 | config_get_bool disabled "${peer_config}" "disabled" 0 |
| 39 | config_get public_key "${peer_config}" "public_key" |
| 40 | config_get preshared_key "${peer_config}" "preshared_key" |
| 41 | config_get allowed_ips "${peer_config}" "allowed_ips" |
| 42 | config_get_bool route_allowed_ips "${peer_config}" "route_allowed_ips" 0 |
| 43 | config_get endpoint_host "${peer_config}" "endpoint_host" |
| 44 | config_get endpoint_port "${peer_config}" "endpoint_port" |
| 45 | config_get persistent_keepalive "${peer_config}" "persistent_keepalive" |
| 46 | |
| 47 | if [ "${disabled}" -eq 1 ]; then |
| 48 | # skip disabled peers |
| 49 | return 0 |
| 50 | fi |
| 51 | |
| 52 | if [ -z "$public_key" ]; then |
| 53 | echo "Skipping peer config $peer_config because public key is not defined." |
| 54 | return 0 |
| 55 | fi |
| 56 | |
| 57 | echo "[Peer]" >> "${wg_cfg}" |
| 58 | echo "PublicKey=${public_key}" >> "${wg_cfg}" |
| 59 | if [ "${preshared_key}" ]; then |
| 60 | echo "PresharedKey=${preshared_key}" >> "${wg_cfg}" |
| 61 | fi |
| 62 | for allowed_ip in $allowed_ips; do |
| 63 | echo "AllowedIPs=${allowed_ip}" >> "${wg_cfg}" |
| 64 | done |
| 65 | if [ "${endpoint_host}" ]; then |
| 66 | case "${endpoint_host}" in |
| 67 | *:*) |
| 68 | endpoint="[${endpoint_host}]" |
| 69 | ;; |
| 70 | *) |
| 71 | endpoint="${endpoint_host}" |
| 72 | ;; |
| 73 | esac |
| 74 | if [ "${endpoint_port}" ]; then |
| 75 | endpoint="${endpoint}:${endpoint_port}" |
| 76 | else |
| 77 | endpoint="${endpoint}:51820" |
| 78 | fi |
| 79 | echo "Endpoint=${endpoint}" >> "${wg_cfg}" |
| 80 | fi |
| 81 | if [ "${persistent_keepalive}" ]; then |
| 82 | echo "PersistentKeepalive=${persistent_keepalive}" >> "${wg_cfg}" |
| 83 | fi |
| 84 | |
| 85 | if [ ${route_allowed_ips} -ne 0 ]; then |
| 86 | for allowed_ip in ${allowed_ips}; do |
| 87 | case "${allowed_ip}" in |
| 88 | *:*/*) |
| 89 | proto_add_ipv6_route "${allowed_ip%%/*}" "${allowed_ip##*/}" |
| 90 | ;; |
| 91 | *.*/*) |
| 92 | proto_add_ipv4_route "${allowed_ip%%/*}" "${allowed_ip##*/}" |
| 93 | ;; |
| 94 | *:*) |
| 95 | proto_add_ipv6_route "${allowed_ip%%/*}" "128" |
| 96 | ;; |
| 97 | *.*) |
| 98 | proto_add_ipv4_route "${allowed_ip%%/*}" "32" |
| 99 | ;; |
| 100 | esac |
| 101 | done |
| 102 | fi |
| 103 | } |
| 104 | |
| 105 | ensure_key_is_generated() { |
| 106 | local private_key |
| 107 | private_key="$(uci get network."$1".private_key)" |
| 108 | |
| 109 | if [ "$private_key" == "generate" ]; then |
| 110 | local ucitmp |
| 111 | oldmask="$(umask)" |
| 112 | umask 077 |
| 113 | ucitmp="$(mktemp -d)" |
| 114 | private_key="$("${WG}" genkey)" |
| 115 | uci -q -t "$ucitmp" set network."$1".private_key="$private_key" && \ |
| 116 | uci -q -t "$ucitmp" commit network |
| 117 | rm -rf "$ucitmp" |
| 118 | umask "$oldmask" |
| 119 | fi |
| 120 | } |
| 121 | |
| 122 | proto_wireguard_setup() { |
| 123 | local config="$1" |
| 124 | local wg_dir="/tmp/wireguard" |
| 125 | local wg_cfg="${wg_dir}/${config}" |
| 126 | |
| 127 | local private_key |
| 128 | local listen_port |
| 129 | local mtu |
| 130 | |
| 131 | ensure_key_is_generated "${config}" |
| 132 | |
| 133 | config_load network |
| 134 | config_get private_key "${config}" "private_key" |
| 135 | config_get listen_port "${config}" "listen_port" |
| 136 | config_get addresses "${config}" "addresses" |
| 137 | config_get mtu "${config}" "mtu" |
| 138 | config_get fwmark "${config}" "fwmark" |
| 139 | config_get ip6prefix "${config}" "ip6prefix" |
| 140 | config_get nohostroute "${config}" "nohostroute" |
| 141 | config_get tunlink "${config}" "tunlink" |
| 142 | |
| 143 | ip link del dev "${config}" 2>/dev/null |
| 144 | ip link add dev "${config}" type wireguard |
| 145 | |
| 146 | if [ "${mtu}" ]; then |
| 147 | ip link set mtu "${mtu}" dev "${config}" |
| 148 | fi |
| 149 | |
| 150 | proto_init_update "${config}" 1 |
| 151 | |
| 152 | umask 077 |
| 153 | mkdir -p "${wg_dir}" |
| 154 | echo "[Interface]" > "${wg_cfg}" |
| 155 | echo "PrivateKey=${private_key}" >> "${wg_cfg}" |
| 156 | if [ "${listen_port}" ]; then |
| 157 | echo "ListenPort=${listen_port}" >> "${wg_cfg}" |
| 158 | fi |
| 159 | if [ "${fwmark}" ]; then |
| 160 | echo "FwMark=${fwmark}" >> "${wg_cfg}" |
| 161 | fi |
| 162 | config_foreach proto_wireguard_setup_peer "wireguard_${config}" |
| 163 | |
| 164 | # apply configuration file |
| 165 | ${WG} setconf ${config} "${wg_cfg}" |
| 166 | WG_RETURN=$? |
| 167 | |
| 168 | rm -f "${wg_cfg}" |
| 169 | |
| 170 | if [ ${WG_RETURN} -ne 0 ]; then |
| 171 | sleep 5 |
| 172 | proto_setup_failed "${config}" |
| 173 | exit 1 |
| 174 | fi |
| 175 | |
| 176 | for address in ${addresses}; do |
| 177 | case "${address}" in |
| 178 | *:*/*) |
| 179 | proto_add_ipv6_address "${address%%/*}" "${address##*/}" |
| 180 | ;; |
| 181 | *.*/*) |
| 182 | proto_add_ipv4_address "${address%%/*}" "${address##*/}" |
| 183 | ;; |
| 184 | *:*) |
| 185 | proto_add_ipv6_address "${address%%/*}" "128" |
| 186 | ;; |
| 187 | *.*) |
| 188 | proto_add_ipv4_address "${address%%/*}" "32" |
| 189 | ;; |
| 190 | esac |
| 191 | done |
| 192 | |
| 193 | for prefix in ${ip6prefix}; do |
| 194 | proto_add_ipv6_prefix "$prefix" |
| 195 | done |
| 196 | |
| 197 | # endpoint dependency |
| 198 | if [ "${nohostroute}" != "1" ]; then |
| 199 | wg show "${config}" endpoints | \ |
| 200 | sed -E 's/\[?([0-9.:a-f]+)\]?:([0-9]+)/\1 \2/' | \ |
| 201 | while IFS=$'\t ' read -r key address port; do |
| 202 | [ -n "${port}" ] || continue |
| 203 | proto_add_host_dependency "${config}" "${address}" "${tunlink}" |
| 204 | done |
| 205 | fi |
| 206 | |
| 207 | proto_send_update "${config}" |
| 208 | } |
| 209 | |
| 210 | proto_wireguard_teardown() { |
| 211 | local config="$1" |
| 212 | ip link del dev "${config}" >/dev/null 2>&1 |
| 213 | } |
| 214 | |
| 215 | [ -n "$INCLUDE_ONLY" ] || { |
| 216 | add_protocol wireguard |
| 217 | } |