Browse Source

Merge pull request #7066 from haukepetersen/add_net_l2filter

net: added module for filtering packets based on l2 addresses
master
Martine Lenders 6 years ago committed by GitHub
parent
commit
9ab62b9758
  1. 4
      Makefile.dep
  2. 3
      cpu/native/netdev_tap/netdev_tap.c
  3. 4
      drivers/include/net/netdev.h
  4. 23
      drivers/netdev_eth/netdev_eth.c
  5. 15
      drivers/netdev_ieee802154/netdev_ieee802154.c
  6. 2
      makefiles/pseudomodules.inc.mk
  7. 3
      sys/Makefile
  8. 129
      sys/include/net/l2filter.h
  9. 20
      sys/include/net/netopt.h
  10. 2
      sys/net/crosslayer/netopt/netopt.c
  11. 7
      sys/net/gnrc/link_layer/netdev/gnrc_netdev_eth.c
  12. 13
      sys/net/gnrc/link_layer/netdev/gnrc_netdev_ieee802154.c
  13. 1
      sys/net/link_layer/l2filter/Makefile
  14. 107
      sys/net/link_layer/l2filter/l2filter.c
  15. 79
      sys/shell/commands/sc_netif.c

4
Makefile.dep

@ -594,6 +594,10 @@ ifneq (,$(filter spiffs,$(USEMODULE)))
USEMODULE += mtd
endif
ifneq (,$(filter l2filter_%,$(USEMODULE)))
USEMODULE += l2filter
endif
# include package dependencies
-include $(USEPKG:%=$(RIOTPKG)/%/Makefile.dep)

3
cpu/native/netdev_tap/netdev_tap.c

@ -144,7 +144,8 @@ static int _set(netdev_t *dev, netopt_t opt, void *value, size_t value_len)
_set_promiscous(dev, ((bool *)value)[0]);
break;
default:
return -ENOTSUP;
res = netdev_eth_set(dev, opt, value, value_len);
break;
}
return res;

4
drivers/include/net/netdev.h

