net: npf: add the ability to do MAC address masked matching

Add the ability to do matching on partial MAC addresses.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
Nicolas Pitre 2021-11-22 16:34:21 -05:00 committed by Carles Cufí
commit a3a31257df
3 changed files with 87 additions and 6 deletions

View file

@ -41,15 +41,15 @@ typedef bool (npf_test_fn_t)(struct npf_test *test, struct net_pkt *pkt);
/** @brief common filter test structure to be embedded into larger structures */ /** @brief common filter test structure to be embedded into larger structures */
struct npf_test { struct npf_test {
npf_test_fn_t *fn; /*< packet condition test function */ npf_test_fn_t *fn; /**< packet condition test function */
}; };
/** @brief filter rule structure */ /** @brief filter rule structure */
struct npf_rule { struct npf_rule {
sys_snode_t node; sys_snode_t node;
enum net_verdict result; /*< result if all tests pass */ enum net_verdict result; /**< result if all tests pass */
uint32_t nb_tests; /*< number of tests in this rule */ uint32_t nb_tests; /**< number of tests for this rule */
struct npf_test *tests[]; /*< pointers to @ref npf_test instances */ struct npf_test *tests[]; /**< pointers to @ref npf_test instances */
}; };
/** @brief Default rule list termination for accepting a packet */ /** @brief Default rule list termination for accepting a packet */
@ -310,6 +310,7 @@ struct npf_test_eth_addr {
struct npf_test test; struct npf_test test;
unsigned int nb_addresses; unsigned int nb_addresses;
struct net_eth_addr *addresses; struct net_eth_addr *addresses;
struct net_eth_addr mask;
}; };
extern npf_test_fn_t npf_eth_src_addr_match; extern npf_test_fn_t npf_eth_src_addr_match;
@ -333,6 +334,7 @@ extern npf_test_fn_t npf_eth_dst_addr_unmatch;
.addresses = (_addr_array), \ .addresses = (_addr_array), \
.nb_addresses = ARRAY_SIZE(_addr_array), \ .nb_addresses = ARRAY_SIZE(_addr_array), \
.test.fn = npf_eth_src_addr_match, \ .test.fn = npf_eth_src_addr_match, \
.mask.addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, \
} }
/** /**
@ -349,6 +351,7 @@ extern npf_test_fn_t npf_eth_dst_addr_unmatch;
.addresses = (_addr_array), \ .addresses = (_addr_array), \
.nb_addresses = ARRAY_SIZE(_addr_array), \ .nb_addresses = ARRAY_SIZE(_addr_array), \
.test.fn = npf_eth_src_addr_unmatch, \ .test.fn = npf_eth_src_addr_unmatch, \
.mask.addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, \
} }
/** /**
@ -365,6 +368,7 @@ extern npf_test_fn_t npf_eth_dst_addr_unmatch;
.addresses = (_addr_array), \ .addresses = (_addr_array), \
.nb_addresses = ARRAY_SIZE(_addr_array), \ .nb_addresses = ARRAY_SIZE(_addr_array), \
.test.fn = npf_eth_dst_addr_match, \ .test.fn = npf_eth_dst_addr_match, \
.mask.addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, \
} }
/** /**
@ -381,6 +385,43 @@ extern npf_test_fn_t npf_eth_dst_addr_unmatch;
.addresses = (_addr_array), \ .addresses = (_addr_array), \
.nb_addresses = ARRAY_SIZE(_addr_array), \ .nb_addresses = ARRAY_SIZE(_addr_array), \
.test.fn = npf_eth_dst_addr_unmatch, \ .test.fn = npf_eth_dst_addr_unmatch, \
.mask.addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, \
}
/**
* @brief Statically define a "source address match with mask" packet filter condition
*
* This tests if the packet source address matches any of the Ethernet
* addresses contained in the provided set after applying specified mask.
*
* @param _name Name of the condition
* @param _addr_array Array of <tt>struct net_eth_addr</tt> items to test against
* @param ... up to 6 mask bytes
*/
#define NPF_ETH_SRC_ADDR_MASK_MATCH(_name, _addr_array, ...) \
struct npf_test_eth_addr _name = { \
.addresses = (_addr_array), \
.nb_addresses = ARRAY_SIZE(_addr_array), \
.mask.addr = { __VA_ARGS__ }, \
.test.fn = npf_eth_src_addr_match, \
}
/**
* @brief Statically define a "destination address match with mask" packet filter condition
*
* This tests if the packet destination address matches any of the Ethernet
* addresses contained in the provided set after applying specified mask.
*
* @param _name Name of the condition
* @param _addr_array Array of <tt>struct net_eth_addr</tt> items to test against
* @param ... up to 6 mask bytes
*/
#define NPF_ETH_DST_ADDR_MASK_MATCH(_name, _addr_array, ...) \
struct npf_test_eth_addr _name = { \
.addresses = (_addr_array), \
.nb_addresses = ARRAY_SIZE(_addr_array), \
.mask.addr = { __VA_ARGS__ }, \
.test.fn = npf_eth_dst_addr_match, \
} }
/** @cond INTERNAL_HIDDEN */ /** @cond INTERNAL_HIDDEN */

