1/* $NetBSD: npf_nat_test.c,v 1.1.2.2 2012/08/13 17:49:53 riz Exp $ */ 2 3/* 4 * NPF NAT test. 5 * 6 * Public Domain. 7 */ 8 9#include <sys/types.h> 10 11#include "npf_impl.h" 12#include "npf_test.h" 13 14#define IFNAME_EXT "npftest0" 15#define IFNAME_INT "npftest1" 16 17#define LOCAL_IP1 "10.1.1.1" 18#define LOCAL_IP2 "10.1.1.2" 19 20/* Note: RFC 5737 compliant addresses. */ 21#define PUB_IP1 "192.0.2.1" 22#define PUB_IP2 "192.0.2.2" 23#define REMOTE_IP1 "192.0.2.3" 24#define REMOTE_IP2 "192.0.2.4" 25 26#define RESULT_PASS 0 27#define RESULT_BLOCK ENETUNREACH 28 29#define NPF_BINAT (NPF_NATIN | NPF_NATOUT) 30 31static const struct test_case { 32 const char * src; 33 in_port_t sport; 34 const char * dst; 35 in_port_t dport; 36 int ttype; 37 const char * ifname; 38 int di; 39 int ret; 40 const char * taddr; 41 in_port_t tport; 42} test_cases[] = { 43 44 /* 45 * Traditional NAPT (outbound NAT): 46 * map $ext_if dynamic $local_net -> $pub_ip1 47 */ 48 { 49 LOCAL_IP1, 15000, REMOTE_IP1, 7000, 50 NPF_NATOUT, IFNAME_EXT, PFIL_OUT, 51 RESULT_PASS, PUB_IP1, 53472 52 }, 53 { 54 LOCAL_IP1, 15000, REMOTE_IP1, 7000, 55 NPF_NATOUT, IFNAME_EXT, PFIL_OUT, 56 RESULT_PASS, PUB_IP1, 53472 57 }, 58 { 59 LOCAL_IP1, 15000, REMOTE_IP1, 7000, 60 NPF_NATOUT, IFNAME_EXT, PFIL_IN, 61 RESULT_BLOCK, NULL, 0 62 }, 63 { 64 REMOTE_IP1, 7000, LOCAL_IP1, 15000, 65 NPF_NATOUT, IFNAME_EXT, PFIL_IN, 66 RESULT_BLOCK, NULL, 0 67 }, 68 { 69 REMOTE_IP1, 7000, PUB_IP1, 53472, 70 NPF_NATOUT, IFNAME_INT, PFIL_IN, 71 RESULT_BLOCK, NULL, 0 72 }, 73 { 74 REMOTE_IP1, 7000, PUB_IP1, 53472, 75 NPF_NATOUT, IFNAME_EXT, PFIL_IN, 76 RESULT_PASS, LOCAL_IP1, 15000 77 }, 78 79 /* 80 * NAT redirect (inbound NAT): 81 * map $ext_if dynamic $local_ip1 port 8000 <- $pub_ip1 port 8000 82 */ 83 { 84 REMOTE_IP2, 16000, PUB_IP1, 8000, 85 NPF_NATIN, IFNAME_EXT, PFIL_IN, 86 RESULT_PASS, LOCAL_IP1, 6000 87 }, 88 { 89 LOCAL_IP1, 6000, REMOTE_IP2, 16000, 90 NPF_NATIN, IFNAME_EXT, PFIL_OUT, 91 RESULT_PASS, PUB_IP1, 8000 92 }, 93 94 /* 95 * Bi-directional NAT (inbound + outbound NAT): 96 * map $ext_if dynamic $local_ip2 <-> $pub_ip2 97 */ 98 { 99 REMOTE_IP2, 17000, PUB_IP2, 9000, 100 NPF_BINAT, IFNAME_EXT, PFIL_IN, 101 RESULT_PASS, LOCAL_IP2, 9000 102 }, 103 { 104 LOCAL_IP2, 9000, REMOTE_IP2, 17000, 105 NPF_BINAT, IFNAME_EXT, PFIL_OUT, 106 RESULT_PASS, PUB_IP2, 9000 107 }, 108 { 109 LOCAL_IP2, 18000, REMOTE_IP2, 9000, 110 NPF_BINAT, IFNAME_EXT, PFIL_OUT, 111 RESULT_PASS, PUB_IP2, 18000 112 }, 113 { 114 REMOTE_IP2, 9000, PUB_IP2, 18000, 115 NPF_BINAT, IFNAME_EXT, PFIL_IN, 116 RESULT_PASS, LOCAL_IP2, 18000 117 }, 118 119}; 120 121static bool 122nmatch_addr(const char *saddr, const struct in_addr *addr2) 123{ 124 const in_addr_t addr1 = inet_addr(saddr); 125 return memcmp(&addr1, &addr2->s_addr, sizeof(in_addr_t)) != 0; 126} 127 128static bool 129checkresult(bool verbose, unsigned i, struct mbuf *m, ifnet_t *ifp, int error) 130{ 131 const struct test_case *t = &test_cases[i]; 132 npf_cache_t npc = { .npc_info = 0 }; 133 nbuf_t nbuf; 134 135 if (verbose) { 136 printf("packet %d (expected %d ret %d)\n", i+1, t->ret, error); 137 } 138 if (error) { 139 return error == t->ret; 140 } 141 142 nbuf_init(&nbuf, m, ifp); 143 if (!npf_cache_all(&npc, &nbuf)) { 144 printf("error: could not fetch the packet data"); 145 return false; 146 } 147 148 const struct ip *ip = npc.npc_ip.v4; 149 const struct udphdr *uh = npc.npc_l4.udp; 150 151 if (verbose) { 152 printf("\tpost-translation: src %s (%d)", 153 inet_ntoa(ip->ip_src), ntohs(uh->uh_sport)); 154 printf(" dst %s (%d)\n", 155 inet_ntoa(ip->ip_dst), ntohs(uh->uh_dport)); 156 } 157 158 const bool forw = t->di == PFIL_OUT; 159 const char *saddr = forw ? t->taddr : t->src; 160 const char *daddr = forw ? t->dst : t->taddr; 161 in_addr_t sport = forw ? t->tport : t->sport; 162 in_addr_t dport = forw ? t->dport : t->tport; 163 164 bool defect = false; 165 defect |= nmatch_addr(saddr, &ip->ip_src); 166 defect |= sport != ntohs(uh->uh_sport); 167 defect |= nmatch_addr(daddr, &ip->ip_dst); 168 defect |= dport != ntohs(uh->uh_dport); 169 170 return !defect && error == t->ret; 171} 172 173static struct mbuf * 174fill_packet(const struct test_case *t) 175{ 176 struct mbuf *m; 177 struct ip *ip; 178 struct udphdr *uh; 179 180 m = mbuf_construct(IPPROTO_UDP); 181 uh = mbuf_return_hdrs(m, false, &ip); 182 ip->ip_src.s_addr = inet_addr(t->src); 183 ip->ip_dst.s_addr = inet_addr(t->dst); 184 uh->uh_sport = htons(t->sport); 185 uh->uh_dport = htons(t->dport); 186 return m; 187} 188 189bool 190npf_nat_test(bool verbose) 191{ 192 for (unsigned i = 0; i < __arraycount(test_cases); i++) { 193 const struct test_case *t = &test_cases[i]; 194 ifnet_t *ifp = ifunit(t->ifname); 195 struct mbuf *m = fill_packet(t); 196 int error; 197 bool ret; 198 199 if (ifp == NULL) { 200 printf("Interface %s is not configured.\n", t->ifname); 201 return false; 202 } 203 error = npf_packet_handler(NULL, &m, ifp, t->di); 204 ret = checkresult(verbose, i, m, ifp, error); 205 if (m) { 206 m_freem(m); 207 } 208 if (!ret) { 209 return false; 210 } 211 } 212 return true; 213} 214