| 1 | # 6to4.sh - IPv6-in-IPv4 tunnel backend |
| 2 | # Copyright (c) 2010-2011 OpenWrt.org |
| 3 | |
| 4 | find_6to4_wanif() { |
| 5 | local if=$(ip -4 r l e 0.0.0.0/0); if="${if#default* dev }"; if="${if%% *}" |
| 6 | [ -n "$if" ] && grep -qs "^ *$if:" /proc/net/dev && echo "$if" |
| 7 | } |
| 8 | |
| 9 | find_6to4_wanip() { |
| 10 | local ip=$(ip -4 a s dev "$1"); ip="${ip#*inet }" |
| 11 | echo "${ip%%[^0-9.]*}" |
| 12 | } |
| 13 | |
| 14 | find_6to4_prefix() { |
| 15 | local ip4="$1" |
| 16 | local oIFS="$IFS"; IFS="."; set -- $ip4; IFS="$oIFS" |
| 17 | |
| 18 | printf "2002:%02x%02x:%02x%02x\n" $1 $2 $3 $4 |
| 19 | } |
| 20 | |
| 21 | test_6to4_rfc1918() |
| 22 | { |
| 23 | local oIFS="$IFS"; IFS="."; set -- $1; IFS="$oIFS" |
| 24 | [ $1 -eq 10 ] && return 0 |
| 25 | [ $1 -eq 192 ] && [ $2 -eq 168 ] && return 0 |
| 26 | [ $1 -eq 172 ] && [ $2 -ge 16 ] && [ $2 -le 31 ] && return 0 |
| 27 | return 1 |
| 28 | } |
| 29 | |
| 30 | set_6to4_radvd_interface() { |
| 31 | local cfgid="$1" |
| 32 | local lanif="${2:-lan}" |
| 33 | local ifmtu="${3:-1280}" |
| 34 | local ifsection="" |
| 35 | |
| 36 | find_ifsection() { |
| 37 | local net |
| 38 | local cfg="$1" |
| 39 | config_get net "$cfg" interface |
| 40 | |
| 41 | [ "$net" = "$lanif" ] && { |
| 42 | ifsection="$cfg" |
| 43 | return 1 |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | config_foreach find_ifsection interface |
| 48 | |
| 49 | [ -z "$ifsection" ] && { |
| 50 | ifsection="iface_$sid" |
| 51 | uci_set_state radvd "$ifsection" "" interface |
| 52 | uci_set_state radvd "$ifsection" interface "$lanif" |
| 53 | } |
| 54 | |
| 55 | uci_set_state radvd "$ifsection" ignore 0 |
| 56 | uci_set_state radvd "$ifsection" IgnoreIfMissing 1 |
| 57 | uci_set_state radvd "$ifsection" AdvSendAdvert 1 |
| 58 | uci_set_state radvd "$ifsection" MaxRtrAdvInterval 30 |
| 59 | uci_set_state radvd "$ifsection" AdvLinkMTU "$ifmtu" |
| 60 | } |
| 61 | |
| 62 | set_6to4_radvd_prefix() { |
| 63 | local cfgid="$1" |
| 64 | local lanif="${2:-lan}" |
| 65 | local wanif="${3:-wan}" |
| 66 | local prefix="${4:-0:0:0:1::/64}" |
| 67 | local vlt="${5:-300}" |
| 68 | local plt="${6:-120}" |
| 69 | local pfxsection="" |
| 70 | |
| 71 | find_pfxsection() { |
| 72 | local net base |
| 73 | local cfg="$1" |
| 74 | config_get net "$cfg" interface |
| 75 | config_get base "$cfg" Base6to4Interface |
| 76 | |
| 77 | [ "$net" = "$lanif" ] && [ "$base" = "$wanif" ] && { |
| 78 | pfxsection="$cfg" |
| 79 | return 1 |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | config_foreach find_pfxsection prefix |
| 84 | |
| 85 | [ -z "$pfxsection" ] && { |
| 86 | pfxsection="prefix_${sid}_${lanif}" |
| 87 | uci_set_state radvd "$pfxsection" "" prefix |
| 88 | uci_set_state radvd "$pfxsection" ignore 0 |
| 89 | uci_set_state radvd "$pfxsection" interface "$lanif" |
| 90 | uci_set_state radvd "$pfxsection" prefix "$prefix" |
| 91 | uci_set_state radvd "$pfxsection" AdvOnLink 1 |
| 92 | uci_set_state radvd "$pfxsection" AdvAutonomous 1 |
| 93 | uci_set_state radvd "$pfxsection" AdvValidLifetime "$vlt" |
| 94 | uci_set_state radvd "$pfxsection" AdvPreferredLifetime "$plt" |
| 95 | uci_set_state radvd "$pfxsection" Base6to4Interface "$wanif" |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | |
| 100 | # Hook into scan_interfaces() to synthesize a .device option |
| 101 | # This is needed for /sbin/ifup to properly dispatch control |
| 102 | # to setup_interface_6to4() even if no .ifname is set in |
| 103 | # the configuration. |
| 104 | scan_6to4() { |
| 105 | config_set "$1" device "6to4-$1" |
| 106 | } |
| 107 | |
| 108 | coldplug_interface_6to4() { |
| 109 | setup_interface_6to4 "6to4-$1" "$1" |
| 110 | } |
| 111 | |
| 112 | setup_interface_6to4() { |
| 113 | local iface="$1" |
| 114 | local cfg="$2" |
| 115 | local link="6to4-$cfg" |
| 116 | |
| 117 | local local4=$(uci_get network "$cfg" ipaddr) |
| 118 | |
| 119 | local mtu |
| 120 | config_get mtu "$cfg" mtu |
| 121 | |
| 122 | local ttl |
| 123 | config_get ttl "$cfg" ttl |
| 124 | |
| 125 | local metric |
| 126 | config_get metric "$cfg" metric |
| 127 | |
| 128 | local defaultroute |
| 129 | config_get_bool defaultroute "$cfg" defaultroute 1 |
| 130 | |
| 131 | local wanif=$(find_6to4_wanif) |
| 132 | [ -z "$wanif" ] && { |
| 133 | logger -t "$link" "Cannot find wan interface - aborting" |
| 134 | return |
| 135 | } |
| 136 | |
| 137 | local wancfg=$(find_config "$wanif") |
| 138 | [ -z "$wancfg" ] && { |
| 139 | logger -t "$link" "Cannot find wan network - aborting" |
| 140 | return |
| 141 | } |
| 142 | |
| 143 | # If local4 is unset, guess local IPv4 address from the |
| 144 | # interface used by the default route. |
| 145 | [ -z "$local4" ] && { |
| 146 | [ -n "$wanif" ] && { |
| 147 | local4=$(find_6to4_wanip "$wanif") |
| 148 | uci_set_state network "$cfg" wan_device "$wanif" |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | test_6to4_rfc1918 "$local4" && { |
| 153 | logger -t "$link" "Local wan ip $local4 is private - aborting" |
| 154 | return |
| 155 | } |
| 156 | |
| 157 | [ -n "$local4" ] && { |
| 158 | logger -t "$link" "Starting ..." |
| 159 | |
| 160 | # creating the tunnel below will trigger a net subsystem event |
| 161 | # prevent it from touching or iface by disabling .auto here |
| 162 | uci_set_state network "$cfg" ifname $link |
| 163 | uci_set_state network "$cfg" auto 0 |
| 164 | |
| 165 | # find our local prefix |
| 166 | local prefix6=$(find_6to4_prefix "$local4") |
| 167 | local local6="$prefix6::1/16" |
| 168 | |
| 169 | logger -t "$link" " * IPv4 address is $local4" |
| 170 | logger -t "$link" " * IPv6 address is $local6" |
| 171 | ip tunnel add $link mode sit remote any local $local4 ttl ${ttl:-64} |
| 172 | ip link set $link up |
| 173 | ip link set mtu ${mtu:-1280} dev $link |
| 174 | ip addr add $local6 dev $link |
| 175 | |
| 176 | uci_set_state network "$cfg" ipaddr $local4 |
| 177 | uci_set_state network "$cfg" ip6addr $local6 |
| 178 | |
| 179 | [ "$defaultroute" = 1 ] && { |
| 180 | logger -t "$link" " * Adding default route" |
| 181 | ip -6 route add ::/0 via ::192.88.99.1 metric ${metric:-1} dev $link |
| 182 | uci_set_state network "$cfg" defaultroute 1 |
| 183 | } |
| 184 | |
| 185 | [ -f /etc/config/radvd ] && /etc/init.d/radvd enabled && { |
| 186 | local sid="6to4_$cfg" |
| 187 | |
| 188 | uci_revert_state radvd |
| 189 | config_load radvd |
| 190 | |
| 191 | # find delegation target |
| 192 | local adv_interface |
| 193 | config_get adv_interface "$cfg" adv_interface |
| 194 | |
| 195 | local adv_subnet=$(uci_get network "$cfg" adv_subnet) |
| 196 | adv_subnet=$((0x${adv_subnet:-1})) |
| 197 | |
| 198 | local adv_subnets="" |
| 199 | |
| 200 | for adv_interface in ${adv_interface:-lan}; do |
| 201 | local adv_ifname |
| 202 | config_get adv_ifname "${adv_interface:-lan}" ifname |
| 203 | |
| 204 | grep -qs "^ *$adv_ifname:" /proc/net/dev && { |
| 205 | local adv_valid_lifetime adv_preferred_lifetime |
| 206 | config_get adv_valid_lifetime "$cfg" adv_valid_lifetime |
| 207 | config_get adv_preferred_lifetime "$cfg" adv_preferred_lifetime |
| 208 | |
| 209 | local subnet6="$(printf "%s:%x::1/64" "$prefix6" $adv_subnet)" |
| 210 | |
| 211 | logger -t "$link" " * Advertising IPv6 subnet $subnet6 on ${adv_interface:-lan} ($adv_ifname)" |
| 212 | ip -6 addr add $subnet6 dev $adv_ifname |
| 213 | |
| 214 | set_6to4_radvd_interface "$sid" "$adv_interface" "$mtu" |
| 215 | set_6to4_radvd_prefix "$sid" "$adv_interface" \ |
| 216 | "$wancfg" "$(printf "0:0:0:%x::/64" $adv_subnet)" \ |
| 217 | "$adv_valid_lifetime" "$adv_preferred_lifetime" |
| 218 | |
| 219 | adv_subnets="${adv_subnets:+$adv_subnets }$adv_ifname:$subnet6" |
| 220 | adv_subnet=$(($adv_subnet + 1)) |
| 221 | } |
| 222 | done |
| 223 | |
| 224 | uci_set_state network "$cfg" adv_subnets "$adv_subnets" |
| 225 | |
| 226 | /etc/init.d/radvd restart |
| 227 | } |
| 228 | |
| 229 | logger -t "$link" "... started" |
| 230 | |
| 231 | env -i ACTION="ifup" INTERFACE="$cfg" DEVICE="$link" PROTO=6to4 /sbin/hotplug-call "iface" & |
| 232 | } || { |
| 233 | echo "Cannot determine local IPv4 address for 6to4 tunnel $cfg - skipping" |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | stop_interface_6to4() { |
| 238 | local cfg="$1" |
| 239 | local link="6to4-$cfg" |
| 240 | |
| 241 | local local6=$(uci_get_state network "$cfg" ip6addr) |
| 242 | local defaultroute=$(uci_get_state network "$cfg" defaultroute) |
| 243 | |
| 244 | local adv_subnets=$(uci_get_state network "$cfg" adv_subnets) |
| 245 | |
| 246 | grep -qs "^ *$link:" /proc/net/dev && { |
| 247 | logger -t "$link" "Shutting down ..." |
| 248 | env -i ACTION="ifdown" INTERFACE="$cfg" DEVICE="$link" PROTO=6to4 /sbin/hotplug-call "iface" & |
| 249 | |
| 250 | [ -n "$adv_subnets" ] && { |
| 251 | uci_revert_state radvd |
| 252 | /etc/init.d/radvd enabled && /etc/init.d/radvd restart |
| 253 | |
| 254 | local adv_subnet |
| 255 | for adv_subnet in $adv_subnets; do |
| 256 | local ifname="${adv_subnet%%:*}" |
| 257 | local subnet="${adv_subnet#*:}" |
| 258 | |
| 259 | logger -t "$link" " * Removing IPv6 subnet $subnet from interface $ifname" |
| 260 | ip -6 addr del $subnet dev $ifname |
| 261 | done |
| 262 | } |
| 263 | |
| 264 | [ "$defaultroute" = "1" ] && \ |
| 265 | ip -6 route del ::/0 via ::192.88.99.1 dev $link |
| 266 | |
| 267 | ip addr del $local6 dev $link |
| 268 | ip link set $link down |
| 269 | ip tunnel del $link |
| 270 | |
| 271 | logger -t "$link" "... stopped" |
| 272 | } |
| 273 | } |
| 274 | |