Skip to content

Commit

Permalink
Cs
Browse files Browse the repository at this point in the history
adding gluon ebtables support from T-X freifunk-gluon/gluon#1113
  • Loading branch information
Adorfer committed May 26, 2017
1 parent 0e01436 commit 5b1f168
Show file tree
Hide file tree
Showing 11 changed files with 336 additions and 0 deletions.
54 changes: 54 additions & 0 deletions gluon-ebtables-limit-arp/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=gluon-ebtables-limit-arp
PKG_VERSION:=1
PKG_RELEASE:=1

PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

include ../gluon.mk

define Package/gluon-ebtables-limit-arp
SECTION:=gluon
CATEGORY:=Gluon
TITLE:=Ebtables limiter for ARP packets
DEPENDS:=+gluon-core +gluon-ebtables
endef

define Package/gluon-ebtables-limit-arp/description
Gluon community wifi mesh firmware framework: Ebtables rules to
rate-limit ARP packets.

These filters limit the amount of ARP Requests devices are allowed
to send into the mesh from a particular node to 1 per second on
average.

A burst of up to 50 ARP Requests is allowed until the rate-limiting
takes effect (see --limit-burst in the ebtables manpage).

Furthermore, ARP Requests with a target IP already present in the
batman-adv DAT Cache are excluded from the rate-limiting,
both regarding counting and filtering, as batman-adv will respond
locally with no burden for the mesh. Therefore, this limiter
should not affect popular target IPs, like gateways.

However it should mitigate the problem of curious people or
smart devices scanning the whole IP range. Which could create
a significant amount of overhead for all participants so far.
endef

define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
endef

define Build/Configure
endef

define Build/Compile
endef

