Root/package/firewall/files/uci_firewall.sh

1#!/bin/sh
2# Copyright (C) 2008 John Crispin <blogic@openwrt.org>
3
4. /etc/functions.sh
5
6IPTABLES="echo iptables"
7IPTABLES=iptables
8
9config_clear
10include /lib/network
11scan_interfaces
12
13CONFIG_APPEND=1
14config_load firewall
15
16config fw_zones
17ZONE_LIST=$CONFIG_SECTION
18
19CUSTOM_CHAINS=1
20DEF_INPUT=DROP
21DEF_OUTPUT=DROP
22DEF_FORWARD=DROP
23CONNTRACK_ZONES=
24NOTRACK_DISABLED=
25
26find_item() {
27    local item="$1"; shift
28    for i in "$@"; do
29        [ "$i" = "$item" ] && return 0
30    done
31    return 1
32}
33
34load_policy() {
35    config_get input $1 input
36    config_get output $1 output
37    config_get forward $1 forward
38
39    DEF_INPUT="${input:-$DEF_INPUT}"
40    DEF_OUTPUT="${output:-$DEF_OUTPUT}"
41    DEF_FORWARD="${forward:-$DEF_FORWARD}"
42}
43
44create_zone() {
45    local exists
46
47    [ "$1" == "loopback" ] && return
48
49    config_get exists $ZONE_LIST $1
50    [ -n "$exists" ] && return
51    config_set $ZONE_LIST $1 1
52
53    $IPTABLES -N zone_$1
54    $IPTABLES -N zone_$1_MSSFIX
55    $IPTABLES -N zone_$1_ACCEPT
56    $IPTABLES -N zone_$1_DROP
57    $IPTABLES -N zone_$1_REJECT
58    $IPTABLES -N zone_$1_forward
59    [ "$4" ] && $IPTABLES -A output -j zone_$1_$4
60    $IPTABLES -N zone_$1_nat -t nat
61    $IPTABLES -N zone_$1_prerouting -t nat
62    $IPTABLES -t raw -N zone_$1_notrack
63    [ "$6" == "1" ] && $IPTABLES -t nat -A POSTROUTING -j zone_$1_nat
64    [ "$7" == "1" ] && $IPTABLES -I FORWARD 1 -j zone_$1_MSSFIX
65}
66
67
68addif() {
69    local network="$1"
70    local ifname="$2"
71    local zone="$3"
72
73    local n_if n_zone
74    config_get n_if core "${network}_ifname"
75    config_get n_zone core "${network}_zone"
76    [ -n "$n_zone" ] && {
77        if [ "$n_zone" != "$zone" ]; then
78            delif "$network" "$n_if" "$n_zone"
79        else
80            return
81        fi
82    }
83
84    logger "adding $network ($ifname) to firewall zone $zone"
85    $IPTABLES -A input -i "$ifname" -j zone_${zone}
86    $IPTABLES -I zone_${zone}_MSSFIX 1 -o "$ifname" -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
87    $IPTABLES -I zone_${zone}_ACCEPT 1 -o "$ifname" -j ACCEPT
88    $IPTABLES -I zone_${zone}_DROP 1 -o "$ifname" -j DROP
89    $IPTABLES -I zone_${zone}_REJECT 1 -o "$ifname" -j reject
90    $IPTABLES -I zone_${zone}_ACCEPT 1 -i "$ifname" -j ACCEPT
91    $IPTABLES -I zone_${zone}_DROP 1 -i "$ifname" -j DROP
92    $IPTABLES -I zone_${zone}_REJECT 1 -i "$ifname" -j reject
93    $IPTABLES -I zone_${zone}_nat 1 -t nat -o "$ifname" -j MASQUERADE
94    $IPTABLES -I PREROUTING 1 -t nat -i "$ifname" -j zone_${zone}_prerouting
95    $IPTABLES -A forward -i "$ifname" -j zone_${zone}_forward
96    $IPTABLES -t raw -I PREROUTING 1 -i "$ifname" -j zone_${zone}_notrack
97    uci_set_state firewall core "${network}_ifname" "$ifname"
98    uci_set_state firewall core "${network}_zone" "$zone"
99    ACTION=add ZONE="$zone" INTERFACE="$network" DEVICE="$ifname" /sbin/hotplug-call firewall
100}
101
102delif() {
103    local network="$1"
104    local ifname="$2"
105    local zone="$3"
106
107    logger "removing $network ($ifname) from firewall zone $zone"
108    $IPTABLES -D input -i "$ifname" -j zone_$zone
109    $IPTABLES -D zone_${zone}_MSSFIX -o "$ifname" -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
110    $IPTABLES -D zone_${zone}_ACCEPT -o "$ifname" -j ACCEPT
111    $IPTABLES -D zone_${zone}_DROP -o "$ifname" -j DROP
112    $IPTABLES -D zone_${zone}_REJECT -o "$ifname" -j reject
113    $IPTABLES -D zone_${zone}_ACCEPT -i "$ifname" -j ACCEPT
114    $IPTABLES -D zone_${zone}_DROP -i "$ifname" -j DROP
115    $IPTABLES -D zone_${zone}_REJECT -i "$ifname" -j reject
116    $IPTABLES -D zone_${zone}_nat -t nat -o "$ifname" -j MASQUERADE
117    $IPTABLES -D PREROUTING -t nat -i "$ifname" -j zone_${zone}_prerouting
118    $IPTABLES -D forward -i "$ifname" -j zone_${zone}_forward
119    uci_revert_state firewall core "${network}_ifname"
120    uci_revert_state firewall core "${network}_zone"
121    ACTION=remove ZONE="$zone" INTERFACE="$network" DEVICE="$ifname" /sbin/hotplug-call firewall
122}
123
124load_synflood() {
125    local rate=${1:-25}
126    local burst=${2:-50}
127    echo "Loading synflood protection"
128    $IPTABLES -N syn_flood
129    $IPTABLES -A syn_flood -p tcp --syn -m limit --limit $rate/second --limit-burst $burst -j RETURN
130    $IPTABLES -A syn_flood -j DROP
131    $IPTABLES -A INPUT -p tcp --syn -j syn_flood
132}
133
134fw_set_chain_policy() {
135    local chain=$1
136    local target=$2
137    [ "$target" == "REJECT" ] && {
138        $IPTABLES -A $chain -j reject
139        target=DROP
140    }
141    $IPTABLES -P $chain $target
142}
143
144fw_clear() {
145    $IPTABLES -F
146    $IPTABLES -t nat -F
147    $IPTABLES -t nat -X
148    $IPTABLES -t raw -F
149    $IPTABLES -t raw -X
150    $IPTABLES -X
151}
152
153fw_defaults() {
154    [ -n "$DEFAULTS_APPLIED" ] && {
155        echo "Error: multiple defaults sections detected"
156        return;
157    }
158    DEFAULTS_APPLIED=1
159
160    load_policy "$1"
161
162    echo 1 > /proc/sys/net/ipv4/tcp_syncookies
163    for f in /proc/sys/net/ipv4/conf/*/accept_redirects
164    do
165        echo 0 > $f
166    done
167    for f in /proc/sys/net/ipv4/conf/*/accept_source_route
168    do
169        echo 0 > $f
170    done
171
172    uci_revert_state firewall core
173    uci_set_state firewall core "" firewall_state
174
175    $IPTABLES -P INPUT DROP
176    $IPTABLES -P OUTPUT DROP
177    $IPTABLES -P FORWARD DROP
178
179    fw_clear
180    config_get_bool drop_invalid $1 drop_invalid 0
181
182    [ "$drop_invalid" -gt 0 ] && {
183        $IPTABLES -A INPUT -m state --state INVALID -j DROP
184        $IPTABLES -A OUTPUT -m state --state INVALID -j DROP
185        $IPTABLES -A FORWARD -m state --state INVALID -j DROP
186        NOTRACK_DISABLED=1
187    }
188
189    $IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
190    $IPTABLES -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
191    $IPTABLES -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
192
193    $IPTABLES -A INPUT -i lo -j ACCEPT
194    $IPTABLES -A OUTPUT -o lo -j ACCEPT
195
196    config_get syn_flood $1 syn_flood
197    config_get syn_rate $1 syn_rate
198    config_get syn_burst $1 syn_burst
199    [ "$syn_flood" == "1" ] && load_synflood $syn_rate $syn_burst
200
201    echo "Adding custom chains"
202    fw_custom_chains
203
204    $IPTABLES -N input
205    $IPTABLES -N output
206    $IPTABLES -N forward
207
208    $IPTABLES -A INPUT -j input
209    $IPTABLES -A OUTPUT -j output
210    $IPTABLES -A FORWARD -j forward
211
212    $IPTABLES -N reject
213    $IPTABLES -A reject -p tcp -j REJECT --reject-with tcp-reset
214    $IPTABLES -A reject -j REJECT --reject-with icmp-port-unreachable
215
216    fw_set_chain_policy INPUT "$DEF_INPUT"
217    fw_set_chain_policy OUTPUT "$DEF_OUTPUT"
218    fw_set_chain_policy FORWARD "$DEF_FORWARD"
219}
220
221fw_zone_defaults() {
222    local name
223    local network
224    local masq
225
226    config_get name $1 name
227    config_get network $1 network
228    config_get_bool masq $1 masq "0"
229    config_get_bool conntrack $1 conntrack "0"
230    config_get_bool mtu_fix $1 mtu_fix 0
231
232    load_policy $1
233    [ "$forward" ] && $IPTABLES -A zone_${name}_forward -j zone_${name}_${forward}
234    [ "$input" ] && $IPTABLES -A zone_${name} -j zone_${name}_${input}
235}
236
237fw_zone() {
238    local name
239    local network
240    local masq
241
242    config_get name $1 name
243    config_get network $1 network
244    config_get_bool masq $1 masq "0"
245    config_get_bool conntrack $1 conntrack "0"
246    config_get_bool mtu_fix $1 mtu_fix 0
247
248    load_policy $1
249    [ "$conntrack" = "1" -o "$masq" = "1" ] && append CONNTRACK_ZONES "$name"
250    [ -z "$network" ] && network=$name
251    create_zone "$name" "$network" "$input" "$output" "$forward" "$masq" "$mtu_fix"
252    fw_custom_chains_zone "$name"
253}
254
255fw_rule() {
256    local src
257    local src_ip
258    local src_mac
259    local src_port
260    local src_mac
261    local dest
262    local dest_ip
263    local dest_port
264    local proto
265    local icmp_type
266    local target
267    local ruleset
268
269    config_get src $1 src
270    config_get src_ip $1 src_ip
271    config_get src_mac $1 src_mac
272    config_get src_port $1 src_port
273    config_get dest $1 dest
274    config_get dest_ip $1 dest_ip
275    config_get dest_port $1 dest_port
276    config_get proto $1 proto
277    config_get icmp_type $1 icmp_type
278    config_get target $1 target
279    config_get ruleset $1 ruleset
280
281    src_port_first=${src_port%-*}
282    src_port_last=${src_port#*-}
283    [ "$src_port_first" -ne "$src_port_last" ] && { \
284        src_port="$src_port_first:$src_port_last"; }
285
286    dest_port_first=${dest_port%-*}
287    dest_port_last=${dest_port#*-}
288    [ "$dest_port_first" -ne "$dest_port_last" ] && { \
289        dest_port="$dest_port_first:$dest_port_last"; }
290
291    ZONE=input
292    TARGET=$target
293    [ -z "$target" ] && target=DROP
294    [ -n "$src" -a -z "$dest" ] && ZONE=zone_$src
295    [ -n "$src" -a -n "$dest" ] && ZONE=zone_${src}_forward
296    [ -n "$dest" ] && TARGET=zone_${dest}_$target
297
298    eval 'RULE_COUNT=$((++RULE_COUNT_'$ZONE'))'
299
300    add_rule() {
301        $IPTABLES -I $ZONE $RULE_COUNT \
302            ${proto:+-p $proto} \
303            ${icmp_type:+--icmp-type $icmp_type} \
304            ${src_ip:+-s $src_ip} \
305            ${src_port:+--sport $src_port} \
306            ${src_mac:+-m mac --mac-source $src_mac} \
307            ${dest_ip:+-d $dest_ip} \
308            ${dest_port:+--dport $dest_port} \
309            -j $TARGET
310    }
311    [ "$proto" == "tcpudp" -o -z "$proto" ] && {
312        proto=tcp
313        add_rule
314        proto=udp
315        add_rule
316        return
317    }
318    add_rule
319}
320
321fw_forwarding() {
322    local src
323    local dest
324    local masq
325
326    config_get src $1 src
327    config_get dest $1 dest
328    [ -n "$src" ] && z_src=zone_${src}_forward || z_src=forward
329    [ -n "$dest" ] && z_dest=zone_${dest}_ACCEPT || z_dest=ACCEPT
330    $IPTABLES -I $z_src 1 -j $z_dest
331
332    # propagate masq zone flag
333    find_item "$src" $CONNTRACK_ZONES && append CONNTRACK_ZONES $dest
334    find_item "$dest" $CONNTRACK_ZONES && append CONNTRACK_ZONES $src
335}
336
337fw_redirect() {
338    local src
339    local src_ip
340    local src_port
341    local src_dport
342    local src_mac
343    local dest_ip
344    local dest_port dest_port2
345    local proto
346
347    config_get src $1 src
348    config_get src_ip $1 src_ip
349    config_get src_dip $1 src_dip
350    config_get src_port $1 src_port
351    config_get src_dport $1 src_dport
352    config_get src_mac $1 src_mac
353    config_get dest_ip $1 dest_ip
354    config_get dest_port $1 dest_port
355    config_get proto $1 proto
356    [ -z "$src" -o -z "$dest_ip$dest_port" ] && { \
357        echo "redirect needs src and dest_ip or dest_port"; return ; }
358
359    find_item "$src" $CONNTRACK_ZONES || \
360        append CONNTRACK_ZONES "$src"
361
362    src_port_first=${src_port%-*}
363    src_port_last=${src_port#*-}
364    [ "$src_port_first" != "$src_port_last" ] && { \
365        src_port="$src_port_first:$src_port_last"; }
366
367    src_dport_first=${src_dport%-*}
368    src_dport_last=${src_dport#*-}
369    [ "$src_dport_first" != "$src_dport_last" ] && { \
370        src_dport="$src_dport_first:$src_dport_last"; }
371
372    dest_port2=${dest_port:-$src_dport}
373    dest_port_first=${dest_port2%-*}
374    dest_port_last=${dest_port2#*-}
375    [ "$dest_port_first" != "$dest_port_last" ] && { \
376        dest_port2="$dest_port_first:$dest_port_last"; }
377
378    add_rule() {
379        $IPTABLES -A zone_${src}_prerouting -t nat \
380            ${proto:+-p $proto} \
381            ${src_ip:+-s $src_ip} \
382            ${src_dip:+-d $src_dip} \
383            ${src_port:+--sport $src_port} \
384            ${src_dport:+--dport $src_dport} \
385            ${src_mac:+-m mac --mac-source $src_mac} \
386            -j DNAT --to-destination $dest_ip${dest_port:+:$dest_port}
387
388        [ -n "$dest_ip" ] && \
389        $IPTABLES -I zone_${src}_forward 1 \
390            ${proto:+-p $proto} \
391            -d $dest_ip \
392            ${src_ip:+-s $src_ip} \
393            ${src_port:+--sport $src_port} \
394            ${dest_port2:+--dport $dest_port2} \
395            ${src_mac:+-m mac --mac-source $src_mac} \
396            -j ACCEPT
397    }
398
399    [ "$proto" == "tcpudp" -o -z "$proto" ] && {
400        proto=tcp
401        add_rule
402        proto=udp
403        add_rule
404        return
405    }
406    add_rule
407}
408
409fw_include() {
410    local path
411    config_get path $1 path
412    [ -e $path ] && . $path
413}
414
415get_interface_zones() {
416    local interface="$2"
417    local name
418    local network
419    config_get name $1 name
420    config_get network $1 network
421    [ -z "$network" ] && network=$name
422    for n in $network; do
423        [ "$n" = "$interface" ] && append add_zone "$name"
424    done
425}
426
427fw_event() {
428    local action="$1"
429    local interface="$2"
430    local ifname="$(sh -c ". /etc/functions.sh; include /lib/network; scan_interfaces; config_get "$interface" ifname")"
431    add_zone=
432    local up
433
434    [ -z "$ifname" ] && return 0
435    config_foreach get_interface_zones zone "$interface"
436    [ -z "$add_zone" ] && return 0
437
438    case "$action" in
439        ifup)
440            for z in $add_zone; do
441                local loaded
442                config_get loaded core loaded
443                [ -n "$loaded" ] && addif "$interface" "$ifname" "$z"
444            done
445        ;;
446        ifdown)
447            config_get up "$interface" up
448
449            for z in $ZONE; do
450                [ "$up" == "1" ] && delif "$interface" "$ifname" "$z"
451            done
452        ;;
453    esac
454}
455
456fw_addif() {
457    local up
458    local ifname
459    config_get up $1 up
460    [ -n "$up" ] || return 0
461    fw_event ifup "$1"
462}
463
464fw_custom_chains() {
465    [ -n "$CUSTOM_CHAINS" ] || return 0
466    $IPTABLES -N input_rule
467    $IPTABLES -N output_rule
468    $IPTABLES -N forwarding_rule
469    $IPTABLES -N prerouting_rule -t nat
470    $IPTABLES -N postrouting_rule -t nat
471
472    $IPTABLES -A INPUT -j input_rule
473    $IPTABLES -A OUTPUT -j output_rule
474    $IPTABLES -A FORWARD -j forwarding_rule
475    $IPTABLES -A PREROUTING -t nat -j prerouting_rule
476    $IPTABLES -A POSTROUTING -t nat -j postrouting_rule
477}
478
479fw_custom_chains_zone() {
480    local zone="$1"
481
482    [ -n "$CUSTOM_CHAINS" ] || return 0
483    $IPTABLES -N input_${zone}
484    $IPTABLES -N forwarding_${zone}
485    $IPTABLES -N prerouting_${zone} -t nat
486    $IPTABLES -I zone_${zone} 1 -j input_${zone}
487    $IPTABLES -I zone_${zone}_forward 1 -j forwarding_${zone}
488    $IPTABLES -I zone_${zone}_prerouting 1 -t nat -j prerouting_${zone}
489}
490
491fw_check_notrack() {
492    local zone="$1"
493    config_get name "$zone" name
494    [ -n "$NOTRACK_DISABLED" ] || \
495        find_item "$name" $CONNTRACK_ZONES || \
496        $IPTABLES -t raw -A zone_${name}_notrack -j NOTRACK
497}
498
499fw_init() {
500    DEFAULTS_APPLIED=
501
502    echo "Loading defaults"
503    config_foreach fw_defaults defaults
504    echo "Loading zones"
505    config_foreach fw_zone zone
506    echo "Loading forwarding"
507    config_foreach fw_forwarding forwarding
508    echo "Loading redirects"
509    config_foreach fw_redirect redirect
510    echo "Loading rules"
511    config_foreach fw_rule rule
512    echo "Loading includes"
513    config_foreach fw_include include
514    echo "Loading zone defaults"
515    config_foreach fw_zone_defaults zone
516    uci_set_state firewall core loaded 1
517    config_set core loaded 1
518    config_foreach fw_check_notrack zone
519    INTERFACES="$(sh -c '
520        . /etc/functions.sh; config_load network
521        echo_up() { local up; config_get_bool up "$1" up 0; [ $up = 1 ] && echo "$1"; }
522        config_foreach echo_up interface
523    ')"
524    for interface in $INTERFACES; do
525        fw_event ifup "$interface"
526    done
527}
528
529fw_stop() {
530    fw_clear
531    $IPTABLES -P INPUT ACCEPT
532    $IPTABLES -P OUTPUT ACCEPT
533    $IPTABLES -P FORWARD ACCEPT
534    uci_revert_state firewall
535}
536

Archive Download this file



interactive