applications/luci-splash: Add known leases when restarting splash
[project/luci.git] / applications / luci-splash / root / etc / init.d / luci_splash
1 #!/bin/sh /etc/rc.common
2
3 START=70
4 EXTRA_COMMANDS=clear_leases
5 LIMIT_DOWN=0
6 LIMIT_DOWN_BURST=0
7 LIMIT_UP=0
8 TC=/usr/sbin/tc
9 IPT=/usr/sbin/iptables
10 IPT6=/usr/sbin/ip6tables
11
12 IPT_REPLAY=/var/run/luci_splash.iptlog
13 LOCK=/var/run/luci_splash.lock
14 [ -x $IPT6 ] && [ -f /proc/net/ipv6_route ] && HAS_IPV6=1
15
16 silent() {
17 "$@" 2>/dev/null
18 }
19
20 ipt_log() {
21 $IPT -I "$@"
22 echo $IPT -D "$@" >> $IPT_REPLAY
23 }
24
25 ipt6_log() {
26 [ "$HAS_IPV6" = 1 ] || return
27 $IPT6 -I "$@"
28 echo $IPT6 -D "$@" >> $IPT_REPLAY
29 }
30
31
32 iface_add() {
33 local cfg="$1"
34
35 config_get zone "$cfg" zone
36 [ -n "$zone" ] || return 0
37
38 config_get net "$cfg" network
39 [ -n "$net" ] || return 0
40
41 config_get ifname "$net" ifname
42 [ -n "$ifname" ] || return 0
43
44 config_get ipaddr "$net" ipaddr
45 [ -n "$ipaddr" ] || return 0
46
47 config_get netmask "$net" netmask
48 [ -n "$netmask" ] || return 0
49
50 config_get ip6addr "$net" ip6addr
51
52 config_get type "$net" type
53
54 parentiface="$(uci -q get network.${net}.ifname)"
55
56 [ -n "$parentiface" ] && [ ! "$type" = "bridge" ] && {
57 parentiface=${parentiface#@}
58 config_get parentproto "$parentiface" proto
59 config_get parentipaddr "$parentiface" ipaddr
60 config_get parentnetmask "$parentiface" netmask
61 }
62
63 eval "$(ipcalc.sh $ipaddr $netmask)"
64
65 logger -s -p info -t splash "Add $NETWORK/$PREFIX ($ifname) to splashed networks."
66
67 ### Add interface specific chain entry rules
68 ipt_log "prerouting_${zone}_rule" -i "${ifname%:*}" -s "$NETWORK/$PREFIX" -j luci_splash_prerouting -t nat
69 ipt_log "forwarding_${zone}_rule" -i "${ifname%:*}" -s "$NETWORK/$PREFIX" -j luci_splash_forwarding -t filter
70
71 if [ "$HAS_IPV6" = 1 ] && [ -n "$ip6addr" ]; then
72 ipt6_log "forwarding_${zone}_rule" -i "${ifname%:*}" -s "$ip6addr" -j luci_splash_forwarding -t filter
73 fi
74
75 ### Allow traffic to the same subnet
76 $IPT -t nat -I luci_splash_prerouting -d "$ipaddr/${netmask:-32}" -j RETURN
77 $IPT -t filter -I luci_splash_forwarding -d "$ipaddr/${netmask:-32}" -j RETURN
78
79 ### Allow traffic to the mesh subnet
80 [ "$parentproto" = "static" -a -n "$parentipaddr" ] && {
81 $IPT -t nat -I luci_splash_prerouting -d "$parentipaddr/${parentnetmask:-32}" -j RETURN
82 $IPT -t filter -I luci_splash_forwarding -d "$parentipaddr/${parentnetmask:-32}" -j RETURN
83 }
84
85 qos_iface_add "$ifname" "$NETWORK" "$PREFIX"
86 }
87
88 iface_del() {
89 config_get zone "$1" zone
90 [ -n "$zone" ] || return 0
91
92 config_get net "$1" network
93 [ -n "$net" ] || return 0
94
95 config_get ifname "$net" ifname
96 [ -n "$ifname" ] || return 0
97
98 # Clear interface specific rules
99 [ -s $IPT_REPLAY ] && {
100 logger -s -p info -t splash "Remove $ifname from splashed networks."
101 grep -- "-i ${ifname%:*}" $IPT_REPLAY | while read ln; do silent $ln; done
102 sed -ie "/-i ${ifname%:*}/d" $IPT_REPLAY
103 }
104
105 qos_iface_del "$ifname"
106 }
107
108 mac_add() {
109 config_get mac "$1" mac
110 append MACS "$mac"
111 }
112
113 whitelist_add() {
114 config_get mac "$1" mac
115 iface=$2
116 $TC filter add dev "$iface" parent ffff: protocol ip prio 1 u32 match ether src $mac police pass
117 $TC filter add dev "$iface" parent 1:0 protocol ip prio 1 u32 match ether dst classid 1:1
118 }
119
120
121 subnet_add() {
122 local cfg="$1"
123
124 config_get ipaddr "$cfg" ipaddr
125 config_get netmask "$cfg" netmask
126
127 [ -n "$ipaddr" ] && {
128 $IPT -t nat -I luci_splash_prerouting -d "$ipaddr/${netmask:-32}" -j RETURN
129 $IPT -t filter -I luci_splash_forwarding -d "$ipaddr/${netmask:-32}" -j RETURN
130 }
131 }
132
133 qos_iface_add() {
134 local iface="$1"
135 local network="$2"
136 local prefix="$3"
137
138 # 77 -> download root qdisc
139 # ffff -> upload root qdisc
140
141 silent $TC qdisc del dev "$iface" root handle 1:
142 silent $TC class del dev "$iface" parent 1: classid 1:ffff
143 silent $TC class del dev "$iface" parent 1: classid 1:1
144 silent $TC filter del dev "$iface" parent ffff: protocol ip prio 1 u32
145 silent $TC filter del dev "$iface" parent ffff: protocol ip prio 2 u32
146 silent $TC filter del dev "$iface" parent ffff: protocol ip prio 3 u32
147
148 if [ "$LIMIT_UP" -gt 0 -a "$LIMIT_DOWN" -gt 0 ]; then
149 # Setup qdiscs
150 $TC qdisc add dev "$iface" root handle 1: htb default 1
151 silent $TC qdisc add dev "$iface" ingress
152
153 # Default class - all clients which are not otherwise handled are put in that class
154 # and share that bandwidth.
155 $TC class add dev "$iface" parent 1: classid 1:ffff htb rate ${LIMIT_DOWN}kbit
156
157 # default class and class for whitelisted clients = unlimited
158 $TC class add dev "$iface" parent 1: classid 1:1 htb rate 100mbit
159
160 # All traffic to the dhcp subnet is put into the limited class
161 $TC filter add dev "$iface" parent 1:0 protocol ip prio 3 u32 match ip dst $network/$prefix classid 1:ffff
162 $TC qdisc add dev "$iface" parent 1:ffff sfq perturb 10
163 $TC filter add dev "$iface" parent ffff: protocol ip prio 3 u32 match ip src $network/$prefix police rate ${LIMIT_UP}kbit mtu 6k burst 6k drop
164
165 # classify packets by their iptables MARK set in luci_splash_mark_in (mangle table)
166 # every client gets his own class and so his own bandwidth limit
167 $TC filter add dev "$iface" parent 1:0 protocol ip prio 2 fw
168
169 config_foreach whitelist_add whitelist $iface
170 fi
171 }
172
173 qos_iface_del() {
174 local iface="$1"
175 silent $TC qdisc del dev "$iface" root handle 77:
176 }
177
178 boot() {
179 ### Setup splash-relay
180 uci get uhttpd.splash 2>/dev/null || {
181 uci batch <<EOF
182 set uhttpd.splash=uhttpd
183 set uhttpd.splash.home="/www/cgi-bin/splash/"
184 set uhttpd.splash.interpreter=".sh=/bin/ash"
185 set uhttpd.splash.listen_http="8082"
186 set uhttpd.splash.index_page="splash.sh"
187 set uhttpd.splash.error_page="/splash.sh"
188 set uhttpd.splash.http_keepalive='0'
189 commit uhttpd
190 EOF
191 }
192
193 ### We are started by the firewall include
194 exit 0
195 }
196
197 start() {
198 lock $LOCK
199 logger -s -p info -t splash "Starting luci-splash"
200 include /lib/network
201 . /lib/functions/network.sh
202 scan_interfaces
203 config_load luci_splash
204
205 ### Find QoS limits
206 config_get LIMIT_UP general limit_up
207 config_get LIMIT_DOWN general limit_down
208 config_get LIMIT_DOWN_BURST general limit_down_burst
209
210 LIMIT_UP="$((8*${LIMIT_UP:-0}))"
211 LIMIT_DOWN="$((8*${LIMIT_DOWN:-0}))"
212 LIMIT_DOWN_BURST="${LIMIT_DOWN_BURST:+$((8*$LIMIT_DOWN_BURST))}"
213 LIMIT_DOWN_BURST="${LIMIT_DOWN_BURST:-$(($LIMIT_DOWN / 5 * 6))}"
214
215 ### Load required modules
216 [ "$LIMIT_UP" -gt 0 -a "$LIMIT_DOWN" -gt 0 ] && {
217 silent insmod act_police
218 silent insmod cls_fw
219 silent insmod cls_u32
220 silent insmod sch_htb
221 silent insmod sch_sfq
222 silent insmod sch_ingress
223 }
224
225 ### Create subchains
226 $IPT -t nat -N luci_splash_prerouting
227 $IPT -t nat -N luci_splash_leases
228 $IPT -t filter -N luci_splash_forwarding
229 $IPT -t filter -N luci_splash_filter
230
231 if [ "$HAS_IPV6" = 1 ]; then
232 $IPT6 -t filter -N luci_splash_forwarding
233 $IPT6 -t filter -N luci_splash_filter
234 fi
235
236 ### Clear iptables replay log
237 [ -s $IPT_REPLAY ] && . $IPT_REPLAY
238 echo -n > $IPT_REPLAY
239
240 ### Add interface independant prerouting rules
241 $IPT -t nat -A luci_splash_prerouting -j luci_splash_leases
242 $IPT -t nat -A luci_splash_leases -p udp --dport 53 -j REDIRECT --to-ports 53
243 $IPT -t nat -A luci_splash_leases -p tcp --dport 80 -j REDIRECT --to-ports 8082
244
245 ### Add interface independant forwarding rules
246 $IPT -t filter -A luci_splash_forwarding -j luci_splash_filter
247 $IPT -t filter -A luci_splash_filter -p tcp -j REJECT --reject-with tcp-reset
248 $IPT -t filter -A luci_splash_filter -j REJECT --reject-with icmp-net-prohibited
249
250 if [ "$HAS_IPV6" = 1 ]; then
251 $IPT6 -t filter -A luci_splash_forwarding -j luci_splash_filter
252 $IPT6 -t filter -A luci_splash_filter -p tcp -j REJECT --reject-with tcp-reset
253 $IPT6 -t filter -A luci_splash_filter -j REJECT --reject-with adm-prohibited
254 fi
255
256 ### Add QoS chain
257 $IPT -t mangle -N luci_splash_mark_out
258 $IPT -t mangle -N luci_splash_mark_in
259 $IPT -t mangle -I PREROUTING -j luci_splash_mark_out
260 $IPT -t mangle -I POSTROUTING -j luci_splash_mark_in
261
262 if [ "$HAS_IPV6" = 1 ]; then
263 $IPT6 -t mangle -N luci_splash_mark_out
264 $IPT6 -t mangle -N luci_splash_mark_in
265 $IPT6 -t mangle -I PREROUTING -j luci_splash_mark_out
266 $IPT6 -t mangle -I POSTROUTING -j luci_splash_mark_in
267 fi
268
269 ### Build the main and portal rule
270 config_foreach iface_add iface
271 config_foreach subnet_add subnet
272
273 ### Add the community homepage to the list of allowed destination subnets
274 hp=$(uci -q get freifunk.community.homepage) && {
275 chp=${hp#http*://}
276 chp=${chp%%/*}
277 $IPT -t nat -I luci_splash_prerouting -d "${chp}/32" -j RETURN
278 $IPT -t filter -I luci_splash_forwarding -d "${chp}/32" -j RETURN
279 }
280
281 ### Find active mac addresses
282 MACS=""
283
284
285 config_foreach mac_add blacklist
286 config_foreach mac_add whitelist
287
288 config_load luci_splash_leases
289 config_foreach mac_add lease
290
291 ### Add crontab entry
292 test -f /etc/crontabs/root || touch /etc/crontabs/root
293 grep -q luci-splash /etc/crontabs/root || {
294 echo '*/5 * * * * /usr/sbin/luci-splash sync' >> /etc/crontabs/root
295 }
296
297 lock -u $LOCK
298
299 ### Populate iptables
300 [ -n "$MACS" ] && luci-splash add-rules $MACS
301 }
302
303 stop() {
304 lock $LOCK
305
306 include /lib/network
307 scan_interfaces
308 config_load luci_splash
309
310 ### Clear interface rules
311 config_foreach iface_del iface
312
313 silent $IPT -t mangle -D PREROUTING -j luci_splash_mark_out
314 silent $IPT -t mangle -D POSTROUTING -j luci_splash_mark_in
315
316 if [ "$HAS_IPV6" = 1 ]; then
317 silent $IPT6 -t mangle -D PREROUTING -j luci_splash_mark_out
318 silent $IPT6 -t mangle -D POSTROUTING -j luci_splash_mark_in
319 fi
320
321 ### Clear subchains
322 silent $IPT -t nat -F luci_splash_prerouting
323 silent $IPT -t nat -F luci_splash_leases
324 silent $IPT -t filter -F luci_splash_forwarding
325 silent $IPT -t filter -F luci_splash_filter
326 silent $IPT -t mangle -F luci_splash_mark_out
327 silent $IPT -t mangle -F luci_splash_mark_in
328
329 if [ "$HAS_IPV6" = 1 ]; then
330 $IPT6 -t filter -F luci_splash_forwarding
331 $IPT6 -t filter -F luci_splash_filter
332 $IPT6 -t mangle -F luci_splash_mark_out
333 $IPT6 -t mangle -F luci_splash_mark_in
334 fi
335
336 ### Delete subchains
337 silent $IPT -t nat -X luci_splash_prerouting
338 silent $IPT -t nat -X luci_splash_leases
339 silent $IPT -t filter -X luci_splash_forwarding
340 silent $IPT -t filter -X luci_splash_filter
341 silent $IPT -t mangle -X luci_splash_mark_out
342 silent $IPT -t mangle -X luci_splash_mark_in
343 if [ "$HAS_IPV6" = 1 ]; then
344 $IPT6 -t filter -X luci_splash_forwarding
345 $IPT6 -t filter -X luci_splash_filter
346 $IPT6 -t mangle -X luci_splash_mark_out
347 $IPT6 -t mangle -X luci_splash_mark_in
348 fi
349 sed -ie '/\/usr\/sbin\/luci-splash sync/d' /var/spool/cron/crontabs/root
350
351 lock -u $LOCK
352 }
353
354 clear_leases() {
355 ### Find active mac addresses
356 MACS=""
357 config_foreach mac_add lease
358
359 ### Clear leases
360 [ -n "$MACS" ] && luci-splash remove $MACS
361 }
362