Merge pull request #23787 from stangri/master-curl
[feed/packages.git] / net / yggdrasil / files / yggdrasil.sh
1 #!/bin/sh
2
3
4 [ -n "$INCLUDE_ONLY" ] || {
5 . /lib/functions.sh
6 . ../netifd-proto.sh
7 init_proto "$@"
8 }
9
10 proto_yggdrasil_init_config() {
11 available=1
12
13 # Yggdrasil
14 proto_config_add_string "private_key"
15 proto_config_add_boolean "allocate_listen_addresses"
16
17 # Jumper
18 proto_config_add_boolean "jumper_enable"
19 proto_config_add_string "jumper_loglevel"
20 proto_config_add_boolean "jumper_autofill_listen_addresses"
21 proto_config_add_string "jumper_config"
22 }
23
24 proto_yggdrasil_setup_peer_if_non_interface() {
25 local peer_config="$1"
26 local peer_address
27 local peer_interface
28 config_get peer_address "${peer_config}" "address"
29 config_get peer_interface "${peer_config}" "interface"
30 if [ -z ${peer_interface} ]; then
31 json_add_string "" ${peer_address}
32 fi;
33 }
34
35 proto_yggdrasil_dump_peer_interface() {
36 local peer_config="$1"
37 local peer_interface
38
39 config_get peer_interface "${peer_config}" "interface"
40
41 if [ ! -z ${peer_interface} ]; then
42 peer_interfaces="${peer_interfaces}\n${peer_interface}"
43 fi;
44 }
45
46 proto_yggdrasil_setup_peer_if_interface() {
47 local peer_config="$1"
48 local peer_address
49 local peer_interface
50 config_get peer_interface "${peer_config}" "interface"
51 if [ "${peer_interface}" = "${peer_interface_filter}" ]; then
52 config_get peer_address "${peer_config}" "address"
53 json_add_string "" ${peer_address}
54 fi;
55 }
56
57 proto_yggdrasil_append_to_interface_regex() {
58 if [ -z "${regex}" ]; then
59 regex="$1"
60 else
61 regex="${regex}|$1";
62 fi;
63 }
64
65 proto_yggdrasil_setup_multicast_interface() {
66 local interface_config="$1"
67 local beacon
68 local listen
69 local port=0
70 local password
71 local regex=""
72
73 config_get beacon "${interface_config}" "beacon"
74 config_get listen "${interface_config}" "listen"
75 config_get port "${interface_config}" "port"
76 config_get password "${interface_config}" "password"
77
78 json_add_object ""
79 json_add_boolean "Beacon" $beacon
80 json_add_boolean "Listen" $listen
81 if [ ! -z ${port} ]; then
82 json_add_int "Port" $port
83 else
84 json_add_int "Port" 0
85 fi;
86 if [ ! -z ${password} ]; then
87 json_add_string "Password" $password
88 fi;
89
90 config_list_foreach "${interface_config}" interface proto_yggdrasil_append_to_interface_regex
91
92 json_add_string "Regex" "^(${regex})\$"
93
94 json_close_object
95 }
96
97 proto_yggdrasil_add_string() {
98 json_add_string "" $1
99 }
100
101 proto_yggdrasil_generate_keypair() {
102 json_load "$(yggdrasil -genconf -json)"
103 json_get_vars PrivateKey
104 json_cleanup
105 private_key=$PrivateKey
106 public_key=${PrivateKey:64}
107 }
108
109 proto_yggdrasil_allocate_listen_addresses() {
110 local config="$1"
111
112 # Collect already defined protocols
113 protocols=""
114 _add_address_protocol() {
115 protocols="${protocols}$(echo $1 | cut -d "://" -f1) "
116 }
117 config_list_foreach "$config" listen_address _add_address_protocol
118
119 # Add new address for each previously unspecified protocol
120 for protocol in "tls" "quic"; do
121 if ! echo "$protocols" | grep "$protocol" &>/dev/null; then
122 # By default linux dynamically alocates ports in the range 32768..60999
123 # `sysctl net.ipv4.ip_local_port_range`
124 random_port=$(( ($RANDOM + $RANDOM) % 22767 + 10000 ))
125 proto_yggdrasil_add_string "${protocol}://127.0.0.1:${random_port}"
126 fi
127 done
128 }
129
130 proto_yggdrasil_generate_jumper_config() {
131 local config="$1"
132 local ygg_sock="$2"
133 local ygg_cfg="$3"
134
135 # Autofill Yggdrasil listeners
136 config_get is_autofill_listeners "$config" "jumper_autofill_listen_addresses"
137 if [ "$is_autofill_listeners" == "1" ]; then
138 echo "yggdrasil_listen = ["
139 _print_address() {
140 echo "\"${1}\","
141 }
142 json_load_file "${ygg_cfg}"
143 json_for_each_item _print_address "Listen"
144 echo "]"
145 fi
146
147 # Print admin api socket
148 echo "yggdrasil_admin_listen = [ \"${ygg_sock}\" ]"
149
150 # Print extra config
151 config_get jumper_config "$config" "jumper_config"
152 echo "${jumper_config}"
153 }
154
155 proto_yggdrasil_setup() {
156 local config="$1"
157 local device="$2"
158 local ygg_dir="/tmp/yggdrasil"
159 local ygg_cfg="${ygg_dir}/${config}.conf"
160 local ygg_sock="unix://${ygg_dir}/${config}.sock"
161
162
163 local private_key
164 local public_key
165 local mtu
166 local listen_addresses
167 local whitelisted_keys
168 local node_info
169 local node_info_privacy
170
171 config_load network
172 config_get private_key "${config}" "private_key"
173 config_get public_key "${config}" "public_key"
174 config_get mtu "${config}" "mtu"
175 config_get node_info "${config}" "node_info"
176 config_get node_info_privacy "${config}" "node_info_privacy"
177
178 if [ -z $private_key ]; then
179 proto_yggdrasil_generate_keypair
180 fi;
181
182 umask 077
183 mkdir -p "${ygg_dir}"
184
185 if [ $private_key = "auto" ]; then
186 proto_yggdrasil_generate_keypair
187 uci -t ${ygg_dir}/.uci.${config} batch <<EOF
188 set network.${config}.private_key='${private_key}'
189 set network.${config}.public_key='${public_key}'
190 EOF
191 uci -t ${ygg_dir}/.uci.${config} commit;
192 fi;
193
194 # Generate config file
195 json_init
196 json_add_string "IfName" ${config}
197 json_add_string "AdminListen" ${ygg_sock}
198
199 json_add_string "PrivateKey" ${private_key}
200 json_add_string "PublicKey" ${public_key}
201
202 if [ ! -z $mtu ]; then
203 json_add_int "IfMTU" ${mtu}
204 fi;
205
206 if [ ! -z $node_info ]; then
207 json_add_string "NodeInfo" "%%_YGGDRASIL_NODEINFO_TEMPLATE_%%"
208 fi;
209
210 json_add_boolean "NodeInfoPrivacy" ${node_info_privacy}
211
212 # Peers
213 json_add_array "Peers"
214 config_foreach proto_yggdrasil_setup_peer_if_non_interface "yggdrasil_${config}_peer"
215 json_close_array
216
217 local peer_interfaces
218 peer_interfaces=""
219 config_foreach proto_yggdrasil_dump_peer_interface "yggdrasil_${config}_peer"
220 peer_interfaces=$(echo -e ${peer_interfaces} | sort | uniq)
221
222 json_add_object "InterfacePeers"
223 for peer_interface_filter in ${peer_interfaces}; do
224 json_add_array "${peer_interface_filter}"
225 config_foreach proto_yggdrasil_setup_peer_if_interface "yggdrasil_${config}_peer"
226 json_close_array
227 done
228 json_close_object
229
230 json_add_array "AllowedPublicKeys"
231 config_list_foreach "$config" allowed_public_key proto_yggdrasil_add_string
232 json_close_array
233
234 json_add_array "Listen"
235 config_list_foreach "$config" listen_address proto_yggdrasil_add_string
236
237 # If needed, add new address for each previously unspecified protocol
238 config_get is_jumper_enabled "$config" "jumper_enable"
239 config_get allocate_listen_addresses "$config" "allocate_listen_addresses"
240 if [ "$is_jumper_enabled" == "1" ] && [ "$allocate_listen_addresses" == "1" ]; then
241 proto_yggdrasil_allocate_listen_addresses "$config"
242 fi
243
244 json_close_array
245
246 json_add_array "MulticastInterfaces"
247 config_foreach proto_yggdrasil_setup_multicast_interface "yggdrasil_${config}_interface"
248 json_close_array
249
250 json_dump > "${ygg_cfg}.1"
251 awk -v s='"%%_YGGDRASIL_NODEINFO_TEMPLATE_%%"' -v r="${node_info}" '{gsub(s, r)} 1' "${ygg_cfg}.1" > ${ygg_cfg}
252 rm "${ygg_cfg}.1"
253
254 proto_run_command "$config" /usr/sbin/yggdrasil -useconffile "${ygg_cfg}"
255 proto_init_update "$config" 1
256 proto_add_ipv6_address "$(yggdrasil -useconffile "${ygg_cfg}" -address)" "7"
257 proto_add_ipv6_prefix "$(yggdrasil -useconffile "${ygg_cfg}" -subnet)"
258 proto_send_update "$config"
259
260 # Start jumper if needed
261 config_get is_jumper_enabled "$config" "jumper_enable"
262 if [ "$is_jumper_enabled" == "1" ] && [ -f /usr/sbin/yggdrasil-jumper ]; then
263 jumper_cfg="${ygg_dir}/${config}-jumper.conf"
264 proto_yggdrasil_generate_jumper_config "$config" "$ygg_sock" "$ygg_cfg" > "$jumper_cfg"
265
266 config_get jumper_loglevel "$config" "jumper_loglevel"
267 sh -c "sleep 2 && exec /usr/sbin/yggdrasil-jumper --loglevel \"${jumper_loglevel:-info}\" --config \"$jumper_cfg\" 2&>1 | logger -t \"${config}-jumper\"" &
268 fi
269 }
270
271 proto_yggdrasil_teardown() {
272 local interface="$1"
273 proto_kill_command "$interface"
274 }
275
276 [ -n "$INCLUDE_ONLY" ] || {
277 add_protocol yggdrasil
278 }