tests: add test case for pointer confusion
When subscribing to IPv6 packets on a router for sniffing, the NETIF header is released prematurely, because of a wrong `gnrc_pktbuf_start_write()` call. This test aims to reproduce this error case.
This commit is contained in:
parent
56085b10a0
commit
b8269316e6
27
tests/gnrc_ipv6_fwd_w_sub/Makefile
Normal file
27
tests/gnrc_ipv6_fwd_w_sub/Makefile
Normal file
@ -0,0 +1,27 @@
|
||||
DEVELHELP := 1
|
||||
include ../Makefile.tests_common
|
||||
|
||||
BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-leonardo \
|
||||
arduino-mega2560 arduino-nano arduino-uno chronos \
|
||||
i-nucleo-lrwan1 msb-430 msb-430h nucleo-f030r8 \
|
||||
nucleo-f031k6 nucleo-f042k6 nucleo-l031k6 \
|
||||
nucleo-l053r8 stm32f0discovery telosb \
|
||||
waspmote-pro wsn430-v1_3b wsn430-v1_4 z1
|
||||
|
||||
USEMODULE += gnrc_ipv6_router_default
|
||||
USEMODULE += gnrc_netif
|
||||
USEMODULE += gnrc_pktbuf_cmd
|
||||
USEMODULE += netdev_eth
|
||||
USEMODULE += netdev_test
|
||||
USEMODULE += od
|
||||
USEMODULE += ps
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
USEMODULE += xtimer
|
||||
|
||||
CFLAGS += -DGNRC_PKTBUF_SIZE=512
|
||||
CFLAGS += -DTEST_SUITES
|
||||
|
||||
TEST_ON_CI_WHITELIST += all
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
10
tests/gnrc_ipv6_fwd_w_sub/README.md
Normal file
10
tests/gnrc_ipv6_fwd_w_sub/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Regression test for forwarding IPv6 packets with a sniffing subscriber
|
||||
|
||||
This only tests if a router can sniff its own forwarded IPv6 traffic. It is
|
||||
**not** a full IPv6 test suite.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
BOARD='<your choice>' make flash test
|
||||
```
|
||||
48
tests/gnrc_ipv6_fwd_w_sub/common.h
Normal file
48
tests/gnrc_ipv6_fwd_w_sub/common.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 tests_gnrc_ipv6_nib Common header for GNRC's NIB tests
|
||||
* @ingroup tests
|
||||
* @brief Common definitions for GNRC's NIB tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "net/gnrc.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _LL0 (0xce)
|
||||
#define _LL1 (0xab)
|
||||
#define _LL2 (0xfe)
|
||||
#define _LL3 (0xad)
|
||||
#define _LL4 (0xf7)
|
||||
#define _LL5 (0x26)
|
||||
|
||||
extern gnrc_netif_t *_mock_netif;
|
||||
|
||||
void _tests_init(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* COMMON_H */
|
||||
/** @} */
|
||||
202
tests/gnrc_ipv6_fwd_w_sub/main.c
Normal file
202
tests/gnrc_ipv6_fwd_w_sub/main.c
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Regression test to test subscribing to IPv6 packets while
|
||||
* forwarding
|
||||
*
|
||||
* @author Martine S. Lenders <m.lenders@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "kernel_types.h"
|
||||
#include "msg.h"
|
||||
#include "net/ethernet/hdr.h"
|
||||
#include "net/ipv6/addr.h"
|
||||
#include "net/udp.h"
|
||||
#include "net/gnrc.h"
|
||||
#include "net/gnrc.h"
|
||||
#include "net/gnrc/ipv6/nib.h"
|
||||
#include "net/netdev_test.h"
|
||||
#include "od.h"
|
||||
#include "sched.h"
|
||||
#include "shell.h"
|
||||
#include "thread.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define DUMPER_QUEUE_SIZE (16)
|
||||
#define NBR_MAC { 0x57, 0x44, 0x33, 0x22, 0x11, 0x00, }
|
||||
#define NBR_LINK_LOCAL { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x55, 0x44, 0x33, 0xff, 0xfe, 0x22, 0x11, 0x00, }
|
||||
#define DST { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0xab, 0xcd, \
|
||||
0x55, 0x44, 0x33, 0xff, 0xfe, 0x22, 0x11, 0x00, }
|
||||
#define DST_PFX_LEN (64U)
|
||||
/* IPv6 header + payload: version+TC FL: 0 plen: 16 NH:17 HL:64 */
|
||||
#define L2_PAYLOAD { 0x60, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x40, \
|
||||
/* source: random address */ \
|
||||
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0xef, 0x01, \
|
||||
0x02, 0xca, 0x4b, 0xef, 0xf4, 0xc2, 0xde, 0x01, \
|
||||
/* destination: DST */ \
|
||||
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0xab, 0xcd, \
|
||||
0x55, 0x44, 0x33, 0xff, 0xfe, 0x22, 0x11, 0x00, \
|
||||
/* random payload of length 16 */ \
|
||||
0x54, 0xb8, 0x59, 0xaf, 0x3a, 0xb4, 0x5c, 0x85, \
|
||||
0x1e, 0xce, 0xe2, 0xeb, 0x05, 0x4e, 0xa3, 0x85, }
|
||||
|
||||
static const uint8_t _nbr_mac[] = NBR_MAC;
|
||||
static const ipv6_addr_t _nbr_link_local = { .u8 = NBR_LINK_LOCAL };
|
||||
static const ipv6_addr_t _dst = { .u8 = DST };
|
||||
static const uint8_t _l2_payload[] = L2_PAYLOAD;
|
||||
static gnrc_netreg_entry_t _dumper;
|
||||
static msg_t _dumper_queue[DUMPER_QUEUE_SIZE];
|
||||
static char _dumper_stack[THREAD_STACKSIZE_MAIN];
|
||||
|
||||
static int _run_test(int argc, char **argv);
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "run_test", "runs the regression test", _run_test },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static void *_dumper_thread(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
msg_init_queue(_dumper_queue, DUMPER_QUEUE_SIZE);
|
||||
|
||||
while (1) {
|
||||
msg_t msg;
|
||||
|
||||
msg_receive(&msg);
|
||||
if (msg.type == GNRC_NETAPI_MSG_TYPE_RCV) {
|
||||
gnrc_pktsnip_t *pkt = msg.content.ptr;
|
||||
|
||||
/* wait a bit to give IPv6 time to handle the packet */
|
||||
xtimer_usleep(500);
|
||||
/* dump pkt. Should be equal to _l2_payloa*/
|
||||
puts("I got a subscription!");
|
||||
od_hex_dump(pkt->data, pkt->size, OD_WIDTH_DEFAULT);
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
else if (msg.type == GNRC_NETAPI_MSG_TYPE_SND) {
|
||||
/* we are not interested in sent packets from the node itself;
|
||||
* just release it */
|
||||
gnrc_pktbuf_release(msg.content.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _dump_etherframe(netdev_t *dev, const iolist_t *iolist)
|
||||
{
|
||||
static uint8_t outbuf[sizeof(ethernet_hdr_t) + sizeof(_l2_payload)];
|
||||
size_t outbuf_len = 0U;
|
||||
|
||||
(void)dev;
|
||||
while (iolist) {
|
||||
if ((outbuf_len + iolist->iol_len) > sizeof(outbuf)) {
|
||||
printf("Ignoring packet: %u > %u\n",
|
||||
(unsigned)(outbuf_len + iolist->iol_len),
|
||||
(unsigned)sizeof(outbuf));
|
||||
/* ignore larger packets */
|
||||
return outbuf_len;
|
||||
}
|
||||
memcpy(&outbuf[outbuf_len], iolist->iol_base, iolist->iol_len);
|
||||
outbuf_len += iolist->iol_len;
|
||||
iolist = iolist->iol_next;
|
||||
}
|
||||
|
||||
puts("Forwarded Ethernet frame:");
|
||||
od_hex_dump(outbuf, outbuf_len, OD_WIDTH_DEFAULT);
|
||||
return outbuf_len;
|
||||
}
|
||||
|
||||
static gnrc_pktsnip_t *_build_recvd_pkt(void)
|
||||
{
|
||||
gnrc_pktsnip_t *netif;
|
||||
gnrc_pktsnip_t *pkt;
|
||||
gnrc_netif_hdr_t *netif_hdr;
|
||||
|
||||
netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
assert(netif);
|
||||
netif_hdr = netif->data;
|
||||
netif_hdr->if_pid = _mock_netif->pid;
|
||||
pkt = gnrc_pktbuf_add(netif, _l2_payload, sizeof(_l2_payload),
|
||||
GNRC_NETTYPE_IPV6);
|
||||
assert(pkt);
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static int _run_test(int argc, char **argv)
|
||||
{
|
||||
int subscribers;
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
if (_dumper.target.pid <= KERNEL_PID_UNDEF) {
|
||||
gnrc_netreg_entry_init_pid(&_dumper, GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
thread_create(_dumper_stack,
|
||||
sizeof(_dumper_stack),
|
||||
THREAD_PRIORITY_MAIN - 1, 0,
|
||||
_dumper_thread, NULL,
|
||||
"dumper"));
|
||||
assert(_dumper.target.pid > KERNEL_PID_UNDEF);
|
||||
/* give dumper thread time to run */
|
||||
xtimer_usleep(200);
|
||||
}
|
||||
/* activate dumping of sent ethernet frames */
|
||||
netdev_test_set_send_cb((netdev_test_t *)_mock_netif->dev,
|
||||
_dump_etherframe);
|
||||
/* first, test forwarding without subscription */
|
||||
subscribers = gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6,
|
||||
GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
_build_recvd_pkt());
|
||||
/* only IPv6 should be subscribed at the moment */
|
||||
assert(subscribers == 1);
|
||||
/* subscribe dumper thread for any IPv6 packets */
|
||||
gnrc_netreg_register(GNRC_NETTYPE_IPV6, &_dumper);
|
||||
/* now test forwarding with subscription */
|
||||
subscribers = gnrc_netapi_dispatch_receive(GNRC_NETTYPE_IPV6,
|
||||
GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
_build_recvd_pkt());
|
||||
/* assert 2 subscribers: IPv6 and gnrc_pktdump as registered above */
|
||||
assert(subscribers == 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* initialize mock interface */
|
||||
_tests_init();
|
||||
/* define neighbor to forward to */
|
||||
res = gnrc_ipv6_nib_nc_set(&_nbr_link_local, _mock_netif->pid,
|
||||
_nbr_mac, sizeof(_nbr_mac));
|
||||
assert(res == 0);
|
||||
/* set route to neighbor */
|
||||
res = gnrc_ipv6_nib_ft_add(&_dst, DST_PFX_LEN, &_nbr_link_local,
|
||||
_mock_netif->pid, 0);
|
||||
assert(res == 0);
|
||||
/* start shell */
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||
|
||||
/* should be never reached */
|
||||
return 0;
|
||||
}
|
||||
80
tests/gnrc_ipv6_fwd_w_sub/mockup_netif.c
Normal file
80
tests/gnrc_ipv6_fwd_w_sub/mockup_netif.c
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "net/gnrc.h"
|
||||
#include "net/ethernet.h"
|
||||
#include "net/gnrc/ipv6/nib.h"
|
||||
#include "net/gnrc/netif/ethernet.h"
|
||||
#include "net/netdev_test.h"
|
||||
#include "thread.h"
|
||||
|
||||
gnrc_netif_t *_mock_netif = NULL;
|
||||
|
||||
static netdev_test_t _mock_netdev;
|
||||
static char _mock_netif_stack[THREAD_STACKSIZE_MAIN];
|
||||
|
||||
static int _get_device_type(netdev_t *dev, void *value, size_t max_len)
|
||||
{
|
||||
(void)dev;
|
||||
assert(max_len == sizeof(uint16_t));
|
||||
*((uint16_t *)value) = NETDEV_TYPE_ETHERNET;
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
|
||||
static int _get_max_packet_size(netdev_t *dev, void *value, size_t max_len)
|
||||
{
|
||||
(void)dev;
|
||||
assert(max_len == sizeof(uint16_t));
|
||||
*((uint16_t *)value) = ETHERNET_DATA_LEN;
|
||||
return sizeof(uint16_t);
|
||||
}
|
||||
|
||||
static int _get_address(netdev_t *dev, void *value, size_t max_len)
|
||||
{
|
||||
static const uint8_t addr[] = { _LL0, _LL1, _LL2, _LL3, _LL4, _LL5 };
|
||||
|
||||
(void)dev;
|
||||
assert(max_len >= sizeof(addr));
|
||||
memcpy(value, addr, sizeof(addr));
|
||||
return sizeof(addr);
|
||||
}
|
||||
|
||||
void _tests_init(void)
|
||||
{
|
||||
netdev_test_setup(&_mock_netdev, 0);
|
||||
netdev_test_set_get_cb(&_mock_netdev, NETOPT_DEVICE_TYPE,
|
||||
_get_device_type);
|
||||
netdev_test_set_get_cb(&_mock_netdev, NETOPT_MAX_PDU_SIZE,
|
||||
_get_max_packet_size);
|
||||
netdev_test_set_get_cb(&_mock_netdev, NETOPT_ADDRESS,
|
||||
_get_address);
|
||||
_mock_netif = gnrc_netif_ethernet_create(
|
||||
_mock_netif_stack, THREAD_STACKSIZE_DEFAULT, GNRC_NETIF_PRIO,
|
||||
"mockup_eth", &_mock_netdev.netdev
|
||||
);
|
||||
assert(_mock_netif != NULL);
|
||||
gnrc_ipv6_nib_init();
|
||||
gnrc_netif_acquire(_mock_netif);
|
||||
gnrc_ipv6_nib_init_iface(_mock_netif);
|
||||
gnrc_netif_release(_mock_netif);
|
||||
/* we do not want to test for SLAAC here so just assure the configured
|
||||
* address is valid */
|
||||
assert(!ipv6_addr_is_unspecified(&_mock_netif->ipv6.addrs[0]));
|
||||
_mock_netif->ipv6.addrs_flags[0] &= ~GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_MASK;
|
||||
_mock_netif->ipv6.addrs_flags[0] |= GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
44
tests/gnrc_ipv6_fwd_w_sub/tests/01-run.py
Executable file
44
tests/gnrc_ipv6_fwd_w_sub/tests/01-run.py
Executable file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2019 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.
|
||||
|
||||
import sys
|
||||
|
||||
from testrunner import run
|
||||
|
||||
|
||||
def testfunc(child):
|
||||
child.sendline("run_test")
|
||||
child.expect(r"Forwarded Ethernet frame:")
|
||||
child.expect(r"00000000 57 44 33 22 11 00 CE AB FE AD F7 26 86 DD 60 00")
|
||||
child.expect(r"00000010 00 00 00 10 11 3F 20 01 0D B8 00 00 EF 01 02 CA")
|
||||
child.expect(r"00000020 4B EF F4 C2 DE 01 20 01 0D B8 00 00 AB CD 55 44")
|
||||
child.expect(r"00000030 33 FF FE 22 11 00 54 B8 59 AF 3A B4 5C 85 1E CE")
|
||||
child.expect(r"00000040 E2 EB 05 4E A3 85")
|
||||
child.expect(r"Forwarded Ethernet frame:")
|
||||
child.expect(r"00000000 57 44 33 22 11 00 CE AB FE AD F7 26 86 DD 60 00")
|
||||
child.expect(r"00000010 00 00 00 10 11 3F 20 01 0D B8 00 00 EF 01 02 CA")
|
||||
child.expect(r"00000020 4B EF F4 C2 DE 01 20 01 0D B8 00 00 AB CD 55 44")
|
||||
child.expect(r"00000030 33 FF FE 22 11 00 54 B8 59 AF 3A B4 5C 85 1E CE")
|
||||
child.expect(r"00000040 E2 EB 05 4E A3 85")
|
||||
child.expect(r"I got a subscription!")
|
||||
child.expect(r"00000000 60 00 00 00 00 10 11 40 20 01 0D B8 00 00 EF 01")
|
||||
child.expect(r"00000010 02 CA 4B EF F4 C2 DE 01 20 01 0D B8 00 00 AB CD")
|
||||
child.expect(r"00000020 55 44 33 FF FE 22 11 00 54 B8 59 AF 3A B4 5C 85")
|
||||
child.expect(r"00000030 1E CE E2 EB 05 4E A3 85")
|
||||
child.sendline("pktbuf")
|
||||
child.expect(r"packet buffer: first byte: (0x[0-9a-fA-F]+), "
|
||||
r"last byte: 0x[0-9a-fA-F]+ \(size: (\d+)\)")
|
||||
start_addr = child.match.group(1)
|
||||
size = child.match.group(2)
|
||||
child.expect(r" position of last byte used: \d+")
|
||||
child.expect(r"~ unused: {} \(next: (\(nil\)|0(x0+)?), size: +{}\) ~"
|
||||
.format(start_addr, size))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run(testfunc, timeout=5, echo=True))
|
||||
Loading…
x
Reference in New Issue
Block a user