From a3a31257df7044e083bbcc03fb25d5026f076562 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 22 Nov 2021 16:34:21 -0500 Subject: [PATCH] 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 --- include/net/net_pkt_filter.h | 49 +++++++++++++++++++++++++++++--- subsys/net/pkt_filter/ethernet.c | 16 ++++++++++- tests/net/npf/src/main.c | 28 +++++++++++++++++- 3 files changed, 87 insertions(+), 6 deletions(-) diff --git a/include/net/net_pkt_filter.h b/include/net/net_pkt_filter.h index 23900e2a811..1d8c48d5300 100644 --- a/include/net/net_pkt_filter.h +++ b/include/net/net_pkt_filter.h @@ -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 */ 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 */ struct npf_rule { sys_snode_t node; - enum net_verdict result; /*< result if all tests pass */ - uint32_t nb_tests; /*< number of tests in this rule */ - struct npf_test *tests[]; /*< pointers to @ref npf_test instances */ + enum net_verdict result; /**< result if all tests pass */ + uint32_t nb_tests; /**< number of tests for this rule */ + struct npf_test *tests[]; /**< pointers to @ref npf_test instances */ }; /** @brief Default rule list termination for accepting a packet */ @@ -310,6 +310,7 @@ struct npf_test_eth_addr { struct npf_test test; unsigned int nb_addresses; struct net_eth_addr *addresses; + struct net_eth_addr mask; }; 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), \ .nb_addresses = ARRAY_SIZE(_addr_array), \ .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), \ .nb_addresses = ARRAY_SIZE(_addr_array), \ .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), \ .nb_addresses = ARRAY_SIZE(_addr_array), \ .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), \ .nb_addresses = ARRAY_SIZE(_addr_array), \ .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 struct net_eth_addr 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 struct net_eth_addr 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 */ diff --git a/subsys/net/pkt_filter/ethernet.c b/subsys/net/pkt_filter/ethernet.c index cca8a404370..1b9cd8bd0fc 100644 --- a/subsys/net/pkt_filter/ethernet.c +++ b/subsys/net/pkt_filter/ethernet.c @@ -10,15 +10,29 @@ LOG_MODULE_REGISTER(npf_ethernet, CONFIG_NET_PKT_FILTER_LOG_LEVEL); #include #include +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) { struct npf_test_eth_addr *test_eth_addr = CONTAINER_OF(test, struct npf_test_eth_addr, test); 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; while (nb_addr) { - if (memcmp(addr, pkt_addr, sizeof(struct net_eth_addr)) == 0) { + if (addr_mask_compare(addr, pkt_addr, mask)) { return true; } addr++; diff --git a/tests/net/npf/src/main.c b/tests/net/npf/src/main.c index a177bd9c0b1..410e5ee78a1 100644 --- a/tests/net/npf/src/main.c +++ b/tests/net/npf/src/main.c @@ -281,13 +281,39 @@ static void test_npf_eth_mac_address(void) 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) { ztest_test_suite(net_pkt_filter_test, ztest_unit_test(test_npf_iface), ztest_unit_test(test_npf_example1), 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); }