| b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | #!/bin/sh |
| 2 | # map.sh - IPv4-in-IPv6 tunnel backend |
| 3 | # |
| 4 | # Author: Steven Barth <cyrus@openwrt.org> |
| 5 | # Copyright (c) 2014 cisco Systems, Inc. |
| 6 | # |
| 7 | # This program is free software; you can redistribute it and/or modify |
| 8 | # it under the terms of the GNU General Public License version 2 |
| 9 | # as published by the Free Software Foundation |
| 10 | # |
| 11 | # This program is distributed in the hope that it will be useful, |
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | # GNU General Public License for more details. |
| 15 | |
| 16 | [ -n "$INCLUDE_ONLY" ] || { |
| 17 | . /lib/functions.sh |
| 18 | . /lib/functions/network.sh |
| 19 | . ../netifd-proto.sh |
| 20 | init_proto "$@" |
| 21 | } |
| 22 | |
| 23 | proto_map_setup() { |
| 24 | local cfg="$1" |
| 25 | local iface="$2" |
| 26 | local link="map-$cfg" |
| 27 | |
| 28 | local maptype type legacymap mtu ttl tunlink zone encaplimit |
| 29 | local rule ipaddr ip4prefixlen ip6prefix ip6prefixlen peeraddr ealen psidlen psid offset |
| 30 | json_get_vars maptype type legacymap mtu ttl tunlink zone encaplimit |
| 31 | json_get_vars rule ipaddr ip4prefixlen ip6prefix ip6prefixlen peeraddr ealen psidlen psid offset |
| 32 | |
| 33 | [ "$zone" = "-" ] && zone="" |
| 34 | |
| 35 | # Compatibility with older config: use $type if $maptype is missing |
| 36 | [ -z "$maptype" ] && maptype="$type" |
| 37 | [ -z "$maptype" ] && maptype="map-e" |
| 38 | [ -z "$ip4prefixlen" ] && ip4prefixlen=32 |
| 39 | |
| 40 | ( proto_add_host_dependency "$cfg" "::" "$tunlink" ) |
| 41 | |
| 42 | # fixme: handle RA/DHCPv6 address race for LW |
| 43 | [ "$maptype" = lw4o6 ] && sleep 5 |
| 44 | |
| 45 | if [ -z "$rule" ]; then |
| 46 | rule="type=$maptype,ipv6prefix=$ip6prefix,prefix6len=$ip6prefixlen,ipv4prefix=$ipaddr,prefix4len=$ip4prefixlen" |
| 47 | [ -n "$psid" ] && rule="$rule,psid=$psid" |
| 48 | [ -n "$psidlen" ] && rule="$rule,psidlen=$psidlen" |
| 49 | [ -n "$offset" ] && rule="$rule,offset=$offset" |
| 50 | [ -n "$ealen" ] && rule="$rule,ealen=$ealen" |
| 51 | if [ "$maptype" = "map-t" ]; then |
| 52 | rule="$rule,dmr=$peeraddr" |
| 53 | else |
| 54 | rule="$rule,br=$peeraddr" |
| 55 | fi |
| 56 | fi |
| 57 | |
| 58 | echo "rule=$rule" > /tmp/map-$cfg.rules |
| 59 | RULE_DATA=$(LEGACY="$legacymap" mapcalc ${tunlink:-\*} $rule) |
| 60 | if [ "$?" != 0 ]; then |
| 61 | proto_notify_error "$cfg" "INVALID_MAP_RULE" |
| 62 | proto_block_restart "$cfg" |
| 63 | return |
| 64 | fi |
| 65 | |
| 66 | echo "$RULE_DATA" >> /tmp/map-$cfg.rules |
| 67 | eval $RULE_DATA |
| 68 | |
| 69 | if [ -z "$RULE_BMR" ]; then |
| 70 | proto_notify_error "$cfg" "NO_MATCHING_PD" |
| 71 | proto_block_restart "$cfg" |
| 72 | return |
| 73 | fi |
| 74 | |
| 75 | k=$RULE_BMR |
| 76 | if [ "$maptype" = "lw4o6" -o "$maptype" = "map-e" ]; then |
| 77 | proto_init_update "$link" 1 |
| 78 | proto_add_ipv4_address $(eval "echo \$RULE_${k}_IPV4ADDR") "" "" "" |
| 79 | |
| 80 | proto_add_tunnel |
| 81 | json_add_string mode ipip6 |
| 82 | json_add_int mtu "${mtu:-1280}" |
| 83 | json_add_int ttl "${ttl:-64}" |
| 84 | json_add_string local $(eval "echo \$RULE_${k}_IPV6ADDR") |
| 85 | json_add_string remote $(eval "echo \$RULE_${k}_BR") |
| 86 | json_add_string link $(eval "echo \$RULE_${k}_PD6IFACE") |
| 87 | json_add_object "data" |
| 88 | [ -n "$encaplimit" ] && json_add_string encaplimit "$encaplimit" |
| 89 | if [ "$maptype" = "map-e" ]; then |
| 90 | json_add_array "fmrs" |
| 91 | for i in $(seq $RULE_COUNT); do |
| 92 | [ "$(eval "echo \$RULE_${i}_FMR")" != 1 ] && continue |
| 93 | json_add_object "" |
| 94 | json_add_string prefix6 "$(eval "echo \$RULE_${i}_IPV6PREFIX")/$(eval "echo \$RULE_${i}_PREFIX6LEN")" |
| 95 | json_add_string prefix4 "$(eval "echo \$RULE_${i}_IPV4PREFIX")/$(eval "echo \$RULE_${i}_PREFIX4LEN")" |
| 96 | json_add_int ealen $(eval "echo \$RULE_${i}_EALEN") |
| 97 | json_add_int offset $(eval "echo \$RULE_${i}_OFFSET") |
| 98 | json_close_object |
| 99 | done |
| 100 | json_close_array |
| 101 | fi |
| 102 | json_close_object |
| 103 | |
| 104 | |
| 105 | proto_close_tunnel |
| 106 | elif [ "$maptype" = "map-t" -a -f "/proc/net/nat46/control" ]; then |
| 107 | proto_init_update "$link" 1 |
| 108 | local style="MAP" |
| 109 | [ "$legacymap" = 1 ] && style="MAP0" |
| 110 | |
| 111 | echo add $link > /proc/net/nat46/control |
| 112 | local cfgstr="local.style $style local.v4 $(eval "echo \$RULE_${k}_IPV4PREFIX")/$(eval "echo \$RULE_${k}_PREFIX4LEN")" |
| 113 | cfgstr="$cfgstr local.v6 $(eval "echo \$RULE_${k}_IPV6PREFIX")/$(eval "echo \$RULE_${k}_PREFIX6LEN")" |
| 114 | cfgstr="$cfgstr local.ea-len $(eval "echo \$RULE_${k}_EALEN") local.psid-offset $(eval "echo \$RULE_${k}_OFFSET")" |
| 115 | cfgstr="$cfgstr remote.v4 0.0.0.0/0 remote.v6 $(eval "echo \$RULE_${k}_DMR") remote.style RFC6052 remote.ea-len 0 remote.psid-offset 0" |
| 116 | echo config $link $cfgstr > /proc/net/nat46/control |
| 117 | |
| 118 | for i in $(seq $RULE_COUNT); do |
| 119 | [ "$(eval "echo \$RULE_${i}_FMR")" != 1 ] && continue |
| 120 | local cfgstr="remote.style $style remote.v4 $(eval "echo \$RULE_${i}_IPV4PREFIX")/$(eval "echo \$RULE_${i}_PREFIX4LEN")" |
| 121 | cfgstr="$cfgstr remote.v6 $(eval "echo \$RULE_${i}_IPV6PREFIX")/$(eval "echo \$RULE_${i}_PREFIX6LEN")" |
| 122 | cfgstr="$cfgstr remote.ea-len $(eval "echo \$RULE_${i}_EALEN") remote.psid-offset $(eval "echo \$RULE_${i}_OFFSET")" |
| 123 | echo insert $link $cfgstr > /proc/net/nat46/control |
| 124 | done |
| 125 | else |
| 126 | proto_notify_error "$cfg" "UNSUPPORTED_TYPE" |
| 127 | proto_block_restart "$cfg" |
| 128 | fi |
| 129 | |
| 130 | proto_add_ipv4_route "0.0.0.0" 0 |
| 131 | proto_add_data |
| 132 | [ -n "$zone" ] && json_add_string zone "$zone" |
| 133 | |
| 134 | json_add_array firewall |
| 135 | if [ -z "$(eval "echo \$RULE_${k}_PORTSETS")" ]; then |
| 136 | json_add_object "" |
| 137 | json_add_string type nat |
| 138 | json_add_string target SNAT |
| 139 | json_add_string family inet |
| 140 | json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR") |
| 141 | json_close_object |
| 142 | else |
| 143 | for portset in $(eval "echo \$RULE_${k}_PORTSETS"); do |
| 144 | for proto in icmp tcp udp; do |
| 145 | json_add_object "" |
| 146 | json_add_string type nat |
| 147 | json_add_string target SNAT |
| 148 | json_add_string family inet |
| 149 | json_add_string proto "$proto" |
| 150 | json_add_boolean connlimit_ports 1 |
| 151 | json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR") |
| 152 | json_add_string snat_port "$portset" |
| 153 | json_close_object |
| 154 | done |
| 155 | done |
| 156 | fi |
| 157 | if [ "$maptype" = "map-t" ]; then |
| 158 | [ -z "$zone" ] && zone=$(fw3 -q network $iface 2>/dev/null) |
| 159 | |
| 160 | [ -n "$zone" ] && { |
| 161 | json_add_object "" |
| 162 | json_add_string type rule |
| 163 | json_add_string family inet6 |
| 164 | json_add_string proto all |
| 165 | json_add_string direction in |
| 166 | json_add_string dest "$zone" |
| 167 | json_add_string src "$zone" |
| 168 | json_add_string src_ip $(eval "echo \$RULE_${k}_IPV6ADDR") |
| 169 | json_add_string target ACCEPT |
| 170 | json_close_object |
| 171 | json_add_object "" |
| 172 | json_add_string type rule |
| 173 | json_add_string family inet6 |
| 174 | json_add_string proto all |
| 175 | json_add_string direction out |
| 176 | json_add_string dest "$zone" |
| 177 | json_add_string src "$zone" |
| 178 | json_add_string dest_ip $(eval "echo \$RULE_${k}_IPV6ADDR") |
| 179 | json_add_string target ACCEPT |
| 180 | json_close_object |
| 181 | } |
| 182 | proto_add_ipv6_route $(eval "echo \$RULE_${k}_IPV6ADDR") 128 |
| 183 | fi |
| 184 | json_close_array |
| 185 | proto_close_data |
| 186 | |
| 187 | proto_send_update "$cfg" |
| 188 | |
| 189 | if [ "$maptype" = "lw4o6" -o "$maptype" = "map-e" ]; then |
| 190 | json_init |
| 191 | json_add_string name "${cfg}_" |
| 192 | json_add_string ifname "@$(eval "echo \$RULE_${k}_PD6IFACE")" |
| 193 | json_add_string proto "static" |
| 194 | json_add_array ip6addr |
| 195 | json_add_string "" "$(eval "echo \$RULE_${k}_IPV6ADDR")" |
| 196 | json_close_array |
| 197 | json_close_object |
| 198 | ubus call network add_dynamic "$(json_dump)" |
| 199 | fi |
| 200 | } |
| 201 | |
| 202 | proto_map_teardown() { |
| 203 | local cfg="$1" |
| 204 | local link="map-$cfg" |
| 205 | |
| 206 | json_get_var type type |
| 207 | |
| 208 | [ -z "$maptype" ] && maptype="$type" |
| 209 | [ -z "$maptype" ] && maptype="map-e" |
| 210 | |
| 211 | case "$maptype" in |
| 212 | "map-e"|"lw4o6") ifdown "${cfg}_" ;; |
| 213 | "map-t") [ -f "/proc/net/nat46/control" ] && echo del $link > /proc/net/nat46/control ;; |
| 214 | esac |
| 215 | |
| 216 | rm -f /tmp/map-$cfg.rules |
| 217 | } |
| 218 | |
| 219 | proto_map_init_config() { |
| 220 | no_device=1 |
| 221 | available=1 |
| 222 | |
| 223 | proto_config_add_string "maptype" |
| 224 | proto_config_add_string "rule" |
| 225 | proto_config_add_string "ipaddr" |
| 226 | proto_config_add_int "ip4prefixlen" |
| 227 | proto_config_add_string "ip6prefix" |
| 228 | proto_config_add_int "ip6prefixlen" |
| 229 | proto_config_add_string "peeraddr" |
| 230 | proto_config_add_int "ealen" |
| 231 | proto_config_add_int "psidlen" |
| 232 | proto_config_add_int "psid" |
| 233 | proto_config_add_int "offset" |
| 234 | proto_config_add_boolean "legacymap" |
| 235 | |
| 236 | proto_config_add_string "tunlink" |
| 237 | proto_config_add_int "mtu" |
| 238 | proto_config_add_int "ttl" |
| 239 | proto_config_add_string "zone" |
| 240 | proto_config_add_string "encaplimit" |
| 241 | } |
| 242 | |
| 243 | [ -n "$INCLUDE_ONLY" ] || { |
| 244 | add_protocol map |
| 245 | } |