1 /* $NetBSD: npf_nat_test.c,v 1.1 2012/08/12 03:35:14 rmind 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 31 static 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 121 static bool 122 nmatch_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 128 static bool 129 checkresult(bool verbose, unsigned i, struct mbuf *m, int error) 130 { 131 const struct test_case *t = &test_cases[i]; 132 npf_cache_t npc = { .npc_info = 0 }; 133 134 if (verbose) { 135 printf("packet %d (expected %d ret %d)\n", i+1, t->ret, error); 136 } 137 if (error) { 138 return error == t->ret; 139 } 140 if (!npf_cache_all(&npc, m)) { 141 printf("error: could not fetch the packet data"); 142 return false; 143 } 144 145 const struct ip *ip = &npc.npc_ip.v4; 146 const struct udphdr *uh = &npc.npc_l4.udp; 147 148 if (verbose) { 149 printf("\tpost-translation: src %s (%d)", 150 inet_ntoa(ip->ip_src), ntohs(uh->uh_sport)); 151 printf(" dst %s (%d)\n", 152 inet_ntoa(ip->ip_dst), ntohs(uh->uh_dport)); 153 } 154 155 const bool forw = t->di == PFIL_OUT; 156 const char *saddr = forw ? t->taddr : t->src; 157 const char *daddr = forw ? t->dst : t->taddr; 158 in_addr_t sport = forw ? t->tport : t->sport; 159 in_addr_t dport = forw ? t->dport : t->tport; 160 161 bool defect = false; 162 defect |= nmatch_addr(saddr, &ip->ip_src); 163 defect |= sport != ntohs(uh->uh_sport); 164 defect |= nmatch_addr(daddr, &ip->ip_dst); 165 defect |= dport != ntohs(uh->uh_dport); 166 167 return !defect && error == t->ret; 168 } 169 170 static struct mbuf * 171 fill_packet(const struct test_case *t) 172 { 173 struct mbuf *m; 174 struct ip *ip; 175 struct udphdr *uh; 176 177 m = mbuf_construct(IPPROTO_UDP); 178 uh = mbuf_return_hdrs(m, false, &ip); 179 ip->ip_src.s_addr = inet_addr(t->src); 180 ip->ip_dst.s_addr = inet_addr(t->dst); 181 uh->uh_sport = htons(t->sport); 182 uh->uh_dport = htons(t->dport); 183 return m; 184 } 185 186 bool 187 npf_nat_test(bool verbose) 188 { 189 for (unsigned i = 0; i < __arraycount(test_cases); i++) { 190 const struct test_case *t = &test_cases[i]; 191 ifnet_t *ifp = ifunit(t->ifname); 192 struct mbuf *m = fill_packet(t); 193 int error; 194 bool ret; 195 196 if (ifp == NULL) { 197 printf("Interface %s is not configured.\n", t->ifname); 198 return false; 199 } 200 error = npf_packet_handler(NULL, &m, ifp, t->di); 201 ret = checkresult(verbose, i, m, error); 202 if (m) { 203 m_freem(m); 204 } 205 if (!ret) { 206 return false; 207 } 208 } 209 return true; 210 } 211