Skip to content
Snippets Groups Projects
Unverified Commit cf329daa authored by Jan-Philipp Litza's avatar Jan-Philipp Litza Committed by Matthias Schiffer
Browse files

Add package gluon-radv-filterd

This package drops all incoming router advertisements except for the
default router with the best metric according to B.A.T.M.A.N. advanced.

Note that advertisements originating from the node itself (for example
via gluon-radvd) are not affected.
parent 7ae8a511
No related branches found
No related tags found
No related merge requests found
...@@ -60,6 +60,7 @@ Several Freifunk communities in Germany use Gluon as the foundation of their Fre ...@@ -60,6 +60,7 @@ Several Freifunk communities in Germany use Gluon as the foundation of their Fre
package/gluon-ebtables-filter-ra-dhcp package/gluon-ebtables-filter-ra-dhcp
package/gluon-ebtables-segment-mld package/gluon-ebtables-segment-mld
package/gluon-ebtables-source-filter package/gluon-ebtables-source-filter
package/gluon-radv-filterd
package/gluon-web-admin package/gluon-web-admin
package/gluon-web-logging package/gluon-web-logging
......
gluon-radv-filterd
==================
This package drops all incoming router advertisements except for the
default router with the best metric according to B.A.T.M.A.N. advanced.
Note that advertisements originating from the node itself (for example
via gluon-radvd) are not affected and considered at all.
Selected router
---------------
The router selection mechanism is independent from the batman-adv gateway mode.
In contrast, the device originating the router advertisment could be any router
or client connected to the mesh, as radv-filterd captures all router
advertisements originating from it. All nodes announcing router advertisement
**with** a default lifetime greater than 0 are being considered as candidates.
In case a router is not a batman-adv originator itself, its TQ is defined by
the originator it is connected to. This lookup uses the batman-adv global
translation table.
Initially the router is the selected by choosing the candidate with the
strongest TQ. When another candidate can provide a better TQ metric it is not
picked up as the selected router until it will outperform the currently
selected router by X metric units. The hysteresis threshold is configurable
and prevents excessive flapping of the gateway.
"Local" routers
---------------
The package has functionality to select "local" routers, i.e. those connected
via cable or WLAN instead of via the mesh (technically: appearing in the
``transtable_local``), a fake TQ of 512 so that they are always preferred.
However, if used together with the :doc:`gluon-ebtables-filter-ra-dhcp`
package, these router advertisements are filtered anyway and reach neither the
node nor any other client. You currently have to disable the package or insert
custom ebtables rules in order to use local routers.
respondd module
---------------
This package also contains a module for respondd that announces the currently
selected router via the ``statistics.gateway6`` property using its interface MAC
address. Note that this is different from the ``statistics.gateway`` property,
which contains the MAC address of the main B.A.T.M.A.N. adv slave interface of
the selected IPv4 gateway.
site.conf
---------
radv_filterd.threshold : optional
- minimal difference in TQ value that another gateway has to be better than
the currently chosen gateway to become the new chosen gateway
- defaults to ``20``
Example::
radv_filterd = {
threshold = 20,
}
include $(TOPDIR)/rules.mk
PKG_NAME:=gluon-radv-filterd
PKG_VERSION:=1
PKG_RELEASE:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include ../gluon.mk
define Package/gluon-radv-filterd
SECTION:=gluon
CATEGORY:=Gluon
TITLE:=Filter IPv6 router advertisements
DEPENDS:=+gluon-ebtables +libgluonutil +libbatadv +libnl-tiny
endef
MAKE_VARS += \
LIBNL_NAME="libnl-tiny" \
LIBNL_GENL_NAME="libnl-tiny"
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Package/gluon-radv-filterd/install
$(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/usr/sbin/
$(INSTALL_BIN) $(PKG_BUILD_DIR)/gluon-radv-filterd $(1)/usr/sbin/
$(INSTALL_DIR) $(1)/lib/gluon/respondd
$(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/radv-filterd.so
endef
define Package/gluon-radv-filterd/postinst
#!/bin/sh
$(call GluonCheckSite,check_site.lua)
endef
$(eval $(call BuildPackage,gluon-radv-filterd))
need_number({'radv_filterd', 'threshold'}, false)
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=50
DAEMON=/usr/sbin/gluon-radv-filterd
start_service() {
local threshold="$(lua -e 'print(require("gluon.site").radv_filterd.threshold(20))')"
procd_open_instance
procd_set_param command $DAEMON -i br-client -c RADV_FILTER -t $threshold
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
procd_set_param netdev br-client
procd_set_param stderr 1
procd_close_instance
}
service_triggers() {
procd_open_trigger
procd_add_raw_trigger "interface.*" 1000 /etc/init.d/gluon-radv-filterd reload
procd_close_trigger
}
chain('RADV_FILTER', 'DROP')
rule 'FORWARD -p IPv6 -i bat0 --ip6-protocol ipv6-icmp --ip6-icmp-type router-advertisement -j RADV_FILTER'
rule 'RADV_FILTER -j ACCEPT'
all: gluon-radv-filterd respondd.so
CPPFLAGS += -D_GNU_SOURCE
ifeq ($(origin PKG_CONFIG), undefined)
PKG_CONFIG = pkg-config
ifeq ($(shell which $(PKG_CONFIG) 2>/dev/null),)
$(error $(PKG_CONFIG) not found)
endif
endif
ifeq ($(origin LIBNL_CFLAGS) $(origin LIBNL_LDLIBS), undefined undefined)
LIBNL_NAME ?= libnl-3.0
ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBNL_NAME) 2>/dev/null),)
$(error No $(LIBNL_NAME) development libraries found!)
endif
LIBNL_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBNL_NAME))
LIBNL_LDLIBS += $(shell $(PKG_CONFIG) --libs $(LIBNL_NAME))
endif
CFLAGS += $(LIBNL_CFLAGS)
LDLIBS += $(LIBNL_LDLIBS)
ifeq ($(origin LIBNL_GENL_CFLAGS) $(origin LIBNL_GENL_LDLIBS), undefined undefined)
LIBNL_GENL_NAME ?= libnl-genl-3.0
ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBNL_GENL_NAME) 2>/dev/null),)
$(error No $(LIBNL_GENL_NAME) development libraries found!)
endif
LIBNL_GENL_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBNL_GENL_NAME))
LIBNL_GENL_LDLIBS += $(shell $(PKG_CONFIG) --libs $(LIBNL_GENL_NAME))
endif
CFLAGS += $(LIBNL_GENL_CFLAGS)
LDLIBS += $(LIBNL_GENL_LDLIBS)
ifeq ($(origin LIBBATADV_CFLAGS) $(origin LIBBATADV_LDLIBS), undefined undefined)
LIBBATADV_NAME ?= libbatadv
ifeq ($(shell $(PKG_CONFIG) --modversion $(LIBBATADV_NAME) 2>/dev/null),)
$(error No $(LIBBATADV_NAME) development libraries found!)
endif
LIBBATADV_CFLAGS += $(shell $(PKG_CONFIG) --cflags $(LIBBATADV_NAME))
LIBBATADV_LDLIBS += $(shell $(PKG_CONFIG) --libs $(LIBBATADV_NAME))
endif
CFLAGS += $(LIBBATADV_CFLAGS)
LDLIBS += $(LIBBATADV_LDLIBS)
gluon-radv-filterd: gluon-radv-filterd.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS)
respondd.so: respondd.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -o $@ $^ $(LDLIBS) -lgluonutil
This diff is collapsed.
#include <stdint.h>
#include <linux/if_ether.h>
#define F_MAC "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"
#define F_MAC_LEN 17
#define F_MAC_VAR(var) \
(var).ether_addr_octet[0], (var).ether_addr_octet[1], \
(var).ether_addr_octet[2], (var).ether_addr_octet[3], \
(var).ether_addr_octet[4], (var).ether_addr_octet[5]
#define F_MAC_VAR_REF(var) \
&(var).ether_addr_octet[0], &(var).ether_addr_octet[1], \
&(var).ether_addr_octet[2], &(var).ether_addr_octet[3], \
&(var).ether_addr_octet[4], &(var).ether_addr_octet[5]
#define MAC2ETHER(_ether, _mac) memcpy((_ether).ether_addr_octet, \
(_mac), ETH_ALEN)
#define ether_addr_equal(_a, _b) (memcmp((_a).ether_addr_octet, \
(_b).ether_addr_octet, ETH_ALEN) == 0)
#include <respondd.h>
#include <json-c/json.h>
#include <libgluonutil.h>
#include <net/ethernet.h>
#include <stdio.h>
#include "mac.h"
static struct json_object * get_radv_filter() {
FILE *f = popen("exec ebtables --concurrent -L RADV_FILTER", "r");
char *line = NULL;
size_t len = 0;
struct ether_addr mac = {};
struct ether_addr unspec = {};
char macstr[F_MAC_LEN + 1] = "";
if (!f)
return NULL;
while (getline(&line, &len, f) > 0) {
if (sscanf(line, "-s " F_MAC " -j ACCEPT\n", F_MAC_VAR_REF(mac)) == ETH_ALEN)
break;
}
free(line);
pclose(f);
memset(&unspec, 0, sizeof(unspec));
if (ether_addr_equal(mac, unspec)) {
return NULL;
} else {
snprintf(macstr, sizeof(macstr), F_MAC, F_MAC_VAR(mac));
return gluonutil_wrap_string(macstr);
}
}
static struct json_object * respondd_provider_statistics() {
struct json_object *ret = json_object_new_object();
json_object_object_add(ret, "gateway6", get_radv_filter());
return ret;
}
const struct respondd_provider_info respondd_providers[] = {
{"statistics", respondd_provider_statistics},
{}
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment