Skip to content

Commit

Permalink
Change BCP38 to use custom iptables chains and add autodetection for …
Browse files Browse the repository at this point in the history
…upstream IP.
  • Loading branch information
tohojo committed Mar 20, 2014
1 parent 426a56a commit b609985
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 61 deletions.
2 changes: 1 addition & 1 deletion net/bcp38/Makefile
Expand Up @@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=bcp38
PKG_VERSION:=3
PKG_VERSION:=4
PKG_RELEASE:=1

include $(INCLUDE_DIR)/package.mk
Expand Down
2 changes: 2 additions & 0 deletions net/bcp38/files/bcp38.config
@@ -1,5 +1,7 @@
config bcp38
option enabled 1
option interface 'ge00'
option detect_upstream 1
list match '127.0.0.0/8'
list match '0.0.0.0/8' # RFC 1700
list match '240.0.0.0/4' # RFC 5745
Expand Down
47 changes: 0 additions & 47 deletions net/bcp38/files/firewall.rules

This file was deleted.

79 changes: 66 additions & 13 deletions net/bcp38/files/run.sh
Expand Up @@ -2,6 +2,7 @@

STOP=$1
IPSET_NAME=bcp38-ipv4
IPTABLES_CHAIN=BCP38

. /lib/functions.sh

Expand All @@ -13,31 +14,83 @@ add_bcp38_rule()
local action="$2"

if [ "$action" == "nomatch" ]; then
ipset add $IPSET_NAME $subnet nomatch
ipset add "$IPSET_NAME" "$subnet" nomatch
else
ipset add $IPSET_NAME $subnet
ipset add "$IPSET_NAME" "$subnet"
fi
}

detect_upstream()
{
local interface="$1"

subnets=$(ip route show dev "$interface" | grep 'scope link' | awk '{print $1}')
for subnet in $subnets; do
# ipset test doesn't work for subnets, so strip out the subnet part
# and test for that; add as exception if there's a match
addr=$(echo $subnet | sed 's|/[0-9]\+$||')
ipset test "$IPSET_NAME" $addr 2>/dev/null && add_bcp38_rule $subnet nomatch
done
}

run() {
local enabled
config_get_bool enabled $1 enabled 0
local section="$1"
local enabled
local interface
local detect_upstream
config_get_bool enabled "$section" enabled 0
config_get interface "$section" interface
config_get detect_upstream "$section" detect_upstream

if [ "$enabled" -eq "1" -a -z "$STOP" ] ; then
config_list_foreach $1 match add_bcp38_rule match
config_list_foreach $1 nomatch add_bcp38_rule nomatch
if [ "$enabled" -eq "1" -a -n "$interface" -a -z "$STOP" ] ; then
setup_ipset
setup_iptables "$interface"
config_list_foreach "$section" match add_bcp38_rule match
config_list_foreach "$section" nomatch add_bcp38_rule nomatch
[ "$detect_upstream" -eq "1" ] && detect_upstream "$interface"
fi
exit 0
}

setup_ipset()
{
ipset create "$IPSET_NAME" hash:net family ipv4
ipset flush "$IPSET_NAME"
}

setup_iptables()
{
local interface="$1"
iptables -N "$IPTABLES_CHAIN" 2>/dev/null
iptables -F "$IPTABLES_CHAIN" 2>/dev/null

iptables -I output_rule -j "$IPTABLES_CHAIN"
iptables -I input_rule -j "$IPTABLES_CHAIN"
iptables -I forwarding_rule -j "$IPTABLES_CHAIN"

# always accept DHCP traffic
iptables -A "$IPTABLES_CHAIN" -p udp --dport 67:68 --sport 67:68 -j RETURN
iptables -A "$IPTABLES_CHAIN" -o "$interface" -m set --match-set "$IPSET_NAME" dst -j REJECT --reject-with icmp-net-unreachable
iptables -A "$IPTABLES_CHAIN" -i "$interface" -m set --match-set "$IPSET_NAME" src -j DROP
}

destroy_ipset()
{
ipset flush "$IPSET_NAME" 2>/dev/null
ipset destroy "$IPSET_NAME" 2>/dev/null
}

die()
destroy_iptables()
{
echo "$@" >&2
exit 1
iptables -D output_rule -j "$IPTABLES_CHAIN" 2>/dev/null
iptables -D input_rule -j "$IPTABLES_CHAIN" 2>/dev/null
iptables -D forwarding_rule -j "$IPTABLES_CHAIN" 2>/dev/null
iptables -F "$IPTABLES_CHAIN" 2>/dev/null
iptables -X "$IPTABLES_CHAIN" 2>/dev/null
}

# Make sure the ipset starts out empty
ipset list $IPSET_NAME >/dev/null 2>&1 || die "No ipset with name $IPSET_NAME exists. Create it first"
ipset flush $IPSET_NAME
destroy_iptables
destroy_ipset
config_foreach run bcp38

exit 0

0 comments on commit b609985

Please sign in to comment.