1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2015-2019 Yandex LLC
5 * Copyright (c) 2015 Alexander V. Chernikov <[email protected]>
6 * Copyright (c) 2016-2019 Andrey V. Elsukov <[email protected]>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/counter.h>
36 #include <sys/ck.h>
37 #include <sys/epoch.h>
38 #include <sys/errno.h>
39 #include <sys/hash.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/mbuf.h>
44 #include <sys/module.h>
45 #include <sys/rmlock.h>
46 #include <sys/socket.h>
47 #include <sys/syslog.h>
48 #include <sys/sysctl.h>
49
50 #include <net/if.h>
51 #include <net/if_var.h>
52 #include <net/if_pflog.h>
53 #include <net/pfil.h>
54
55 #include <netinet/in.h>
56 #include <netinet/ip.h>
57 #include <netinet/ip_var.h>
58 #include <netinet/ip_fw.h>
59 #include <netinet/ip6.h>
60 #include <netinet/icmp6.h>
61 #include <netinet/ip_icmp.h>
62 #include <netinet/tcp.h>
63 #include <netinet/udp.h>
64 #include <netinet6/in6_var.h>
65 #include <netinet6/ip6_var.h>
66 #include <netinet6/ip_fw_nat64.h>
67
68 #include <netpfil/ipfw/ip_fw_private.h>
69 #include <netpfil/pf/pf.h>
70
71 #include "nat64lsn.h"
72
73 MALLOC_DEFINE(M_NAT64LSN, "NAT64LSN", "NAT64LSN");
74
75 #define NAT64LSN_EPOCH_ENTER(et) NET_EPOCH_ENTER_ET(et)
76 #define NAT64LSN_EPOCH_EXIT(et) NET_EPOCH_EXIT_ET(et)
77 #define NAT64LSN_EPOCH_ASSERT() MPASS(in_epoch(net_epoch_preempt))
78 #define NAT64LSN_EPOCH_CALL(c, f) epoch_call(net_epoch_preempt, (c), (f))
79
80 static uma_zone_t nat64lsn_host_zone;
81 static uma_zone_t nat64lsn_pgchunk_zone;
82 static uma_zone_t nat64lsn_pg_zone;
83 static uma_zone_t nat64lsn_aliaslink_zone;
84 static uma_zone_t nat64lsn_state_zone;
85 static uma_zone_t nat64lsn_job_zone;
86
87 static void nat64lsn_periodic(void *data);
88 #define PERIODIC_DELAY 4
89 #define NAT64_LOOKUP(chain, cmd) \
90 (struct nat64lsn_cfg *)SRV_OBJECT((chain), (cmd)->arg1)
91 /*
92 * Delayed job queue, used to create new hosts
93 * and new portgroups
94 */
95 enum nat64lsn_jtype {
96 JTYPE_NEWHOST = 1,
97 JTYPE_NEWPORTGROUP,
98 JTYPE_DESTROY,
99 };
100
101 struct nat64lsn_job_item {
102 STAILQ_ENTRY(nat64lsn_job_item) entries;
103 enum nat64lsn_jtype jtype;
104
105 union {
106 struct { /* used by JTYPE_NEWHOST, JTYPE_NEWPORTGROUP */
107 struct mbuf *m;
108 struct nat64lsn_host *host;
109 struct nat64lsn_state *state;
110 uint32_t src6_hval;
111 uint32_t state_hval;
112 struct ipfw_flow_id f_id;
113 in_addr_t faddr;
114 uint16_t port;
115 uint8_t proto;
116 uint8_t done;
117 };
118 struct { /* used by JTYPE_DESTROY */
119 struct nat64lsn_hosts_slist hosts;
120 struct nat64lsn_pg_slist portgroups;
121 struct nat64lsn_pgchunk *pgchunk;
122 struct epoch_context epoch_ctx;
123 };
124 };
125 };
126
127 static struct mtx jmtx;
128 #define JQUEUE_LOCK_INIT() mtx_init(&jmtx, "qlock", NULL, MTX_DEF)
129 #define JQUEUE_LOCK_DESTROY() mtx_destroy(&jmtx)
130 #define JQUEUE_LOCK() mtx_lock(&jmtx)
131 #define JQUEUE_UNLOCK() mtx_unlock(&jmtx)
132
133 static int nat64lsn_alloc_host(struct nat64lsn_cfg *cfg,
134 struct nat64lsn_job_item *ji);
135 static int nat64lsn_alloc_pg(struct nat64lsn_cfg *cfg,
136 struct nat64lsn_job_item *ji);
137 static struct nat64lsn_job_item *nat64lsn_create_job(
138 struct nat64lsn_cfg *cfg, int jtype);
139 static void nat64lsn_enqueue_job(struct nat64lsn_cfg *cfg,
140 struct nat64lsn_job_item *ji);
141 static void nat64lsn_job_destroy(epoch_context_t ctx);
142 static void nat64lsn_destroy_host(struct nat64lsn_host *host);
143 static void nat64lsn_destroy_pg(struct nat64lsn_pg *pg);
144
145 static int nat64lsn_translate4(struct nat64lsn_cfg *cfg,
146 const struct ipfw_flow_id *f_id, struct mbuf **mp);
147 static int nat64lsn_translate6(struct nat64lsn_cfg *cfg,
148 struct ipfw_flow_id *f_id, struct mbuf **mp);
149 static int nat64lsn_translate6_internal(struct nat64lsn_cfg *cfg,
150 struct mbuf **mp, struct nat64lsn_state *state, uint8_t flags);
151
152 #define NAT64_BIT_TCP_FIN 0 /* FIN was seen */
153 #define NAT64_BIT_TCP_SYN 1 /* First syn in->out */
154 #define NAT64_BIT_TCP_ESTAB 2 /* Packet with Ack */
155 #define NAT64_BIT_READY_IPV4 6 /* state is ready for translate4 */
156 #define NAT64_BIT_STALE 7 /* state is going to be expired */
157
158 #define NAT64_FLAG_FIN (1 << NAT64_BIT_TCP_FIN)
159 #define NAT64_FLAG_SYN (1 << NAT64_BIT_TCP_SYN)
160 #define NAT64_FLAG_ESTAB (1 << NAT64_BIT_TCP_ESTAB)
161 #define NAT64_FLAGS_TCP (NAT64_FLAG_SYN|NAT64_FLAG_ESTAB|NAT64_FLAG_FIN)
162
163 #define NAT64_FLAG_READY (1 << NAT64_BIT_READY_IPV4)
164 #define NAT64_FLAG_STALE (1 << NAT64_BIT_STALE)
165
166 static inline uint8_t
convert_tcp_flags(uint8_t flags)167 convert_tcp_flags(uint8_t flags)
168 {
169 uint8_t result;
170
171 result = flags & (TH_FIN|TH_SYN);
172 result |= (flags & TH_RST) >> 2; /* Treat RST as FIN */
173 result |= (flags & TH_ACK) >> 2; /* Treat ACK as estab */
174
175 return (result);
176 }
177
178 static void
nat64lsn_log(struct pfloghdr * plog,struct mbuf * m,sa_family_t family,struct nat64lsn_state * state)179 nat64lsn_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family,
180 struct nat64lsn_state *state)
181 {
182
183 memset(plog, 0, sizeof(*plog));
184 plog->length = PFLOG_REAL_HDRLEN;
185 plog->af = family;
186 plog->action = PF_NAT;
187 plog->dir = PF_IN;
188 plog->rulenr = htonl(state->ip_src);
189 plog->subrulenr = htonl((uint32_t)(state->aport << 16) |
190 (state->proto << 8) | (state->ip_dst & 0xff));
191 plog->ruleset[0] = '\0';
192 strlcpy(plog->ifname, "NAT64LSN", sizeof(plog->ifname));
193 ipfw_bpf_mtap2(plog, PFLOG_HDRLEN, m);
194 }
195
196 #define HVAL(p, n, s) jenkins_hash32((const uint32_t *)(p), (n), (s))
197 #define HOST_HVAL(c, a) HVAL((a),\
198 sizeof(struct in6_addr) / sizeof(uint32_t), (c)->hash_seed)
199 #define HOSTS(c, v) ((c)->hosts_hash[(v) & ((c)->hosts_hashsize - 1)])
200
201 #define ALIASLINK_HVAL(c, f) HVAL(&(f)->dst_ip6,\
202 sizeof(struct in6_addr) * 2 / sizeof(uint32_t), (c)->hash_seed)
203 #define ALIAS_BYHASH(c, v) \
204 ((c)->aliases[(v) & ((1 << (32 - (c)->plen4)) - 1)])
205 static struct nat64lsn_aliaslink*
nat64lsn_get_aliaslink(struct nat64lsn_cfg * cfg __unused,struct nat64lsn_host * host,const struct ipfw_flow_id * f_id __unused)206 nat64lsn_get_aliaslink(struct nat64lsn_cfg *cfg __unused,
207 struct nat64lsn_host *host, const struct ipfw_flow_id *f_id __unused)
208 {
209
210 /*
211 * We can implement some different algorithms how
212 * select an alias address.
213 * XXX: for now we use first available.
214 */
215 return (CK_SLIST_FIRST(&host->aliases));
216 }
217
218 #define STATE_HVAL(c, d) HVAL((d), 2, (c)->hash_seed)
219 #define STATE_HASH(h, v) \
220 ((h)->states_hash[(v) & ((h)->states_hashsize - 1)])
221 #define STATES_CHUNK(p, v) \
222 ((p)->chunks_count == 1 ? (p)->states : \
223 ((p)->states_chunk[CHUNK_BY_FADDR(p, v)]))
224
225 #ifdef __LP64__
226 #define FREEMASK_FFSLL(pg, faddr) \
227 ffsll(*FREEMASK_CHUNK((pg), (faddr)))
228 #define FREEMASK_BTR(pg, faddr, bit) \
229 ck_pr_btr_64(FREEMASK_CHUNK((pg), (faddr)), (bit))
230 #define FREEMASK_BTS(pg, faddr, bit) \
231 ck_pr_bts_64(FREEMASK_CHUNK((pg), (faddr)), (bit))
232 #define FREEMASK_ISSET(pg, faddr, bit) \
233 ISSET64(*FREEMASK_CHUNK((pg), (faddr)), (bit))
234 #define FREEMASK_COPY(pg, n, out) \
235 (out) = ck_pr_load_64(FREEMASK_CHUNK((pg), (n)))
236 #else
237 static inline int
freemask_ffsll(uint32_t * freemask)238 freemask_ffsll(uint32_t *freemask)
239 {
240 int i;
241
242 if ((i = ffsl(freemask[0])) != 0)
243 return (i);
244 if ((i = ffsl(freemask[1])) != 0)
245 return (i + 32);
246 return (0);
247 }
248 #define FREEMASK_FFSLL(pg, faddr) \
249 freemask_ffsll(FREEMASK_CHUNK((pg), (faddr)))
250 #define FREEMASK_BTR(pg, faddr, bit) \
251 ck_pr_btr_32(FREEMASK_CHUNK((pg), (faddr)) + (bit) / 32, (bit) % 32)
252 #define FREEMASK_BTS(pg, faddr, bit) \
253 ck_pr_bts_32(FREEMASK_CHUNK((pg), (faddr)) + (bit) / 32, (bit) % 32)
254 #define FREEMASK_ISSET(pg, faddr, bit) \
255 ISSET32(*(FREEMASK_CHUNK((pg), (faddr)) + (bit) / 32), (bit) % 32)
256 #define FREEMASK_COPY(pg, n, out) \
257 (out) = ck_pr_load_32(FREEMASK_CHUNK((pg), (n))) | \
258 ((uint64_t)ck_pr_load_32(FREEMASK_CHUNK((pg), (n)) + 1) << 32)
259 #endif /* !__LP64__ */
260
261
262 #define NAT64LSN_TRY_PGCNT 32
263 static struct nat64lsn_pg*
nat64lsn_get_pg(uint32_t * chunkmask,uint32_t * pgmask,struct nat64lsn_pgchunk ** chunks,struct nat64lsn_pg ** pgptr,uint32_t * pgidx,in_addr_t faddr)264 nat64lsn_get_pg(uint32_t *chunkmask, uint32_t *pgmask,
265 struct nat64lsn_pgchunk **chunks, struct nat64lsn_pg **pgptr,
266 uint32_t *pgidx, in_addr_t faddr)
267 {
268 struct nat64lsn_pg *pg, *oldpg;
269 uint32_t idx, oldidx;
270 int cnt;
271
272 cnt = 0;
273 /* First try last used PG */
274 oldpg = pg = ck_pr_load_ptr(pgptr);
275 idx = oldidx = ck_pr_load_32(pgidx);
276 /* If pgidx is out of range, reset it to the first pgchunk */
277 if (!ISSET32(*chunkmask, idx / 32))
278 idx = 0;
279 do {
280 ck_pr_fence_load();
281 if (pg != NULL && FREEMASK_BITCOUNT(pg, faddr) > 0) {
282 /*
283 * If last used PG has not free states,
284 * try to update pointer.
285 * NOTE: it can be already updated by jobs handler,
286 * thus we use CAS operation.
287 */
288 if (cnt > 0)
289 ck_pr_cas_ptr(pgptr, oldpg, pg);
290 return (pg);
291 }
292 /* Stop if idx is out of range */
293 if (!ISSET32(*chunkmask, idx / 32))
294 break;
295
296 if (ISSET32(pgmask[idx / 32], idx % 32))
297 pg = ck_pr_load_ptr(
298 &chunks[idx / 32]->pgptr[idx % 32]);
299 else
300 pg = NULL;
301
302 idx++;
303 } while (++cnt < NAT64LSN_TRY_PGCNT);
304
305 /* If pgidx is out of range, reset it to the first pgchunk */
306 if (!ISSET32(*chunkmask, idx / 32))
307 idx = 0;
308 ck_pr_cas_32(pgidx, oldidx, idx);
309 return (NULL);
310 }
311
312 static struct nat64lsn_state*
nat64lsn_get_state6to4(struct nat64lsn_cfg * cfg,struct nat64lsn_host * host,const struct ipfw_flow_id * f_id,uint32_t hval,in_addr_t faddr,uint16_t port,uint8_t proto)313 nat64lsn_get_state6to4(struct nat64lsn_cfg *cfg, struct nat64lsn_host *host,
314 const struct ipfw_flow_id *f_id, uint32_t hval, in_addr_t faddr,
315 uint16_t port, uint8_t proto)
316 {
317 struct nat64lsn_aliaslink *link;
318 struct nat64lsn_state *state;
319 struct nat64lsn_pg *pg;
320 int i, offset;
321
322 NAT64LSN_EPOCH_ASSERT();
323
324 /* Check that we already have state for given arguments */
325 CK_SLIST_FOREACH(state, &STATE_HASH(host, hval), entries) {
326 if (state->proto == proto && state->ip_dst == faddr &&
327 state->sport == port && state->dport == f_id->dst_port)
328 return (state);
329 }
330
331 link = nat64lsn_get_aliaslink(cfg, host, f_id);
332 if (link == NULL)
333 return (NULL);
334
335 switch (proto) {
336 case IPPROTO_TCP:
337 pg = nat64lsn_get_pg(
338 &link->alias->tcp_chunkmask, link->alias->tcp_pgmask,
339 link->alias->tcp, &link->alias->tcp_pg,
340 &link->alias->tcp_pgidx, faddr);
341 break;
342 case IPPROTO_UDP:
343 pg = nat64lsn_get_pg(
344 &link->alias->udp_chunkmask, link->alias->udp_pgmask,
345 link->alias->udp, &link->alias->udp_pg,
346 &link->alias->udp_pgidx, faddr);
347 break;
348 case IPPROTO_ICMP:
349 pg = nat64lsn_get_pg(
350 &link->alias->icmp_chunkmask, link->alias->icmp_pgmask,
351 link->alias->icmp, &link->alias->icmp_pg,
352 &link->alias->icmp_pgidx, faddr);
353 break;
354 default:
355 panic("%s: wrong proto %d", __func__, proto);
356 }
357 if (pg == NULL)
358 return (NULL);
359
360 /* Check that PG has some free states */
361 state = NULL;
362 i = FREEMASK_BITCOUNT(pg, faddr);
363 while (i-- > 0) {
364 offset = FREEMASK_FFSLL(pg, faddr);
365 if (offset == 0) {
366 /*
367 * We lost the race.
368 * No more free states in this PG.
369 */
370 break;
371 }
372
373 /* Lets try to atomically grab the state */
374 if (FREEMASK_BTR(pg, faddr, offset - 1)) {
375 state = &STATES_CHUNK(pg, faddr)->state[offset - 1];
376 /* Initialize */
377 state->flags = proto != IPPROTO_TCP ? 0 :
378 convert_tcp_flags(f_id->_flags);
379 state->proto = proto;
380 state->aport = pg->base_port + offset - 1;
381 state->dport = f_id->dst_port;
382 state->sport = port;
383 state->ip6_dst = f_id->dst_ip6;
384 state->ip_dst = faddr;
385 state->ip_src = link->alias->addr;
386 state->hval = hval;
387 state->host = host;
388 SET_AGE(state->timestamp);
389
390 /* Insert new state into host's hash table */
391 HOST_LOCK(host);
392 CK_SLIST_INSERT_HEAD(&STATE_HASH(host, hval),
393 state, entries);
394 host->states_count++;
395 /*
396 * XXX: In case if host is going to be expired,
397 * reset NAT64LSN_DEADHOST flag.
398 */
399 host->flags &= ~NAT64LSN_DEADHOST;
400 HOST_UNLOCK(host);
401 NAT64STAT_INC(&cfg->base.stats, screated);
402 /* Mark the state as ready for translate4 */
403 ck_pr_fence_store();
404 ck_pr_bts_32(&state->flags, NAT64_BIT_READY_IPV4);
405 break;
406 }
407 }
408 return (state);
409 }
410
411 /*
412 * Inspects icmp packets to see if the message contains different
413 * packet header so we need to alter @addr and @port.
414 */
415 static int
inspect_icmp_mbuf(struct mbuf ** mp,uint8_t * proto,uint32_t * addr,uint16_t * port)416 inspect_icmp_mbuf(struct mbuf **mp, uint8_t *proto, uint32_t *addr,
417 uint16_t *port)
418 {
419 struct icmp *icmp;
420 struct ip *ip;
421 int off;
422 uint8_t inner_proto;
423
424 ip = mtod(*mp, struct ip *); /* Outer IP header */
425 off = (ip->ip_hl << 2) + ICMP_MINLEN;
426 if ((*mp)->m_len < off)
427 *mp = m_pullup(*mp, off);
428 if (*mp == NULL)
429 return (ENOMEM);
430
431 ip = mtod(*mp, struct ip *); /* Outer IP header */
432 icmp = L3HDR(ip, struct icmp *);
433 switch (icmp->icmp_type) {
434 case ICMP_ECHO:
435 case ICMP_ECHOREPLY:
436 /* Use icmp ID as distinguisher */
437 *port = ntohs(icmp->icmp_id);
438 return (0);
439 case ICMP_UNREACH:
440 case ICMP_TIMXCEED:
441 break;
442 default:
443 return (EOPNOTSUPP);
444 }
445 /*
446 * ICMP_UNREACH and ICMP_TIMXCEED contains IP header + 64 bits
447 * of ULP header.
448 */
449 if ((*mp)->m_pkthdr.len < off + sizeof(struct ip) + ICMP_MINLEN)
450 return (EINVAL);
451 if ((*mp)->m_len < off + sizeof(struct ip) + ICMP_MINLEN)
452 *mp = m_pullup(*mp, off + sizeof(struct ip) + ICMP_MINLEN);
453 if (*mp == NULL)
454 return (ENOMEM);
455 ip = mtodo(*mp, off); /* Inner IP header */
456 inner_proto = ip->ip_p;
457 off += ip->ip_hl << 2; /* Skip inner IP header */
458 *addr = ntohl(ip->ip_src.s_addr);
459 if ((*mp)->m_len < off + ICMP_MINLEN)
460 *mp = m_pullup(*mp, off + ICMP_MINLEN);
461 if (*mp == NULL)
462 return (ENOMEM);
463 switch (inner_proto) {
464 case IPPROTO_TCP:
465 case IPPROTO_UDP:
466 /* Copy source port from the header */
467 *port = ntohs(*((uint16_t *)mtodo(*mp, off)));
468 *proto = inner_proto;
469 return (0);
470 case IPPROTO_ICMP:
471 /*
472 * We will translate only ICMP errors for our ICMP
473 * echo requests.
474 */
475 icmp = mtodo(*mp, off);
476 if (icmp->icmp_type != ICMP_ECHO)
477 return (EOPNOTSUPP);
478 *port = ntohs(icmp->icmp_id);
479 return (0);
480 };
481 return (EOPNOTSUPP);
482 }
483
484 static struct nat64lsn_state*
nat64lsn_get_state4to6(struct nat64lsn_cfg * cfg,struct nat64lsn_alias * alias,in_addr_t faddr,uint16_t port,uint8_t proto)485 nat64lsn_get_state4to6(struct nat64lsn_cfg *cfg, struct nat64lsn_alias *alias,
486 in_addr_t faddr, uint16_t port, uint8_t proto)
487 {
488 struct nat64lsn_state *state;
489 struct nat64lsn_pg *pg;
490 int chunk_idx, pg_idx, state_idx;
491
492 NAT64LSN_EPOCH_ASSERT();
493
494 if (port < NAT64_MIN_PORT)
495 return (NULL);
496 /*
497 * Alias keeps 32 pgchunks for each protocol.
498 * Each pgchunk has 32 pointers to portgroup.
499 * Each portgroup has 64 states for ports.
500 */
501 port -= NAT64_MIN_PORT;
502 chunk_idx = port / 2048;
503
504 port -= chunk_idx * 2048;
505 pg_idx = port / 64;
506 state_idx = port % 64;
507
508 /*
509 * First check in proto_chunkmask that we have allocated PG chunk.
510 * Then check in proto_pgmask that we have valid PG pointer.
511 */
512 pg = NULL;
513 switch (proto) {
514 case IPPROTO_TCP:
515 if (ISSET32(alias->tcp_chunkmask, chunk_idx) &&
516 ISSET32(alias->tcp_pgmask[chunk_idx], pg_idx)) {
517 pg = alias->tcp[chunk_idx]->pgptr[pg_idx];
518 break;
519 }
520 return (NULL);
521 case IPPROTO_UDP:
522 if (ISSET32(alias->udp_chunkmask, chunk_idx) &&
523 ISSET32(alias->udp_pgmask[chunk_idx], pg_idx)) {
524 pg = alias->udp[chunk_idx]->pgptr[pg_idx];
525 break;
526 }
527 return (NULL);
528 case IPPROTO_ICMP:
529 if (ISSET32(alias->icmp_chunkmask, chunk_idx) &&
530 ISSET32(alias->icmp_pgmask[chunk_idx], pg_idx)) {
531 pg = alias->icmp[chunk_idx]->pgptr[pg_idx];
532 break;
533 }
534 return (NULL);
535 default:
536 panic("%s: wrong proto %d", __func__, proto);
537 }
538 if (pg == NULL)
539 return (NULL);
540
541 if (FREEMASK_ISSET(pg, faddr, state_idx))
542 return (NULL);
543
544 state = &STATES_CHUNK(pg, faddr)->state[state_idx];
545 ck_pr_fence_load();
546 if (ck_pr_load_32(&state->flags) & NAT64_FLAG_READY)
547 return (state);
548 return (NULL);
549 }
550
551 static int
nat64lsn_translate4(struct nat64lsn_cfg * cfg,const struct ipfw_flow_id * f_id,struct mbuf ** mp)552 nat64lsn_translate4(struct nat64lsn_cfg *cfg,
553 const struct ipfw_flow_id *f_id, struct mbuf **mp)
554 {
555 struct pfloghdr loghdr, *logdata;
556 struct in6_addr src6;
557 struct nat64lsn_state *state;
558 struct nat64lsn_alias *alias;
559 uint32_t addr, flags;
560 uint16_t port, ts;
561 int ret;
562 uint8_t proto;
563
564 addr = f_id->dst_ip;
565 port = f_id->dst_port;
566 proto = f_id->proto;
567 if (addr < cfg->prefix4 || addr > cfg->pmask4) {
568 NAT64STAT_INC(&cfg->base.stats, nomatch4);
569 return (cfg->nomatch_verdict);
570 }
571
572 /* Check if protocol is supported */
573 switch (proto) {
574 case IPPROTO_ICMP:
575 ret = inspect_icmp_mbuf(mp, &proto, &addr, &port);
576 if (ret != 0) {
577 if (ret == ENOMEM) {
578 NAT64STAT_INC(&cfg->base.stats, nomem);
579 return (IP_FW_DENY);
580 }
581 NAT64STAT_INC(&cfg->base.stats, noproto);
582 return (cfg->nomatch_verdict);
583 }
584 if (addr < cfg->prefix4 || addr > cfg->pmask4) {
585 NAT64STAT_INC(&cfg->base.stats, nomatch4);
586 return (cfg->nomatch_verdict);
587 }
588 /* FALLTHROUGH */
589 case IPPROTO_TCP:
590 case IPPROTO_UDP:
591 break;
592 default:
593 NAT64STAT_INC(&cfg->base.stats, noproto);
594 return (cfg->nomatch_verdict);
595 }
596
597 alias = &ALIAS_BYHASH(cfg, addr);
598 MPASS(addr == alias->addr);
599
600 /* Check that we have state for this port */
601 state = nat64lsn_get_state4to6(cfg, alias, f_id->src_ip,
602 port, proto);
603 if (state == NULL) {
604 NAT64STAT_INC(&cfg->base.stats, nomatch4);
605 return (cfg->nomatch_verdict);
606 }
607
608 /* TODO: Check flags to see if we need to do some static mapping */
609
610 /* Update some state fields if need */
611 SET_AGE(ts);
612 if (f_id->proto == IPPROTO_TCP)
613 flags = convert_tcp_flags(f_id->_flags);
614 else
615 flags = 0;
616 if (state->timestamp != ts)
617 state->timestamp = ts;
618 if ((state->flags & flags) != flags)
619 state->flags |= flags;
620
621 port = htons(state->sport);
622 src6 = state->ip6_dst;
623
624 if (cfg->base.flags & NAT64_LOG) {
625 logdata = &loghdr;
626 nat64lsn_log(logdata, *mp, AF_INET, state);
627 } else
628 logdata = NULL;
629
630 /*
631 * We already have src6 with embedded address, but it is possible,
632 * that src_ip is different than state->ip_dst, this is why we
633 * do embedding again.
634 */
635 nat64_embed_ip4(&src6, cfg->base.plat_plen, htonl(f_id->src_ip));
636 ret = nat64_do_handle_ip4(*mp, &src6, &state->host->addr, port,
637 &cfg->base, logdata);
638 if (ret == NAT64SKIP)
639 return (cfg->nomatch_verdict);
640 if (ret == NAT64RETURN)
641 *mp = NULL;
642 return (IP_FW_DENY);
643 }
644
645 /*
646 * Check if particular state is stale and should be deleted.
647 * Return 1 if true, 0 otherwise.
648 */
649 static int
nat64lsn_check_state(struct nat64lsn_cfg * cfg,struct nat64lsn_state * state)650 nat64lsn_check_state(struct nat64lsn_cfg *cfg, struct nat64lsn_state *state)
651 {
652 int age, ttl;
653
654 /* State was marked as stale in previous pass. */
655 if (ISSET32(state->flags, NAT64_BIT_STALE))
656 return (1);
657
658 /* State is not yet initialized, it is going to be READY */
659 if (!ISSET32(state->flags, NAT64_BIT_READY_IPV4))
660 return (0);
661
662 age = GET_AGE(state->timestamp);
663 switch (state->proto) {
664 case IPPROTO_TCP:
665 if (ISSET32(state->flags, NAT64_BIT_TCP_FIN))
666 ttl = cfg->st_close_ttl;
667 else if (ISSET32(state->flags, NAT64_BIT_TCP_ESTAB))
668 ttl = cfg->st_estab_ttl;
669 else if (ISSET32(state->flags, NAT64_BIT_TCP_SYN))
670 ttl = cfg->st_syn_ttl;
671 else
672 ttl = cfg->st_syn_ttl;
673 if (age > ttl)
674 return (1);
675 break;
676 case IPPROTO_UDP:
677 if (age > cfg->st_udp_ttl)
678 return (1);
679 break;
680 case IPPROTO_ICMP:
681 if (age > cfg->st_icmp_ttl)
682 return (1);
683 break;
684 }
685 return (0);
686 }
687
688 static int
nat64lsn_maintain_pg(struct nat64lsn_cfg * cfg,struct nat64lsn_pg * pg)689 nat64lsn_maintain_pg(struct nat64lsn_cfg *cfg, struct nat64lsn_pg *pg)
690 {
691 struct nat64lsn_state *state;
692 struct nat64lsn_host *host;
693 uint64_t freemask;
694 int c, i, update_age;
695
696 update_age = 0;
697 for (c = 0; c < pg->chunks_count; c++) {
698 FREEMASK_COPY(pg, c, freemask);
699 for (i = 0; i < 64; i++) {
700 if (ISSET64(freemask, i))
701 continue;
702 state = &STATES_CHUNK(pg, c)->state[i];
703 if (nat64lsn_check_state(cfg, state) == 0) {
704 update_age = 1;
705 continue;
706 }
707 /*
708 * Expire state:
709 * 1. Mark as STALE and unlink from host's hash.
710 * 2. Set bit in freemask.
711 */
712 if (ISSET32(state->flags, NAT64_BIT_STALE)) {
713 /*
714 * State was marked as STALE in previous
715 * pass. Now it is safe to release it.
716 */
717 state->flags = 0;
718 ck_pr_fence_store();
719 FREEMASK_BTS(pg, c, i);
720 NAT64STAT_INC(&cfg->base.stats, sdeleted);
721 continue;
722 }
723 MPASS(state->flags & NAT64_FLAG_READY);
724
725 host = state->host;
726 HOST_LOCK(host);
727 CK_SLIST_REMOVE(&STATE_HASH(host, state->hval),
728 state, nat64lsn_state, entries);
729 host->states_count--;
730 HOST_UNLOCK(host);
731
732 /* Reset READY flag */
733 ck_pr_btr_32(&state->flags, NAT64_BIT_READY_IPV4);
734 /* And set STALE flag */
735 ck_pr_bts_32(&state->flags, NAT64_BIT_STALE);
736 ck_pr_fence_store();
737 /*
738 * Now translate6 will not use this state, wait
739 * until it become safe for translate4, then mark
740 * state as free.
741 */
742 }
743 }
744
745 /*
746 * We have some alive states, update timestamp.
747 */
748 if (update_age)
749 SET_AGE(pg->timestamp);
750
751 if (GET_AGE(pg->timestamp) < cfg->pg_delete_delay)
752 return (0);
753
754 return (1);
755 }
756
757 static void
nat64lsn_expire_portgroups(struct nat64lsn_cfg * cfg,struct nat64lsn_pg_slist * portgroups)758 nat64lsn_expire_portgroups(struct nat64lsn_cfg *cfg,
759 struct nat64lsn_pg_slist *portgroups)
760 {
761 struct nat64lsn_alias *alias;
762 struct nat64lsn_pg *pg, *tpg, *firstpg, **pgptr;
763 uint32_t *pgmask, *pgidx;
764 int i, idx;
765
766 for (i = 0; i < 1 << (32 - cfg->plen4); i++) {
767 alias = &cfg->aliases[i];
768 CK_SLIST_FOREACH_SAFE(pg, &alias->portgroups, entries, tpg) {
769 if (nat64lsn_maintain_pg(cfg, pg) == 0)
770 continue;
771 /* Always keep first PG */
772 if (pg->base_port == NAT64_MIN_PORT)
773 continue;
774 /*
775 * PG is expired, unlink it and schedule for
776 * deferred destroying.
777 */
778 idx = (pg->base_port - NAT64_MIN_PORT) / 64;
779 switch (pg->proto) {
780 case IPPROTO_TCP:
781 pgmask = alias->tcp_pgmask;
782 pgptr = &alias->tcp_pg;
783 pgidx = &alias->tcp_pgidx;
784 firstpg = alias->tcp[0]->pgptr[0];
785 break;
786 case IPPROTO_UDP:
787 pgmask = alias->udp_pgmask;
788 pgptr = &alias->udp_pg;
789 pgidx = &alias->udp_pgidx;
790 firstpg = alias->udp[0]->pgptr[0];
791 break;
792 case IPPROTO_ICMP:
793 pgmask = alias->icmp_pgmask;
794 pgptr = &alias->icmp_pg;
795 pgidx = &alias->icmp_pgidx;
796 firstpg = alias->icmp[0]->pgptr[0];
797 break;
798 }
799 /* Reset the corresponding bit in pgmask array. */
800 ck_pr_btr_32(&pgmask[idx / 32], idx % 32);
801 ck_pr_fence_store();
802 /* If last used PG points to this PG, reset it. */
803 ck_pr_cas_ptr(pgptr, pg, firstpg);
804 ck_pr_cas_32(pgidx, idx, 0);
805 /* Unlink PG from alias's chain */
806 ALIAS_LOCK(alias);
807 CK_SLIST_REMOVE(&alias->portgroups, pg,
808 nat64lsn_pg, entries);
809 alias->portgroups_count--;
810 ALIAS_UNLOCK(alias);
811 /* And link to job's chain for deferred destroying */
812 NAT64STAT_INC(&cfg->base.stats, spgdeleted);
813 CK_SLIST_INSERT_HEAD(portgroups, pg, entries);
814 }
815 }
816 }
817
818 static void
nat64lsn_expire_hosts(struct nat64lsn_cfg * cfg,struct nat64lsn_hosts_slist * hosts)819 nat64lsn_expire_hosts(struct nat64lsn_cfg *cfg,
820 struct nat64lsn_hosts_slist *hosts)
821 {
822 struct nat64lsn_host *host, *tmp;
823 int i;
824
825 for (i = 0; i < cfg->hosts_hashsize; i++) {
826 CK_SLIST_FOREACH_SAFE(host, &cfg->hosts_hash[i],
827 entries, tmp) {
828 /* Is host was marked in previous call? */
829 if (host->flags & NAT64LSN_DEADHOST) {
830 if (host->states_count > 0) {
831 host->flags &= ~NAT64LSN_DEADHOST;
832 continue;
833 }
834 /*
835 * Unlink host from hash table and schedule
836 * it for deferred destroying.
837 */
838 CFG_LOCK(cfg);
839 CK_SLIST_REMOVE(&cfg->hosts_hash[i], host,
840 nat64lsn_host, entries);
841 cfg->hosts_count--;
842 CFG_UNLOCK(cfg);
843 CK_SLIST_INSERT_HEAD(hosts, host, entries);
844 continue;
845 }
846 if (GET_AGE(host->timestamp) < cfg->host_delete_delay)
847 continue;
848 if (host->states_count > 0)
849 continue;
850 /* Mark host as going to be expired in next pass */
851 host->flags |= NAT64LSN_DEADHOST;
852 ck_pr_fence_store();
853 }
854 }
855 }
856
857 static struct nat64lsn_pgchunk*
nat64lsn_expire_pgchunk(struct nat64lsn_cfg * cfg)858 nat64lsn_expire_pgchunk(struct nat64lsn_cfg *cfg)
859 {
860 #if 0
861 struct nat64lsn_alias *alias;
862 struct nat64lsn_pgchunk *chunk;
863 uint32_t pgmask;
864 int i, c;
865
866 for (i = 0; i < 1 << (32 - cfg->plen4); i++) {
867 alias = &cfg->aliases[i];
868 if (GET_AGE(alias->timestamp) < cfg->pgchunk_delete_delay)
869 continue;
870 /* Always keep single chunk allocated */
871 for (c = 1; c < 32; c++) {
872 if ((alias->tcp_chunkmask & (1 << c)) == 0)
873 break;
874 chunk = ck_pr_load_ptr(&alias->tcp[c]);
875 if (ck_pr_load_32(&alias->tcp_pgmask[c]) != 0)
876 continue;
877 ck_pr_btr_32(&alias->tcp_chunkmask, c);
878 ck_pr_fence_load();
879 if (ck_pr_load_32(&alias->tcp_pgmask[c]) != 0)
880 continue;
881 }
882 }
883 #endif
884 return (NULL);
885 }
886
887 #if 0
888 static void
889 nat64lsn_maintain_hosts(struct nat64lsn_cfg *cfg)
890 {
891 struct nat64lsn_host *h;
892 struct nat64lsn_states_slist *hash;
893 int i, j, hsize;
894
895 for (i = 0; i < cfg->hosts_hashsize; i++) {
896 CK_SLIST_FOREACH(h, &cfg->hosts_hash[i], entries) {
897 if (h->states_count / 2 < h->states_hashsize ||
898 h->states_hashsize >= NAT64LSN_MAX_HSIZE)
899 continue;
900 hsize = h->states_hashsize * 2;
901 hash = malloc(sizeof(*hash)* hsize, M_NOWAIT);
902 if (hash == NULL)
903 continue;
904 for (j = 0; j < hsize; j++)
905 CK_SLIST_INIT(&hash[i]);
906
907 ck_pr_bts_32(&h->flags, NAT64LSN_GROWHASH);
908 }
909 }
910 }
911 #endif
912
913 /*
914 * This procedure is used to perform various maintance
915 * on dynamic hash list. Currently it is called every 4 seconds.
916 */
917 static void
nat64lsn_periodic(void * data)918 nat64lsn_periodic(void *data)
919 {
920 struct nat64lsn_job_item *ji;
921 struct nat64lsn_cfg *cfg;
922
923 cfg = (struct nat64lsn_cfg *) data;
924 CURVNET_SET(cfg->vp);
925 if (cfg->hosts_count > 0) {
926 ji = uma_zalloc(nat64lsn_job_zone, M_NOWAIT);
927 if (ji != NULL) {
928 ji->jtype = JTYPE_DESTROY;
929 CK_SLIST_INIT(&ji->hosts);
930 CK_SLIST_INIT(&ji->portgroups);
931 nat64lsn_expire_hosts(cfg, &ji->hosts);
932 nat64lsn_expire_portgroups(cfg, &ji->portgroups);
933 ji->pgchunk = nat64lsn_expire_pgchunk(cfg);
934 NAT64LSN_EPOCH_CALL(&ji->epoch_ctx,
935 nat64lsn_job_destroy);
936 } else
937 NAT64STAT_INC(&cfg->base.stats, jnomem);
938 }
939 callout_schedule(&cfg->periodic, hz * PERIODIC_DELAY);
940 CURVNET_RESTORE();
941 }
942
943 #define ALLOC_ERROR(stage, type) ((stage) ? 10 * (type) + (stage): 0)
944 #define HOST_ERROR(stage) ALLOC_ERROR(stage, 1)
945 #define PG_ERROR(stage) ALLOC_ERROR(stage, 2)
946 static int
nat64lsn_alloc_host(struct nat64lsn_cfg * cfg,struct nat64lsn_job_item * ji)947 nat64lsn_alloc_host(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
948 {
949 char a[INET6_ADDRSTRLEN];
950 struct nat64lsn_aliaslink *link;
951 struct nat64lsn_host *host;
952 struct nat64lsn_state *state;
953 uint32_t hval, data[2];
954 int i;
955
956 /* Check that host was not yet added. */
957 NAT64LSN_EPOCH_ASSERT();
958 CK_SLIST_FOREACH(host, &HOSTS(cfg, ji->src6_hval), entries) {
959 if (IN6_ARE_ADDR_EQUAL(&ji->f_id.src_ip6, &host->addr)) {
960 /* The host was allocated in previous call. */
961 ji->host = host;
962 goto get_state;
963 }
964 }
965
966 host = ji->host = uma_zalloc(nat64lsn_host_zone, M_NOWAIT);
967 if (ji->host == NULL)
968 return (HOST_ERROR(1));
969
970 host->states_hashsize = NAT64LSN_HSIZE;
971 host->states_hash = malloc(sizeof(struct nat64lsn_states_slist) *
972 host->states_hashsize, M_NAT64LSN, M_NOWAIT);
973 if (host->states_hash == NULL) {
974 uma_zfree(nat64lsn_host_zone, host);
975 return (HOST_ERROR(2));
976 }
977
978 link = uma_zalloc(nat64lsn_aliaslink_zone, M_NOWAIT);
979 if (link == NULL) {
980 free(host->states_hash, M_NAT64LSN);
981 uma_zfree(nat64lsn_host_zone, host);
982 return (HOST_ERROR(3));
983 }
984
985 /* Initialize */
986 HOST_LOCK_INIT(host);
987 SET_AGE(host->timestamp);
988 host->addr = ji->f_id.src_ip6;
989 host->hval = ji->src6_hval;
990 host->flags = 0;
991 host->states_count = 0;
992 host->states_hashsize = NAT64LSN_HSIZE;
993 CK_SLIST_INIT(&host->aliases);
994 for (i = 0; i < host->states_hashsize; i++)
995 CK_SLIST_INIT(&host->states_hash[i]);
996
997 /* Determine alias from flow hash. */
998 hval = ALIASLINK_HVAL(cfg, &ji->f_id);
999 link->alias = &ALIAS_BYHASH(cfg, hval);
1000 CK_SLIST_INSERT_HEAD(&host->aliases, link, host_entries);
1001
1002 ALIAS_LOCK(link->alias);
1003 CK_SLIST_INSERT_HEAD(&link->alias->hosts, link, alias_entries);
1004 link->alias->hosts_count++;
1005 ALIAS_UNLOCK(link->alias);
1006
1007 CFG_LOCK(cfg);
1008 CK_SLIST_INSERT_HEAD(&HOSTS(cfg, ji->src6_hval), host, entries);
1009 cfg->hosts_count++;
1010 CFG_UNLOCK(cfg);
1011
1012 get_state:
1013 data[0] = ji->faddr;
1014 data[1] = (ji->f_id.dst_port << 16) | ji->port;
1015 ji->state_hval = hval = STATE_HVAL(cfg, data);
1016 state = nat64lsn_get_state6to4(cfg, host, &ji->f_id, hval,
1017 ji->faddr, ji->port, ji->proto);
1018 /*
1019 * We failed to obtain new state, used alias needs new PG.
1020 * XXX: or another alias should be used.
1021 */
1022 if (state == NULL) {
1023 /* Try to allocate new PG */
1024 if (nat64lsn_alloc_pg(cfg, ji) != PG_ERROR(0))
1025 return (HOST_ERROR(4));
1026 /* We assume that nat64lsn_alloc_pg() got state */
1027 } else
1028 ji->state = state;
1029
1030 ji->done = 1;
1031 DPRINTF(DP_OBJ, "ALLOC HOST %s %p",
1032 inet_ntop(AF_INET6, &host->addr, a, sizeof(a)), host);
1033 return (HOST_ERROR(0));
1034 }
1035
1036 static int
nat64lsn_find_pg_place(uint32_t * data)1037 nat64lsn_find_pg_place(uint32_t *data)
1038 {
1039 int i;
1040
1041 for (i = 0; i < 32; i++) {
1042 if (~data[i] == 0)
1043 continue;
1044 return (i * 32 + ffs(~data[i]) - 1);
1045 }
1046 return (-1);
1047 }
1048
1049 static int
nat64lsn_alloc_proto_pg(struct nat64lsn_cfg * cfg,struct nat64lsn_alias * alias,uint32_t * chunkmask,uint32_t * pgmask,struct nat64lsn_pgchunk ** chunks,struct nat64lsn_pg ** pgptr,uint8_t proto)1050 nat64lsn_alloc_proto_pg(struct nat64lsn_cfg *cfg,
1051 struct nat64lsn_alias *alias, uint32_t *chunkmask,
1052 uint32_t *pgmask, struct nat64lsn_pgchunk **chunks,
1053 struct nat64lsn_pg **pgptr, uint8_t proto)
1054 {
1055 struct nat64lsn_pg *pg;
1056 int i, pg_idx, chunk_idx;
1057
1058 /* Find place in pgchunk where PG can be added */
1059 pg_idx = nat64lsn_find_pg_place(pgmask);
1060 if (pg_idx < 0) /* no more PGs */
1061 return (PG_ERROR(1));
1062 /* Check that we have allocated pgchunk for given PG index */
1063 chunk_idx = pg_idx / 32;
1064 if (!ISSET32(*chunkmask, chunk_idx)) {
1065 chunks[chunk_idx] = uma_zalloc(nat64lsn_pgchunk_zone,
1066 M_NOWAIT);
1067 if (chunks[chunk_idx] == NULL)
1068 return (PG_ERROR(2));
1069 ck_pr_bts_32(chunkmask, chunk_idx);
1070 ck_pr_fence_store();
1071 }
1072 /* Allocate PG and states chunks */
1073 pg = uma_zalloc(nat64lsn_pg_zone, M_NOWAIT);
1074 if (pg == NULL)
1075 return (PG_ERROR(3));
1076 pg->chunks_count = cfg->states_chunks;
1077 if (pg->chunks_count > 1) {
1078 pg->freemask_chunk = malloc(pg->chunks_count *
1079 sizeof(uint64_t), M_NAT64LSN, M_NOWAIT);
1080 if (pg->freemask_chunk == NULL) {
1081 uma_zfree(nat64lsn_pg_zone, pg);
1082 return (PG_ERROR(4));
1083 }
1084 pg->states_chunk = malloc(pg->chunks_count *
1085 sizeof(struct nat64lsn_states_chunk *), M_NAT64LSN,
1086 M_NOWAIT | M_ZERO);
1087 if (pg->states_chunk == NULL) {
1088 free(pg->freemask_chunk, M_NAT64LSN);
1089 uma_zfree(nat64lsn_pg_zone, pg);
1090 return (PG_ERROR(5));
1091 }
1092 for (i = 0; i < pg->chunks_count; i++) {
1093 pg->states_chunk[i] = uma_zalloc(
1094 nat64lsn_state_zone, M_NOWAIT);
1095 if (pg->states_chunk[i] == NULL)
1096 goto states_failed;
1097 }
1098 memset(pg->freemask_chunk, 0xff,
1099 sizeof(uint64_t) * pg->chunks_count);
1100 } else {
1101 pg->states = uma_zalloc(nat64lsn_state_zone, M_NOWAIT);
1102 if (pg->states == NULL) {
1103 uma_zfree(nat64lsn_pg_zone, pg);
1104 return (PG_ERROR(6));
1105 }
1106 memset(&pg->freemask64, 0xff, sizeof(uint64_t));
1107 }
1108
1109 /* Initialize PG and hook it to pgchunk */
1110 SET_AGE(pg->timestamp);
1111 pg->proto = proto;
1112 pg->base_port = NAT64_MIN_PORT + 64 * pg_idx;
1113 ck_pr_store_ptr(&chunks[chunk_idx]->pgptr[pg_idx % 32], pg);
1114 ck_pr_fence_store();
1115 ck_pr_bts_32(&pgmask[pg_idx / 32], pg_idx % 32);
1116 ck_pr_store_ptr(pgptr, pg);
1117
1118 ALIAS_LOCK(alias);
1119 CK_SLIST_INSERT_HEAD(&alias->portgroups, pg, entries);
1120 SET_AGE(alias->timestamp);
1121 alias->portgroups_count++;
1122 ALIAS_UNLOCK(alias);
1123 NAT64STAT_INC(&cfg->base.stats, spgcreated);
1124 return (PG_ERROR(0));
1125
1126 states_failed:
1127 for (i = 0; i < pg->chunks_count; i++)
1128 uma_zfree(nat64lsn_state_zone, pg->states_chunk[i]);
1129 free(pg->freemask_chunk, M_NAT64LSN);
1130 free(pg->states_chunk, M_NAT64LSN);
1131 uma_zfree(nat64lsn_pg_zone, pg);
1132 return (PG_ERROR(7));
1133 }
1134
1135 static int
nat64lsn_alloc_pg(struct nat64lsn_cfg * cfg,struct nat64lsn_job_item * ji)1136 nat64lsn_alloc_pg(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
1137 {
1138 struct nat64lsn_aliaslink *link;
1139 struct nat64lsn_alias *alias;
1140 int ret;
1141
1142 link = nat64lsn_get_aliaslink(cfg, ji->host, &ji->f_id);
1143 if (link == NULL)
1144 return (PG_ERROR(1));
1145
1146 /*
1147 * TODO: check that we did not already allocated PG in
1148 * previous call.
1149 */
1150
1151 ret = 0;
1152 alias = link->alias;
1153 /* Find place in pgchunk where PG can be added */
1154 switch (ji->proto) {
1155 case IPPROTO_TCP:
1156 ret = nat64lsn_alloc_proto_pg(cfg, alias,
1157 &alias->tcp_chunkmask, alias->tcp_pgmask,
1158 alias->tcp, &alias->tcp_pg, ji->proto);
1159 break;
1160 case IPPROTO_UDP:
1161 ret = nat64lsn_alloc_proto_pg(cfg, alias,
1162 &alias->udp_chunkmask, alias->udp_pgmask,
1163 alias->udp, &alias->udp_pg, ji->proto);
1164 break;
1165 case IPPROTO_ICMP:
1166 ret = nat64lsn_alloc_proto_pg(cfg, alias,
1167 &alias->icmp_chunkmask, alias->icmp_pgmask,
1168 alias->icmp, &alias->icmp_pg, ji->proto);
1169 break;
1170 default:
1171 panic("%s: wrong proto %d", __func__, ji->proto);
1172 }
1173 if (ret == PG_ERROR(1)) {
1174 /*
1175 * PG_ERROR(1) means that alias lacks free PGs
1176 * XXX: try next alias.
1177 */
1178 printf("NAT64LSN: %s: failed to obtain PG\n",
1179 __func__);
1180 return (ret);
1181 }
1182 if (ret == PG_ERROR(0)) {
1183 ji->state = nat64lsn_get_state6to4(cfg, ji->host, &ji->f_id,
1184 ji->state_hval, ji->faddr, ji->port, ji->proto);
1185 if (ji->state == NULL)
1186 ret = PG_ERROR(8);
1187 else
1188 ji->done = 1;
1189 }
1190 return (ret);
1191 }
1192
1193 static void
nat64lsn_do_request(void * data)1194 nat64lsn_do_request(void *data)
1195 {
1196 struct epoch_tracker et;
1197 struct nat64lsn_job_head jhead;
1198 struct nat64lsn_job_item *ji, *ji2;
1199 struct nat64lsn_cfg *cfg;
1200 int jcount;
1201 uint8_t flags;
1202
1203 cfg = (struct nat64lsn_cfg *)data;
1204 if (cfg->jlen == 0)
1205 return;
1206
1207 CURVNET_SET(cfg->vp);
1208 STAILQ_INIT(&jhead);
1209
1210 /* Grab queue */
1211 JQUEUE_LOCK();
1212 STAILQ_SWAP(&jhead, &cfg->jhead, nat64lsn_job_item);
1213 jcount = cfg->jlen;
1214 cfg->jlen = 0;
1215 JQUEUE_UNLOCK();
1216
1217 /* TODO: check if we need to resize hash */
1218
1219 NAT64STAT_INC(&cfg->base.stats, jcalls);
1220 DPRINTF(DP_JQUEUE, "count=%d", jcount);
1221
1222 /*
1223 * TODO:
1224 * What we should do here is to build a hash
1225 * to ensure we don't have lots of duplicate requests.
1226 * Skip this for now.
1227 *
1228 * TODO: Limit per-call number of items
1229 */
1230
1231 NAT64LSN_EPOCH_ENTER(et);
1232 STAILQ_FOREACH(ji, &jhead, entries) {
1233 switch (ji->jtype) {
1234 case JTYPE_NEWHOST:
1235 if (nat64lsn_alloc_host(cfg, ji) != HOST_ERROR(0))
1236 NAT64STAT_INC(&cfg->base.stats, jhostfails);
1237 break;
1238 case JTYPE_NEWPORTGROUP:
1239 if (nat64lsn_alloc_pg(cfg, ji) != PG_ERROR(0))
1240 NAT64STAT_INC(&cfg->base.stats, jportfails);
1241 break;
1242 default:
1243 continue;
1244 }
1245 if (ji->done != 0) {
1246 flags = ji->proto != IPPROTO_TCP ? 0 :
1247 convert_tcp_flags(ji->f_id._flags);
1248 nat64lsn_translate6_internal(cfg, &ji->m,
1249 ji->state, flags);
1250 NAT64STAT_INC(&cfg->base.stats, jreinjected);
1251 }
1252 }
1253 NAT64LSN_EPOCH_EXIT(et);
1254
1255 ji = STAILQ_FIRST(&jhead);
1256 while (ji != NULL) {
1257 ji2 = STAILQ_NEXT(ji, entries);
1258 /*
1259 * In any case we must free mbuf if
1260 * translator did not consumed it.
1261 */
1262 m_freem(ji->m);
1263 uma_zfree(nat64lsn_job_zone, ji);
1264 ji = ji2;
1265 }
1266 CURVNET_RESTORE();
1267 }
1268
1269 static struct nat64lsn_job_item *
nat64lsn_create_job(struct nat64lsn_cfg * cfg,int jtype)1270 nat64lsn_create_job(struct nat64lsn_cfg *cfg, int jtype)
1271 {
1272 struct nat64lsn_job_item *ji;
1273
1274 /*
1275 * Do not try to lock possibly contested mutex if we're near the
1276 * limit. Drop packet instead.
1277 */
1278 ji = NULL;
1279 if (cfg->jlen >= cfg->jmaxlen)
1280 NAT64STAT_INC(&cfg->base.stats, jmaxlen);
1281 else {
1282 ji = uma_zalloc(nat64lsn_job_zone, M_NOWAIT);
1283 if (ji == NULL)
1284 NAT64STAT_INC(&cfg->base.stats, jnomem);
1285 }
1286 if (ji == NULL) {
1287 NAT64STAT_INC(&cfg->base.stats, dropped);
1288 DPRINTF(DP_DROPS, "failed to create job");
1289 } else {
1290 ji->jtype = jtype;
1291 ji->done = 0;
1292 }
1293 return (ji);
1294 }
1295
1296 static void
nat64lsn_enqueue_job(struct nat64lsn_cfg * cfg,struct nat64lsn_job_item * ji)1297 nat64lsn_enqueue_job(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
1298 {
1299
1300 JQUEUE_LOCK();
1301 STAILQ_INSERT_TAIL(&cfg->jhead, ji, entries);
1302 NAT64STAT_INC(&cfg->base.stats, jrequests);
1303 cfg->jlen++;
1304
1305 if (callout_pending(&cfg->jcallout) == 0)
1306 callout_reset(&cfg->jcallout, 1, nat64lsn_do_request, cfg);
1307 JQUEUE_UNLOCK();
1308 }
1309
1310 static void
nat64lsn_job_destroy(epoch_context_t ctx)1311 nat64lsn_job_destroy(epoch_context_t ctx)
1312 {
1313 struct nat64lsn_job_item *ji;
1314 struct nat64lsn_host *host;
1315 struct nat64lsn_pg *pg;
1316 int i;
1317
1318 ji = __containerof(ctx, struct nat64lsn_job_item, epoch_ctx);
1319 MPASS(ji->jtype == JTYPE_DESTROY);
1320 while (!CK_SLIST_EMPTY(&ji->hosts)) {
1321 host = CK_SLIST_FIRST(&ji->hosts);
1322 CK_SLIST_REMOVE_HEAD(&ji->hosts, entries);
1323 if (host->states_count > 0) {
1324 /*
1325 * XXX: The state has been created
1326 * during host deletion.
1327 */
1328 printf("NAT64LSN: %s: destroying host with %d "
1329 "states\n", __func__, host->states_count);
1330 }
1331 nat64lsn_destroy_host(host);
1332 }
1333 while (!CK_SLIST_EMPTY(&ji->portgroups)) {
1334 pg = CK_SLIST_FIRST(&ji->portgroups);
1335 CK_SLIST_REMOVE_HEAD(&ji->portgroups, entries);
1336 for (i = 0; i < pg->chunks_count; i++) {
1337 if (FREEMASK_BITCOUNT(pg, i) != 64) {
1338 /*
1339 * XXX: The state has been created during
1340 * PG deletion.
1341 */
1342 printf("NAT64LSN: %s: destroying PG %p "
1343 "with non-empty chunk %d\n", __func__,
1344 pg, i);
1345 }
1346 }
1347 nat64lsn_destroy_pg(pg);
1348 }
1349 uma_zfree(nat64lsn_pgchunk_zone, ji->pgchunk);
1350 uma_zfree(nat64lsn_job_zone, ji);
1351 }
1352
1353 static int
nat64lsn_request_host(struct nat64lsn_cfg * cfg,const struct ipfw_flow_id * f_id,struct mbuf ** mp,uint32_t hval,in_addr_t faddr,uint16_t port,uint8_t proto)1354 nat64lsn_request_host(struct nat64lsn_cfg *cfg,
1355 const struct ipfw_flow_id *f_id, struct mbuf **mp, uint32_t hval,
1356 in_addr_t faddr, uint16_t port, uint8_t proto)
1357 {
1358 struct nat64lsn_job_item *ji;
1359
1360 ji = nat64lsn_create_job(cfg, JTYPE_NEWHOST);
1361 if (ji != NULL) {
1362 ji->m = *mp;
1363 ji->f_id = *f_id;
1364 ji->faddr = faddr;
1365 ji->port = port;
1366 ji->proto = proto;
1367 ji->src6_hval = hval;
1368
1369 nat64lsn_enqueue_job(cfg, ji);
1370 NAT64STAT_INC(&cfg->base.stats, jhostsreq);
1371 *mp = NULL;
1372 }
1373 return (IP_FW_DENY);
1374 }
1375
1376 static int
nat64lsn_request_pg(struct nat64lsn_cfg * cfg,struct nat64lsn_host * host,const struct ipfw_flow_id * f_id,struct mbuf ** mp,uint32_t hval,in_addr_t faddr,uint16_t port,uint8_t proto)1377 nat64lsn_request_pg(struct nat64lsn_cfg *cfg, struct nat64lsn_host *host,
1378 const struct ipfw_flow_id *f_id, struct mbuf **mp, uint32_t hval,
1379 in_addr_t faddr, uint16_t port, uint8_t proto)
1380 {
1381 struct nat64lsn_job_item *ji;
1382
1383 ji = nat64lsn_create_job(cfg, JTYPE_NEWPORTGROUP);
1384 if (ji != NULL) {
1385 ji->m = *mp;
1386 ji->f_id = *f_id;
1387 ji->faddr = faddr;
1388 ji->port = port;
1389 ji->proto = proto;
1390 ji->state_hval = hval;
1391 ji->host = host;
1392
1393 nat64lsn_enqueue_job(cfg, ji);
1394 NAT64STAT_INC(&cfg->base.stats, jportreq);
1395 *mp = NULL;
1396 }
1397 return (IP_FW_DENY);
1398 }
1399
1400 static int
nat64lsn_translate6_internal(struct nat64lsn_cfg * cfg,struct mbuf ** mp,struct nat64lsn_state * state,uint8_t flags)1401 nat64lsn_translate6_internal(struct nat64lsn_cfg *cfg, struct mbuf **mp,
1402 struct nat64lsn_state *state, uint8_t flags)
1403 {
1404 struct pfloghdr loghdr, *logdata;
1405 int ret;
1406 uint16_t ts;
1407
1408 /* Update timestamp and flags if needed */
1409 SET_AGE(ts);
1410 if (state->timestamp != ts)
1411 state->timestamp = ts;
1412 if ((state->flags & flags) != 0)
1413 state->flags |= flags;
1414
1415 if (cfg->base.flags & NAT64_LOG) {
1416 logdata = &loghdr;
1417 nat64lsn_log(logdata, *mp, AF_INET6, state);
1418 } else
1419 logdata = NULL;
1420
1421 ret = nat64_do_handle_ip6(*mp, htonl(state->ip_src),
1422 htons(state->aport), &cfg->base, logdata);
1423 if (ret == NAT64SKIP)
1424 return (cfg->nomatch_verdict);
1425 if (ret == NAT64RETURN)
1426 *mp = NULL;
1427 return (IP_FW_DENY);
1428 }
1429
1430 static int
nat64lsn_translate6(struct nat64lsn_cfg * cfg,struct ipfw_flow_id * f_id,struct mbuf ** mp)1431 nat64lsn_translate6(struct nat64lsn_cfg *cfg, struct ipfw_flow_id *f_id,
1432 struct mbuf **mp)
1433 {
1434 struct nat64lsn_state *state;
1435 struct nat64lsn_host *host;
1436 struct icmp6_hdr *icmp6;
1437 uint32_t addr, hval, data[2];
1438 int offset, proto;
1439 uint16_t port;
1440 uint8_t flags;
1441
1442 /* Check if protocol is supported */
1443 port = f_id->src_port;
1444 proto = f_id->proto;
1445 switch (f_id->proto) {
1446 case IPPROTO_ICMPV6:
1447 /*
1448 * For ICMPv6 echo reply/request we use icmp6_id as
1449 * local port.
1450 */
1451 offset = 0;
1452 proto = nat64_getlasthdr(*mp, &offset);
1453 if (proto < 0) {
1454 NAT64STAT_INC(&cfg->base.stats, dropped);
1455 DPRINTF(DP_DROPS, "mbuf isn't contigious");
1456 return (IP_FW_DENY);
1457 }
1458 if (proto == IPPROTO_ICMPV6) {
1459 icmp6 = mtodo(*mp, offset);
1460 if (icmp6->icmp6_type == ICMP6_ECHO_REQUEST ||
1461 icmp6->icmp6_type == ICMP6_ECHO_REPLY)
1462 port = ntohs(icmp6->icmp6_id);
1463 }
1464 proto = IPPROTO_ICMP;
1465 /* FALLTHROUGH */
1466 case IPPROTO_TCP:
1467 case IPPROTO_UDP:
1468 break;
1469 default:
1470 NAT64STAT_INC(&cfg->base.stats, noproto);
1471 return (cfg->nomatch_verdict);
1472 }
1473
1474 /* Extract IPv4 from destination IPv6 address */
1475 addr = nat64_extract_ip4(&f_id->dst_ip6, cfg->base.plat_plen);
1476 if (addr == 0 || nat64_check_private_ip4(&cfg->base, addr) != 0) {
1477 char a[INET_ADDRSTRLEN];
1478
1479 NAT64STAT_INC(&cfg->base.stats, dropped);
1480 DPRINTF(DP_DROPS, "dropped due to embedded IPv4 address %s",
1481 inet_ntop(AF_INET, &addr, a, sizeof(a)));
1482 return (IP_FW_DENY); /* XXX: add extra stats? */
1483 }
1484
1485 /* Try to find host */
1486 hval = HOST_HVAL(cfg, &f_id->src_ip6);
1487 CK_SLIST_FOREACH(host, &HOSTS(cfg, hval), entries) {
1488 if (IN6_ARE_ADDR_EQUAL(&f_id->src_ip6, &host->addr))
1489 break;
1490 }
1491 /* We use IPv4 address in host byte order */
1492 addr = ntohl(addr);
1493 if (host == NULL)
1494 return (nat64lsn_request_host(cfg, f_id, mp,
1495 hval, addr, port, proto));
1496
1497 flags = proto != IPPROTO_TCP ? 0 : convert_tcp_flags(f_id->_flags);
1498
1499 data[0] = addr;
1500 data[1] = (f_id->dst_port << 16) | port;
1501 hval = STATE_HVAL(cfg, data);
1502 state = nat64lsn_get_state6to4(cfg, host, f_id, hval, addr,
1503 port, proto);
1504 if (state == NULL)
1505 return (nat64lsn_request_pg(cfg, host, f_id, mp, hval, addr,
1506 port, proto));
1507 return (nat64lsn_translate6_internal(cfg, mp, state, flags));
1508 }
1509
1510 /*
1511 * Main dataplane entry point.
1512 */
1513 int
ipfw_nat64lsn(struct ip_fw_chain * ch,struct ip_fw_args * args,ipfw_insn * cmd,int * done)1514 ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args,
1515 ipfw_insn *cmd, int *done)
1516 {
1517 struct epoch_tracker et;
1518 struct nat64lsn_cfg *cfg;
1519 ipfw_insn *icmd;
1520 int ret;
1521
1522 IPFW_RLOCK_ASSERT(ch);
1523
1524 *done = 0; /* continue the search in case of failure */
1525 icmd = cmd + 1;
1526 if (cmd->opcode != O_EXTERNAL_ACTION ||
1527 cmd->arg1 != V_nat64lsn_eid ||
1528 icmd->opcode != O_EXTERNAL_INSTANCE ||
1529 (cfg = NAT64_LOOKUP(ch, icmd)) == NULL)
1530 return (IP_FW_DENY);
1531
1532 *done = 1; /* terminate the search */
1533
1534 NAT64LSN_EPOCH_ENTER(et);
1535 switch (args->f_id.addr_type) {
1536 case 4:
1537 ret = nat64lsn_translate4(cfg, &args->f_id, &args->m);
1538 break;
1539 case 6:
1540 /*
1541 * Check that destination IPv6 address matches our prefix6.
1542 */
1543 if ((cfg->base.flags & NAT64LSN_ANYPREFIX) == 0 &&
1544 memcmp(&args->f_id.dst_ip6, &cfg->base.plat_prefix,
1545 cfg->base.plat_plen / 8) != 0) {
1546 ret = cfg->nomatch_verdict;
1547 break;
1548 }
1549 ret = nat64lsn_translate6(cfg, &args->f_id, &args->m);
1550 break;
1551 default:
1552 ret = cfg->nomatch_verdict;
1553 }
1554 NAT64LSN_EPOCH_EXIT(et);
1555
1556 if (ret != IP_FW_PASS && args->m != NULL) {
1557 m_freem(args->m);
1558 args->m = NULL;
1559 }
1560 return (ret);
1561 }
1562
1563 static int
nat64lsn_state_ctor(void * mem,int size,void * arg,int flags)1564 nat64lsn_state_ctor(void *mem, int size, void *arg, int flags)
1565 {
1566 struct nat64lsn_states_chunk *chunk;
1567 int i;
1568
1569 chunk = (struct nat64lsn_states_chunk *)mem;
1570 for (i = 0; i < 64; i++)
1571 chunk->state[i].flags = 0;
1572 return (0);
1573 }
1574
1575 void
nat64lsn_init_internal(void)1576 nat64lsn_init_internal(void)
1577 {
1578
1579 nat64lsn_host_zone = uma_zcreate("NAT64LSN hosts",
1580 sizeof(struct nat64lsn_host), NULL, NULL, NULL, NULL,
1581 UMA_ALIGN_PTR, 0);
1582 nat64lsn_pgchunk_zone = uma_zcreate("NAT64LSN portgroup chunks",
1583 sizeof(struct nat64lsn_pgchunk), NULL, NULL, NULL, NULL,
1584 UMA_ALIGN_PTR, 0);
1585 nat64lsn_pg_zone = uma_zcreate("NAT64LSN portgroups",
1586 sizeof(struct nat64lsn_pg), NULL, NULL, NULL, NULL,
1587 UMA_ALIGN_PTR, 0);
1588 nat64lsn_aliaslink_zone = uma_zcreate("NAT64LSN links",
1589 sizeof(struct nat64lsn_aliaslink), NULL, NULL, NULL, NULL,
1590 UMA_ALIGN_PTR, 0);
1591 nat64lsn_state_zone = uma_zcreate("NAT64LSN states",
1592 sizeof(struct nat64lsn_states_chunk), nat64lsn_state_ctor,
1593 NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
1594 nat64lsn_job_zone = uma_zcreate("NAT64LSN jobs",
1595 sizeof(struct nat64lsn_job_item), NULL, NULL, NULL, NULL,
1596 UMA_ALIGN_PTR, 0);
1597 JQUEUE_LOCK_INIT();
1598 }
1599
1600 void
nat64lsn_uninit_internal(void)1601 nat64lsn_uninit_internal(void)
1602 {
1603
1604 /* XXX: epoch_task drain */
1605 JQUEUE_LOCK_DESTROY();
1606 uma_zdestroy(nat64lsn_host_zone);
1607 uma_zdestroy(nat64lsn_pgchunk_zone);
1608 uma_zdestroy(nat64lsn_pg_zone);
1609 uma_zdestroy(nat64lsn_aliaslink_zone);
1610 uma_zdestroy(nat64lsn_state_zone);
1611 uma_zdestroy(nat64lsn_job_zone);
1612 }
1613
1614 void
nat64lsn_start_instance(struct nat64lsn_cfg * cfg)1615 nat64lsn_start_instance(struct nat64lsn_cfg *cfg)
1616 {
1617
1618 CALLOUT_LOCK(cfg);
1619 callout_reset(&cfg->periodic, hz * PERIODIC_DELAY,
1620 nat64lsn_periodic, cfg);
1621 CALLOUT_UNLOCK(cfg);
1622 }
1623
1624 struct nat64lsn_cfg *
nat64lsn_init_instance(struct ip_fw_chain * ch,in_addr_t prefix,int plen)1625 nat64lsn_init_instance(struct ip_fw_chain *ch, in_addr_t prefix, int plen)
1626 {
1627 struct nat64lsn_cfg *cfg;
1628 struct nat64lsn_alias *alias;
1629 int i, naddr;
1630
1631 cfg = malloc(sizeof(struct nat64lsn_cfg), M_NAT64LSN,
1632 M_WAITOK | M_ZERO);
1633
1634 CFG_LOCK_INIT(cfg);
1635 CALLOUT_LOCK_INIT(cfg);
1636 STAILQ_INIT(&cfg->jhead);
1637 cfg->vp = curvnet;
1638 COUNTER_ARRAY_ALLOC(cfg->base.stats.cnt, NAT64STATS, M_WAITOK);
1639
1640 cfg->hash_seed = arc4random();
1641 cfg->hosts_hashsize = NAT64LSN_HOSTS_HSIZE;
1642 cfg->hosts_hash = malloc(sizeof(struct nat64lsn_hosts_slist) *
1643 cfg->hosts_hashsize, M_NAT64LSN, M_WAITOK | M_ZERO);
1644 for (i = 0; i < cfg->hosts_hashsize; i++)
1645 CK_SLIST_INIT(&cfg->hosts_hash[i]);
1646
1647 naddr = 1 << (32 - plen);
1648 cfg->prefix4 = prefix;
1649 cfg->pmask4 = prefix | (naddr - 1);
1650 cfg->plen4 = plen;
1651 cfg->aliases = malloc(sizeof(struct nat64lsn_alias) * naddr,
1652 M_NAT64LSN, M_WAITOK | M_ZERO);
1653 for (i = 0; i < naddr; i++) {
1654 alias = &cfg->aliases[i];
1655 alias->addr = prefix + i; /* host byte order */
1656 CK_SLIST_INIT(&alias->hosts);
1657 ALIAS_LOCK_INIT(alias);
1658 }
1659
1660 callout_init_mtx(&cfg->periodic, &cfg->periodic_lock, 0);
1661 callout_init(&cfg->jcallout, CALLOUT_MPSAFE);
1662
1663 return (cfg);
1664 }
1665
1666 static void
nat64lsn_destroy_pg(struct nat64lsn_pg * pg)1667 nat64lsn_destroy_pg(struct nat64lsn_pg *pg)
1668 {
1669 int i;
1670
1671 if (pg->chunks_count == 1) {
1672 uma_zfree(nat64lsn_state_zone, pg->states);
1673 } else {
1674 for (i = 0; i < pg->chunks_count; i++)
1675 uma_zfree(nat64lsn_state_zone, pg->states_chunk[i]);
1676 free(pg->states_chunk, M_NAT64LSN);
1677 free(pg->freemask_chunk, M_NAT64LSN);
1678 }
1679 uma_zfree(nat64lsn_pg_zone, pg);
1680 }
1681
1682 static void
nat64lsn_destroy_alias(struct nat64lsn_cfg * cfg,struct nat64lsn_alias * alias)1683 nat64lsn_destroy_alias(struct nat64lsn_cfg *cfg,
1684 struct nat64lsn_alias *alias)
1685 {
1686 struct nat64lsn_pg *pg;
1687 int i;
1688
1689 while (!CK_SLIST_EMPTY(&alias->portgroups)) {
1690 pg = CK_SLIST_FIRST(&alias->portgroups);
1691 CK_SLIST_REMOVE_HEAD(&alias->portgroups, entries);
1692 nat64lsn_destroy_pg(pg);
1693 }
1694 for (i = 0; i < 32; i++) {
1695 if (ISSET32(alias->tcp_chunkmask, i))
1696 uma_zfree(nat64lsn_pgchunk_zone, alias->tcp[i]);
1697 if (ISSET32(alias->udp_chunkmask, i))
1698 uma_zfree(nat64lsn_pgchunk_zone, alias->udp[i]);
1699 if (ISSET32(alias->icmp_chunkmask, i))
1700 uma_zfree(nat64lsn_pgchunk_zone, alias->icmp[i]);
1701 }
1702 ALIAS_LOCK_DESTROY(alias);
1703 }
1704
1705 static void
nat64lsn_destroy_host(struct nat64lsn_host * host)1706 nat64lsn_destroy_host(struct nat64lsn_host *host)
1707 {
1708 struct nat64lsn_aliaslink *link;
1709
1710 while (!CK_SLIST_EMPTY(&host->aliases)) {
1711 link = CK_SLIST_FIRST(&host->aliases);
1712 CK_SLIST_REMOVE_HEAD(&host->aliases, host_entries);
1713
1714 ALIAS_LOCK(link->alias);
1715 CK_SLIST_REMOVE(&link->alias->hosts, link,
1716 nat64lsn_aliaslink, alias_entries);
1717 link->alias->hosts_count--;
1718 ALIAS_UNLOCK(link->alias);
1719
1720 uma_zfree(nat64lsn_aliaslink_zone, link);
1721 }
1722 HOST_LOCK_DESTROY(host);
1723 free(host->states_hash, M_NAT64LSN);
1724 uma_zfree(nat64lsn_host_zone, host);
1725 }
1726
1727 void
nat64lsn_destroy_instance(struct nat64lsn_cfg * cfg)1728 nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg)
1729 {
1730 struct nat64lsn_host *host;
1731 int i;
1732
1733 CALLOUT_LOCK(cfg);
1734 callout_drain(&cfg->periodic);
1735 CALLOUT_UNLOCK(cfg);
1736 callout_drain(&cfg->jcallout);
1737
1738 for (i = 0; i < cfg->hosts_hashsize; i++) {
1739 while (!CK_SLIST_EMPTY(&cfg->hosts_hash[i])) {
1740 host = CK_SLIST_FIRST(&cfg->hosts_hash[i]);
1741 CK_SLIST_REMOVE_HEAD(&cfg->hosts_hash[i], entries);
1742 nat64lsn_destroy_host(host);
1743 }
1744 }
1745
1746 for (i = 0; i < (1 << (32 - cfg->plen4)); i++)
1747 nat64lsn_destroy_alias(cfg, &cfg->aliases[i]);
1748
1749 CALLOUT_LOCK_DESTROY(cfg);
1750 CFG_LOCK_DESTROY(cfg);
1751 COUNTER_ARRAY_FREE(cfg->base.stats.cnt, NAT64STATS);
1752 free(cfg->hosts_hash, M_NAT64LSN);
1753 free(cfg->aliases, M_NAT64LSN);
1754 free(cfg, M_NAT64LSN);
1755 }
1756
1757