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.

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