View file

@ -10,15 +10,29 @@ LOG_MODULE_REGISTER(npf_ethernet, CONFIG_NET_PKT_FILTER_LOG_LEVEL);
#include <net/ethernet.h> #include <net/ethernet.h>
#include <net/net_pkt_filter.h> #include <net/net_pkt_filter.h>
static bool addr_mask_compare(struct net_eth_addr *addr1,
struct net_eth_addr *addr2,
struct net_eth_addr *mask)
{
for (int i = 0; i < 6; i++) {
if ((addr1->addr[i] & mask->addr[i]) !=
(addr2->addr[i] & mask->addr[i])) {
return false;
}
}
return true;
}
static bool addr_match(struct npf_test *test, struct net_eth_addr *pkt_addr) static bool addr_match(struct npf_test *test, struct net_eth_addr *pkt_addr)
{ {
struct npf_test_eth_addr *test_eth_addr = struct npf_test_eth_addr *test_eth_addr =
CONTAINER_OF(test, struct npf_test_eth_addr, test); CONTAINER_OF(test, struct npf_test_eth_addr, test);
struct net_eth_addr *addr = test_eth_addr->addresses; struct net_eth_addr *addr = test_eth_addr->addresses;
struct net_eth_addr *mask = &test_eth_addr->mask;
unsigned int nb_addr = test_eth_addr->nb_addresses; unsigned int nb_addr = test_eth_addr->nb_addresses;
while (nb_addr) { while (nb_addr) {
if (memcmp(addr, pkt_addr, sizeof(struct net_eth_addr)) == 0) { if (addr_mask_compare(addr, pkt_addr, mask)) {
return true; return true;
} }
addr++; addr++;

View file

@ -281,13 +281,39 @@ static void test_npf_eth_mac_address(void)
zassert_true(npf_remove_recv_rule(&accept_unmatched_dst_addr), ""); zassert_true(npf_remove_recv_rule(&accept_unmatched_dst_addr), "");
} }
static NPF_ETH_SRC_ADDR_MASK_MATCH(matched_src_addr_mask, mac_address_list,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00);
static NPF_RULE(accept_matched_src_addr_mask, NET_OK, matched_src_addr_mask);
static void test_npf_eth_mac_addr_mask(void)
{
struct net_pkt *pkt = build_test_pkt(NET_ETH_PTYPE_IP, 100, NULL);
/* test standard match rule from previous test */
npf_insert_recv_rule(&npf_default_drop);
npf_insert_recv_rule(&accept_matched_src_addr);
zassert_true(net_pkt_filter_recv_ok(pkt), "");
/* clobber one nibble of matching address from previous test */
mac_address_list[1].addr[5] = 0x00;
zassert_false(net_pkt_filter_recv_ok(pkt), "");
/* insert masked address match rule */
npf_insert_recv_rule(&accept_matched_src_addr_mask);
zassert_true(net_pkt_filter_recv_ok(pkt), "");
/* cleanup */
zassert_true(npf_remove_all_recv_rules(), "");
}
void test_main(void) void test_main(void)
{ {
ztest_test_suite(net_pkt_filter_test, ztest_test_suite(net_pkt_filter_test,
ztest_unit_test(test_npf_iface), ztest_unit_test(test_npf_iface),
ztest_unit_test(test_npf_example1), ztest_unit_test(test_npf_example1),
ztest_unit_test(test_npf_example2), ztest_unit_test(test_npf_example2),
ztest_unit_test(test_npf_eth_mac_address)); ztest_unit_test(test_npf_eth_mac_address),
ztest_unit_test(test_npf_eth_mac_addr_mask));
ztest_run_test_suite(net_pkt_filter_test); ztest_run_test_suite(net_pkt_filter_test);
} }