Index: tests/sys/netinet/libalias/2_natout.c =================================================================== --- /dev/null +++ tests/sys/netinet/libalias/2_natout.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include + +#include "util.h" + +/* common ip ranges */ +static struct in_addr masq = { htonl(0x01020304) }; +static struct in_addr pub = { htonl(0x0102dead) }; +static struct in_addr prv1 = { htonl(0x0a00dead) }; +static struct in_addr prv2 = { htonl(0xac10dead) }; +static struct in_addr prv3 = { htonl(0xc0a8dead) }; +static struct in_addr cgn = { htonl(0x6440dead) }; +static struct in_addr ext = { htonl(0x12345678) }; + +#define NAT_CHECK(pip, src, msq) do { \ + int res; \ + struct in_addr dst = pip->ip_dst; \ + pip->ip_src = src; \ + res = LibAliasOut(la, pip, 64); \ + ATF_CHECK_MSG(res == PKT_ALIAS_OK, \ + ">%d< not met PKT_ALIAS_OK", res); \ + ATF_CHECK(addr_eq(msq, pip->ip_src)); \ + ATF_CHECK(addr_eq(dst, pip->ip_dst)); \ +} while(0) + +#define NAT_FAIL(pip, src, dst) do { \ + int res; \ + pip->ip_src = src; \ + pip->ip_dst = dst; \ + res = LibAliasOut(la, pip, 64); \ + ATF_CHECK_MSG(res != PKT_ALIAS_OK), \ + ">%d< not met !PKT_ALIAS_OK", res); \ + ATF_CHECK(addr_eq(src, pip->ip_src)); \ + ATF_CHECK(addr_eq(dst, pip->ip_dst)); \ +} while(0) + +#define UNNAT_CHECK(pip, src, dst, rel) do { \ + int res; \ + pip->ip_src = src; \ + pip->ip_dst = dst; \ + res = LibAliasIn(la, pip, 64); \ + ATF_CHECK_MSG(res == PKT_ALIAS_OK, \ + ">%d< not met PKT_ALIAS_OK", res); \ + ATF_CHECK(addr_eq(src, pip->ip_src)); \ + ATF_CHECK(addr_eq(rel, pip->ip_dst)); \ +} while(0) + +#define UNNAT_FAIL(pip, src, dst) do { \ + int res; \ + pip->ip_src = src; \ + pip->ip_dst = dst; \ + res = LibAliasIn(la, pip, 64); \ + ATF_CHECK(res != PKT_ALIAS_OK, \ + ">%d< not met !PKT_ALIAS_OK", res));\ + ATF_CHECK(addr_eq(src, pip->ip_src)); \ + ATF_CHECK(addr_eq(dst, pip->ip_dst)); \ +} while(0) + +ATF_TC_WITHOUT_HEAD(1_simplemasq); +ATF_TC_BODY(1_simplemasq, dummy) +{ + struct libalias *la = LibAliasInit(NULL); + struct ip *pip; + + ATF_REQUIRE(la != NULL); + LibAliasSetAddress(la, masq); + LibAliasSetMode(la, 0, ~0); + + pip = ip_packet(prv1, ext, 254, 64); + NAT_CHECK(pip, prv1, masq); + NAT_CHECK(pip, prv2, masq); + NAT_CHECK(pip, prv3, masq); + NAT_CHECK(pip, cgn, masq); + NAT_CHECK(pip, pub, masq); + + free(pip); + LibAliasUninit(la); +} + +ATF_TC_WITHOUT_HEAD(2_unregistered); +ATF_TC_BODY(2_unregistered, dummy) +{ + struct libalias *la = LibAliasInit(NULL); + struct ip *pip; + + ATF_REQUIRE(la != NULL); + LibAliasSetAddress(la, masq); + LibAliasSetMode(la, PKT_ALIAS_UNREGISTERED_ONLY, ~0); + + pip = ip_packet(prv1, ext, 254, 64); + NAT_CHECK(pip, prv1, masq); + NAT_CHECK(pip, prv2, masq); + NAT_CHECK(pip, prv3, masq); + NAT_CHECK(pip, cgn, cgn); + NAT_CHECK(pip, pub, pub); + + /* + * State is only for new connections + * Because they are now active, + * the mode setting should be ignored + */ + LibAliasSetMode(la, 0, PKT_ALIAS_UNREGISTERED_ONLY); + NAT_CHECK(pip, prv1, masq); + NAT_CHECK(pip, prv2, masq); + NAT_CHECK(pip, prv3, masq); + NAT_CHECK(pip, cgn, cgn); + NAT_CHECK(pip, pub, pub); + + free(pip); + LibAliasUninit(la); +} + +ATF_TC_WITHOUT_HEAD(3_cgn); +ATF_TC_BODY(3_cgn, dummy) +{ + struct libalias *la = LibAliasInit(NULL); + struct ip *pip; + + ATF_REQUIRE(la != NULL); + LibAliasSetAddress(la, masq); + LibAliasSetMode(la, PKT_ALIAS_UNREGISTERED_CGN, ~0); + + pip = ip_packet(prv1, ext, 254, 64); + NAT_CHECK(pip, prv1, masq); + NAT_CHECK(pip, prv2, masq); + NAT_CHECK(pip, prv3, masq); + NAT_CHECK(pip, cgn, masq); + NAT_CHECK(pip, pub, pub); + + /* + * State is only for new connections + * Because they are now active, + * the mode setting should be ignored + */ + LibAliasSetMode(la, 0, PKT_ALIAS_UNREGISTERED_CGN); + NAT_CHECK(pip, prv1, masq); + NAT_CHECK(pip, prv2, masq); + NAT_CHECK(pip, prv3, masq); + NAT_CHECK(pip, cgn, masq); + NAT_CHECK(pip, pub, pub); + + free(pip); + LibAliasUninit(la); +} + +ATF_TC_WITHOUT_HEAD(4_udp); +ATF_TC_BODY(4_udp, dummy) +{ + struct libalias *la = LibAliasInit(NULL); + struct ip *po, *pi; + struct udphdr *ui, *uo; + + ATF_REQUIRE(la != NULL); + LibAliasSetAddress(la, masq); + + po = ip_packet(prv1, ext, 0, 64); + uo = set_udp(po, 123, 456); + printf("Query %u -> %u\n", ntohs(uo->uh_sport), ntohs(uo->uh_dport)); + NAT_CHECK(po, prv1, masq); + printf("Natted query %u -> %u\n", ntohs(uo->uh_sport), ntohs(uo->uh_dport)); + + pi = ip_packet(ext, prv1, 0, 80); + ui = set_udp(pi, ntohs(uo->uh_dport), ntohs(uo->uh_sport)); + printf("Response %u - %u\n", ntohs(uo->uh_sport), ntohs(uo->uh_dport)); + UNNAT_CHECK(pi, ext, masq, prv1); + printf("Unnatted response %u - %u\n", ntohs(uo->uh_sport), ntohs(uo->uh_dport)); + ATF_CHECK(uo->uh_sport == ui->uh_dport); + ATF_CHECK(uo->uh_dport == ui->uh_sport); + + free(pi); + free(po); + LibAliasUninit(la); +} + +ATF_TP_ADD_TCS(natout) +{ + /* Use "dd if=/dev/random bs=2 count=1 | od -x" to reproduce */ + srand(0x0b61); + + ATF_TP_ADD_TC(natout, 1_simplemasq); + ATF_TP_ADD_TC(natout, 2_unregistered); + ATF_TP_ADD_TC(natout, 3_cgn); + ATF_TP_ADD_TC(natout, 4_udp); + + return atf_no_error(); +} Index: tests/sys/netinet/libalias/Makefile =================================================================== --- tests/sys/netinet/libalias/Makefile +++ tests/sys/netinet/libalias/Makefile @@ -1,16 +1,17 @@ # $FreeBSD$ -.include - PACKAGE= tests TESTSDIR= ${TESTSBASE}/sys/netinet/libalias BINDIR= ${TESTSDIR} -ATF_TESTS_C+= 1_instance +ATF_TESTS_C+= 1_instance \ + 2_natout \ LIBADD+= alias +SRCS.2_natout= 2_natout.c util.c + .include # Index: tests/sys/netinet/libalias/util.h =================================================================== --- /dev/null +++ tests/sys/netinet/libalias/util.h @@ -0,0 +1,21 @@ +#include + +#include +#include +#include + +#ifndef _UTIL_H +#define _UTIL_H + +void hexdump(void *p, size_t len); +struct ip * ip_packet(struct in_addr src, struct in_addr dst, u_char protocol, size_t len); +struct udphdr * set_udp(struct ip *p, u_short sport, u_short dport); + +inline int +addr_eq(struct in_addr a, struct in_addr b) { + return a.s_addr == b.s_addr; +} + +#define a2h(a) ntohl(a.s_addr) + +#endif /* _UTIL_H */ \ No newline at end of file Index: tests/sys/netinet/libalias/util.c =================================================================== --- /dev/null +++ tests/sys/netinet/libalias/util.c @@ -0,0 +1,59 @@ +#include +#include +#include + +#include + +#include "util.h" + +void +hexdump(void *p, size_t len) { + size_t i; + unsigned char *c = p; + + for (i = 0; i < len; i++) { + printf(" %02x", c[i]); + switch (i & 0xf) { + case 0xf: printf("\n"); break; + case 0x8: printf(" "); break; + default: break; + } + } + if ((i & 0xf) != 0x0) + printf("\n"); +} + +struct ip * +ip_packet(struct in_addr src, struct in_addr dst, u_char protocol, size_t len) { + struct ip * p; + + ATF_REQUIRE(len >= 64 && len <= IP_MAXPACKET); + + p = calloc(1, len); + ATF_REQUIRE(p != NULL); + + p->ip_v = IPVERSION; + p->ip_hl = sizeof(*p)/4; + p->ip_len = htons(len); + p->ip_ttl = IPDEFTTL; + p->ip_src = src; + p->ip_dst = dst; + p->ip_p = protocol; + ATF_REQUIRE(p->ip_hl == 5); + + return (p); +} + +struct udphdr * +set_udp(struct ip *p, u_short sport, u_short dport) { + struct udphdr *u = (void *)((uint32_t *)(void *)p + p->ip_hl); + int payload = ntohs(p->ip_len) - 4*p->ip_hl; + + ATF_REQUIRE(payload >= (int)sizeof(*u)); + p->ip_p = IPPROTO_UDP; + u->uh_sport = htons(sport); + u->uh_dport = htons(dport); + u->uh_ulen = htons(payload); + return (u); +} +