diff options
Diffstat (limited to 'tests/osmo-pcap-test')
-rw-r--r-- | tests/osmo-pcap-test/.gitignore | 24 | ||||
-rw-r--r-- | tests/osmo-pcap-test/Make_global.am | 6 | ||||
-rw-r--r-- | tests/osmo-pcap-test/Makefile.am | 12 | ||||
-rw-r--r-- | tests/osmo-pcap-test/configure.ac | 28 | ||||
-rw-r--r-- | tests/osmo-pcap-test/l3_ipv4.c | 44 | ||||
-rw-r--r-- | tests/osmo-pcap-test/l4_tcp.c | 38 | ||||
-rw-r--r-- | tests/osmo-pcap-test/l4_udp.c | 38 | ||||
-rw-r--r-- | tests/osmo-pcap-test/main.c | 215 | ||||
-rw-r--r-- | tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr-dtx.pcap | bin | 0 -> 149092 bytes | |||
-rw-r--r-- | tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr.pcap | bin | 0 -> 239416 bytes | |||
-rw-r--r-- | tests/osmo-pcap-test/proto.c | 53 | ||||
-rw-r--r-- | tests/osmo-pcap-test/proto.h | 40 |
12 files changed, 498 insertions, 0 deletions
diff --git a/tests/osmo-pcap-test/.gitignore b/tests/osmo-pcap-test/.gitignore new file mode 100644 index 0000000..68f19b2 --- /dev/null +++ b/tests/osmo-pcap-test/.gitignore @@ -0,0 +1,24 @@ +Makefile +Makefile.in +.deps +.libs +*.o +*.lo +*.la +aclocal.m4 +acinclude.m4 +aminclude.am +m4/*.m4 +autom4te.cache +config.h* +config.sub +config.log +config.status +config.guess +configure +depcomp +missing +ltmain.sh +install-sh +stamp-h1 +libtool diff --git a/tests/osmo-pcap-test/Make_global.am b/tests/osmo-pcap-test/Make_global.am new file mode 100644 index 0000000..b44fdfe --- /dev/null +++ b/tests/osmo-pcap-test/Make_global.am @@ -0,0 +1,6 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include -I../../../include + +AM_CFLAGS = -std=gnu99 -W -Wall \ + -Wmissing-prototypes -Wwrite-strings -Wcast-qual -Wfloat-equal -Wshadow -Wpointer-arith -Wbad-function-cast -Wsign-compare -Waggregate-return -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wstrict-prototypes -Wundef \ + -Wno-unused-parameter \ + ${LIBOSMOCORE_CFLAGS} diff --git a/tests/osmo-pcap-test/Makefile.am b/tests/osmo-pcap-test/Makefile.am new file mode 100644 index 0000000..6420faf --- /dev/null +++ b/tests/osmo-pcap-test/Makefile.am @@ -0,0 +1,12 @@ +include $(top_srcdir)/Make_global.am + +check_PROGRAMS = osmo-pcap-test + +osmo_pcap_test_SOURCES = proto.c \ + l3_ipv4.c \ + l4_tcp.c \ + l4_udp.c \ + main.c + +osmo_pcap_test_LDFLAGS = -lpcap \ + -losmocore diff --git a/tests/osmo-pcap-test/configure.ac b/tests/osmo-pcap-test/configure.ac new file mode 100644 index 0000000..0d496db --- /dev/null +++ b/tests/osmo-pcap-test/configure.ac @@ -0,0 +1,28 @@ +AC_INIT(osmo-pcap-test, 0.0.1, pablo@gnumonks.org) +AC_CONFIG_AUX_DIR([build-aux]) + +AC_CANONICAL_HOST +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE([-Wall foreign subdir-objects + tar-pax no-dist-gzip dist-bzip2 1.6]) + +dnl kernel style compile messages +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.0) + +AC_PROG_CC +AC_DISABLE_STATIC +AM_PROG_LIBTOOL +AC_PROG_INSTALL +AC_PROG_LN_S +AM_PROG_LEX +AC_PROG_YACC + +case "$host" in +*-*-linux*) ;; +*) AC_MSG_ERROR([Linux only, dude!]);; +esac + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/tests/osmo-pcap-test/l3_ipv4.c b/tests/osmo-pcap-test/l3_ipv4.c new file mode 100644 index 0000000..83e3479 --- /dev/null +++ b/tests/osmo-pcap-test/l3_ipv4.c @@ -0,0 +1,44 @@ +/* + * (C) 2012 by Pablo Neira Ayuso <pablo@gnumonks.org> + * (C) 2012 by On Waves ehf <http://www.on-waves.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later vers + */ + +#include <stdlib.h> +#include <netinet/ip.h> +#include <linux/if_ether.h> + +#include "proto.h" + +#define PRINT_CMP(...) + +static int l3_ipv4_pkt_l4proto_num(const uint8_t *pkt) +{ + const struct iphdr *iph = (const struct iphdr *)pkt; + + return iph->protocol; +} + +static int l3_ipv4_pkt_l3hdr_len(const uint8_t *pkt) +{ + const struct iphdr *iph = (const struct iphdr *)pkt; + + return iph->ihl << 2; +} + +static struct osmo_pcap_proto_l2l3 ipv4 = { + .l2protonum = ETH_P_IP, + .l3protonum = AF_INET, + .l2hdr_len = ETH_HLEN, + .l3pkt_hdr_len = l3_ipv4_pkt_l3hdr_len, + .l4pkt_proto = l3_ipv4_pkt_l4proto_num, +}; + +void l2l3_ipv4_init(void) +{ + osmo_pcap_proto_l2l3_register(&ipv4); +} diff --git a/tests/osmo-pcap-test/l4_tcp.c b/tests/osmo-pcap-test/l4_tcp.c new file mode 100644 index 0000000..1e024b5 --- /dev/null +++ b/tests/osmo-pcap-test/l4_tcp.c @@ -0,0 +1,38 @@ +/* + * (C) 2012 by Pablo Neira Ayuso <pablo@gnumonks.org> + * (C) 2012 by On Waves ehf <http://www.on-waves.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later vers + */ + +#include <netinet/ip.h> +#include <netinet/tcp.h> + +#include "proto.h" + +static int l4_tcp_pkt_hdr_len(const uint8_t *pkt) +{ + const struct tcphdr *tcph = (const struct tcphdr *)pkt; + + return tcph->doff << 2; +} + +static int l4_tcp_pkt_no_data(const uint8_t *pkt) +{ + const struct tcphdr *tcph = (const struct tcphdr *)pkt; + return tcph->syn || tcph->fin || tcph->rst || !tcph->psh; +} + +static struct osmo_pcap_proto_l4 tcp = { + .l4protonum = IPPROTO_TCP, + .l4pkt_hdr_len = l4_tcp_pkt_hdr_len, + .l4pkt_no_data = l4_tcp_pkt_no_data, +}; + +void l4_tcp_init(void) +{ + osmo_pcap_proto_l4_register(&tcp); +} diff --git a/tests/osmo-pcap-test/l4_udp.c b/tests/osmo-pcap-test/l4_udp.c new file mode 100644 index 0000000..0a4266e --- /dev/null +++ b/tests/osmo-pcap-test/l4_udp.c @@ -0,0 +1,38 @@ +/* + * (C) 2012 by Pablo Neira Ayuso <pablo@gnumonks.org> + * (C) 2012 by On Waves ehf <http://www.on-waves.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later vers + */ + +#include <netinet/ip.h> +#include <netinet/udp.h> + +#include "proto.h" + +static int l4_udp_pkt_hdr_len(const uint8_t *pkt) +{ + const struct udphdr *udph = (const struct udphdr *)pkt; + + return ntohs(udph->len); +} + +static int l4_udp_pkt_no_data(const uint8_t *pkt) +{ + /* UDP has no control packets. */ + return 0; +} + +static struct osmo_pcap_proto_l4 udp = { + .l4protonum = IPPROTO_UDP, + .l4pkt_hdr_len = l4_udp_pkt_hdr_len, + .l4pkt_no_data = l4_udp_pkt_no_data, +}; + +void l4_udp_init(void) +{ + osmo_pcap_proto_l4_register(&udp); +} diff --git a/tests/osmo-pcap-test/main.c b/tests/osmo-pcap-test/main.c new file mode 100644 index 0000000..3a62d95 --- /dev/null +++ b/tests/osmo-pcap-test/main.c @@ -0,0 +1,215 @@ +/* + * (C) 2012 by Pablo Neira Ayuso <pablo@gnumonks.org> + * (C) 2012 by On Waves ehf <http://www.on-waves.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later vers + */ + +#include <stdio.h> +#include <pcap.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <string.h> +#include <dlfcn.h> +#include <unistd.h> + +#include <linux/if_ether.h> + +#include "proto.h" + +#include <osmocom/core/msgb.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/select.h> + +struct osmo_pcap_test_stats { + uint32_t pkts; + uint32_t skip; + uint32_t processed; + uint32_t unsupported_l3; + uint32_t unsupported_l4; +} osmo_pcap_test_stats; + +static int +osmo_pcap_process_packet(const uint8_t *pkt, uint32_t pktlen, + struct osmo_pcap_proto_l2l3 *l3h, + struct osmo_pcap_proto_l4 *l4h, + int (*cb)(struct msgb *msgb)) +{ + unsigned int l3hdr_len, skip_hdr_len; + struct msgb *msgb; + int ret; + + /* skip layer 2, 3 and 4 headers */ + l3hdr_len = l3h->l3pkt_hdr_len(pkt + ETH_HLEN); + skip_hdr_len = l3h->l2hdr_len + l3hdr_len + + l4h->l4pkt_hdr_len(pkt + ETH_HLEN + l3hdr_len); + + /* This packet contains no data, skip it. */ + if (l4h->l4pkt_no_data(pkt + l3hdr_len + ETH_HLEN)) { + osmo_pcap_test_stats.skip++; + return 0; + } + + /* get application layer data. */ + pkt += skip_hdr_len; + pktlen -= skip_hdr_len; + + /* Create the fake network buffer. */ + msgb = msgb_alloc(pktlen, "OSMO/PCAP test"); + if (msgb == NULL) { + fprintf(stderr, "Not enough memory\n"); + return -1; + } + memcpy(msgb->data, pkt, pktlen); + msgb_put(msgb, pktlen); + + ret = cb(msgb); + + msgb_free(msgb); + + osmo_pcap_test_stats.processed++; + + return ret; +} + +static pcap_t *osmo_pcap_test_open(const char *pcapfile) +{ + pcap_t *handle; + char errbuf[PCAP_ERRBUF_SIZE]; + + handle = pcap_open_offline(pcapfile, errbuf); + if (handle == NULL) { + fprintf(stderr, "couldn't open pcap file %s: %s\n", + pcapfile, errbuf); + return NULL; + } + + return handle; +} + +static void osmo_pcap_test_close(pcap_t *handle) +{ + pcap_close(handle); +} + +static struct osmo_pcap { + pcap_t *h; + struct osmo_timer_list timer; + struct timeval last; +} osmo_pcap; + +static int +osmo_pcap_test_run(pcap_t *handle, uint8_t pnum, int (*cb)(struct msgb *msgb)) +{ + struct osmo_pcap_proto_l2l3 *l3h; + struct osmo_pcap_proto_l4 *l4h; + struct pcap_pkthdr pcaph; + const u_char *pkt; + struct timeval res; + uint8_t l4protonum; + +retry: + pkt = pcap_next(handle, &pcaph); + if (pkt == NULL) + return -1; + + osmo_pcap_test_stats.pkts++; + + l3h = osmo_pcap_proto_l2l3_find(pkt); + if (l3h == NULL) { + osmo_pcap_test_stats.unsupported_l3++; + goto retry; + } + l4protonum = l3h->l4pkt_proto(pkt + ETH_HLEN); + + /* filter l4 protocols we are not interested in */ + if (l4protonum != pnum) { + osmo_pcap_test_stats.skip++; + goto retry; + } + + l4h = osmo_pcap_proto_l4_find(pkt, l4protonum); + if (l4h == NULL) { + osmo_pcap_test_stats.unsupported_l4++; + goto retry; + } + + /* first packet that is going to be processed */ + if (osmo_pcap_test_stats.processed == 0) + memcpy(&osmo_pcap.last, &pcaph.ts, sizeof(struct timeval)); + + /* retry with next packet if this has been skipped. */ + if (osmo_pcap_process_packet(pkt, pcaph.caplen, l3h, l4h, cb) < 0) + goto retry; + + /* calculate waiting time */ + timersub(&pcaph.ts, &osmo_pcap.last, &res); + printf("waiting %lu.%.6lu seconds\n", res.tv_sec, res.tv_usec); + osmo_timer_schedule(&osmo_pcap.timer, res.tv_sec, res.tv_usec); + + memcpy(&osmo_pcap.last, &pcaph.ts, sizeof(struct timeval)); + + return 0; +} + +static int osmo_osmux_xfrm_encode(struct msgb *msgb) +{ + return 0; +} + +static void osmo_pcap_pkt_timer_cb(void *data) +{ + if (osmo_pcap_test_run(osmo_pcap.h, IPPROTO_UDP, + osmo_osmux_xfrm_encode) < 0) { + printf("pkts=%d processed=%d skip=%d " + "unsupported_l3=%d unsupported_l4=%d\n", + osmo_pcap_test_stats.pkts, + osmo_pcap_test_stats.processed, + osmo_pcap_test_stats.skip, + osmo_pcap_test_stats.unsupported_l3, + osmo_pcap_test_stats.unsupported_l4); + printf("\e[1;34mDone.\e[0m\n"); + osmo_pcap_test_close(osmo_pcap.h); + exit(EXIT_SUCCESS); + } +} + +int main(int argc, char *argv[]) +{ + int ret; + + if (argc != 2) { + fprintf(stderr, "Wrong usage:\n"); + fprintf(stderr, "%s <pcap_file>\n", argv[0]); + fprintf(stderr, "example: %s file.pcap\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Initialization of supported layer 3 and 4 protocols here. */ + l2l3_ipv4_init(); + l4_tcp_init(); + l4_udp_init(); + + printf("\e[1;34mStarting test...\e[0m\n"); + + osmo_pcap.h = osmo_pcap_test_open(argv[1]); + if (osmo_pcap.h == NULL) + exit(EXIT_FAILURE); + + osmo_pcap.timer.cb = osmo_pcap_pkt_timer_cb; + + /* first run */ + osmo_pcap_pkt_timer_cb(NULL); + + while(1) { + osmo_select_main(0); + } + + return ret; +} diff --git a/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr-dtx.pcap b/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr-dtx.pcap Binary files differnew file mode 100644 index 0000000..1b8a3e5 --- /dev/null +++ b/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr-dtx.pcap diff --git a/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr.pcap b/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr.pcap Binary files differnew file mode 100644 index 0000000..d2a9e45 --- /dev/null +++ b/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr.pcap diff --git a/tests/osmo-pcap-test/proto.c b/tests/osmo-pcap-test/proto.c new file mode 100644 index 0000000..f90f07c --- /dev/null +++ b/tests/osmo-pcap-test/proto.c @@ -0,0 +1,53 @@ +/* + * (C) 2012 by Pablo Neira Ayuso <pablo@gnumonks.org> + * (C) 2012 by On Waves ehf <http://www.on-waves.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later vers + */ + +#include <stdlib.h> +#include <netinet/in.h> +#include <linux/if_ether.h> + +#include <osmocom/core/linuxlist.h> +#include "proto.h" + +static LLIST_HEAD(l2l3_proto_list); +static LLIST_HEAD(l4_proto_list); + +struct osmo_pcap_proto_l2l3 *osmo_pcap_proto_l2l3_find(const uint8_t *pkt) +{ + const struct ethhdr *eh = (const struct ethhdr *)pkt; + struct osmo_pcap_proto_l2l3 *cur; + + llist_for_each_entry(cur, &l2l3_proto_list, head) { + if (ntohs(cur->l2protonum) == eh->h_proto) + return cur; + } + return NULL; +} + +void osmo_pcap_proto_l2l3_register(struct osmo_pcap_proto_l2l3 *h) +{ + llist_add(&h->head, &l2l3_proto_list); +} + +struct osmo_pcap_proto_l4 * +osmo_pcap_proto_l4_find(const uint8_t *pkt, unsigned int l4protocol) +{ + struct osmo_pcap_proto_l4 *cur; + + llist_for_each_entry(cur, &l4_proto_list, head) { + if (cur->l4protonum == l4protocol) + return cur; + } + return NULL; +} + +void osmo_pcap_proto_l4_register(struct osmo_pcap_proto_l4 *h) +{ + llist_add(&h->head, &l4_proto_list); +} diff --git a/tests/osmo-pcap-test/proto.h b/tests/osmo-pcap-test/proto.h new file mode 100644 index 0000000..8cb41ed --- /dev/null +++ b/tests/osmo-pcap-test/proto.h @@ -0,0 +1,40 @@ +#ifndef _OSMO_PCAP_PROTO_H_ +#define _OSMO_PCAP_PROTO_H_ + +#include <stdint.h> + +#include <osmocom/core/linuxlist.h> + +struct osmo_pcap_proto_l4 { + struct llist_head head; + + unsigned int l4protonum; + + int (*l4pkt_hdr_len)(const uint8_t *pkt); + int (*l4pkt_no_data)(const uint8_t *pkt); +}; + +struct osmo_pcap_proto_l2l3 { + struct llist_head head; + + unsigned int l2protonum; + unsigned int l2hdr_len; + + unsigned int l3protonum; + + int (*l3pkt_hdr_len)(const uint8_t *pkt); + int (*l4pkt_proto)(const uint8_t *pkt); +}; + +struct osmo_pcap_proto_l2l3 *osmo_pcap_proto_l2l3_find(const uint8_t *pkt); +void osmo_pcap_proto_l2l3_register(struct osmo_pcap_proto_l2l3 *h); + +struct osmo_pcap_proto_l4 *osmo_pcap_proto_l4_find(const uint8_t *pkt, unsigned int l4protonum); +void osmo_pcap_proto_l4_register(struct osmo_pcap_proto_l4 *h); + +/* Initialization of supported protocols here. */ +void l2l3_ipv4_init(void); +void l4_tcp_init(void); +void l4_udp_init(void); + +#endif |