1 /*- 2 * Copyright (c) 2015 Yandex LLC 3 * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org> 4 * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/counter.h> 35 #include <sys/errno.h> 36 #include <sys/kernel.h> 37 #include <sys/lock.h> 38 #include <sys/malloc.h> 39 #include <sys/mbuf.h> 40 #include <sys/module.h> 41 #include <sys/rmlock.h> 42 #include <sys/rwlock.h> 43 #include <sys/socket.h> 44 #include <sys/sockopt.h> 45 #include <sys/queue.h> 46 47 #include <net/if.h> 48 #include <net/pfil.h> 49 50 #include <netinet/in.h> 51 #include <netinet/ip.h> 52 #include <netinet/ip_var.h> 53 #include <netinet/ip_fw.h> 54 #include <netinet6/ip_fw_nat64.h> 55 56 #include <netpfil/ipfw/ip_fw_private.h> 57 58 #include "nat64lsn.h" 59 60 VNET_DEFINE(uint16_t, nat64lsn_eid) = 0; 61 62 static struct nat64lsn_cfg * 63 nat64lsn_find(struct namedobj_instance *ni, const char *name, uint8_t set) 64 { 65 struct nat64lsn_cfg *cfg; 66 67 cfg = (struct nat64lsn_cfg *)ipfw_objhash_lookup_name_type(ni, set, 68 IPFW_TLV_NAT64LSN_NAME, name); 69 70 return (cfg); 71 } 72 73 static void 74 nat64lsn_default_config(ipfw_nat64lsn_cfg *uc) 75 { 76 77 if (uc->max_ports == 0) 78 uc->max_ports = NAT64LSN_MAX_PORTS; 79 else 80 uc->max_ports = roundup(uc->max_ports, NAT64_CHUNK_SIZE); 81 if (uc->max_ports > NAT64_CHUNK_SIZE * NAT64LSN_MAXPGPTR) 82 uc->max_ports = NAT64_CHUNK_SIZE * NAT64LSN_MAXPGPTR; 83 if (uc->jmaxlen == 0) 84 uc->jmaxlen = NAT64LSN_JMAXLEN; 85 if (uc->jmaxlen > 65536) 86 uc->jmaxlen = 65536; 87 if (uc->nh_delete_delay == 0) 88 uc->nh_delete_delay = NAT64LSN_HOST_AGE; 89 if (uc->pg_delete_delay == 0) 90 uc->pg_delete_delay = NAT64LSN_PG_AGE; 91 if (uc->st_syn_ttl == 0) 92 uc->st_syn_ttl = NAT64LSN_TCP_SYN_AGE; 93 if (uc->st_close_ttl == 0) 94 uc->st_close_ttl = NAT64LSN_TCP_FIN_AGE; 95 if (uc->st_estab_ttl == 0) 96 uc->st_estab_ttl = NAT64LSN_TCP_EST_AGE; 97 if (uc->st_udp_ttl == 0) 98 uc->st_udp_ttl = NAT64LSN_UDP_AGE; 99 if (uc->st_icmp_ttl == 0) 100 uc->st_icmp_ttl = NAT64LSN_ICMP_AGE; 101 } 102 103 /* 104 * Creates new nat64lsn instance. 105 * Data layout (v0)(current): 106 * Request: [ ipfw_obj_lheader ipfw_nat64lsn_cfg ] 107 * 108 * Returns 0 on success 109 */ 110 static int 111 nat64lsn_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 112 struct sockopt_data *sd) 113 { 114 ipfw_obj_lheader *olh; 115 ipfw_nat64lsn_cfg *uc; 116 struct nat64lsn_cfg *cfg; 117 struct namedobj_instance *ni; 118 uint32_t addr4, mask4; 119 120 if (sd->valsize != sizeof(*olh) + sizeof(*uc)) 121 return (EINVAL); 122 123 olh = (ipfw_obj_lheader *)sd->kbuf; 124 uc = (ipfw_nat64lsn_cfg *)(olh + 1); 125 126 if (ipfw_check_object_name_generic(uc->name) != 0) 127 return (EINVAL); 128 129 if (uc->agg_prefix_len > 127 || uc->set >= IPFW_MAX_SETS) 130 return (EINVAL); 131 132 if (uc->plen4 > 32) 133 return (EINVAL); 134 if (nat64_check_prefix6(&uc->prefix6, uc->plen6) != 0) 135 return (EINVAL); 136 137 /* XXX: Check prefix4 to be global */ 138 addr4 = ntohl(uc->prefix4.s_addr); 139 mask4 = ~((1 << (32 - uc->plen4)) - 1); 140 if ((addr4 & mask4) != addr4) 141 return (EINVAL); 142 if (uc->min_port == 0) 143 uc->min_port = NAT64_MIN_PORT; 144 if (uc->max_port == 0) 145 uc->max_port = 65535; 146 if (uc->min_port > uc->max_port) 147 return (EINVAL); 148 uc->min_port = roundup(uc->min_port, NAT64_CHUNK_SIZE); 149 uc->max_port = roundup(uc->max_port, NAT64_CHUNK_SIZE); 150 151 nat64lsn_default_config(uc); 152 153 ni = CHAIN_TO_SRV(ch); 154 IPFW_UH_RLOCK(ch); 155 if (nat64lsn_find(ni, uc->name, uc->set) != NULL) { 156 IPFW_UH_RUNLOCK(ch); 157 return (EEXIST); 158 } 159 IPFW_UH_RUNLOCK(ch); 160 161 cfg = nat64lsn_init_instance(ch, 1 << (32 - uc->plen4)); 162 strlcpy(cfg->name, uc->name, sizeof(cfg->name)); 163 cfg->no.name = cfg->name; 164 cfg->no.etlv = IPFW_TLV_NAT64LSN_NAME; 165 cfg->no.set = uc->set; 166 167 cfg->base.prefix6 = uc->prefix6; 168 cfg->base.plen6 = uc->plen6; 169 cfg->base.flags = uc->flags & NAT64LSN_FLAGSMASK; 170 if (IN6_IS_ADDR_WKPFX(&cfg->base.prefix6)) 171 cfg->base.flags |= NAT64_WKPFX; 172 173 cfg->prefix4 = addr4; 174 cfg->pmask4 = addr4 | ~mask4; 175 cfg->plen4 = uc->plen4; 176 177 cfg->max_chunks = uc->max_ports / NAT64_CHUNK_SIZE; 178 cfg->agg_prefix_len = uc->agg_prefix_len; 179 cfg->agg_prefix_max = uc->agg_prefix_max; 180 181 cfg->min_chunk = uc->min_port / NAT64_CHUNK_SIZE; 182 cfg->max_chunk = uc->max_port / NAT64_CHUNK_SIZE; 183 184 cfg->jmaxlen = uc->jmaxlen; 185 cfg->nh_delete_delay = uc->nh_delete_delay; 186 cfg->pg_delete_delay = uc->pg_delete_delay; 187 cfg->st_syn_ttl = uc->st_syn_ttl; 188 cfg->st_close_ttl = uc->st_close_ttl; 189 cfg->st_estab_ttl = uc->st_estab_ttl; 190 cfg->st_udp_ttl = uc->st_udp_ttl; 191 cfg->st_icmp_ttl = uc->st_icmp_ttl; 192 193 cfg->nomatch_verdict = IP_FW_DENY; 194 195 IPFW_UH_WLOCK(ch); 196 197 if (nat64lsn_find(ni, uc->name, uc->set) != NULL) { 198 IPFW_UH_WUNLOCK(ch); 199 nat64lsn_destroy_instance(cfg); 200 return (EEXIST); 201 } 202 203 if (ipfw_objhash_alloc_idx(CHAIN_TO_SRV(ch), &cfg->no.kidx) != 0) { 204 IPFW_UH_WUNLOCK(ch); 205 nat64lsn_destroy_instance(cfg); 206 return (ENOSPC); 207 } 208 ipfw_objhash_add(CHAIN_TO_SRV(ch), &cfg->no); 209 210 /* Okay, let's link data */ 211 SRV_OBJECT(ch, cfg->no.kidx) = cfg; 212 nat64lsn_start_instance(cfg); 213 214 IPFW_UH_WUNLOCK(ch); 215 return (0); 216 } 217 218 static void 219 nat64lsn_detach_config(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg) 220 { 221 222 IPFW_UH_WLOCK_ASSERT(ch); 223 224 ipfw_objhash_del(CHAIN_TO_SRV(ch), &cfg->no); 225 ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), cfg->no.kidx); 226 } 227 228 /* 229 * Destroys nat64 instance. 230 * Data layout (v0)(current): 231 * Request: [ ipfw_obj_header ] 232 * 233 * Returns 0 on success 234 */ 235 static int 236 nat64lsn_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 237 struct sockopt_data *sd) 238 { 239 struct nat64lsn_cfg *cfg; 240 ipfw_obj_header *oh; 241 242 if (sd->valsize != sizeof(*oh)) 243 return (EINVAL); 244 245 oh = (ipfw_obj_header *)op3; 246 247 IPFW_UH_WLOCK(ch); 248 cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); 249 if (cfg == NULL) { 250 IPFW_UH_WUNLOCK(ch); 251 return (ESRCH); 252 } 253 254 if (cfg->no.refcnt > 0) { 255 IPFW_UH_WUNLOCK(ch); 256 return (EBUSY); 257 } 258 259 ipfw_reset_eaction_instance(ch, V_nat64lsn_eid, cfg->no.kidx); 260 SRV_OBJECT(ch, cfg->no.kidx) = NULL; 261 nat64lsn_detach_config(ch, cfg); 262 IPFW_UH_WUNLOCK(ch); 263 264 nat64lsn_destroy_instance(cfg); 265 return (0); 266 } 267 268 #define __COPY_STAT_FIELD(_cfg, _stats, _field) \ 269 (_stats)->_field = NAT64STAT_FETCH(&(_cfg)->base.stats, _field) 270 static void 271 export_stats(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg, 272 struct ipfw_nat64lsn_stats *stats) 273 { 274 275 __COPY_STAT_FIELD(cfg, stats, opcnt64); 276 __COPY_STAT_FIELD(cfg, stats, opcnt46); 277 __COPY_STAT_FIELD(cfg, stats, ofrags); 278 __COPY_STAT_FIELD(cfg, stats, ifrags); 279 __COPY_STAT_FIELD(cfg, stats, oerrors); 280 __COPY_STAT_FIELD(cfg, stats, noroute4); 281 __COPY_STAT_FIELD(cfg, stats, noroute6); 282 __COPY_STAT_FIELD(cfg, stats, nomatch4); 283 __COPY_STAT_FIELD(cfg, stats, noproto); 284 __COPY_STAT_FIELD(cfg, stats, nomem); 285 __COPY_STAT_FIELD(cfg, stats, dropped); 286 287 __COPY_STAT_FIELD(cfg, stats, jcalls); 288 __COPY_STAT_FIELD(cfg, stats, jrequests); 289 __COPY_STAT_FIELD(cfg, stats, jhostsreq); 290 __COPY_STAT_FIELD(cfg, stats, jportreq); 291 __COPY_STAT_FIELD(cfg, stats, jhostfails); 292 __COPY_STAT_FIELD(cfg, stats, jportfails); 293 __COPY_STAT_FIELD(cfg, stats, jmaxlen); 294 __COPY_STAT_FIELD(cfg, stats, jnomem); 295 __COPY_STAT_FIELD(cfg, stats, jreinjected); 296 __COPY_STAT_FIELD(cfg, stats, screated); 297 __COPY_STAT_FIELD(cfg, stats, sdeleted); 298 __COPY_STAT_FIELD(cfg, stats, spgcreated); 299 __COPY_STAT_FIELD(cfg, stats, spgdeleted); 300 301 stats->hostcount = cfg->ihcount; 302 stats->tcpchunks = cfg->protochunks[NAT_PROTO_TCP]; 303 stats->udpchunks = cfg->protochunks[NAT_PROTO_UDP]; 304 stats->icmpchunks = cfg->protochunks[NAT_PROTO_ICMP]; 305 } 306 #undef __COPY_STAT_FIELD 307 308 static void 309 nat64lsn_export_config(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg, 310 ipfw_nat64lsn_cfg *uc) 311 { 312 313 uc->flags = cfg->base.flags & NAT64LSN_FLAGSMASK; 314 uc->max_ports = cfg->max_chunks * NAT64_CHUNK_SIZE; 315 uc->agg_prefix_len = cfg->agg_prefix_len; 316 uc->agg_prefix_max = cfg->agg_prefix_max; 317 318 uc->jmaxlen = cfg->jmaxlen; 319 uc->nh_delete_delay = cfg->nh_delete_delay; 320 uc->pg_delete_delay = cfg->pg_delete_delay; 321 uc->st_syn_ttl = cfg->st_syn_ttl; 322 uc->st_close_ttl = cfg->st_close_ttl; 323 uc->st_estab_ttl = cfg->st_estab_ttl; 324 uc->st_udp_ttl = cfg->st_udp_ttl; 325 uc->st_icmp_ttl = cfg->st_icmp_ttl; 326 uc->prefix4.s_addr = htonl(cfg->prefix4); 327 uc->prefix6 = cfg->base.prefix6; 328 uc->plen4 = cfg->plen4; 329 uc->plen6 = cfg->base.plen6; 330 uc->set = cfg->no.set; 331 strlcpy(uc->name, cfg->no.name, sizeof(uc->name)); 332 } 333 334 struct nat64_dump_arg { 335 struct ip_fw_chain *ch; 336 struct sockopt_data *sd; 337 }; 338 339 static int 340 export_config_cb(struct namedobj_instance *ni, struct named_object *no, 341 void *arg) 342 { 343 struct nat64_dump_arg *da = (struct nat64_dump_arg *)arg; 344 ipfw_nat64lsn_cfg *uc; 345 346 uc = (struct _ipfw_nat64lsn_cfg *)ipfw_get_sopt_space(da->sd, 347 sizeof(*uc)); 348 nat64lsn_export_config(da->ch, (struct nat64lsn_cfg *)no, uc); 349 return (0); 350 } 351 352 /* 353 * Lists all nat64 lsn instances currently available in kernel. 354 * Data layout (v0)(current): 355 * Request: [ ipfw_obj_lheader ] 356 * Reply: [ ipfw_obj_lheader ipfw_nat64lsn_cfg x N ] 357 * 358 * Returns 0 on success 359 */ 360 static int 361 nat64lsn_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 362 struct sockopt_data *sd) 363 { 364 ipfw_obj_lheader *olh; 365 struct nat64_dump_arg da; 366 367 /* Check minimum header size */ 368 if (sd->valsize < sizeof(ipfw_obj_lheader)) 369 return (EINVAL); 370 371 olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh)); 372 373 IPFW_UH_RLOCK(ch); 374 olh->count = ipfw_objhash_count_type(CHAIN_TO_SRV(ch), 375 IPFW_TLV_NAT64LSN_NAME); 376 olh->objsize = sizeof(ipfw_nat64lsn_cfg); 377 olh->size = sizeof(*olh) + olh->count * olh->objsize; 378 379 if (sd->valsize < olh->size) { 380 IPFW_UH_RUNLOCK(ch); 381 return (ENOMEM); 382 } 383 memset(&da, 0, sizeof(da)); 384 da.ch = ch; 385 da.sd = sd; 386 ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), export_config_cb, &da, 387 IPFW_TLV_NAT64LSN_NAME); 388 IPFW_UH_RUNLOCK(ch); 389 390 return (0); 391 } 392 393 /* 394 * Change existing nat64lsn instance configuration. 395 * Data layout (v0)(current): 396 * Request: [ ipfw_obj_header ipfw_nat64lsn_cfg ] 397 * Reply: [ ipfw_obj_header ipfw_nat64lsn_cfg ] 398 * 399 * Returns 0 on success 400 */ 401 static int 402 nat64lsn_config(struct ip_fw_chain *ch, ip_fw3_opheader *op, 403 struct sockopt_data *sd) 404 { 405 ipfw_obj_header *oh; 406 ipfw_nat64lsn_cfg *uc; 407 struct nat64lsn_cfg *cfg; 408 struct namedobj_instance *ni; 409 410 if (sd->valsize != sizeof(*oh) + sizeof(*uc)) 411 return (EINVAL); 412 413 oh = (ipfw_obj_header *)ipfw_get_sopt_space(sd, 414 sizeof(*oh) + sizeof(*uc)); 415 uc = (ipfw_nat64lsn_cfg *)(oh + 1); 416 417 if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 || 418 oh->ntlv.set >= IPFW_MAX_SETS) 419 return (EINVAL); 420 421 ni = CHAIN_TO_SRV(ch); 422 if (sd->sopt->sopt_dir == SOPT_GET) { 423 IPFW_UH_RLOCK(ch); 424 cfg = nat64lsn_find(ni, oh->ntlv.name, oh->ntlv.set); 425 if (cfg == NULL) { 426 IPFW_UH_RUNLOCK(ch); 427 return (EEXIST); 428 } 429 nat64lsn_export_config(ch, cfg, uc); 430 IPFW_UH_RUNLOCK(ch); 431 return (0); 432 } 433 434 nat64lsn_default_config(uc); 435 436 IPFW_UH_WLOCK(ch); 437 cfg = nat64lsn_find(ni, oh->ntlv.name, oh->ntlv.set); 438 if (cfg == NULL) { 439 IPFW_UH_WUNLOCK(ch); 440 return (EEXIST); 441 } 442 443 /* 444 * For now allow to change only following values: 445 * jmaxlen, nh_del_age, pg_del_age, tcp_syn_age, tcp_close_age, 446 * tcp_est_age, udp_age, icmp_age, flags, max_ports. 447 */ 448 449 cfg->max_chunks = uc->max_ports / NAT64_CHUNK_SIZE; 450 cfg->jmaxlen = uc->jmaxlen; 451 cfg->nh_delete_delay = uc->nh_delete_delay; 452 cfg->pg_delete_delay = uc->pg_delete_delay; 453 cfg->st_syn_ttl = uc->st_syn_ttl; 454 cfg->st_close_ttl = uc->st_close_ttl; 455 cfg->st_estab_ttl = uc->st_estab_ttl; 456 cfg->st_udp_ttl = uc->st_udp_ttl; 457 cfg->st_icmp_ttl = uc->st_icmp_ttl; 458 cfg->base.flags &= ~NAT64LSN_FLAGSMASK; 459 cfg->base.flags |= uc->flags & NAT64LSN_FLAGSMASK; 460 461 IPFW_UH_WUNLOCK(ch); 462 463 return (0); 464 } 465 466 /* 467 * Get nat64lsn statistics. 468 * Data layout (v0)(current): 469 * Request: [ ipfw_obj_header ] 470 * Reply: [ ipfw_obj_header ipfw_counter_tlv ] 471 * 472 * Returns 0 on success 473 */ 474 static int 475 nat64lsn_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, 476 struct sockopt_data *sd) 477 { 478 struct ipfw_nat64lsn_stats stats; 479 struct nat64lsn_cfg *cfg; 480 ipfw_obj_header *oh; 481 ipfw_obj_ctlv *ctlv; 482 size_t sz; 483 484 sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ctlv) + sizeof(stats); 485 if (sd->valsize % sizeof(uint64_t)) 486 return (EINVAL); 487 if (sd->valsize < sz) 488 return (ENOMEM); 489 oh = (ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 490 if (oh == NULL) 491 return (EINVAL); 492 memset(&stats, 0, sizeof(stats)); 493 494 IPFW_UH_RLOCK(ch); 495 cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); 496 if (cfg == NULL) { 497 IPFW_UH_RUNLOCK(ch); 498 return (ESRCH); 499 } 500 501 export_stats(ch, cfg, &stats); 502 IPFW_UH_RUNLOCK(ch); 503 504 ctlv = (ipfw_obj_ctlv *)(oh + 1); 505 memset(ctlv, 0, sizeof(*ctlv)); 506 ctlv->head.type = IPFW_TLV_COUNTERS; 507 ctlv->head.length = sz - sizeof(ipfw_obj_header); 508 ctlv->count = sizeof(stats) / sizeof(uint64_t); 509 ctlv->objsize = sizeof(uint64_t); 510 ctlv->version = IPFW_NAT64_VERSION; 511 memcpy(ctlv + 1, &stats, sizeof(stats)); 512 return (0); 513 } 514 515 /* 516 * Reset nat64lsn statistics. 517 * Data layout (v0)(current): 518 * Request: [ ipfw_obj_header ] 519 * 520 * Returns 0 on success 521 */ 522 static int 523 nat64lsn_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, 524 struct sockopt_data *sd) 525 { 526 struct nat64lsn_cfg *cfg; 527 ipfw_obj_header *oh; 528 529 if (sd->valsize != sizeof(*oh)) 530 return (EINVAL); 531 oh = (ipfw_obj_header *)sd->kbuf; 532 if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 || 533 oh->ntlv.set >= IPFW_MAX_SETS) 534 return (EINVAL); 535 536 IPFW_UH_WLOCK(ch); 537 cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); 538 if (cfg == NULL) { 539 IPFW_UH_WUNLOCK(ch); 540 return (ESRCH); 541 } 542 COUNTER_ARRAY_ZERO(cfg->base.stats.cnt, NAT64STATS); 543 IPFW_UH_WUNLOCK(ch); 544 return (0); 545 } 546 547 /* 548 * Reply: [ ipfw_obj_header ipfw_obj_data [ ipfw_nat64lsn_stg 549 * ipfw_nat64lsn_state x count, ... ] ] 550 */ 551 static int 552 export_pg_states(struct nat64lsn_cfg *cfg, struct nat64lsn_portgroup *pg, 553 ipfw_nat64lsn_stg *stg, struct sockopt_data *sd) 554 { 555 ipfw_nat64lsn_state *ste; 556 struct nat64lsn_state *st; 557 int i, count; 558 559 NAT64_LOCK(pg->host); 560 count = 0; 561 for (i = 0; i < 64; i++) { 562 if (PG_IS_BUSY_IDX(pg, i)) 563 count++; 564 } 565 DPRINTF(DP_STATE, "EXPORT PG %d, count %d", pg->idx, count); 566 567 if (count == 0) { 568 stg->count = 0; 569 NAT64_UNLOCK(pg->host); 570 return (0); 571 } 572 ste = (ipfw_nat64lsn_state *)ipfw_get_sopt_space(sd, 573 count * sizeof(ipfw_nat64lsn_state)); 574 if (ste == NULL) { 575 NAT64_UNLOCK(pg->host); 576 return (1); 577 } 578 579 stg->alias4.s_addr = pg->aaddr; 580 stg->proto = nat64lsn_rproto_map[pg->nat_proto]; 581 stg->flags = 0; 582 stg->host6 = pg->host->addr; 583 stg->count = count; 584 for (i = 0; i < 64; i++) { 585 if (PG_IS_FREE_IDX(pg, i)) 586 continue; 587 st = &pg->states[i]; 588 ste->daddr.s_addr = st->u.s.faddr; 589 ste->dport = st->u.s.fport; 590 ste->aport = pg->aport + i; 591 ste->sport = st->u.s.lport; 592 ste->flags = st->flags; /* XXX filter flags */ 593 ste->idle = GET_AGE(st->timestamp); 594 ste++; 595 } 596 NAT64_UNLOCK(pg->host); 597 598 return (0); 599 } 600 601 static int 602 get_next_idx(struct nat64lsn_cfg *cfg, uint32_t *addr, uint8_t *nat_proto, 603 uint16_t *port) 604 { 605 606 if (*port < 65536 - NAT64_CHUNK_SIZE) { 607 *port += NAT64_CHUNK_SIZE; 608 return (0); 609 } 610 *port = 0; 611 612 if (*nat_proto < NAT_MAX_PROTO - 1) { 613 *nat_proto += 1; 614 return (0); 615 } 616 *nat_proto = 1; 617 618 if (*addr < cfg->pmask4) { 619 *addr += 1; 620 return (0); 621 } 622 623 /* End of space. */ 624 return (1); 625 } 626 627 #define PACK_IDX(addr, proto, port) \ 628 ((uint64_t)addr << 32) | ((uint32_t)port << 16) | (proto << 8) 629 #define UNPACK_IDX(idx, addr, proto, port) \ 630 (addr) = (uint32_t)((idx) >> 32); \ 631 (port) = (uint16_t)(((idx) >> 16) & 0xFFFF); \ 632 (proto) = (uint8_t)(((idx) >> 8) & 0xFF) 633 634 static struct nat64lsn_portgroup * 635 get_next_pg(struct nat64lsn_cfg *cfg, uint32_t *addr, uint8_t *nat_proto, 636 uint16_t *port) 637 { 638 struct nat64lsn_portgroup *pg; 639 uint64_t pre_pack, post_pack; 640 641 pg = NULL; 642 pre_pack = PACK_IDX(*addr, *nat_proto, *port); 643 for (;;) { 644 if (get_next_idx(cfg, addr, nat_proto, port) != 0) { 645 /* End of states */ 646 return (pg); 647 } 648 649 pg = GET_PORTGROUP(cfg, *addr, *nat_proto, *port); 650 if (pg != NULL) 651 break; 652 } 653 654 post_pack = PACK_IDX(*addr, *nat_proto, *port); 655 if (pre_pack == post_pack) 656 DPRINTF(DP_STATE, "XXX: PACK_IDX %u %d %d", 657 *addr, *nat_proto, *port); 658 return (pg); 659 } 660 661 static NAT64NOINLINE struct nat64lsn_portgroup * 662 get_first_pg(struct nat64lsn_cfg *cfg, uint32_t *addr, uint8_t *nat_proto, 663 uint16_t *port) 664 { 665 struct nat64lsn_portgroup *pg; 666 667 pg = GET_PORTGROUP(cfg, *addr, *nat_proto, *port); 668 if (pg == NULL) 669 pg = get_next_pg(cfg, addr, nat_proto, port); 670 671 return (pg); 672 } 673 674 /* 675 * Lists nat64lsn states. 676 * Data layout (v0)(current): 677 * Request: [ ipfw_obj_header ipfw_obj_data [ uint64_t ]] 678 * Reply: [ ipfw_obj_header ipfw_obj_data [ 679 * ipfw_nat64lsn_stg ipfw_nat64lsn_state x N] ] 680 * 681 * Returns 0 on success 682 */ 683 static int 684 nat64lsn_states(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 685 struct sockopt_data *sd) 686 { 687 ipfw_obj_header *oh; 688 ipfw_obj_data *od; 689 ipfw_nat64lsn_stg *stg; 690 struct nat64lsn_cfg *cfg; 691 struct nat64lsn_portgroup *pg, *pg_next; 692 uint64_t next_idx; 693 size_t sz; 694 uint32_t addr, states; 695 uint16_t port; 696 uint8_t nat_proto; 697 698 sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_data) + 699 sizeof(uint64_t); 700 /* Check minimum header size */ 701 if (sd->valsize < sz) 702 return (EINVAL); 703 704 oh = (ipfw_obj_header *)sd->kbuf; 705 od = (ipfw_obj_data *)(oh + 1); 706 if (od->head.type != IPFW_TLV_OBJDATA || 707 od->head.length != sz - sizeof(ipfw_obj_header)) 708 return (EINVAL); 709 710 next_idx = *(uint64_t *)(od + 1); 711 /* Translate index to the request position to start from */ 712 UNPACK_IDX(next_idx, addr, nat_proto, port); 713 if (nat_proto >= NAT_MAX_PROTO) 714 return (EINVAL); 715 if (nat_proto == 0 && addr != 0) 716 return (EINVAL); 717 718 IPFW_UH_RLOCK(ch); 719 cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); 720 if (cfg == NULL) { 721 IPFW_UH_RUNLOCK(ch); 722 return (ESRCH); 723 } 724 /* Fill in starting point */ 725 if (addr == 0) { 726 addr = cfg->prefix4; 727 nat_proto = 1; 728 port = 0; 729 } 730 if (addr < cfg->prefix4 || addr > cfg->pmask4) { 731 IPFW_UH_RUNLOCK(ch); 732 DPRINTF(DP_GENERIC | DP_STATE, "XXX: %ju %u %u", 733 (uintmax_t)next_idx, addr, cfg->pmask4); 734 return (EINVAL); 735 } 736 737 sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_data) + 738 sizeof(ipfw_nat64lsn_stg); 739 if (sd->valsize < sz) 740 return (ENOMEM); 741 oh = (ipfw_obj_header *)ipfw_get_sopt_space(sd, sz); 742 od = (ipfw_obj_data *)(oh + 1); 743 od->head.type = IPFW_TLV_OBJDATA; 744 od->head.length = sz - sizeof(ipfw_obj_header); 745 stg = (ipfw_nat64lsn_stg *)(od + 1); 746 747 pg = get_first_pg(cfg, &addr, &nat_proto, &port); 748 if (pg == NULL) { 749 /* No states */ 750 stg->next_idx = 0xFF; 751 stg->count = 0; 752 IPFW_UH_RUNLOCK(ch); 753 return (0); 754 } 755 states = 0; 756 pg_next = NULL; 757 while (pg != NULL) { 758 pg_next = get_next_pg(cfg, &addr, &nat_proto, &port); 759 if (pg_next == NULL) 760 stg->next_idx = 0xFF; 761 else 762 stg->next_idx = PACK_IDX(addr, nat_proto, port); 763 764 if (export_pg_states(cfg, pg, stg, sd) != 0) { 765 IPFW_UH_RUNLOCK(ch); 766 return (states == 0 ? ENOMEM: 0); 767 } 768 states += stg->count; 769 od->head.length += stg->count * sizeof(ipfw_nat64lsn_state); 770 sz += stg->count * sizeof(ipfw_nat64lsn_state); 771 if (pg_next != NULL) { 772 sz += sizeof(ipfw_nat64lsn_stg); 773 if (sd->valsize < sz) 774 break; 775 stg = (ipfw_nat64lsn_stg *)ipfw_get_sopt_space(sd, 776 sizeof(ipfw_nat64lsn_stg)); 777 } 778 pg = pg_next; 779 } 780 IPFW_UH_RUNLOCK(ch); 781 return (0); 782 } 783 784 static struct ipfw_sopt_handler scodes[] = { 785 { IP_FW_NAT64LSN_CREATE, 0, HDIR_BOTH, nat64lsn_create }, 786 { IP_FW_NAT64LSN_DESTROY,0, HDIR_SET, nat64lsn_destroy }, 787 { IP_FW_NAT64LSN_CONFIG, 0, HDIR_BOTH, nat64lsn_config }, 788 { IP_FW_NAT64LSN_LIST, 0, HDIR_GET, nat64lsn_list }, 789 { IP_FW_NAT64LSN_STATS, 0, HDIR_GET, nat64lsn_stats }, 790 { IP_FW_NAT64LSN_RESET_STATS,0, HDIR_SET, nat64lsn_reset_stats }, 791 { IP_FW_NAT64LSN_LIST_STATES,0, HDIR_GET, nat64lsn_states }, 792 }; 793 794 static int 795 nat64lsn_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 796 { 797 ipfw_insn *icmd; 798 799 icmd = cmd - 1; 800 if (icmd->opcode != O_EXTERNAL_ACTION || 801 icmd->arg1 != V_nat64lsn_eid) 802 return (1); 803 804 *puidx = cmd->arg1; 805 *ptype = 0; 806 return (0); 807 } 808 809 static void 810 nat64lsn_update_arg1(ipfw_insn *cmd, uint16_t idx) 811 { 812 813 cmd->arg1 = idx; 814 } 815 816 static int 817 nat64lsn_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, 818 struct named_object **pno) 819 { 820 int err; 821 822 err = ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti, 823 IPFW_TLV_NAT64LSN_NAME, pno); 824 return (err); 825 } 826 827 static struct named_object * 828 nat64lsn_findbykidx(struct ip_fw_chain *ch, uint16_t idx) 829 { 830 struct namedobj_instance *ni; 831 struct named_object *no; 832 833 IPFW_UH_WLOCK_ASSERT(ch); 834 ni = CHAIN_TO_SRV(ch); 835 no = ipfw_objhash_lookup_kidx(ni, idx); 836 KASSERT(no != NULL, ("NAT64LSN with index %d not found", idx)); 837 838 return (no); 839 } 840 841 static int 842 nat64lsn_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, 843 enum ipfw_sets_cmd cmd) 844 { 845 846 return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NAT64LSN_NAME, 847 set, new_set, cmd)); 848 } 849 850 static struct opcode_obj_rewrite opcodes[] = { 851 { 852 .opcode = O_EXTERNAL_INSTANCE, 853 .etlv = IPFW_TLV_EACTION /* just show it isn't table */, 854 .classifier = nat64lsn_classify, 855 .update = nat64lsn_update_arg1, 856 .find_byname = nat64lsn_findbyname, 857 .find_bykidx = nat64lsn_findbykidx, 858 .manage_sets = nat64lsn_manage_sets, 859 }, 860 }; 861 862 static int 863 destroy_config_cb(struct namedobj_instance *ni, struct named_object *no, 864 void *arg) 865 { 866 struct nat64lsn_cfg *cfg; 867 struct ip_fw_chain *ch; 868 869 ch = (struct ip_fw_chain *)arg; 870 cfg = (struct nat64lsn_cfg *)SRV_OBJECT(ch, no->kidx); 871 SRV_OBJECT(ch, no->kidx) = NULL; 872 nat64lsn_detach_config(ch, cfg); 873 nat64lsn_destroy_instance(cfg); 874 return (0); 875 } 876 877 int 878 nat64lsn_init(struct ip_fw_chain *ch, int first) 879 { 880 881 if (first != 0) 882 nat64lsn_init_internal(); 883 V_nat64lsn_eid = ipfw_add_eaction(ch, ipfw_nat64lsn, "nat64lsn"); 884 if (V_nat64lsn_eid == 0) 885 return (ENXIO); 886 IPFW_ADD_SOPT_HANDLER(first, scodes); 887 IPFW_ADD_OBJ_REWRITER(first, opcodes); 888 return (0); 889 } 890 891 void 892 nat64lsn_uninit(struct ip_fw_chain *ch, int last) 893 { 894 895 IPFW_DEL_OBJ_REWRITER(last, opcodes); 896 IPFW_DEL_SOPT_HANDLER(last, scodes); 897 ipfw_del_eaction(ch, V_nat64lsn_eid); 898 /* 899 * Since we already have deregistered external action, 900 * our named objects become unaccessible via rules, because 901 * all rules were truncated by ipfw_del_eaction(). 902 * So, we can unlink and destroy our named objects without holding 903 * IPFW_WLOCK(). 904 */ 905 IPFW_UH_WLOCK(ch); 906 ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), destroy_config_cb, ch, 907 IPFW_TLV_NAT64LSN_NAME); 908 V_nat64lsn_eid = 0; 909 IPFW_UH_WUNLOCK(ch); 910 if (last != 0) 911 nat64lsn_uninit_internal(); 912 } 913 914