Fix regression with IPv6 source-dest-routes
[project/netifd.git] / scripts / netifd-proto.sh
1 NETIFD_MAIN_DIR="${NETIFD_MAIN_DIR:-/lib/netifd}"
2
3 . /usr/share/libubox/jshn.sh
4 . $NETIFD_MAIN_DIR/utils.sh
5
6 proto_config_add_int() {
7 config_add_int "$@"
8 }
9
10 proto_config_add_string() {
11 config_add_string "$@"
12 }
13
14 proto_config_add_boolean() {
15 config_add_boolean "$@"
16 }
17
18 _proto_do_teardown() {
19 json_load "$data"
20 eval "proto_$1_teardown \"$interface\" \"$ifname\""
21 }
22
23 _proto_do_renew() {
24 json_load "$data"
25 eval "proto_$1_renew \"$interface\" \"$ifname\""
26 }
27
28 _proto_do_setup() {
29 json_load "$data"
30 _EXPORT_VAR=0
31 _EXPORT_VARS=
32 eval "proto_$1_setup \"$interface\" \"$ifname\""
33 }
34
35 proto_init_update() {
36 local ifname="$1"
37 local up="$2"
38 local external="$3"
39
40 PROTO_KEEP=0
41 PROTO_INIT=1
42 PROTO_TUNNEL_OPEN=
43 PROTO_IPADDR=
44 PROTO_IP6ADDR=
45 PROTO_ROUTE=
46 PROTO_ROUTE6=
47 PROTO_PREFIX6=
48 PROTO_DNS=
49 PROTO_DNS_SEARCH=
50 json_init
51 json_add_int action 0
52 [ -n "$ifname" -a "*" != "$ifname" ] && json_add_string "ifname" "$ifname"
53 json_add_boolean "link-up" "$up"
54 [ -n "$3" ] && json_add_boolean "address-external" "$external"
55 }
56
57 proto_set_keep() {
58 PROTO_KEEP="$1"
59 }
60
61 proto_close_nested() {
62 [ -n "$PROTO_NESTED_OPEN" ] && json_close_object
63 PROTO_NESTED_OPEN=
64 }
65
66 proto_add_nested() {
67 PROTO_NESTED_OPEN=1
68 json_add_object "$1"
69 }
70
71 proto_add_tunnel() {
72 proto_add_nested "tunnel"
73 }
74
75 proto_close_tunnel() {
76 proto_close_nested
77 }
78
79 proto_add_data() {
80 proto_add_nested "data"
81 }
82
83 proto_close_data() {
84 proto_close_nested
85 }
86
87 proto_add_dns_server() {
88 local address="$1"
89
90 append PROTO_DNS "$address"
91 }
92
93 proto_add_dns_search() {
94 local address="$1"
95
96 append PROTO_DNS_SEARCH "$address"
97 }
98
99 proto_add_ipv4_address() {
100 local address="$1"
101 local mask="$2"
102 local broadcast="$3"
103 local ptp="$4"
104
105 append PROTO_IPADDR "$address/$mask/$broadcast/$ptp"
106 }
107
108 proto_add_ipv6_address() {
109 local address="$1"
110 local mask="$2"
111 local preferred="$3"
112 local valid="$4"
113 local offlink="$5"
114 local class="$6"
115
116 append PROTO_IP6ADDR "$address/$mask/$preferred/$valid/$offlink/$class"
117 }
118
119 proto_add_ipv4_route() {
120 local target="$1"
121 local mask="$2"
122 local gw="$3"
123 local source="$4"
124
125 append PROTO_ROUTE "$target/$mask/$gw////$source"
126 }
127
128 proto_add_ipv6_route() {
129 local target="$1"
130 local mask="$2"
131 local gw="$3"
132 local metric="$4"
133 local valid="$5"
134 local source="$6"
135 local table="$7"
136
137 append PROTO_ROUTE6 "$target/$mask/$gw/$metric/$valid/$table/$source"
138 }
139
140 proto_add_ipv6_prefix() {
141 local prefix="$1"
142 local valid="$2"
143 local preferred="$3"
144
145 if [ -z "$valid" ]; then
146 append PROTO_PREFIX6 "$prefix"
147 else
148 [ -z "$preferred" ] && preferred="$valid"
149 append PROTO_PREFIX6 "$prefix,$valid,$preferred"
150 fi
151 }
152
153 _proto_push_ipv4_addr() {
154 local str="$1"
155 local address mask broadcast ptp
156
157 address="${str%%/*}"
158 str="${str#*/}"
159 mask="${str%%/*}"
160 str="${str#*/}"
161 broadcast="${str%%/*}"
162 str="${str#*/}"
163 ptp="$str"
164
165 json_add_object ""
166 json_add_string ipaddr "$address"
167 [ -n "$mask" ] && json_add_string mask "$mask"
168 [ -n "$broadcast" ] && json_add_string broadcast "$broadcast"
169 [ -n "$ptp" ] && json_add_string ptp "$ptp"
170 json_close_object
171 }
172
173 _proto_push_ipv6_addr() {
174 local str="$1"
175 local address mask preferred valid offlink
176
177 address="${str%%/*}"
178 str="${str#*/}"
179 mask="${str%%/*}"
180 str="${str#*/}"
181 preferred="${str%%/*}"
182 str="${str#*/}"
183 valid="${str%%/*}"
184 str="${str#*/}"
185 offlink="${str%%/*}"
186 str="${str#*/}"
187 class="${str%%/*}"
188
189 json_add_object ""
190 json_add_string ipaddr "$address"
191 [ -n "$mask" ] && json_add_string mask "$mask"
192 [ -n "$preferred" ] && json_add_int preferred "$preferred"
193 [ -n "$valid" ] && json_add_int valid "$valid"
194 [ -n "$offlink" ] && json_add_boolean offlink "$offlink"
195 [ -n "$class" ] && json_add_string class "$class"
196 json_close_object
197 }
198
199 _proto_push_string() {
200 json_add_string "" "$1"
201 }
202
203 _proto_push_route() {
204 local str="$1";
205 local target="${str%%/*}"
206 str="${str#*/}"
207 local mask="${str%%/*}"
208 str="${str#*/}"
209 local gw="${str%%/*}"
210 str="${str#*/}"
211 local metric="${str%%/*}"
212 str="${str#*/}"
213 local valid="${str%%/*}"
214 str="${str#*/}"
215 local table="${str%%/*}"
216 str="${str#*/}"
217 local source="${str}"
218
219 json_add_object ""
220 json_add_string target "$target"
221 json_add_string netmask "$mask"
222 [ -n "$gw" ] && json_add_string gateway "$gw"
223 [ -n "$metric" ] && json_add_int metric "$metric"
224 [ -n "$valid" ] && json_add_int valid "$valid"
225 [ -n "$source" ] && json_add_string source "$source"
226 [ -n "$table" ] && json_add_string table "$table"
227 json_close_object
228 }
229
230 _proto_push_array() {
231 local name="$1"
232 local val="$2"
233 local cb="$3"
234
235 [ -n "$val" ] || return 0
236 json_add_array "$name"
237 for item in $val; do
238 eval "$cb \"\$item\""
239 done
240 json_close_array
241 }
242
243 _proto_notify() {
244 local interface="$1"
245 local options="$2"
246 json_add_string "interface" "$interface"
247 ubus $options call network.interface notify_proto "$(json_dump)"
248 }
249
250 proto_send_update() {
251 local interface="$1"
252
253 proto_close_nested
254 json_add_boolean keep "$PROTO_KEEP"
255 _proto_push_array "ipaddr" "$PROTO_IPADDR" _proto_push_ipv4_addr
256 _proto_push_array "ip6addr" "$PROTO_IP6ADDR" _proto_push_ipv6_addr
257 _proto_push_array "routes" "$PROTO_ROUTE" _proto_push_route
258 _proto_push_array "routes6" "$PROTO_ROUTE6" _proto_push_route
259 _proto_push_array "ip6prefix" "$PROTO_PREFIX6" _proto_push_string
260 _proto_push_array "dns" "$PROTO_DNS" _proto_push_string
261 _proto_push_array "dns_search" "$PROTO_DNS_SEARCH" _proto_push_string
262 _proto_notify "$interface"
263 }
264
265 proto_export() {
266 local var="VAR${_EXPORT_VAR}"
267 _EXPORT_VAR="$(($_EXPORT_VAR + 1))"
268 export -- "$var=$1"
269 append _EXPORT_VARS "$var"
270 }
271
272 proto_run_command() {
273 local interface="$1"; shift
274
275 json_init
276 json_add_int action 1
277 json_add_array command
278 while [ $# -gt 0 ]; do
279 json_add_string "" "$1"
280 shift
281 done
282 json_close_array
283 [ -n "$_EXPORT_VARS" ] && {
284 json_add_array env
285 for var in $_EXPORT_VARS; do
286 eval "json_add_string \"\" \"\${$var}\""
287 done
288 json_close_array
289 }
290 _proto_notify "$interface"
291 }
292
293 proto_kill_command() {
294 local interface="$1"; shift
295
296 json_init
297 json_add_int action 2
298 [ -n "$1" ] && json_add_int signal "$1"
299 _proto_notify "$interface"
300 }
301
302 proto_notify_error() {
303 local interface="$1"; shift
304
305 json_init
306 json_add_int action 3
307 json_add_array error
308 while [ $# -gt 0 ]; do
309 json_add_string "" "$1"
310 shift
311 done
312 json_close_array
313 _proto_notify "$interface"
314 }
315
316 proto_block_restart() {
317 local interface="$1"; shift
318
319 json_init
320 json_add_int action 4
321 _proto_notify "$interface"
322 }
323
324 proto_set_available() {
325 local interface="$1"
326 local state="$2"
327 json_init
328 json_add_int action 5
329 json_add_boolean available "$state"
330 _proto_notify "$interface"
331 }
332
333 proto_add_host_dependency() {
334 local interface="$1"
335 local host="$2"
336 local ifname="$3"
337
338 # execute in subshell to not taint callers env
339 # see tickets #11046, #11545, #11570
340 (
341 json_init
342 json_add_int action 6
343 json_add_string host "$host"
344 [ -n "$ifname" ] && json_add_string ifname "$ifname"
345 _proto_notify "$interface" -S
346 )
347 }
348
349 proto_setup_failed() {
350 local interface="$1"
351 json_init
352 json_add_int action 7
353 _proto_notify "$interface"
354 }
355
356 init_proto() {
357 proto="$1"; shift
358 cmd="$1"; shift
359
360 case "$cmd" in
361 dump)
362 add_protocol() {
363 no_device=0
364 available=0
365 renew_handler=0
366
367 add_default_handler "proto_$1_init_config"
368
369 json_init
370 json_add_string "name" "$1"
371 json_add_array "config"
372 eval "proto_$1_init_config"
373 json_close_array
374 json_add_boolean no-device "$no_device"
375 json_add_boolean available "$available"
376 json_add_boolean renew-handler "$renew_handler"
377 json_dump
378 }
379 ;;
380 setup|teardown|renew)
381 interface="$1"; shift
382 data="$1"; shift
383 ifname="$1"; shift
384
385 add_protocol() {
386 [[ "$proto" == "$1" ]] || return 0
387
388 case "$cmd" in
389 setup) _proto_do_setup "$1";;
390 teardown) _proto_do_teardown "$1" ;;
391 renew) _proto_do_renew "$1" ;;
392 *) return 1 ;;
393 esac
394 }
395 ;;
396 esac
397 }