nat64clat_control.c revision 345264
1345264Sae/*- 2345264Sae * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3345264Sae * 4345264Sae * Copyright (c) 2019 Yandex LLC 5345264Sae * Copyright (c) 2019 Andrey V. Elsukov <ae@FreeBSD.org> 6345264Sae * Copyright (c) 2019 Boris N. Lytochkin <lytboris@gmail.com> 7345264Sae * 8345264Sae * Redistribution and use in source and binary forms, with or without 9345264Sae * modification, are permitted provided that the following conditions 10345264Sae * are met: 11345264Sae * 12345264Sae * 1. Redistributions of source code must retain the above copyright 13345264Sae * notice, this list of conditions and the following disclaimer. 14345264Sae * 2. Redistributions in binary form must reproduce the above copyright 15345264Sae * notice, this list of conditions and the following disclaimer in the 16345264Sae * documentation and/or other materials provided with the distribution. 17345264Sae * 18345264Sae * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19345264Sae * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20345264Sae * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21345264Sae * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22345264Sae * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23345264Sae * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24345264Sae * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25345264Sae * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26345264Sae * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27345264Sae * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28345264Sae */ 29345264Sae 30345264Sae#include <sys/cdefs.h> 31345264Sae__FBSDID("$FreeBSD: head/sys/netpfil/ipfw/nat64/nat64clat_control.c 345264 2019-03-18 11:44:53Z ae $"); 32345264Sae 33345264Sae#include <sys/param.h> 34345264Sae#include <sys/systm.h> 35345264Sae#include <sys/counter.h> 36345264Sae#include <sys/errno.h> 37345264Sae#include <sys/kernel.h> 38345264Sae#include <sys/lock.h> 39345264Sae#include <sys/malloc.h> 40345264Sae#include <sys/mbuf.h> 41345264Sae#include <sys/module.h> 42345264Sae#include <sys/rmlock.h> 43345264Sae#include <sys/rwlock.h> 44345264Sae#include <sys/socket.h> 45345264Sae#include <sys/sockopt.h> 46345264Sae#include <sys/syslog.h> 47345264Sae#include <sys/sysctl.h> 48345264Sae 49345264Sae#include <net/if.h> 50345264Sae#include <net/if_var.h> 51345264Sae#include <net/route.h> 52345264Sae#include <net/vnet.h> 53345264Sae 54345264Sae#include <netinet/in.h> 55345264Sae#include <netinet/ip_var.h> 56345264Sae#include <netinet/ip_fw.h> 57345264Sae#include <netinet6/in6_var.h> 58345264Sae#include <netinet6/ip6_var.h> 59345264Sae#include <netinet6/ip_fw_nat64.h> 60345264Sae 61345264Sae#include <netpfil/ipfw/ip_fw_private.h> 62345264Sae 63345264Sae#include "nat64clat.h" 64345264Sae 65345264SaeVNET_DEFINE(uint16_t, nat64clat_eid) = 0; 66345264Sae 67345264Saestatic struct nat64clat_cfg *nat64clat_alloc_config(const char *name, 68345264Sae uint8_t set); 69345264Saestatic void nat64clat_free_config(struct nat64clat_cfg *cfg); 70345264Saestatic struct nat64clat_cfg *nat64clat_find(struct namedobj_instance *ni, 71345264Sae const char *name, uint8_t set); 72345264Sae 73345264Saestatic struct nat64clat_cfg * 74345264Saenat64clat_alloc_config(const char *name, uint8_t set) 75345264Sae{ 76345264Sae struct nat64clat_cfg *cfg; 77345264Sae 78345264Sae cfg = malloc(sizeof(struct nat64clat_cfg), M_IPFW, M_WAITOK | M_ZERO); 79345264Sae COUNTER_ARRAY_ALLOC(cfg->base.stats.cnt, NAT64STATS, M_WAITOK); 80345264Sae cfg->no.name = cfg->name; 81345264Sae cfg->no.etlv = IPFW_TLV_NAT64CLAT_NAME; 82345264Sae cfg->no.set = set; 83345264Sae strlcpy(cfg->name, name, sizeof(cfg->name)); 84345264Sae return (cfg); 85345264Sae} 86345264Sae 87345264Saestatic void 88345264Saenat64clat_free_config(struct nat64clat_cfg *cfg) 89345264Sae{ 90345264Sae 91345264Sae COUNTER_ARRAY_FREE(cfg->base.stats.cnt, NAT64STATS); 92345264Sae free(cfg, M_IPFW); 93345264Sae} 94345264Sae 95345264Saestatic void 96345264Saenat64clat_export_config(struct ip_fw_chain *ch, struct nat64clat_cfg *cfg, 97345264Sae ipfw_nat64clat_cfg *uc) 98345264Sae{ 99345264Sae uc->plat_prefix = cfg->base.plat_prefix; 100345264Sae uc->plat_plen = cfg->base.plat_plen; 101345264Sae uc->clat_prefix = cfg->base.clat_prefix; 102345264Sae uc->clat_plen = cfg->base.clat_plen; 103345264Sae uc->flags = cfg->base.flags & NAT64CLAT_FLAGSMASK; 104345264Sae uc->set = cfg->no.set; 105345264Sae strlcpy(uc->name, cfg->no.name, sizeof(uc->name)); 106345264Sae} 107345264Sae 108345264Saestruct nat64clat_dump_arg { 109345264Sae struct ip_fw_chain *ch; 110345264Sae struct sockopt_data *sd; 111345264Sae}; 112345264Sae 113345264Saestatic int 114345264Saeexport_config_cb(struct namedobj_instance *ni, struct named_object *no, 115345264Sae void *arg) 116345264Sae{ 117345264Sae struct nat64clat_dump_arg *da = (struct nat64clat_dump_arg *)arg; 118345264Sae ipfw_nat64clat_cfg *uc; 119345264Sae 120345264Sae uc = (ipfw_nat64clat_cfg *)ipfw_get_sopt_space(da->sd, sizeof(*uc)); 121345264Sae nat64clat_export_config(da->ch, (struct nat64clat_cfg *)no, uc); 122345264Sae return (0); 123345264Sae} 124345264Sae 125345264Saestatic struct nat64clat_cfg * 126345264Saenat64clat_find(struct namedobj_instance *ni, const char *name, uint8_t set) 127345264Sae{ 128345264Sae struct nat64clat_cfg *cfg; 129345264Sae 130345264Sae cfg = (struct nat64clat_cfg *)ipfw_objhash_lookup_name_type(ni, set, 131345264Sae IPFW_TLV_NAT64CLAT_NAME, name); 132345264Sae 133345264Sae return (cfg); 134345264Sae} 135345264Sae 136345264Sae/* 137345264Sae * Creates new consumer-side nat64 translator instance. 138345264Sae * Data layout (v0)(current): 139345264Sae * Request: [ ipfw_obj_lheader ipfw_nat64clat_cfg ] 140345264Sae * 141345264Sae * Returns 0 on success 142345264Sae */ 143345264Saestatic int 144345264Saenat64clat_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 145345264Sae struct sockopt_data *sd) 146345264Sae{ 147345264Sae ipfw_obj_lheader *olh; 148345264Sae ipfw_nat64clat_cfg *uc; 149345264Sae struct namedobj_instance *ni; 150345264Sae struct nat64clat_cfg *cfg; 151345264Sae 152345264Sae if (sd->valsize != sizeof(*olh) + sizeof(*uc)) 153345264Sae return (EINVAL); 154345264Sae 155345264Sae olh = (ipfw_obj_lheader *)sd->kbuf; 156345264Sae uc = (ipfw_nat64clat_cfg *)(olh + 1); 157345264Sae 158345264Sae if (ipfw_check_object_name_generic(uc->name) != 0) 159345264Sae return (EINVAL); 160345264Sae 161345264Sae if (uc->set >= IPFW_MAX_SETS || 162345264Sae nat64_check_prefix6(&uc->plat_prefix, uc->plat_plen) != 0 || 163345264Sae nat64_check_prefix6(&uc->clat_prefix, uc->clat_plen) != 0) 164345264Sae return (EINVAL); 165345264Sae 166345264Sae ni = CHAIN_TO_SRV(ch); 167345264Sae 168345264Sae IPFW_UH_RLOCK(ch); 169345264Sae if (nat64clat_find(ni, uc->name, uc->set) != NULL) { 170345264Sae IPFW_UH_RUNLOCK(ch); 171345264Sae return (EEXIST); 172345264Sae } 173345264Sae IPFW_UH_RUNLOCK(ch); 174345264Sae 175345264Sae cfg = nat64clat_alloc_config(uc->name, uc->set); 176345264Sae cfg->base.plat_prefix = uc->plat_prefix; 177345264Sae cfg->base.plat_plen = uc->plat_plen; 178345264Sae cfg->base.clat_prefix = uc->clat_prefix; 179345264Sae cfg->base.clat_plen = uc->clat_plen; 180345264Sae cfg->base.flags = (uc->flags & NAT64CLAT_FLAGSMASK) | 181345264Sae NAT64_CLATPFX | NAT64_PLATPFX; 182345264Sae if (IN6_IS_ADDR_WKPFX(&cfg->base.plat_prefix)) 183345264Sae cfg->base.flags |= NAT64_WKPFX; 184345264Sae 185345264Sae IPFW_UH_WLOCK(ch); 186345264Sae 187345264Sae if (nat64clat_find(ni, uc->name, uc->set) != NULL) { 188345264Sae IPFW_UH_WUNLOCK(ch); 189345264Sae nat64clat_free_config(cfg); 190345264Sae return (EEXIST); 191345264Sae } 192345264Sae 193345264Sae if (ipfw_objhash_alloc_idx(ni, &cfg->no.kidx) != 0) { 194345264Sae IPFW_UH_WUNLOCK(ch); 195345264Sae nat64clat_free_config(cfg); 196345264Sae return (ENOSPC); 197345264Sae } 198345264Sae ipfw_objhash_add(CHAIN_TO_SRV(ch), &cfg->no); 199345264Sae /* Okay, let's link data */ 200345264Sae SRV_OBJECT(ch, cfg->no.kidx) = cfg; 201345264Sae IPFW_UH_WUNLOCK(ch); 202345264Sae 203345264Sae return (0); 204345264Sae} 205345264Sae 206345264Sae/* 207345264Sae * Change existing nat64clat instance configuration. 208345264Sae * Data layout (v0)(current): 209345264Sae * Request: [ ipfw_obj_header ipfw_nat64clat_cfg ] 210345264Sae * Reply: [ ipfw_obj_header ipfw_nat64clat_cfg ] 211345264Sae * 212345264Sae * Returns 0 on success 213345264Sae */ 214345264Saestatic int 215345264Saenat64clat_config(struct ip_fw_chain *ch, ip_fw3_opheader *op, 216345264Sae struct sockopt_data *sd) 217345264Sae{ 218345264Sae ipfw_obj_header *oh; 219345264Sae ipfw_nat64clat_cfg *uc; 220345264Sae struct nat64clat_cfg *cfg; 221345264Sae struct namedobj_instance *ni; 222345264Sae uint32_t flags; 223345264Sae 224345264Sae if (sd->valsize != sizeof(*oh) + sizeof(*uc)) 225345264Sae return (EINVAL); 226345264Sae 227345264Sae oh = (ipfw_obj_header *)ipfw_get_sopt_space(sd, 228345264Sae sizeof(*oh) + sizeof(*uc)); 229345264Sae uc = (ipfw_nat64clat_cfg *)(oh + 1); 230345264Sae 231345264Sae if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 || 232345264Sae oh->ntlv.set >= IPFW_MAX_SETS) 233345264Sae return (EINVAL); 234345264Sae 235345264Sae ni = CHAIN_TO_SRV(ch); 236345264Sae if (sd->sopt->sopt_dir == SOPT_GET) { 237345264Sae IPFW_UH_RLOCK(ch); 238345264Sae cfg = nat64clat_find(ni, oh->ntlv.name, oh->ntlv.set); 239345264Sae if (cfg == NULL) { 240345264Sae IPFW_UH_RUNLOCK(ch); 241345264Sae return (ENOENT); 242345264Sae } 243345264Sae nat64clat_export_config(ch, cfg, uc); 244345264Sae IPFW_UH_RUNLOCK(ch); 245345264Sae return (0); 246345264Sae } 247345264Sae 248345264Sae IPFW_UH_WLOCK(ch); 249345264Sae cfg = nat64clat_find(ni, oh->ntlv.name, oh->ntlv.set); 250345264Sae if (cfg == NULL) { 251345264Sae IPFW_UH_WUNLOCK(ch); 252345264Sae return (ENOENT); 253345264Sae } 254345264Sae 255345264Sae /* 256345264Sae * For now allow to change only following values: 257345264Sae * plat_prefix, plat_plen, clat_prefix, clat_plen, flags. 258345264Sae */ 259345264Sae flags = 0; 260345264Sae if (uc->plat_plen != cfg->base.plat_plen || 261345264Sae !IN6_ARE_ADDR_EQUAL(&uc->plat_prefix, &cfg->base.plat_prefix)) { 262345264Sae if (nat64_check_prefix6(&uc->plat_prefix, uc->plat_plen) != 0) { 263345264Sae IPFW_UH_WUNLOCK(ch); 264345264Sae return (EINVAL); 265345264Sae } 266345264Sae flags |= NAT64_PLATPFX; 267345264Sae } 268345264Sae 269345264Sae if (uc->clat_plen != cfg->base.clat_plen || 270345264Sae !IN6_ARE_ADDR_EQUAL(&uc->clat_prefix, &cfg->base.clat_prefix)) { 271345264Sae if (nat64_check_prefix6(&uc->clat_prefix, uc->clat_plen) != 0) { 272345264Sae IPFW_UH_WUNLOCK(ch); 273345264Sae return (EINVAL); 274345264Sae } 275345264Sae flags |= NAT64_CLATPFX; 276345264Sae } 277345264Sae 278345264Sae if (flags != 0) { 279345264Sae IPFW_WLOCK(ch); 280345264Sae if (flags & NAT64_PLATPFX) { 281345264Sae cfg->base.plat_prefix = uc->plat_prefix; 282345264Sae cfg->base.plat_plen = uc->plat_plen; 283345264Sae } 284345264Sae if (flags & NAT64_CLATPFX) { 285345264Sae cfg->base.clat_prefix = uc->clat_prefix; 286345264Sae cfg->base.clat_plen = uc->clat_plen; 287345264Sae } 288345264Sae IPFW_WUNLOCK(ch); 289345264Sae } 290345264Sae 291345264Sae cfg->base.flags &= ~NAT64CLAT_FLAGSMASK; 292345264Sae cfg->base.flags |= uc->flags & NAT64CLAT_FLAGSMASK; 293345264Sae 294345264Sae IPFW_UH_WUNLOCK(ch); 295345264Sae return (0); 296345264Sae} 297345264Sae 298345264Saestatic void 299345264Saenat64clat_detach_config(struct ip_fw_chain *ch, struct nat64clat_cfg *cfg) 300345264Sae{ 301345264Sae 302345264Sae IPFW_UH_WLOCK_ASSERT(ch); 303345264Sae 304345264Sae ipfw_objhash_del(CHAIN_TO_SRV(ch), &cfg->no); 305345264Sae ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), cfg->no.kidx); 306345264Sae} 307345264Sae 308345264Sae/* 309345264Sae * Destroys nat64 instance. 310345264Sae * Data layout (v0)(current): 311345264Sae * Request: [ ipfw_obj_header ] 312345264Sae * 313345264Sae * Returns 0 on success 314345264Sae */ 315345264Saestatic int 316345264Saenat64clat_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 317345264Sae struct sockopt_data *sd) 318345264Sae{ 319345264Sae ipfw_obj_header *oh; 320345264Sae struct nat64clat_cfg *cfg; 321345264Sae 322345264Sae if (sd->valsize != sizeof(*oh)) 323345264Sae return (EINVAL); 324345264Sae 325345264Sae oh = (ipfw_obj_header *)sd->kbuf; 326345264Sae if (ipfw_check_object_name_generic(oh->ntlv.name) != 0) 327345264Sae return (EINVAL); 328345264Sae 329345264Sae IPFW_UH_WLOCK(ch); 330345264Sae cfg = nat64clat_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); 331345264Sae if (cfg == NULL) { 332345264Sae IPFW_UH_WUNLOCK(ch); 333345264Sae return (ENOENT); 334345264Sae } 335345264Sae if (cfg->no.refcnt > 0) { 336345264Sae IPFW_UH_WUNLOCK(ch); 337345264Sae return (EBUSY); 338345264Sae } 339345264Sae 340345264Sae ipfw_reset_eaction_instance(ch, V_nat64clat_eid, cfg->no.kidx); 341345264Sae SRV_OBJECT(ch, cfg->no.kidx) = NULL; 342345264Sae nat64clat_detach_config(ch, cfg); 343345264Sae IPFW_UH_WUNLOCK(ch); 344345264Sae 345345264Sae nat64clat_free_config(cfg); 346345264Sae return (0); 347345264Sae} 348345264Sae 349345264Sae/* 350345264Sae * Lists all nat64clat instances currently available in kernel. 351345264Sae * Data layout (v0)(current): 352345264Sae * Request: [ ipfw_obj_lheader ] 353345264Sae * Reply: [ ipfw_obj_lheader ipfw_nat64clat_cfg x N ] 354345264Sae * 355345264Sae * Returns 0 on success 356345264Sae */ 357345264Saestatic int 358345264Saenat64clat_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3, 359345264Sae struct sockopt_data *sd) 360345264Sae{ 361345264Sae ipfw_obj_lheader *olh; 362345264Sae struct nat64clat_dump_arg da; 363345264Sae 364345264Sae /* Check minimum header size */ 365345264Sae if (sd->valsize < sizeof(ipfw_obj_lheader)) 366345264Sae return (EINVAL); 367345264Sae 368345264Sae olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh)); 369345264Sae 370345264Sae IPFW_UH_RLOCK(ch); 371345264Sae olh->count = ipfw_objhash_count_type(CHAIN_TO_SRV(ch), 372345264Sae IPFW_TLV_NAT64CLAT_NAME); 373345264Sae olh->objsize = sizeof(ipfw_nat64clat_cfg); 374345264Sae olh->size = sizeof(*olh) + olh->count * olh->objsize; 375345264Sae 376345264Sae if (sd->valsize < olh->size) { 377345264Sae IPFW_UH_RUNLOCK(ch); 378345264Sae return (ENOMEM); 379345264Sae } 380345264Sae memset(&da, 0, sizeof(da)); 381345264Sae da.ch = ch; 382345264Sae da.sd = sd; 383345264Sae ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), export_config_cb, 384345264Sae &da, IPFW_TLV_NAT64CLAT_NAME); 385345264Sae IPFW_UH_RUNLOCK(ch); 386345264Sae 387345264Sae return (0); 388345264Sae} 389345264Sae 390345264Sae#define __COPY_STAT_FIELD(_cfg, _stats, _field) \ 391345264Sae (_stats)->_field = NAT64STAT_FETCH(&(_cfg)->base.stats, _field) 392345264Saestatic void 393345264Saeexport_stats(struct ip_fw_chain *ch, struct nat64clat_cfg *cfg, 394345264Sae struct ipfw_nat64clat_stats *stats) 395345264Sae{ 396345264Sae 397345264Sae __COPY_STAT_FIELD(cfg, stats, opcnt64); 398345264Sae __COPY_STAT_FIELD(cfg, stats, opcnt46); 399345264Sae __COPY_STAT_FIELD(cfg, stats, ofrags); 400345264Sae __COPY_STAT_FIELD(cfg, stats, ifrags); 401345264Sae __COPY_STAT_FIELD(cfg, stats, oerrors); 402345264Sae __COPY_STAT_FIELD(cfg, stats, noroute4); 403345264Sae __COPY_STAT_FIELD(cfg, stats, noroute6); 404345264Sae __COPY_STAT_FIELD(cfg, stats, noproto); 405345264Sae __COPY_STAT_FIELD(cfg, stats, nomem); 406345264Sae __COPY_STAT_FIELD(cfg, stats, dropped); 407345264Sae} 408345264Sae 409345264Sae/* 410345264Sae * Get nat64clat statistics. 411345264Sae * Data layout (v0)(current): 412345264Sae * Request: [ ipfw_obj_header ] 413345264Sae * Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ]] 414345264Sae * 415345264Sae * Returns 0 on success 416345264Sae */ 417345264Saestatic int 418345264Saenat64clat_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, 419345264Sae struct sockopt_data *sd) 420345264Sae{ 421345264Sae struct ipfw_nat64clat_stats stats; 422345264Sae struct nat64clat_cfg *cfg; 423345264Sae ipfw_obj_header *oh; 424345264Sae ipfw_obj_ctlv *ctlv; 425345264Sae size_t sz; 426345264Sae 427345264Sae sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ctlv) + sizeof(stats); 428345264Sae if (sd->valsize % sizeof(uint64_t)) 429345264Sae return (EINVAL); 430345264Sae if (sd->valsize < sz) 431345264Sae return (ENOMEM); 432345264Sae oh = (ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); 433345264Sae if (oh == NULL) 434345264Sae return (EINVAL); 435345264Sae memset(&stats, 0, sizeof(stats)); 436345264Sae 437345264Sae IPFW_UH_RLOCK(ch); 438345264Sae cfg = nat64clat_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); 439345264Sae if (cfg == NULL) { 440345264Sae IPFW_UH_RUNLOCK(ch); 441345264Sae return (ENOENT); 442345264Sae } 443345264Sae export_stats(ch, cfg, &stats); 444345264Sae IPFW_UH_RUNLOCK(ch); 445345264Sae 446345264Sae ctlv = (ipfw_obj_ctlv *)(oh + 1); 447345264Sae memset(ctlv, 0, sizeof(*ctlv)); 448345264Sae ctlv->head.type = IPFW_TLV_COUNTERS; 449345264Sae ctlv->head.length = sz - sizeof(ipfw_obj_header); 450345264Sae ctlv->count = sizeof(stats) / sizeof(uint64_t); 451345264Sae ctlv->objsize = sizeof(uint64_t); 452345264Sae ctlv->version = IPFW_NAT64_VERSION; 453345264Sae memcpy(ctlv + 1, &stats, sizeof(stats)); 454345264Sae return (0); 455345264Sae} 456345264Sae 457345264Sae/* 458345264Sae * Reset nat64clat statistics. 459345264Sae * Data layout (v0)(current): 460345264Sae * Request: [ ipfw_obj_header ] 461345264Sae * 462345264Sae * Returns 0 on success 463345264Sae */ 464345264Saestatic int 465345264Saenat64clat_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, 466345264Sae struct sockopt_data *sd) 467345264Sae{ 468345264Sae struct nat64clat_cfg *cfg; 469345264Sae ipfw_obj_header *oh; 470345264Sae 471345264Sae if (sd->valsize != sizeof(*oh)) 472345264Sae return (EINVAL); 473345264Sae oh = (ipfw_obj_header *)sd->kbuf; 474345264Sae if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 || 475345264Sae oh->ntlv.set >= IPFW_MAX_SETS) 476345264Sae return (EINVAL); 477345264Sae 478345264Sae IPFW_UH_WLOCK(ch); 479345264Sae cfg = nat64clat_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); 480345264Sae if (cfg == NULL) { 481345264Sae IPFW_UH_WUNLOCK(ch); 482345264Sae return (ENOENT); 483345264Sae } 484345264Sae COUNTER_ARRAY_ZERO(cfg->base.stats.cnt, NAT64STATS); 485345264Sae IPFW_UH_WUNLOCK(ch); 486345264Sae return (0); 487345264Sae} 488345264Sae 489345264Saestatic struct ipfw_sopt_handler scodes[] = { 490345264Sae 491345264Sae { IP_FW_NAT64CLAT_CREATE, 0, HDIR_SET, nat64clat_create }, 492345264Sae { IP_FW_NAT64CLAT_DESTROY,0, HDIR_SET, nat64clat_destroy }, 493345264Sae { IP_FW_NAT64CLAT_CONFIG, 0, HDIR_BOTH, nat64clat_config }, 494345264Sae { IP_FW_NAT64CLAT_LIST, 0, HDIR_GET, nat64clat_list }, 495345264Sae { IP_FW_NAT64CLAT_STATS, 0, HDIR_GET, nat64clat_stats }, 496345264Sae { IP_FW_NAT64CLAT_RESET_STATS,0, HDIR_SET, nat64clat_reset_stats }, 497345264Sae}; 498345264Sae 499345264Saestatic int 500345264Saenat64clat_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 501345264Sae{ 502345264Sae ipfw_insn *icmd; 503345264Sae 504345264Sae icmd = cmd - 1; 505345264Sae if (icmd->opcode != O_EXTERNAL_ACTION || 506345264Sae icmd->arg1 != V_nat64clat_eid) 507345264Sae return (1); 508345264Sae 509345264Sae *puidx = cmd->arg1; 510345264Sae *ptype = 0; 511345264Sae return (0); 512345264Sae} 513345264Sae 514345264Saestatic void 515345264Saenat64clat_update_arg1(ipfw_insn *cmd, uint16_t idx) 516345264Sae{ 517345264Sae 518345264Sae cmd->arg1 = idx; 519345264Sae} 520345264Sae 521345264Saestatic int 522345264Saenat64clat_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, 523345264Sae struct named_object **pno) 524345264Sae{ 525345264Sae int err; 526345264Sae 527345264Sae err = ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti, 528345264Sae IPFW_TLV_NAT64CLAT_NAME, pno); 529345264Sae return (err); 530345264Sae} 531345264Sae 532345264Saestatic struct named_object * 533345264Saenat64clat_findbykidx(struct ip_fw_chain *ch, uint16_t idx) 534345264Sae{ 535345264Sae struct namedobj_instance *ni; 536345264Sae struct named_object *no; 537345264Sae 538345264Sae IPFW_UH_WLOCK_ASSERT(ch); 539345264Sae ni = CHAIN_TO_SRV(ch); 540345264Sae no = ipfw_objhash_lookup_kidx(ni, idx); 541345264Sae KASSERT(no != NULL, ("NAT with index %d not found", idx)); 542345264Sae 543345264Sae return (no); 544345264Sae} 545345264Sae 546345264Saestatic int 547345264Saenat64clat_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, 548345264Sae enum ipfw_sets_cmd cmd) 549345264Sae{ 550345264Sae 551345264Sae return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NAT64CLAT_NAME, 552345264Sae set, new_set, cmd)); 553345264Sae} 554345264Sae 555345264Saestatic struct opcode_obj_rewrite opcodes[] = { 556345264Sae { 557345264Sae .opcode = O_EXTERNAL_INSTANCE, 558345264Sae .etlv = IPFW_TLV_EACTION /* just show it isn't table */, 559345264Sae .classifier = nat64clat_classify, 560345264Sae .update = nat64clat_update_arg1, 561345264Sae .find_byname = nat64clat_findbyname, 562345264Sae .find_bykidx = nat64clat_findbykidx, 563345264Sae .manage_sets = nat64clat_manage_sets, 564345264Sae }, 565345264Sae}; 566345264Sae 567345264Saestatic int 568345264Saedestroy_config_cb(struct namedobj_instance *ni, struct named_object *no, 569345264Sae void *arg) 570345264Sae{ 571345264Sae struct nat64clat_cfg *cfg; 572345264Sae struct ip_fw_chain *ch; 573345264Sae 574345264Sae ch = (struct ip_fw_chain *)arg; 575345264Sae cfg = (struct nat64clat_cfg *)SRV_OBJECT(ch, no->kidx); 576345264Sae SRV_OBJECT(ch, no->kidx) = NULL; 577345264Sae nat64clat_detach_config(ch, cfg); 578345264Sae nat64clat_free_config(cfg); 579345264Sae return (0); 580345264Sae} 581345264Sae 582345264Saeint 583345264Saenat64clat_init(struct ip_fw_chain *ch, int first) 584345264Sae{ 585345264Sae 586345264Sae V_nat64clat_eid = ipfw_add_eaction(ch, ipfw_nat64clat, "nat64clat"); 587345264Sae if (V_nat64clat_eid == 0) 588345264Sae return (ENXIO); 589345264Sae IPFW_ADD_SOPT_HANDLER(first, scodes); 590345264Sae IPFW_ADD_OBJ_REWRITER(first, opcodes); 591345264Sae return (0); 592345264Sae} 593345264Sae 594345264Saevoid 595345264Saenat64clat_uninit(struct ip_fw_chain *ch, int last) 596345264Sae{ 597345264Sae 598345264Sae IPFW_DEL_OBJ_REWRITER(last, opcodes); 599345264Sae IPFW_DEL_SOPT_HANDLER(last, scodes); 600345264Sae ipfw_del_eaction(ch, V_nat64clat_eid); 601345264Sae /* 602345264Sae * Since we already have deregistered external action, 603345264Sae * our named objects become unaccessible via rules, because 604345264Sae * all rules were truncated by ipfw_del_eaction(). 605345264Sae * So, we can unlink and destroy our named objects without holding 606345264Sae * IPFW_WLOCK(). 607345264Sae */ 608345264Sae IPFW_UH_WLOCK(ch); 609345264Sae ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), destroy_config_cb, ch, 610345264Sae IPFW_TLV_NAT64CLAT_NAME); 611345264Sae V_nat64clat_eid = 0; 612345264Sae IPFW_UH_WUNLOCK(ch); 613345264Sae} 614345264Sae 615