1 /* $NetBSD: npf_nat_test.c,v 1.2 2012/12/24 19:05:47 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, 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 173 static struct mbuf * 174 fill_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 189 bool 190 npf_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