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.

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