You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

328 lines
9.1 KiB

  1. #!/bin/sh
  2. mwan3_get_iface_id()
  3. {
  4. let iface_count++
  5. [ "$1" == "$INTERFACE" ] && iface_id=$iface_count
  6. }
  7. mwan3_set_general_iptables()
  8. {
  9. if ! $IPT -S mwan3_ifaces &> /dev/null; then
  10. $IPT -N mwan3_ifaces
  11. fi
  12. if ! $IPT -S mwan3_rules &> /dev/null; then
  13. $IPT -N mwan3_rules
  14. fi
  15. if ! $IPT -S mwan3_connected &> /dev/null; then
  16. $IPT -N mwan3_connected
  17. fi
  18. if ! $IPT -S mwan3_hook &> /dev/null; then
  19. $IPT -N mwan3_hook
  20. $IPT -A mwan3_hook -j CONNMARK --restore-mark --nfmask 0xff00 --ctmask 0xff00
  21. $IPT -A mwan3_hook -m mark --mark 0x0/0xff00 -j mwan3_ifaces
  22. $IPT -A mwan3_hook -m mark --mark 0x0/0xff00 -j mwan3_connected
  23. $IPT -A mwan3_hook -m mark --mark 0x0/0xff00 -j mwan3_rules
  24. $IPT -A mwan3_hook -j CONNMARK --save-mark --nfmask 0xff00 --ctmask 0xff00
  25. fi
  26. if ! $IPT -S mwan3_track_hook &> /dev/null; then
  27. $IPT -N mwan3_track_hook
  28. fi
  29. if ! $IPT -S PREROUTING | grep mwan3_hook &> /dev/null; then
  30. $IPT -A PREROUTING -j mwan3_hook
  31. fi
  32. if ! $IPT -S OUTPUT | grep mwan3_hook &> /dev/null; then
  33. $IPT -A OUTPUT -j mwan3_hook
  34. fi
  35. if ! $IPT -S OUTPUT | grep mwan3_track_hook &> /dev/null; then
  36. $IPT -A OUTPUT -j mwan3_track_hook
  37. fi
  38. $IPT -F mwan3_rules
  39. }
  40. mwan3_set_connected_iptables()
  41. {
  42. local connected_networks
  43. if $IPT -S mwan3_connected &> /dev/null; then
  44. $IPT -F mwan3_connected
  45. for connected_networks in $($IP route | awk '{print $1}' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do
  46. $IPT -A mwan3_connected -d $connected_networks -m mark --mark 0x0/0xff00 -j MARK --set-xmark 0xff00/0xff00
  47. done
  48. $IPT -I mwan3_connected -d 224.0.0.0/3 -m mark --mark 0x0/0xff00 -j MARK --set-xmark 0xff00/0xff00
  49. $IPT -I mwan3_connected -d 127.0.0.0/8 -m mark --mark 0x0/0xff00 -j MARK --set-xmark 0xff00/0xff00
  50. fi
  51. }
  52. mwan3_set_iface_iptables()
  53. {
  54. local local_net local_nets
  55. local_net=$($IP route list dev $DEVICE scope link | awk '{print $1}' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}')
  56. if ! $IPT -S mwan3_iface_$INTERFACE &> /dev/null; then
  57. $IPT -N mwan3_iface_$INTERFACE
  58. fi
  59. $IPT -F mwan3_iface_$INTERFACE
  60. $IPT -D mwan3_ifaces -i $DEVICE -m mark --mark 0x0/0xff00 -j mwan3_iface_$INTERFACE &> /dev/null
  61. if [ $ACTION == "ifup" ]; then
  62. if [ -n "$local_net" ]; then
  63. for local_nets in $local_net ; do
  64. if [ $ACTION == "ifup" ]; then
  65. $IPT -I mwan3_iface_$INTERFACE -s $local_net -m mark --mark 0x0/0xff00 -m comment --comment "$INTERFACE" -j MARK --set-xmark 0xff00/0xff00
  66. fi
  67. done
  68. fi
  69. $IPT -A mwan3_iface_$INTERFACE -m mark --mark 0x0/0xff00 -m comment --comment "$INTERFACE" -j MARK --set-xmark $(($iface_id*256))/0xff00
  70. $IPT -A mwan3_ifaces -i $DEVICE -m mark --mark 0x0/0xff00 -j mwan3_iface_$INTERFACE
  71. fi
  72. if [ $ACTION == "ifdown" ]; then
  73. $IPT -X mwan3_iface_$INTERFACE
  74. fi
  75. }
  76. mwan3_set_iface_route()
  77. {
  78. $IP route flush table $iface_id
  79. [ $ACTION == "ifup" ] && $IP route add table $iface_id default $route_args
  80. }
  81. mwan3_set_iface_rules()
  82. {
  83. while [ -n "$($IP rule list | awk '$1 == "'$(($iface_id+1000)):'"')" ]; do
  84. $IP rule del pref $(($iface_id+1000))
  85. done
  86. while [ -n "$($IP rule list | awk '$1 == "'$(($iface_id+2000)):'"')" ]; do
  87. $IP rule del pref $(($iface_id+2000))
  88. done
  89. while [ -n "$($IP rule list | awk '$1 == "2254:"')" ]; do
  90. $IP rule del pref 2254
  91. done
  92. [ $ACTION == "ifup" ] && $IP rule add pref $(($iface_id+1000)) iif $DEVICE lookup main
  93. [ $ACTION == "ifup" ] && $IP rule add pref $(($iface_id+2000)) fwmark $(($iface_id*256))/0xff00 lookup $iface_id
  94. $IP rule add pref 2254 fwmark 0xfe00/0xff00 unreachable
  95. }
  96. mwan3_track()
  97. {
  98. local track_ip track_ips reliability count timeout interval down up
  99. mwan3_list_track_ips()
  100. {
  101. track_ips="$1 $track_ips"
  102. }
  103. config_list_foreach $INTERFACE track_ip mwan3_list_track_ips
  104. if [ -n "$track_ips" ]; then
  105. config_get reliability $INTERFACE reliability 1
  106. config_get count $INTERFACE count 1
  107. config_get timeout $INTERFACE timeout 4
  108. config_get interval $INTERFACE interval 10
  109. config_get down $INTERFACE down 5
  110. config_get up $INTERFACE up 5
  111. if ! $IPT -S mwan3_track_$INTERFACE &> /dev/null; then
  112. $IPT -N mwan3_track_$INTERFACE
  113. $IPT -A mwan3_track_hook -p icmp -m icmp --icmp-type 8 -m length --length 32 -j mwan3_track_$INTERFACE
  114. fi
  115. $IPT -F mwan3_track_$INTERFACE
  116. for track_ip in $track_ips; do
  117. $IPT -A mwan3_track_$INTERFACE -d $track_ip -j MARK --set-xmark 0xff00/0xff00
  118. done
  119. [ -x /usr/sbin/mwan3track ] && /usr/sbin/mwan3track $INTERFACE $DEVICE $reliability $count $timeout $interval $down $up $track_ips &
  120. else
  121. $IPT -D mwan3_track_hook -p icmp -m icmp --icmp-type 8 -m length --length 32 -j mwan3_track_$INTERFACE &> /dev/null
  122. $IPT -F mwan3_track_$INTERFACE &> /dev/null
  123. $IPT -X mwan3_track_$INTERFACE &> /dev/null
  124. fi
  125. }
  126. mwan3_set_policy()
  127. {
  128. local iface_count iface_id INTERFACE metric probability weight
  129. config_get INTERFACE $1 interface
  130. config_get metric $1 metric 1
  131. config_get weight $1 weight 1
  132. [ -n "$INTERFACE" ] || return 0
  133. config_foreach mwan3_get_iface_id interface
  134. [ -n "$iface_id" ] || return 0
  135. if $IPT -S mwan3_iface_$INTERFACE &> /dev/null; then
  136. if [ "$metric" -lt "$lowest_metric" ]; then
  137. total_weight=$weight
  138. $IPT -F mwan3_policy_$policy
  139. $IPT -A mwan3_policy_$policy -m mark --mark 0x0/0xff00 -m comment --comment "$INTERFACE $weight $weight" -j MARK --set-xmark $(($iface_id*256))/0xff00
  140. lowest_metric=$metric
  141. elif [ "$metric" -eq "$lowest_metric" ]; then
  142. total_weight=$(($total_weight+$weight))
  143. probability=$(($weight*1000/$total_weight))
  144. if [ "$probability" -lt 10 ]; then
  145. probability="0.00$probability"
  146. elif [ $probability -lt 100 ]; then
  147. probability="0.0$probability"
  148. elif [ $probability -lt 1000 ]; then
  149. probability="0.$probability"
  150. else
  151. probability="1"
  152. fi
  153. probability="-m statistic --mode random --probability $probability"
  154. $IPT -I mwan3_policy_$policy -m mark --mark 0x0/0xff00 $probability -m comment --comment "$INTERFACE $weight $total_weight" -j MARK --set-xmark $(($iface_id*256))/0xff00
  155. fi
  156. fi
  157. }
  158. mwan3_set_policies_iptables()
  159. {
  160. local lowest_metric policy total_weight
  161. policy=$1
  162. if [ "$policy" != $(echo "$policy" | cut -c1-15) ]; then
  163. $LOG warn "Policy $policy exceeds max of 15 chars. Not setting policy" && return 0
  164. fi
  165. if ! $IPT -S mwan3_policy_$policy &> /dev/null; then
  166. $IPT -N mwan3_policy_$policy
  167. fi
  168. $IPT -F mwan3_policy_$policy
  169. $IPT -A mwan3_policy_$policy -m mark --mark 0x0/0xff00 -m comment --comment "unreachable" -j MARK --set-xmark 0xfe00/0xff00
  170. lowest_metric=256
  171. total_weight=0
  172. config_list_foreach $policy use_member mwan3_set_policy
  173. $IPT -X $policy &> /dev/null
  174. }
  175. mwan3_set_user_rules_iptables()
  176. {
  177. local proto src_ip src_port dest_ip dest_port use_policy
  178. config_get proto $1 proto all
  179. config_get src_ip $1 src_ip 0.0.0.0/0
  180. config_get src_port $1 src_port 0:65535
  181. config_get dest_ip $1 dest_ip 0.0.0.0/0
  182. config_get dest_port $1 dest_port 0:65535
  183. config_get use_policy $1 use_policy
  184. if [ -n "$use_policy" ]; then
  185. if [ "$use_policy" == "default" ]; then
  186. use_policy="MARK --set-xmark 0xff00/0xff00"
  187. elif [ "$use_policy" == "unreachable" ]; then
  188. use_policy="MARK --set-xmark 0xfe00/0xff00"
  189. else
  190. use_policy="mwan3_policy_$use_policy"
  191. fi
  192. case $proto in
  193. tcp|udp)
  194. $IPT -A mwan3_rules -p $proto -s $src_ip -d $dest_ip -m multiport --sports $src_port -m multiport --dports $dest_port -m mark --mark 0/0xff00 -m comment --comment "$1" -j $use_policy &> /dev/null
  195. ;;
  196. *)
  197. $IPT -A mwan3_rules -p $proto -s $src_ip -d $dest_ip -m mark --mark 0/0xff00 -m comment --comment "$1" -j $use_policy &> /dev/null
  198. ;;
  199. esac
  200. fi
  201. }
  202. mwan3_ifupdown()
  203. {
  204. local counter enabled iface_count iface_id route_args wan_metric
  205. config_load mwan3
  206. config_foreach mwan3_get_iface_id interface
  207. [ -n "$iface_id" ] || return 0
  208. [ "$iface_count" -le 250 ] || return 0
  209. unset iface_count
  210. config_get enabled $INTERFACE enabled 0
  211. counter=0
  212. if [ $ACTION == "ifup" ]; then
  213. [ "$enabled" -eq 1 ] || return 0
  214. while [ -z "$($IP route list dev $DEVICE default | head -1)" -a "$counter" -lt 10 ]; do
  215. sleep 1
  216. let counter++
  217. if [ "$counter" -ge 10 ]; then
  218. $LOG warn "Could not find gateway for interface $INTERFACE ($DEVICE)" && return 0
  219. fi
  220. done
  221. route_args=$($IP route list dev $DEVICE default | head -1 | sed '/.*via \([^ ]*\) .*$/!d;s//via \1/;q' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}')
  222. route_args="nexthop $route_args dev $DEVICE"
  223. fi
  224. while [ "$(pgrep -f -o hotplug-call)" -ne $$ -a "$counter" -lt 60 ]; do
  225. sleep 1
  226. let counter++
  227. if [ "$counter" -ge 60 ]; then
  228. $LOG warn "Timeout waiting for older hotplug processes to finish. $ACTION interface $INTERFACE ($DEVICE) aborted" && return 0
  229. fi
  230. done
  231. $LOG notice "$ACTION interface $INTERFACE ($DEVICE)"
  232. mwan3_set_general_iptables
  233. mwan3_set_iface_iptables
  234. mwan3_set_iface_route
  235. mwan3_set_iface_rules
  236. [ $ACTION == "ifup" ] && mwan3_track
  237. config_foreach mwan3_set_policies_iptables policy
  238. config_foreach mwan3_set_user_rules_iptables rule
  239. }
  240. [ -n "$DEVICE" ] || exit 0
  241. [ -n "$INTERFACE" ] || exit 0
  242. local IP IPT LOG
  243. IP="/usr/sbin/ip -4"
  244. IPT="/usr/sbin/iptables -t mangle -w"
  245. LOG="/usr/bin/logger -t mwan3 -p"
  246. case "$ACTION" in
  247. ifup|ifdown)
  248. mwan3_ifupdown
  249. mwan3_set_connected_iptables
  250. ;;
  251. esac
  252. exit 0