682538564835b912f460120b887e3fe685ca336d
[openwrt.git] / package / 6to4 / files / 6to4.sh
1 #!/bin/sh
2 # 6to4.sh - IPv6-in-IPv4 tunnel backend
3 # Copyright (c) 2010-2012 OpenWrt.org
4
5 [ -n "$INCLUDE_ONLY" ] || {
6         . /etc/functions.sh
7         . ../netifd-proto.sh
8         init_proto "$@"
9 }
10
11 find_6to4_wanif() {
12         local if=$(ip -4 r l e 0.0.0.0/0); if="${if#default* dev }"; if="${if%% *}"
13         [ -n "$if" ] && grep -qs "^ *$if:" /proc/net/dev && echo "$if"
14 }
15
16 find_6to4_wanip() {
17         local ip=$(ip -4 a s dev "$1"); ip="${ip#*inet }"
18         echo "${ip%%[^0-9.]*}"
19 }
20
21 find_6to4_prefix() {
22         local ip4="$1"
23         local oIFS="$IFS"; IFS="."; set -- $ip4; IFS="$oIFS"
24
25         printf "2002:%02x%02x:%02x%02x\n" $1 $2 $3 $4
26 }
27
28 test_6to4_rfc1918()
29 {
30         local oIFS="$IFS"; IFS="."; set -- $1; IFS="$oIFS"
31         [ $1 -eq  10 ] && return 0
32         [ $1 -eq 192 ] && [ $2 -eq 168 ] && return 0
33         [ $1 -eq 172 ] && [ $2 -ge  16 ] && [ $2 -le  31 ] && return 0
34         return 1
35 }
36
37 set_6to4_radvd_interface() {
38         local cfgid="$1"
39         local lanif="${2:-lan}"
40         local ifmtu="${3:-1280}"
41         local ifsection=""
42
43         find_ifsection() {
44                 local net
45                 local cfg="$1"
46                 config_get net "$cfg" interface
47
48                 [ "$net" = "$lanif" ] && {
49                         ifsection="$cfg"
50                         return 1
51                 }
52         }
53
54         config_foreach find_ifsection interface
55
56         [ -z "$ifsection" ] && {
57                 ifsection="iface_$sid"
58                 uci_set_state radvd "$ifsection" "" interface
59                 uci_set_state radvd "$ifsection" interface "$lanif"
60         }
61
62         uci_set_state radvd "$ifsection" ignore            0
63         uci_set_state radvd "$ifsection" IgnoreIfMissing   1
64         uci_set_state radvd "$ifsection" AdvSendAdvert     1
65         uci_set_state radvd "$ifsection" MaxRtrAdvInterval 30
66         uci_set_state radvd "$ifsection" AdvLinkMTU        "$ifmtu"
67 }
68
69 set_6to4_radvd_prefix() {
70         local cfgid="$1"
71         local lanif="${2:-lan}"
72         local wanif="${3:-wan}"
73         local prefix="${4:-0:0:0:1::/64}"
74         local vlt="${5:-300}"
75         local plt="${6:-120}"
76         local pfxsection=""
77
78         find_pfxsection() {
79                 local net base
80                 local cfg="$1"
81                 config_get net  "$cfg" interface
82                 config_get base "$cfg" Base6to4Interface
83
84                 [ "$net" = "$lanif" ] && [ "$base" = "$wanif" ] && {
85                         pfxsection="$cfg"
86                         return 1
87                 }
88         }
89
90         config_foreach find_pfxsection prefix
91
92         [ -z "$pfxsection" ] && {
93                 pfxsection="prefix_${sid}_${lanif}"
94                 uci_set_state radvd "$pfxsection" ""                   prefix
95                 uci_set_state radvd "$pfxsection" ignore               0
96                 uci_set_state radvd "$pfxsection" interface            "$lanif"
97                 uci_set_state radvd "$pfxsection" prefix               "$prefix"
98                 uci_set_state radvd "$pfxsection" AdvOnLink            1
99                 uci_set_state radvd "$pfxsection" AdvAutonomous        1
100                 uci_set_state radvd "$pfxsection" AdvValidLifetime     "$vlt"
101                 uci_set_state radvd "$pfxsection" AdvPreferredLifetime "$plt"
102                 uci_set_state radvd "$pfxsection" Base6to4Interface    "$wanif"
103         }
104 }
105
106 tun_error() {
107         local cfg="$1"; shift;
108
109         [ -n "$1" ] && proto_notify_error "$cfg" "$@"
110         proto_block_restart "$cfg"
111 }
112
113 proto_6to4_setup() {
114         local cfg="$1"
115         local iface="$2"
116         local link="6to4-$cfg"
117
118         json_get_var mtu mtu
119         json_get_var ttl ttl
120         json_get_var local4 ipaddr
121
122         json_get_var adv_subnet adv_subnet
123         json_get_var adv_interface adv_interface
124         json_get_var adv_valid_lifetime adv_valid_lifetime
125         json_get_var adv_preferred_lifetime adv_preferred_lifetime
126
127         local wanif=$(find_6to4_wanif)
128         [ -z "$wanif" ] && {
129                 tun_error "$cfg" "NO_WAN_LINK"
130                 return
131         }
132
133         . /lib/network/config.sh
134         local wancfg="$(find_config "$wanif")"
135         [ -z "$wancfg" ] && {
136                 tun_error "$cfg" "NO_WAN_LINK"
137                 return
138         }
139
140         # If local4 is unset, guess local IPv4 address from the
141         # interface used by the default route.
142         [ -z "$local4" ] && {
143                 [ -n "$wanif" ] && local4=$(find_6to4_wanip "$wanif")
144         }
145
146         [ -z "$local4" ] && {
147                 tun_error "$cfg" "NO_WAN_LINK"
148                 return
149         }
150
151         test_6to4_rfc1918 "$local4" && {
152                 tun_error "$cfg" "INVALID_LOCAL_ADDRESS"
153                 return
154         }
155
156         # find our local prefix
157         local prefix6=$(find_6to4_prefix "$local4")
158         local local6="$prefix6::1"
159
160         proto_init_update "$link" 1
161         proto_add_ipv6_address "$local6" 16
162         proto_add_ipv6_route "::" 0 "::192.88.99.1"
163
164         proto_add_tunnel
165         json_add_string mode sit
166         json_add_int mtu "${mtu:-1280}"
167         json_add_int ttl "${ttl:-64}"
168         json_add_string local "$local4"
169         proto_close_tunnel
170
171         proto_send_update "$cfg"
172
173         [ -f /etc/config/radvd ] && /etc/init.d/radvd enabled && {
174                 local sid="6to4_$cfg"
175
176                 uci_revert_state radvd
177                 config_load radvd
178
179                 adv_subnet=$((0x${adv_subnet:-1}))
180
181                 local adv_subnets=""
182
183                 for adv_interface in ${adv_interface:-lan}; do
184                         local adv_ifname
185                         config_get adv_ifname "${adv_interface:-lan}" ifname
186
187                         grep -qs "^ *$adv_ifname:" /proc/net/dev && {
188                                 local subnet6="$(printf "%s:%x::1/64" "$prefix6" $adv_subnet)"
189
190                                 logger -t "$link" " * Advertising IPv6 subnet $subnet6 on ${adv_interface:-lan} ($adv_ifname)"
191                                 ip -6 addr add $subnet6 dev $adv_ifname
192
193                                 set_6to4_radvd_interface "$sid" "$adv_interface" "$mtu"
194                                 set_6to4_radvd_prefix    "$sid" "$adv_interface" \
195                                         "$wancfg" "$(printf "0:0:0:%x::/64" $adv_subnet)" \
196                                         "$adv_valid_lifetime" "$adv_preferred_lifetime"
197
198                                 adv_subnets="${adv_subnets:+$adv_subnets }$adv_ifname:$subnet6"
199                                 adv_subnet=$(($adv_subnet + 1))
200                         }
201                 done
202
203                 uci_set_state network "$cfg" adv_subnets "$adv_subnets"
204
205                 /etc/init.d/radvd restart
206         }
207 }
208
209 proto_6to4_teardown() {
210         local cfg="$1"
211         local link="6to4-$cfg"
212
213         local adv_subnets=$(uci_get_state network "$cfg" adv_subnets)
214
215         grep -qs "^ *$link:" /proc/net/dev && {
216                 [ -n "$adv_subnets" ] && {
217                         uci_revert_state radvd
218                         /etc/init.d/radvd enabled && /etc/init.d/radvd restart
219                 }
220         }
221 }
222
223 proto_6to4_init_config() {
224         no_device=1             
225         available=1
226
227         proto_config_add_string "ipaddr"
228         proto_config_add_int "mtu"
229         proto_config_add_int "ttl"
230         proto_config_add_string "adv_interface"
231         proto_config_add_string "adv_subnet"
232         proto_config_add_int "adv_valid_lifetime"
233         proto_config_add_int "adv_preferred_lifetime"
234 }
235
236 [ -n "$INCLUDE_ONLY" ] || {
237         add_protocol 6to4
238 }