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