define Package/gluon-ebtables-limit-arp/install
$(CP) ./files/* $(1)/
endef

$(eval $(call BuildPackage,gluon-ebtables-limit-arp))
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/lua

local nixio = require('nixio')

if not nixio.getenv("EBTABLES_ATOMIC_FILE") then
print("Error: Refusing to run without EBTABLES_ATOMIC_FILE")
os.exit(1)
end

os.execute("ebtables -F ARP_LIMIT_DATCHECK")

local popen = io.popen("batctl dc -H")
for line in popen:lines() do
local t={} ; i=1
local bar = line:gmatch("(%d+\.%d+\.%d+\.%d+)%s+(%w+:%w+:%w+:%w+:%w+:%w+)")
local ip, mac

for a, b in bar do
ip = a
mac = b
end

os.execute("ebtables -I ARP_LIMIT_DATCHECK -p ARP --arp-ip-dst " .. ip .. " -j mark --mark-or 0x2 --mark-target RETURN")
end
popen:close()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
chain('ARP_LIMIT', 'DROP')
chain('ARP_LIMIT_DATCHECK', 'RETURN')
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
rule('ARP_LIMIT -j ARP_LIMIT_DATCHECK')
rule('ARP_LIMIT --mark 0x2/0x2 -j RETURN')
rule('ARP_LIMIT --limit 1/sec --limit-burst 50 -j RETURN')

rule('FORWARD -p ARP --logical-out br-client -o bat0 --arp-op Request -j ARP_LIMIT')
38 changes: 38 additions & 0 deletions gluon-ebtables/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=gluon-ebtables
PKG_VERSION:=1
PKG_RELEASE:=1

PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

include $(INCLUDE_DIR)/package.mk


define Package/gluon-ebtables
SECTION:=gluon
CATEGORY:=Gluon
TITLE:=Ebtables support
DEPENDS:=+gluon-core +ebtables +kmod-ebtables-ipv4 +kmod-ebtables-ipv6 +kmod-ipt-core
endef

define Package/gluon-ebtables/description
Gluon community wifi mesh firmware framework: ebtables support
endef

define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
endef

define Build/Configure
endef

define Build/Compile
endef

define Package/gluon-ebtables/install
mkdir -p $(1)/lib/gluon/ebtables-worker
$(CP) ./files/* $(1)/
endef

$(eval $(call BuildPackage,gluon-ebtables))
107 changes: 107 additions & 0 deletions gluon-ebtables/files/etc/init.d/gluon-ebtables
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2013 Project Gluon
#
# Firewall script for inserting and removing ebtables rules.
#
# Example format, for filtering any IPv4 multicast packets to the SSDP UDP port:
# rule FORWARD --logical-out br-client -d Multicast -p IPv4 --ip-protocol udp --ip-destination-port 5355 -j DROP
#
# Removing all rules:
# $ ./firewall-ebtables stop
# Inserting all rules:
# $ ./firewall-ebtables start
# Inserting a specific rule file:
# $ ./firewall-ebtables start /lib/gluon/ebtables/100-mcast-chain
# Removing a specific rule file:
# $ ./firewall-ebtables stop /lib/gluon/ebtables/100-mcast-chain


START=19
STOP=91

LOCK=/tmp/run/ebtables-init.lock
WLOCK=/tmp/run/ebtables-worker.lock

resolve_worker_lock() {
if [ ! -d "/proc/$workerpid" ]; then
echo "Removing stale lock (pid $workerpid)"
rm -r "$WLOCK"
else
echo "Waiting for ebtables-worker to finish (pid $workerpid)"
while true; do
sleep 5
[ ! -d "/proc/$workerpid" ] && break
done
fi
}

get_lock() {
touch "$LOCK"
sync

workerpid="`cat "$WLOCK/pid" 2> /dev/null`"
[ -n "$workerpid" ] && resolve_worker_lock
}

put_lock() {
rm "$LOCK"
}

exec_file() {
local file="$1"

/usr/bin/lua -e "
function rule(command, table)
table = table or 'filter'
os.execute($EBTABLES_RULE)
end
function chain(name, policy, table)
table = table or 'filter'
os.execute($EBTABLES_CHAIN)
end
" "$file"
}

exec_all() {
local sort_arg="$1"

local old_ifs="$IFS"
IFS='
'
for file in `find /lib/gluon/ebtables -type f | sort $sort_arg`; do
exec_file "$file"
done
IFS="$old_ifs"
}


start() {
get_lock
(
export EBTABLES_RULE='"ebtables -t " .. table .. " -A " .. command'
export EBTABLES_CHAIN='"ebtables -t " .. table .. " -N " .. name .. " -P " .. policy'

if [ -z "$1" ]; then
exec_all ''
else
exec_file "$1"
fi
)
put_lock
}

stop() {
get_lock
(
export EBTABLES_RULE='"ebtables -t " .. table .. " -D " .. command'
export EBTABLES_CHAIN='"ebtables -t " .. table .. " -X " .. name'

if [ -z "$1" ]; then
exec_all '-r'
else
exec_file "$1"
fi
)
put_lock
}
5 changes: 5 additions & 0 deletions gluon-ebtables/files/lib/gluon/ebtables/100-dir-chain
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
chain('IN_ONLY', 'RETURN')
chain('OUT_ONLY', 'RETURN')

chain('MULTICAST_OUT', 'RETURN')
chain('MULTICAST_OUT_ICMPV6', 'RETURN')
7 changes: 7 additions & 0 deletions gluon-ebtables/files/lib/gluon/ebtables/101-dir-rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
rule 'IN_ONLY --logical-in br-client -i bat0 -j RETURN'
rule 'IN_ONLY --logical-in br-client -i local-port -j RETURN'
rule 'IN_ONLY --logical-in br-client -j DROP'

rule 'OUT_ONLY --logical-out br-client -o bat0 -j RETURN'
rule 'OUT_ONLY --logical-out br-client -o local-port -j RETURN'
rule 'OUT_ONLY --logical-out br-client -j DROP'
4 changes: 4 additions & 0 deletions gluon-ebtables/files/lib/gluon/ebtables/350-mcast-dir-rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
rule 'OUTPUT -d Multicast --logical-out br-client -o bat0 -j MULTICAST_OUT'
rule 'FORWARD -d Multicast --logical-out br-client -o bat0 -j MULTICAST_OUT'

rule 'MULTICAST_OUT -p IPv6 --ip6-protocol ipv6-icmp -j MULTICAST_OUT_ICMPV6'
1 change: 1 addition & 0 deletions gluon-ebtables/files/usr/lib/micron.d/ebtables-worker
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* * * * * /usr/sbin/ebtables-worker
88 changes: 88 additions & 0 deletions gluon-ebtables/files/usr/sbin/ebtables-worker
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/lua

local nixio = require('nixio')

local workerdir = "/lib/gluon/ebtables-worker"
local workerlock = "/tmp/run/ebtables-worker.lock"
local initlock = "/tmp/run/ebtables-init.lock"

local pid = nixio.getpid()

local function try_get_lock()
if nixio.fs.access(initlock, "f") then
print("Error: Ebtables initialization in progress")
return false
end

if not nixio.fs.mkdir(workerlock .. "." .. pid) then
print("Error: Cannot create private worker lock directory")
return false
end

local pidfd = io.open(workerlock .. "." .. pid .. "/pid", "w")
pidfd:write(pid .. "\n")
pidfd:close()

if not nixio.fs.rename(workerlock .. "." .. pid, workerlock) then
print("Error: A worker is already running")
nixio.fs.remove(workerlock .. "." .. pid)
return false
end

return true
end

local function get_lock()
if not try_get_lock() then
os.exit(1)
end
end

local function try_put_lock()
if not nixio.fs.rename(workerlock, workerlock .. "." .. pid) then
print("Error: Could not remove worker lock (1)")
return false
end

if not nixio.fs.remove(workerlock .. "." .. pid .. "/pid") then
print("Error: Could not remove worker lock (2)")
return false
end

if not nixio.fs.rmdir(workerlock .. "." .. pid) then
print("Error: Could not remove worker lock (3)")
return false
end

return true
end

local function put_lock()
if not try_put_lock() then
os.exit(2)
end
end

local function worker_loop()
for e in nixio.fs.dir(workerdir) do
local f = workerdir .. "/" .. e

if nixio.fs.access(f, "x") and
nixio.fs.stat(f).type ~= "dir" then
print("+++ Running: " .. f)
os.execute(f)
end
end
end

local function worker()
nixio.setenv("EBTABLES_ATOMIC_FILE", "/tmp/.ebtables-worker.tmp")
os.execute("ebtables --atomic-save")
worker_loop()
os.execute("ebtables --atomic-commit")
end

-- Main
get_lock()
worker()
put_lock()

0 comments on commit 5b1f168

Please sign in to comment.