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 18791 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 const int af = t->af; 168 npf_cache_t npc; 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 memset(&npc, 0, sizeof(npf_cache_t)); 180 npc.npc_ctx = npf_getkernctx(); 181 npc.npc_nbuf = &nbuf; 182 183 if (!npf_cache_all(&npc)) { 184 printf("error: could not fetch the packet data"); 185 return false; 186 } 187 188 const struct udphdr *uh = npc.npc_l4.udp; 189 190 if (verbose) { 191 char sbuf[64], dbuf[64]; 192 193 npf_inet_ntop(af, npc.npc_ips[NPF_SRC], sbuf, sizeof(sbuf)); 194 npf_inet_ntop(af, npc.npc_ips[NPF_DST], dbuf, sizeof(dbuf)); 195 196 printf("\tpost-translation: "); 197 printf("src %s (%d) ", sbuf, ntohs(uh->uh_sport)); 198 printf("dst %s (%d)\n", dbuf, ntohs(uh->uh_dport)); 199 } 200 if (error != t->ret) { 201 return false; 202 } 203 204 const bool forw = t->di == PFIL_OUT; 205 const char *saddr = forw ? t->taddr : t->src; 206 const char *daddr = forw ? t->dst : t->taddr; 207 in_addr_t sport = forw ? t->tport : t->sport; 208 in_addr_t dport = forw ? t->dport : t->tport; 209 210 CHECK_TRUE(match_addr(af, saddr, npc.npc_ips[NPF_SRC])); 211 CHECK_TRUE(sport == ntohs(uh->uh_sport)); 212 CHECK_TRUE(match_addr(af, daddr, npc.npc_ips[NPF_DST])); 213 CHECK_TRUE(dport == ntohs(uh->uh_dport)); 214 215 return true; 216 } 217 218 bool 219 npf_nat_test(bool verbose) 220 { 221 npf_t *npf = npf_getkernctx(); 222 223 for (unsigned i = 0; i < __arraycount(test_cases); i++) { 224 const struct test_case *t = &test_cases[i]; 225 ifnet_t *ifp = npf_test_getif(t->ifname); 226 struct mbuf *m; 227 int error; 228 bool ret; 229 230 if (ifp == NULL) { 231 printf("Interface %s is not configured.\n", t->ifname); 232 return false; 233 } 234 m = mbuf_get_pkt(t->af, IPPROTO_UDP, 235 t->src, t->dst, t->sport, t->dport); 236 error = npfk_packet_handler(npf, &m, ifp, t->di); 237 ret = checkresult(verbose, i, m, ifp, error); 238 if (m) { 239 m_freem(m); 240 } 241 CHECK_TRUE(ret); 242 } 243 return true; 244 } 245