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