1 /* 2 * NPF NAT tests. 3 * 4 * Public Domain. 5 */ 6 7 #ifdef _KERNEL 8 #include <sys/types.h> 9 #endif 10 11 #include "npf_impl.h" 12 #include "npf_test.h" 13 14 #define RESULT_PASS 0 15 #define RESULT_BLOCK ENETUNREACH 16 17 #define NPF_BINAT (NPF_NATIN | NPF_NATOUT) 18 19 #define RANDOM_PORT 46759 20 21 static const struct test_case { 22 const char * src; 23 in_port_t sport; 24 const char * dst; 25 in_port_t dport; 26 int ttype; 27 const char * ifname; 28 int di; 29 int ret; 30 int af; 31 const char * taddr; 32 in_port_t tport; 33 } test_cases[] = { 34 35 /* 36 * Traditional NAPT (outbound NAT): 37 * map $ext_if dynamic $local_net -> $pub_ip1 38 */ 39 { 40 LOCAL_IP1, 15000, REMOTE_IP1, 7000, 41 NPF_NATOUT, IFNAME_EXT, PFIL_OUT, 42 RESULT_PASS, AF_INET, PUB_IP1, RANDOM_PORT 43 }, 44 { 45 LOCAL_IP1, 15000, REMOTE_IP1, 7000, 46 NPF_NATOUT, IFNAME_EXT, PFIL_OUT, 47 RESULT_PASS, AF_INET, PUB_IP1, RANDOM_PORT 48 }, 49 { 50 LOCAL_IP1, 15000, REMOTE_IP1, 7000, 51 NPF_NATOUT, IFNAME_EXT, PFIL_IN, 52 RESULT_BLOCK, AF_INET, NULL, 0 53 }, 54 { 55 REMOTE_IP1, 7000, LOCAL_IP1, 15000, 56 NPF_NATOUT, IFNAME_EXT, PFIL_IN, 57 RESULT_BLOCK, AF_INET, NULL, 0 58 }, 59 { 60 REMOTE_IP1, 7000, PUB_IP1, RANDOM_PORT, 61 NPF_NATOUT, IFNAME_INT, PFIL_IN, 62 RESULT_BLOCK, AF_INET, NULL, 0 63 }, 64 { 65 REMOTE_IP1, 7000, PUB_IP1, RANDOM_PORT, 66 NPF_NATOUT, IFNAME_EXT, PFIL_IN, 67 RESULT_PASS, AF_INET, LOCAL_IP1, 15000 68 }, 69 70 /* 71 * NAT redirect (inbound NAT): 72 * map $ext_if dynamic $local_ip1 port 6000 <- $pub_ip1 port 8000 73 */ 74 { 75 REMOTE_IP2, 16000, PUB_IP1, 8000, 76 NPF_NATIN, IFNAME_EXT, PFIL_IN, 77 RESULT_PASS, AF_INET, LOCAL_IP1, 6000 78 }, 79 { 80 LOCAL_IP1, 6000, REMOTE_IP2, 16000, 81 NPF_NATIN, IFNAME_EXT, PFIL_OUT, 82 RESULT_PASS, AF_INET, PUB_IP1, 8000 83 }, 84 85 /* 86 * Bi-directional NAT (inbound + outbound NAT): 87 * map $ext_if dynamic $local_ip2 <-> $pub_ip2 88 */ 89 { 90 REMOTE_IP2, 17000, PUB_IP2, 9000, 91 NPF_BINAT, IFNAME_EXT, PFIL_IN, 92 RESULT_PASS, AF_INET, LOCAL_IP2, 9000 93 }, 94 { 95 LOCAL_IP2, 9000, REMOTE_IP2, 17000, 96 NPF_BINAT, IFNAME_EXT, PFIL_OUT, 97 RESULT_PASS, AF_INET, PUB_IP2, 9000 98 }, 99 { 100 LOCAL_IP2, 18000, REMOTE_IP2, 9000, 101 NPF_BINAT, IFNAME_EXT, PFIL_OUT, 102 RESULT_PASS, AF_INET, PUB_IP2, 18000 103 }, 104 { 105 REMOTE_IP2, 9000, PUB_IP2, 18000, 106 NPF_BINAT, IFNAME_EXT, PFIL_IN, 107 RESULT_PASS, AF_INET, LOCAL_IP2, 18000 108 }, 109 110 /* 111 * Static NAT: plain translation both ways. 112 * map $ext_if static $local_ip3 <-> $pub_ip3 113 */ 114 { 115 LOCAL_IP3, 19000, REMOTE_IP3, 10000, 116 NPF_BINAT, IFNAME_EXT, PFIL_OUT, 117 RESULT_PASS, AF_INET, PUB_IP3, 19000 118 }, 119 { 120 REMOTE_IP3, 10000, PUB_IP3, 19000, 121 NPF_BINAT, IFNAME_EXT, PFIL_IN, 122 RESULT_PASS, AF_INET, LOCAL_IP3, 19000 123 }, 124 125 /* 126 * NETMAP case: 127 * map $ext_if static algo netmap $net_a <-> $net_b 128 */ 129 { 130 NET_A_IP1, 12345, REMOTE_IP4, 12345, 131 NPF_BINAT, IFNAME_EXT, PFIL_OUT, 132 RESULT_PASS, AF_INET, NET_B_IP1, 12345 133 }, 134 135 /* 136 * NPTv6 case: 137 * map $ext_if static algo npt66 $net6_inner <-> $net6_outer 138 */ 139 { 140 LOCAL_IP6, 1000, REMOTE_IP6, 1001, 141 NPF_BINAT, IFNAME_EXT, PFIL_OUT, 142 RESULT_PASS, AF_INET6, EXPECTED_IP6, 1000 143 }, 144 { 145 REMOTE_IP6, 1001, EXPECTED_IP6, 1000, 146 NPF_BINAT, IFNAME_EXT, PFIL_IN, 147 RESULT_PASS, AF_INET6, LOCAL_IP6, 1000 148 }, 149 150 }; 151 152 static bool 153 match_addr(int af, const char *saddr, const npf_addr_t *addr2) 154 { 155 npf_addr_t addr1; 156 size_t len; 157 158 npf_inet_pton(af, saddr, &addr1); 159 len = af == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr); 160 return memcmp(&addr1, addr2, len) == 0; 161 } 162 163 static bool 164 checkresult(bool verbose, unsigned i, struct mbuf *m, ifnet_t *ifp, int error) 165 { 166 const struct test_case *t = &test_cases[i]; 167 npf_cache_t npc = { .npc_info = 0, .npc_ctx = npf_getkernctx() }; 168 const int af = t->af; 169 nbuf_t nbuf; 170 171 if (verbose) { 172 printf("packet %d (expected %d ret %d)\n", i+1, t->ret, error); 173 } 174 if (error) { 175 return error == t->ret; 176 } 177 178 nbuf_init(npf_getkernctx(), &nbuf, m, ifp); 179 npc.npc_nbuf = &nbuf; 180 if (!npf_cache_all(&npc)) { 181 printf("error: could not fetch the packet data"); 182 return false; 183 } 184 185 const struct udphdr *uh = npc.npc_l4.udp; 186 187 if (verbose) { 188 char sbuf[64], dbuf[64]; 189 190 npf_inet_ntop(af, npc.npc_ips[NPF_SRC], sbuf, sizeof(sbuf)); 191 npf_inet_ntop(af, npc.npc_ips[NPF_DST], dbuf, sizeof(dbuf)); 192 193 printf("\tpost-translation:"); 194 printf("src %s (%d) ", sbuf, ntohs(uh->uh_sport)); 195 printf("dst %s (%d)\n", dbuf, ntohs(uh->uh_dport)); 196 } 197 if (error != t->ret) { 198 return false; 199 } 200 201 const bool forw = t->di == PFIL_OUT; 202 const char *saddr = forw ? t->taddr : t->src; 203 const char *daddr = forw ? t->dst : t->taddr; 204 in_addr_t sport = forw ? t->tport : t->sport; 205 in_addr_t dport = forw ? t->dport : t->tport; 206 207 CHECK_TRUE(match_addr(af, saddr, npc.npc_ips[NPF_SRC])); 208 CHECK_TRUE(sport == ntohs(uh->uh_sport)); 209 CHECK_TRUE(match_addr(af, daddr, npc.npc_ips[NPF_DST])); 210 CHECK_TRUE(dport == ntohs(uh->uh_dport)); 211 212 return true; 213 } 214 215 bool 216 npf_nat_test(bool verbose) 217 { 218 npf_t *npf = npf_getkernctx(); 219 220 for (unsigned i = 0; i < __arraycount(test_cases); i++) { 221 const struct test_case *t = &test_cases[i]; 222 ifnet_t *ifp = npf_test_getif(t->ifname); 223 struct mbuf *m; 224 int error; 225 bool ret; 226 227 if (ifp == NULL) { 228 printf("Interface %s is not configured.\n", t->ifname); 229 return false; 230 } 231 m = mbuf_get_pkt(t->af, IPPROTO_UDP, 232 t->src, t->dst, t->sport, t->dport); 233 error = npfk_packet_handler(npf, &m, ifp, t->di); 234 ret = checkresult(verbose, i, m, ifp, error); 235 if (m) { 236 m_freem(m); 237 } 238 CHECK_TRUE(ret); 239 } 240 return true; 241 } 242