@ -54,6 +54,7 @@ extern "C" {
#include <sys/uio.h>
#include "net/netstats.h"
#include "net/l2filter.h"
#include "net/netopt.h"
enum {
@ -120,6 +121,9 @@ struct netdev {
#ifdef MODULE_NETSTATS_L2
netstats_t stats; /**< transceiver's statistics */
#endif
#ifdef MODULE_L2FILTER
l2filter_t filter[L2FILTER_LISTSIZE]; /**< link layer address filters */
#endif
};
/**

23
drivers/netdev_eth/netdev_eth.c

@ -87,6 +87,15 @@ int netdev_eth_get(netdev_t *dev, netopt_t opt, void *value, size_t max_len)
res = sizeof(uintptr_t);
break;
}
#endif
#ifdef MODULE_L2FILTER
case NETOPT_L2FILTER:
{
assert(max_len >= sizeof(l2filter_t **));
*((l2filter_t **)value) = dev->filter;
res = sizeof(l2filter_t **);
break;
}
#endif
default:
{
@ -100,15 +109,27 @@ int netdev_eth_get(netdev_t *dev, netopt_t opt, void *value, size_t max_len)
int netdev_eth_set(netdev_t *dev, netopt_t opt, void *value, size_t value_len)
{
#ifndef MODULE_L2FILTER
(void)dev;
#endif
(void)value;
(void)value_len;
int res = 0;
switch (opt) {
#ifdef MODULE_L2FILTER
case NETOPT_L2FILTER:
res = l2filter_add(dev->filter, value, value_len);
break;
case NETOPT_L2FILTER_RM:
res = l2filter_rm(dev->filter, value, value_len);
break;
#endif
default:
return -ENOTSUP;
res = -ENOTSUP;
break;
}
return res;

15
drivers/netdev_ieee802154/netdev_ieee802154.c

@ -125,6 +125,13 @@ int netdev_ieee802154_get(netdev_ieee802154_t *dev, netopt_t opt, void *value,
*((netstats_t **)value) = &dev->netdev.stats;
res = sizeof(uintptr_t);
break;
#endif
#ifdef MODULE_L2FILTER
case NETOPT_L2FILTER:
assert(max_len >= sizeof(l2filter_t **));
*((l2filter_t **)value) = dev->netdev.filter;
res = sizeof(l2filter_t **);
break;
#endif
default:
break;
@ -207,6 +214,14 @@ int netdev_ieee802154_set(netdev_ieee802154_t *dev, netopt_t opt, void *value,
dev->proto = *((gnrc_nettype_t *)value);
res = sizeof(gnrc_nettype_t);
break;
#endif
#ifdef MODULE_L2FILTER
case NETOPT_L2FILTER:
res = l2filter_add(dev->netdev.filter, value, len);
break;
case NETOPT_L2FILTER_RM:
res = l2filter_rm(dev->netdev.filter, value, len);
break;
#endif
default:
break;

2
makefiles/pseudomodules.inc.mk

@ -17,6 +17,8 @@ PSEUDOMODULES += gnrc_sixlowpan_router
PSEUDOMODULES += gnrc_sixlowpan_router_default
PSEUDOMODULES += gnrc_sock_check_reuse
PSEUDOMODULES += gnrc_txtsnd
PSEUDOMODULES += l2filter_blacklist
PSEUDOMODULES += l2filter_whitelist
PSEUDOMODULES += log
PSEUDOMODULES += log_printfnoformat
PSEUDOMODULES += lwip_arp

3
sys/Makefile

@ -125,6 +125,9 @@ endif
ifneq (,$(filter devfs,$(USEMODULE)))
DIRS += fs/devfs
endif
ifneq (,$(filter l2filter,$(USEMODULE)))
DIRS += net/link_layer/l2filter
endif
DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE})))

129
sys/include/net/l2filter.h

@ -0,0 +1,129 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup net_l2filter Link layer address filter
* @ingroup net
* @brief Module for filtering (black- or white-listing) link layer
* addresses
*
* This module is used as a base for filtering link layer addresses. It allows
* to be (globally) configured in either blacklist or in whitelist mode. This
* configuration is done via RIOTs module system, for whitelist mode simply
* include the module `L2FILTER_WHITELIST`, for blacklist mode include
* `L2FILTER_BLACKLIST`.
*
* The actual memory for the filter lists should be allocated for every network
* device. This is done centrally in netdev_t type.
*
* @{
* @file
* @brief Link layer address filter interface definition
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef L2FILTER_H
#define L2FILTER_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Maximal length of addresses that can be stored in the filter list
*/
#ifndef L2FILTER_ADDR_MAXLEN
#define L2FILTER_ADDR_MAXLEN (8U)
#endif
/**
* @brief Number of slots in each filter list (filter entries per device)
*/
#ifndef L2FILTER_LISTSIZE
#define L2FILTER_LISTSIZE (8U)
#endif
/**
* @brief Filter list entries
*
* The filter list supports address entries with differing length. This is
* useful e.g. for IEEE802.15.4, where the list can store short and long
* addresses at the same time.
*/
typedef struct {
uint8_t addr[L2FILTER_ADDR_MAXLEN]; /**< link layer address */
size_t addr_len; /**< address length in byte */
} l2filter_t;
/**
* @brief Add an entry to a devices filter list
*
* @param[in,out] list pointer to the filter list
* @param[in] addr address to be added to list
* @param[in] addr_len size of @p addr [in byte]
*
* @pre @p list != NULL
* @pre @p addr != NULL
* @pre @p addr_maxlen <= @ref L2FILTER_ADDR_MAXLEN
*
* @return 0 on success
* @return -ENOMEM if no empty slot left in list
*/
int l2filter_add(l2filter_t *list, const void *addr, size_t addr_len);
/**
* @brief Remove an entry from the given filter list
*
* @param[in,out] list pointer to the filter list
* @param[in] addr address to remove from the list
* @param[in] addr_len length of @p addr [in byte]
*
* @pre @p list != NULL
* @pre @p addr != NULL
* @pre @p addr_maxlen <= @ref L2FILTER_ADDR_MAXLEN
*
* @return 0 on success
* @return -ENOENT if @p addr was not found in @p list
*/
int l2filter_rm(l2filter_t *list, const void *addr, size_t addr_len);
/**
* @brief Check if the given address passes the set filters
*
* Independent if the l2filter module is used in blacklist or in whitelist mode,
* this function returns whether the given address passes the filter. In
* whitelist mode, this means that the given address has to be in the list, in
* blacklist mode this means that the given address is not in the list.
*
* @param[in] list list with black-/whitelisted addresses
* @param[in] addr address to check against the entries in @p list
* @param[in] addr_len length of @p addr [in byte]
*
* @pre @p list != NULL
* @pre @p addr != NULL
* @pre @p addr_maxlen <= @ref L2FILTER_ADDR_MAXLEN
*
* @return in whitelist mode: true if @p addr is in @p list
* @return in whitelist mode: false if @p addr is not in @p list
* @return in blacklist mode: true if @p addr is not in @p list
* @return in blacklist mode: false if @p addr is in @p list
*/
bool l2filter_pass(const l2filter_t *list, const void *addr, size_t addr_len);
#ifdef __cplusplus
}
#endif
#endif /* L2FILTER_H */
/** @} */

20
sys/include/net/netopt.h

@ -240,6 +240,26 @@ typedef enum {
*/
NETOPT_RF_TESTMODE,
/**
* @brief add an address to a link layer filter list
*
* 'Getting' this option from a device will return a pointer of type
* @ref l2filter_t to the first entry of a filter list.
* When 'Setting' this option a pointer to an link layer address as well as
* the length of the address are expected as parameters.
*/
NETOPT_L2FILTER,
/**
* @brief remove an address from a link layer filter list
*
* 'Getting' this value always returns -ENOTSUP.
* When 'Setting' this option a pointer to an link layer address as well as
* the length of the address are expected as parameters. 'Setting' this
* option will lead to the given address being removed from the filer list.
*/
NETOPT_L2FILTER_RM,
/* add more options if needed */
/**

2
sys/net/crosslayer/netopt/netopt.c

@ -58,6 +58,8 @@ static const char *_netopt_strmap[] = {
[NETOPT_ENCRYPTION] = "NETOPT_ENCRYPTION",
[NETOPT_ENCRYPTION_KEY] = "NETOPT_ENCRYPTION_KEY",
[NETOPT_RF_TESTMODE] = "NETOPT_RF_TESTMODE",
[NETOPT_L2FILTER] = "NETOPT_L2FILTER",
[NETOPT_L2FILTER_RM] = "NETOPT_L2FILTER_RM",
[NETOPT_NUMOF] = "NETOPT_NUMOF",
};

7
sys/net/gnrc/link_layer/netdev/gnrc_netdev_eth.c

@ -72,6 +72,13 @@ static gnrc_pktsnip_t *_recv(gnrc_netdev_t *gnrc_netdev)
ethernet_hdr_t *hdr = (ethernet_hdr_t *)eth_hdr->data;
#ifdef MODULE_L2FILTER
if (!l2filter_pass(dev->filter, hdr->src, ETHERNET_ADDR_LEN)) {
DEBUG("gnrc_netdev_eth: incoming packet filtered by l2filter\n");
goto safe_out;
}
#endif
/* set payload type from ethertype */
pkt->type = gnrc_nettype_from_ethertype(byteorder_ntohs(hdr->type));

13
sys/net/gnrc/link_layer/netdev/gnrc_netdev_ieee802154.c

@ -16,6 +16,7 @@
#include <stddef.h>
#include "od.h"
#include "net/l2filter.h"
#include "net/gnrc.h"
#include "net/ieee802154.h"
@ -112,7 +113,19 @@ static gnrc_pktsnip_t *_recv(gnrc_netdev_t *gnrc_netdev)
gnrc_pktbuf_release(pkt);
return NULL;
}
hdr = netif_hdr->data;
#ifdef MODULE_L2FILTER
if (!l2filter_pass(netdev->filter, gnrc_netif_hdr_get_src_addr(hdr),
hdr->src_l2addr_len)) {
gnrc_pktbuf_release(pkt);
gnrc_pktbuf_release(netif_hdr);
DEBUG("_recv_ieee802154: packet dropped by l2filter\n");
return NULL;
}
#endif
hdr->lqi = rx_info.lqi;
hdr->rssi = rx_info.rssi;
hdr->if_pid = thread_getpid();

1
sys/net/link_layer/l2filter/Makefile

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

107
sys/net/link_layer/l2filter/l2filter.c

@ -0,0 +1,107 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup net_l2filter
* @{
*
* @file
* @brief Link layer address filter implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <string.h>
#include "assert.h"
#include "net/l2filter.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static inline bool match(const l2filter_t *filter,
const void *addr, size_t addr_len)
{
return ((filter->addr_len == addr_len) &&
(memcmp(filter->addr, addr, addr_len) == 0));
}
void l2filter_init(l2filter_t *list)
{
assert(list);
for (unsigned i = 0; i < L2FILTER_LISTSIZE; i++) {
list[i].addr_len = 0;
}
}
int l2filter_add(l2filter_t *list, const void *addr, size_t addr_len)
{
assert(list && addr && (addr_len <= L2FILTER_ADDR_MAXLEN));
int res = -ENOMEM;
for (unsigned i = 0; i < L2FILTER_LISTSIZE; i++) {
if (list[i].addr_len == 0) {
list[i].addr_len = addr_len;
memcpy(list[i].addr, addr, addr_len);
res = 0;
break;
}
}
return res;
}
int l2filter_rm(l2filter_t *list, const void *addr, size_t addr_len)
{
assert(list && addr && (addr_len <= L2FILTER_ADDR_MAXLEN));
int res = -ENOENT;
for (unsigned i = 0; i < L2FILTER_LISTSIZE; i++) {
if (match(&list[i], addr, addr_len)) {
list[i].addr_len = 0;
res = 0;
break;
}
}
return res;
}
bool l2filter_pass(const l2filter_t *list, const void *addr, size_t addr_len)
{
assert(list && addr && (addr_len <= L2FILTER_ADDR_MAXLEN));
#ifdef MODULE_L2FILTER_WHITELIST
bool res = false;
for (unsigned i = 0; i < L2FILTER_LISTSIZE; i++) {
if (match(&list[i], addr, addr_len)) {
DEBUG("[l2filter] whitelist: address match -> packet passes\n");
res = true;
break;
}
}
DEBUG("[l2filter] whitelist: no match -> packet dropped\n");
#else
bool res = true;
for (unsigned i = 0; i < L2FILTER_LISTSIZE; i++) {
if (match(&list[i], addr, addr_len)) {
DEBUG("[l2filter] blacklist: address match -> packet dropped\n");
res = false;
break;
}
}
DEBUG("[l2fitler] blacklist: no match -> packet passes\n");
#endif
return res;
}

79
sys/shell/commands/sc_netif.c

@ -27,6 +27,7 @@
#include "thread.h"
#include "net/netstats.h"
#include "net/l2filter.h"
#include "net/ipv6/addr.h"
#include "net/gnrc/ipv6/netif.h"
#include "net/gnrc/netif.h"
@ -499,6 +500,30 @@ static void _netif_list(kernel_pid_t dev)
}
#endif
#ifdef MODULE_L2FILTER
l2filter_t *filter = NULL;
res = gnrc_netapi_get(dev, NETOPT_L2FILTER, 0, &filter, sizeof(filter));
if (res > 0) {
#ifdef MODULE_L2FILTER_WHITELIST
puts("\n White-listed link layer addresses:");
#else
puts("\n Black-listed link layer addresses:");
#endif
int count = 0;
for (unsigned i = 0; i < L2FILTER_LISTSIZE; i++) {
if (filter[i].addr_len > 0) {
char hwaddr_str[filter[i].addr_len * 3];
gnrc_netif_addr_to_str(hwaddr_str, sizeof(hwaddr_str),
filter[i].addr, filter[i].addr_len);
printf(" %2i: %s\n", count++, hwaddr_str);
}
}
if (count == 0) {
puts(" --- none ---");
}
}
#endif
#ifdef MODULE_NETSTATS_L2
puts("");
_netif_stats(dev, NETSTATS_LAYER2, false);
@ -771,6 +796,40 @@ static int _netif_set_encrypt_key(kernel_pid_t dev, netopt_t opt, char *key_str)
return 0;
}
#ifdef MODULE_L2FILTER
static int _netif_addrm_l2filter(kernel_pid_t dev, char *val, bool add)
{
uint8_t addr[MAX_ADDR_LEN];
size_t addr_len = gnrc_netif_addr_from_str(addr, sizeof(addr), val);
if ((addr_len == 0) || (addr_len > L2FILTER_ADDR_MAXLEN)) {
puts("error: given address is invalid");
return 1;
}
if (add) {
if (gnrc_netapi_set(dev, NETOPT_L2FILTER, 0, addr, addr_len) < 0) {
puts("unable to add link layer address to filter");
return 1;
}
puts("successfully added address to filter");
}
else {
if (gnrc_netapi_set(dev, NETOPT_L2FILTER_RM, 0, addr, addr_len) < 0) {
puts("unable to remove link layer address from filter");
return 1;
}
puts("successfully removed address to filter");
}
return 0;
}
static void _l2filter_usage(const char *cmd)
{
printf("usage: %s <if_id> l2filter {add|del} <addr>\n", cmd);
}
#endif
static int _netif_set(char *cmd_name, kernel_pid_t dev, char *key, char *value)
{
if ((strcmp("addr", key) == 0) || (strcmp("addr_short", key) == 0)) {
@ -1153,6 +1212,23 @@ int _netif_config(int argc, char **argv)
return _netif_mtu((kernel_pid_t)dev, argv[3]);
}
#ifdef MODULE_L2FILTER
else if (strcmp(argv[2], "l2filter") == 0) {
if (argc < 5) {
_l2filter_usage(argv[2]);
}
else if (strcmp(argv[3], "add") == 0) {
return _netif_addrm_l2filter(dev, argv[4], true);
}
else if (strcmp(argv[3], "del") == 0) {
return _netif_addrm_l2filter(dev, argv[4], false);
}
else {
_l2filter_usage(argv[2]);
}
return 1;
}
#endif
#ifdef MODULE_NETSTATS
else if (strcmp(argv[2], "stats") == 0) {
uint8_t module;
@ -1230,6 +1306,9 @@ int _netif_config(int argc, char **argv)
_flag_usage(argv[0]);
_add_usage(argv[0]);
_del_usage(argv[0]);
#ifdef MODULE_L2FILTER
_l2filter_usage(argv[0]);
#endif
#ifdef MODULE_NETSTATS
_stats_usage(argv[0]);
#endif

Loading…
Cancel
Save