Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/ipfw/nat64/nat64lsn_control.c
| Show First 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
| #include <netinet/ip_var.h> | #include <netinet/ip_var.h> | ||||
| #include <netinet/ip_fw.h> | #include <netinet/ip_fw.h> | ||||
| #include <netinet6/ip_fw_nat64.h> | #include <netinet6/ip_fw_nat64.h> | ||||
| #include <netpfil/ipfw/ip_fw_private.h> | #include <netpfil/ipfw/ip_fw_private.h> | ||||
| #include "nat64lsn.h" | #include "nat64lsn.h" | ||||
| VNET_DEFINE(uint16_t, nat64lsn_eid) = 0; | VNET_DEFINE(uint32_t, nat64lsn_eid) = 0; | ||||
| static struct nat64lsn_cfg * | static struct nat64lsn_instance * | ||||
| nat64lsn_find(struct namedobj_instance *ni, const char *name, uint8_t set) | nat64lsn_find(struct namedobj_instance *ni, const char *name, uint8_t set) | ||||
| { | { | ||||
| struct nat64lsn_cfg *cfg; | struct named_object *no; | ||||
| cfg = (struct nat64lsn_cfg *)ipfw_objhash_lookup_name_type(ni, set, | no = ipfw_objhash_lookup_name_type(ni, set, | ||||
| IPFW_TLV_NAT64LSN_NAME, name); | IPFW_TLV_NAT64LSN_NAME, name); | ||||
| if (no == NULL) | |||||
| return (cfg); | return (NULL); | ||||
| return (__containerof(no, struct nat64lsn_instance, no)); | |||||
| } | } | ||||
| static void | static void | ||||
| nat64lsn_default_config(ipfw_nat64lsn_cfg *uc) | nat64lsn_default_config(ipfw_nat64lsn_cfg *uc) | ||||
| { | { | ||||
| if (uc->jmaxlen == 0) | if (uc->jmaxlen == 0) | ||||
| uc->jmaxlen = NAT64LSN_JMAXLEN; | uc->jmaxlen = NAT64LSN_JMAXLEN; | ||||
| Show All 30 Lines | |||||
| * Returns 0 on success | * Returns 0 on success | ||||
| */ | */ | ||||
| static int | static int | ||||
| nat64lsn_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | nat64lsn_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | ||||
| struct sockopt_data *sd) | struct sockopt_data *sd) | ||||
| { | { | ||||
| ipfw_obj_lheader *olh; | ipfw_obj_lheader *olh; | ||||
| ipfw_nat64lsn_cfg *uc; | ipfw_nat64lsn_cfg *uc; | ||||
| struct nat64lsn_instance *i; | |||||
| struct nat64lsn_cfg *cfg; | struct nat64lsn_cfg *cfg; | ||||
| struct namedobj_instance *ni; | struct namedobj_instance *ni; | ||||
| uint32_t addr4, mask4; | uint32_t addr4, mask4; | ||||
| if (sd->valsize != sizeof(*olh) + sizeof(*uc)) | if (sd->valsize != sizeof(*olh) + sizeof(*uc)) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| olh = (ipfw_obj_lheader *)sd->kbuf; | olh = (ipfw_obj_lheader *)sd->kbuf; | ||||
| Show All 29 Lines | nat64lsn_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | ||||
| ni = CHAIN_TO_SRV(ch); | ni = CHAIN_TO_SRV(ch); | ||||
| IPFW_UH_RLOCK(ch); | IPFW_UH_RLOCK(ch); | ||||
| if (nat64lsn_find(ni, uc->name, uc->set) != NULL) { | if (nat64lsn_find(ni, uc->name, uc->set) != NULL) { | ||||
| IPFW_UH_RUNLOCK(ch); | IPFW_UH_RUNLOCK(ch); | ||||
| return (EEXIST); | return (EEXIST); | ||||
| } | } | ||||
| IPFW_UH_RUNLOCK(ch); | IPFW_UH_RUNLOCK(ch); | ||||
| cfg = nat64lsn_init_instance(ch, addr4, uc->plen4); | i = malloc(sizeof(struct nat64lsn_instance), M_NAT64LSN, | ||||
| strlcpy(cfg->name, uc->name, sizeof(cfg->name)); | M_WAITOK | M_ZERO); | ||||
| cfg->no.name = cfg->name; | strlcpy(i->name, uc->name, sizeof(i->name)); | ||||
| cfg->no.etlv = IPFW_TLV_NAT64LSN_NAME; | i->no.name = i->name; | ||||
| cfg->no.set = uc->set; | i->no.etlv = IPFW_TLV_NAT64LSN_NAME; | ||||
| i->no.set = uc->set; | |||||
| cfg = nat64lsn_init_config(ch, addr4, uc->plen4); | |||||
| cfg->base.plat_prefix = uc->prefix6; | cfg->base.plat_prefix = uc->prefix6; | ||||
| cfg->base.plat_plen = uc->plen6; | cfg->base.plat_plen = uc->plen6; | ||||
| cfg->base.flags = (uc->flags & NAT64LSN_FLAGSMASK) | NAT64_PLATPFX; | cfg->base.flags = (uc->flags & NAT64LSN_FLAGSMASK) | NAT64_PLATPFX; | ||||
| if (IN6_IS_ADDR_WKPFX(&cfg->base.plat_prefix)) | if (IN6_IS_ADDR_WKPFX(&cfg->base.plat_prefix)) | ||||
| cfg->base.flags |= NAT64_WKPFX; | cfg->base.flags |= NAT64_WKPFX; | ||||
| else if (IN6_IS_ADDR_UNSPECIFIED(&cfg->base.plat_prefix)) | else if (IN6_IS_ADDR_UNSPECIFIED(&cfg->base.plat_prefix)) | ||||
| cfg->base.flags |= NAT64LSN_ANYPREFIX; | cfg->base.flags |= NAT64LSN_ANYPREFIX; | ||||
| cfg->states_chunks = uc->states_chunks; | cfg->states_chunks = uc->states_chunks; | ||||
| cfg->jmaxlen = uc->jmaxlen; | cfg->jmaxlen = uc->jmaxlen; | ||||
| cfg->host_delete_delay = uc->nh_delete_delay; | cfg->host_delete_delay = uc->nh_delete_delay; | ||||
| cfg->pg_delete_delay = uc->pg_delete_delay; | cfg->pg_delete_delay = uc->pg_delete_delay; | ||||
| cfg->st_syn_ttl = uc->st_syn_ttl; | cfg->st_syn_ttl = uc->st_syn_ttl; | ||||
| cfg->st_close_ttl = uc->st_close_ttl; | cfg->st_close_ttl = uc->st_close_ttl; | ||||
| cfg->st_estab_ttl = uc->st_estab_ttl; | cfg->st_estab_ttl = uc->st_estab_ttl; | ||||
| cfg->st_udp_ttl = uc->st_udp_ttl; | cfg->st_udp_ttl = uc->st_udp_ttl; | ||||
| cfg->st_icmp_ttl = uc->st_icmp_ttl; | cfg->st_icmp_ttl = uc->st_icmp_ttl; | ||||
| cfg->nomatch_verdict = IP_FW_DENY; | cfg->nomatch_verdict = IP_FW_DENY; | ||||
| IPFW_UH_WLOCK(ch); | IPFW_UH_WLOCK(ch); | ||||
| if (nat64lsn_find(ni, uc->name, uc->set) != NULL) { | if (nat64lsn_find(ni, uc->name, uc->set) != NULL) { | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| nat64lsn_destroy_instance(cfg); | nat64lsn_destroy_config(cfg); | ||||
| free(i, M_NAT64LSN); | |||||
| return (EEXIST); | return (EEXIST); | ||||
| } | } | ||||
| if (ipfw_objhash_alloc_idx(CHAIN_TO_SRV(ch), &cfg->no.kidx) != 0) { | if (ipfw_objhash_alloc_idx(ni, &i->no.kidx) != 0) { | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| nat64lsn_destroy_instance(cfg); | nat64lsn_destroy_config(cfg); | ||||
| free(i, M_NAT64LSN); | |||||
| return (ENOSPC); | return (ENOSPC); | ||||
| } | } | ||||
| ipfw_objhash_add(CHAIN_TO_SRV(ch), &cfg->no); | ipfw_objhash_add(ni, &i->no); | ||||
| /* Okay, let's link data */ | /* Okay, let's link data */ | ||||
| SRV_OBJECT(ch, cfg->no.kidx) = cfg; | i->cfg = cfg; | ||||
| SRV_OBJECT(ch, i->no.kidx) = i; | |||||
| nat64lsn_start_instance(cfg); | nat64lsn_start_instance(cfg); | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| static void | static void | ||||
| nat64lsn_detach_config(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg) | nat64lsn_detach_instance(struct ip_fw_chain *ch, | ||||
| struct nat64lsn_instance *i) | |||||
| { | { | ||||
| IPFW_UH_WLOCK_ASSERT(ch); | IPFW_UH_WLOCK_ASSERT(ch); | ||||
| SRV_OBJECT(ch, i->no.kidx) = NULL; | |||||
| ipfw_objhash_del(CHAIN_TO_SRV(ch), &cfg->no); | ipfw_objhash_del(CHAIN_TO_SRV(ch), &i->no); | ||||
| ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), cfg->no.kidx); | ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), i->no.kidx); | ||||
| } | } | ||||
| /* | /* | ||||
| * Destroys nat64 instance. | * Destroys nat64 instance. | ||||
| * Data layout (v0)(current): | * Data layout (v0)(current): | ||||
| * Request: [ ipfw_obj_header ] | * Request: [ ipfw_obj_header ] | ||||
| * | * | ||||
| * Returns 0 on success | * Returns 0 on success | ||||
| */ | */ | ||||
| static int | static int | ||||
| nat64lsn_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | nat64lsn_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | ||||
| struct sockopt_data *sd) | struct sockopt_data *sd) | ||||
| { | { | ||||
| struct nat64lsn_cfg *cfg; | struct nat64lsn_instance *i; | ||||
| ipfw_obj_header *oh; | ipfw_obj_header *oh; | ||||
| if (sd->valsize != sizeof(*oh)) | if (sd->valsize != sizeof(*oh)) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| oh = (ipfw_obj_header *)op3; | oh = (ipfw_obj_header *)op3; | ||||
| IPFW_UH_WLOCK(ch); | IPFW_UH_WLOCK(ch); | ||||
| cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); | i = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); | ||||
| if (cfg == NULL) { | if (i == NULL) { | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| return (ENOENT); | return (ENOENT); | ||||
| } | } | ||||
| if (cfg->no.refcnt > 0) { | if (i->no.refcnt > 0) { | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| return (EBUSY); | return (EBUSY); | ||||
| } | } | ||||
| ipfw_reset_eaction_instance(ch, V_nat64lsn_eid, cfg->no.kidx); | ipfw_reset_eaction_instance(ch, V_nat64lsn_eid, i->no.kidx); | ||||
| SRV_OBJECT(ch, cfg->no.kidx) = NULL; | nat64lsn_detach_instance(ch, i); | ||||
| nat64lsn_detach_config(ch, cfg); | |||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| nat64lsn_destroy_instance(cfg); | nat64lsn_destroy_config(i->cfg); | ||||
| free(i, M_NAT64LSN); | |||||
| return (0); | return (0); | ||||
| } | } | ||||
| #define __COPY_STAT_FIELD(_cfg, _stats, _field) \ | #define __COPY_STAT_FIELD(_cfg, _stats, _field) \ | ||||
| (_stats)->_field = NAT64STAT_FETCH(&(_cfg)->base.stats, _field) | (_stats)->_field = NAT64STAT_FETCH(&(_cfg)->base.stats, _field) | ||||
| static void | static void | ||||
| export_stats(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg, | export_stats(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg, | ||||
| struct ipfw_nat64lsn_stats *stats) | struct ipfw_nat64lsn_stats *stats) | ||||
| { | { | ||||
| struct nat64lsn_alias *alias; | struct nat64lsn_alias *alias; | ||||
| int i, j; | int i; | ||||
| __COPY_STAT_FIELD(cfg, stats, opcnt64); | __COPY_STAT_FIELD(cfg, stats, opcnt64); | ||||
| __COPY_STAT_FIELD(cfg, stats, opcnt46); | __COPY_STAT_FIELD(cfg, stats, opcnt46); | ||||
| __COPY_STAT_FIELD(cfg, stats, ofrags); | __COPY_STAT_FIELD(cfg, stats, ofrags); | ||||
| __COPY_STAT_FIELD(cfg, stats, ifrags); | __COPY_STAT_FIELD(cfg, stats, ifrags); | ||||
| __COPY_STAT_FIELD(cfg, stats, oerrors); | __COPY_STAT_FIELD(cfg, stats, oerrors); | ||||
| __COPY_STAT_FIELD(cfg, stats, noroute4); | __COPY_STAT_FIELD(cfg, stats, noroute4); | ||||
| __COPY_STAT_FIELD(cfg, stats, noroute6); | __COPY_STAT_FIELD(cfg, stats, noroute6); | ||||
| Show All 14 Lines | export_stats(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg, | ||||
| __COPY_STAT_FIELD(cfg, stats, screated); | __COPY_STAT_FIELD(cfg, stats, screated); | ||||
| __COPY_STAT_FIELD(cfg, stats, sdeleted); | __COPY_STAT_FIELD(cfg, stats, sdeleted); | ||||
| __COPY_STAT_FIELD(cfg, stats, spgcreated); | __COPY_STAT_FIELD(cfg, stats, spgcreated); | ||||
| __COPY_STAT_FIELD(cfg, stats, spgdeleted); | __COPY_STAT_FIELD(cfg, stats, spgdeleted); | ||||
| stats->hostcount = cfg->hosts_count; | stats->hostcount = cfg->hosts_count; | ||||
| for (i = 0; i < (1 << (32 - cfg->plen4)); i++) { | for (i = 0; i < (1 << (32 - cfg->plen4)); i++) { | ||||
| alias = &cfg->aliases[i]; | alias = &cfg->aliases[i]; | ||||
| for (j = 0; j < 32 && ISSET32(alias->tcp_chunkmask, j); j++) | stats->tcpchunks += alias->tcp_pgcount; | ||||
| stats->tcpchunks += bitcount32(alias->tcp_pgmask[j]); | stats->udpchunks += alias->udp_pgcount; | ||||
| for (j = 0; j < 32 && ISSET32(alias->udp_chunkmask, j); j++) | stats->icmpchunks += alias->icmp_pgcount; | ||||
| stats->udpchunks += bitcount32(alias->udp_pgmask[j]); | |||||
| for (j = 0; j < 32 && ISSET32(alias->icmp_chunkmask, j); j++) | |||||
| stats->icmpchunks += bitcount32(alias->icmp_pgmask[j]); | |||||
| } | } | ||||
| } | } | ||||
| #undef __COPY_STAT_FIELD | #undef __COPY_STAT_FIELD | ||||
| static void | static void | ||||
| nat64lsn_export_config(struct ip_fw_chain *ch, struct nat64lsn_cfg *cfg, | nat64lsn_export_config(struct ip_fw_chain *ch, struct nat64lsn_instance *i, | ||||
| ipfw_nat64lsn_cfg *uc) | ipfw_nat64lsn_cfg *uc) | ||||
| { | { | ||||
| struct nat64lsn_cfg *cfg; | |||||
| strlcpy(uc->name, i->no.name, sizeof(uc->name)); | |||||
| uc->set = i->no.set; | |||||
| cfg = i->cfg; | |||||
| uc->flags = cfg->base.flags & NAT64LSN_FLAGSMASK; | uc->flags = cfg->base.flags & NAT64LSN_FLAGSMASK; | ||||
| uc->states_chunks = cfg->states_chunks; | uc->states_chunks = cfg->states_chunks; | ||||
| uc->jmaxlen = cfg->jmaxlen; | uc->jmaxlen = cfg->jmaxlen; | ||||
| uc->nh_delete_delay = cfg->host_delete_delay; | uc->nh_delete_delay = cfg->host_delete_delay; | ||||
| uc->pg_delete_delay = cfg->pg_delete_delay; | uc->pg_delete_delay = cfg->pg_delete_delay; | ||||
| uc->st_syn_ttl = cfg->st_syn_ttl; | uc->st_syn_ttl = cfg->st_syn_ttl; | ||||
| uc->st_close_ttl = cfg->st_close_ttl; | uc->st_close_ttl = cfg->st_close_ttl; | ||||
| uc->st_estab_ttl = cfg->st_estab_ttl; | uc->st_estab_ttl = cfg->st_estab_ttl; | ||||
| uc->st_udp_ttl = cfg->st_udp_ttl; | uc->st_udp_ttl = cfg->st_udp_ttl; | ||||
| uc->st_icmp_ttl = cfg->st_icmp_ttl; | uc->st_icmp_ttl = cfg->st_icmp_ttl; | ||||
| uc->prefix4.s_addr = htonl(cfg->prefix4); | uc->prefix4.s_addr = htonl(cfg->prefix4); | ||||
| uc->prefix6 = cfg->base.plat_prefix; | uc->prefix6 = cfg->base.plat_prefix; | ||||
| uc->plen4 = cfg->plen4; | uc->plen4 = cfg->plen4; | ||||
| uc->plen6 = cfg->base.plat_plen; | uc->plen6 = cfg->base.plat_plen; | ||||
| uc->set = cfg->no.set; | |||||
| strlcpy(uc->name, cfg->no.name, sizeof(uc->name)); | |||||
| } | } | ||||
| struct nat64_dump_arg { | struct nat64_dump_arg { | ||||
| struct ip_fw_chain *ch; | struct ip_fw_chain *ch; | ||||
| struct sockopt_data *sd; | struct sockopt_data *sd; | ||||
| }; | }; | ||||
| static int | static int | ||||
| export_config_cb(struct namedobj_instance *ni, struct named_object *no, | export_config_cb(struct namedobj_instance *ni, struct named_object *no, | ||||
| void *arg) | void *arg) | ||||
| { | { | ||||
| struct nat64_dump_arg *da = (struct nat64_dump_arg *)arg; | struct nat64_dump_arg *da; | ||||
| ipfw_nat64lsn_cfg *uc; | ipfw_nat64lsn_cfg *uc; | ||||
| da = (struct nat64_dump_arg *)arg; | |||||
| uc = (struct _ipfw_nat64lsn_cfg *)ipfw_get_sopt_space(da->sd, | uc = (struct _ipfw_nat64lsn_cfg *)ipfw_get_sopt_space(da->sd, | ||||
| sizeof(*uc)); | sizeof(*uc)); | ||||
| nat64lsn_export_config(da->ch, (struct nat64lsn_cfg *)no, uc); | nat64lsn_export_config(da->ch, | ||||
| __containerof(no, struct nat64lsn_instance, no), uc); | |||||
| return (0); | return (0); | ||||
| } | } | ||||
| /* | /* | ||||
| * Lists all nat64 lsn instances currently available in kernel. | * Lists all nat64 lsn instances currently available in kernel. | ||||
| * Data layout (v0)(current): | * Data layout (v0)(current): | ||||
| * Request: [ ipfw_obj_lheader ] | * Request: [ ipfw_obj_lheader ] | ||||
| * Reply: [ ipfw_obj_lheader ipfw_nat64lsn_cfg x N ] | * Reply: [ ipfw_obj_lheader ipfw_nat64lsn_cfg x N ] | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
| * Returns 0 on success | * Returns 0 on success | ||||
| */ | */ | ||||
| static int | static int | ||||
| nat64lsn_config(struct ip_fw_chain *ch, ip_fw3_opheader *op, | nat64lsn_config(struct ip_fw_chain *ch, ip_fw3_opheader *op, | ||||
| struct sockopt_data *sd) | struct sockopt_data *sd) | ||||
| { | { | ||||
| ipfw_obj_header *oh; | ipfw_obj_header *oh; | ||||
| ipfw_nat64lsn_cfg *uc; | ipfw_nat64lsn_cfg *uc; | ||||
| struct nat64lsn_instance *i; | |||||
| struct nat64lsn_cfg *cfg; | struct nat64lsn_cfg *cfg; | ||||
| struct namedobj_instance *ni; | struct namedobj_instance *ni; | ||||
| if (sd->valsize != sizeof(*oh) + sizeof(*uc)) | if (sd->valsize != sizeof(*oh) + sizeof(*uc)) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| oh = (ipfw_obj_header *)ipfw_get_sopt_space(sd, | oh = (ipfw_obj_header *)ipfw_get_sopt_space(sd, | ||||
| sizeof(*oh) + sizeof(*uc)); | sizeof(*oh) + sizeof(*uc)); | ||||
| uc = (ipfw_nat64lsn_cfg *)(oh + 1); | uc = (ipfw_nat64lsn_cfg *)(oh + 1); | ||||
| if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 || | if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 || | ||||
| oh->ntlv.set >= IPFW_MAX_SETS) | oh->ntlv.set >= IPFW_MAX_SETS) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| ni = CHAIN_TO_SRV(ch); | ni = CHAIN_TO_SRV(ch); | ||||
| if (sd->sopt->sopt_dir == SOPT_GET) { | if (sd->sopt->sopt_dir == SOPT_GET) { | ||||
| IPFW_UH_RLOCK(ch); | IPFW_UH_RLOCK(ch); | ||||
| cfg = nat64lsn_find(ni, oh->ntlv.name, oh->ntlv.set); | i = nat64lsn_find(ni, oh->ntlv.name, oh->ntlv.set); | ||||
| if (cfg == NULL) { | if (i == NULL) { | ||||
| IPFW_UH_RUNLOCK(ch); | IPFW_UH_RUNLOCK(ch); | ||||
| return (ENOENT); | return (ENOENT); | ||||
| } | } | ||||
| nat64lsn_export_config(ch, cfg, uc); | nat64lsn_export_config(ch, i, uc); | ||||
| IPFW_UH_RUNLOCK(ch); | IPFW_UH_RUNLOCK(ch); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| nat64lsn_default_config(uc); | nat64lsn_default_config(uc); | ||||
| IPFW_UH_WLOCK(ch); | IPFW_UH_WLOCK(ch); | ||||
| cfg = nat64lsn_find(ni, oh->ntlv.name, oh->ntlv.set); | i = nat64lsn_find(ni, oh->ntlv.name, oh->ntlv.set); | ||||
| if (cfg == NULL) { | if (i == NULL) { | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| return (ENOENT); | return (ENOENT); | ||||
| } | } | ||||
| /* | /* | ||||
| * For now allow to change only following values: | * For now allow to change only following values: | ||||
| * jmaxlen, nh_del_age, pg_del_age, tcp_syn_age, tcp_close_age, | * jmaxlen, nh_del_age, pg_del_age, tcp_syn_age, tcp_close_age, | ||||
| * tcp_est_age, udp_age, icmp_age, flags, states_chunks. | * tcp_est_age, udp_age, icmp_age, flags, states_chunks. | ||||
| */ | */ | ||||
| cfg = i->cfg; | |||||
| cfg->states_chunks = uc->states_chunks; | cfg->states_chunks = uc->states_chunks; | ||||
| cfg->jmaxlen = uc->jmaxlen; | cfg->jmaxlen = uc->jmaxlen; | ||||
| cfg->host_delete_delay = uc->nh_delete_delay; | cfg->host_delete_delay = uc->nh_delete_delay; | ||||
| cfg->pg_delete_delay = uc->pg_delete_delay; | cfg->pg_delete_delay = uc->pg_delete_delay; | ||||
| cfg->st_syn_ttl = uc->st_syn_ttl; | cfg->st_syn_ttl = uc->st_syn_ttl; | ||||
| cfg->st_close_ttl = uc->st_close_ttl; | cfg->st_close_ttl = uc->st_close_ttl; | ||||
| cfg->st_estab_ttl = uc->st_estab_ttl; | cfg->st_estab_ttl = uc->st_estab_ttl; | ||||
| cfg->st_udp_ttl = uc->st_udp_ttl; | cfg->st_udp_ttl = uc->st_udp_ttl; | ||||
| Show All 14 Lines | |||||
| * | * | ||||
| * Returns 0 on success | * Returns 0 on success | ||||
| */ | */ | ||||
| static int | static int | ||||
| nat64lsn_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, | nat64lsn_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, | ||||
| struct sockopt_data *sd) | struct sockopt_data *sd) | ||||
| { | { | ||||
| struct ipfw_nat64lsn_stats stats; | struct ipfw_nat64lsn_stats stats; | ||||
| struct nat64lsn_cfg *cfg; | struct nat64lsn_instance *i; | ||||
| ipfw_obj_header *oh; | ipfw_obj_header *oh; | ||||
| ipfw_obj_ctlv *ctlv; | ipfw_obj_ctlv *ctlv; | ||||
| size_t sz; | size_t sz; | ||||
| sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ctlv) + sizeof(stats); | sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ctlv) + sizeof(stats); | ||||
| if (sd->valsize % sizeof(uint64_t)) | if (sd->valsize % sizeof(uint64_t)) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| if (sd->valsize < sz) | if (sd->valsize < sz) | ||||
| return (ENOMEM); | return (ENOMEM); | ||||
| oh = (ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); | oh = (ipfw_obj_header *)ipfw_get_sopt_header(sd, sz); | ||||
| if (oh == NULL) | if (oh == NULL) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| memset(&stats, 0, sizeof(stats)); | memset(&stats, 0, sizeof(stats)); | ||||
| IPFW_UH_RLOCK(ch); | IPFW_UH_RLOCK(ch); | ||||
| cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); | i = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); | ||||
| if (cfg == NULL) { | if (i == NULL) { | ||||
| IPFW_UH_RUNLOCK(ch); | IPFW_UH_RUNLOCK(ch); | ||||
| return (ENOENT); | return (ENOENT); | ||||
| } | } | ||||
| export_stats(ch, cfg, &stats); | export_stats(ch, i->cfg, &stats); | ||||
| IPFW_UH_RUNLOCK(ch); | IPFW_UH_RUNLOCK(ch); | ||||
| ctlv = (ipfw_obj_ctlv *)(oh + 1); | ctlv = (ipfw_obj_ctlv *)(oh + 1); | ||||
| memset(ctlv, 0, sizeof(*ctlv)); | memset(ctlv, 0, sizeof(*ctlv)); | ||||
| ctlv->head.type = IPFW_TLV_COUNTERS; | ctlv->head.type = IPFW_TLV_COUNTERS; | ||||
| ctlv->head.length = sz - sizeof(ipfw_obj_header); | ctlv->head.length = sz - sizeof(ipfw_obj_header); | ||||
| ctlv->count = sizeof(stats) / sizeof(uint64_t); | ctlv->count = sizeof(stats) / sizeof(uint64_t); | ||||
| ctlv->objsize = sizeof(uint64_t); | ctlv->objsize = sizeof(uint64_t); | ||||
| ctlv->version = IPFW_NAT64_VERSION; | ctlv->version = IPFW_NAT64_VERSION; | ||||
| memcpy(ctlv + 1, &stats, sizeof(stats)); | memcpy(ctlv + 1, &stats, sizeof(stats)); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| /* | /* | ||||
| * Reset nat64lsn statistics. | * Reset nat64lsn statistics. | ||||
| * Data layout (v0)(current): | * Data layout (v0)(current): | ||||
| * Request: [ ipfw_obj_header ] | * Request: [ ipfw_obj_header ] | ||||
| * | * | ||||
| * Returns 0 on success | * Returns 0 on success | ||||
| */ | */ | ||||
| static int | static int | ||||
| nat64lsn_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, | nat64lsn_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, | ||||
| struct sockopt_data *sd) | struct sockopt_data *sd) | ||||
| { | { | ||||
| struct nat64lsn_cfg *cfg; | struct nat64lsn_instance *i; | ||||
| ipfw_obj_header *oh; | ipfw_obj_header *oh; | ||||
| if (sd->valsize != sizeof(*oh)) | if (sd->valsize != sizeof(*oh)) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| oh = (ipfw_obj_header *)sd->kbuf; | oh = (ipfw_obj_header *)sd->kbuf; | ||||
| if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 || | if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 || | ||||
| oh->ntlv.set >= IPFW_MAX_SETS) | oh->ntlv.set >= IPFW_MAX_SETS) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| IPFW_UH_WLOCK(ch); | IPFW_UH_WLOCK(ch); | ||||
| cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); | i = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); | ||||
| if (cfg == NULL) { | if (i == NULL) { | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| return (ENOENT); | return (ENOENT); | ||||
| } | } | ||||
| COUNTER_ARRAY_ZERO(cfg->base.stats.cnt, NAT64STATS); | COUNTER_ARRAY_ZERO(i->cfg->base.stats.cnt, NAT64STATS); | ||||
| IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| #ifdef __LP64__ | #ifdef __LP64__ | ||||
| #define FREEMASK_COPY(pg, n, out) (out) = *FREEMASK_CHUNK((pg), (n)) | #define FREEMASK_COPY(pg, n, out) (out) = *FREEMASK_CHUNK((pg), (n)) | ||||
| #else | #else | ||||
| #define FREEMASK_COPY(pg, n, out) (out) = *FREEMASK_CHUNK((pg), (n)) | \ | #define FREEMASK_COPY(pg, n, out) (out) = *FREEMASK_CHUNK((pg), (n)) | \ | ||||
| ((uint64_t)*(FREEMASK_CHUNK((pg), (n)) + 1) << 32) | ((uint64_t)*(FREEMASK_CHUNK((pg), (n)) + 1) << 32) | ||||
| #endif | #endif | ||||
| /* | /* | ||||
| * Reply: [ ipfw_obj_header ipfw_obj_data [ ipfw_nat64lsn_stg | * Reply: [ ipfw_obj_header ipfw_obj_data [ ipfw_nat64lsn_stg | ||||
| * ipfw_nat64lsn_state x count, ... ] ] | * ipfw_nat64lsn_state x count, ... ] ] | ||||
| */ | */ | ||||
| static int | static int | ||||
| nat64lsn_export_states_v1(struct nat64lsn_cfg *cfg, union nat64lsn_pgidx *idx, | nat64lsn_export_states(struct nat64lsn_cfg *cfg, union nat64lsn_pgidx *idx, | ||||
| struct nat64lsn_pg *pg, struct sockopt_data *sd, uint32_t *ret_count) | struct nat64lsn_pg *pg, struct sockopt_data *sd, uint32_t *ret_count) | ||||
| { | { | ||||
| ipfw_nat64lsn_state_v1 *s; | ipfw_nat64lsn_state_v1 *s; | ||||
| struct nat64lsn_state *state; | struct nat64lsn_state *state; | ||||
| uint64_t freemask; | uint64_t freemask; | ||||
| uint32_t i, count; | uint32_t i, count; | ||||
| /* validate user input */ | /* validate user input */ | ||||
| ▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | if (ISSET32(alias->udp_pgmask[pg_idx / 32], pg_idx % 32)) | ||||
| return (alias->udp[pg_idx / 32]->pgptr[pg_idx % 32]); | return (alias->udp[pg_idx / 32]->pgptr[pg_idx % 32]); | ||||
| break; | break; | ||||
| } | } | ||||
| return (NULL); | return (NULL); | ||||
| } | } | ||||
| /* | /* | ||||
| * Lists nat64lsn states. | * Lists nat64lsn states. | ||||
| * Data layout (v0): | |||||
| * Request: [ ipfw_obj_header ipfw_obj_data [ uint64_t ]] | |||||
| * Reply: [ ipfw_obj_header ipfw_obj_data [ | |||||
| * ipfw_nat64lsn_stg ipfw_nat64lsn_state x N] ] | |||||
| * | |||||
| * Returns 0 on success | |||||
| */ | |||||
| static int | |||||
| nat64lsn_states_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | |||||
| struct sockopt_data *sd) | |||||
| { | |||||
| /* TODO: implement states listing for old ipfw(8) binaries */ | |||||
| return (EOPNOTSUPP); | |||||
| } | |||||
| /* | |||||
| * Lists nat64lsn states. | |||||
| * Data layout (v1)(current): | * Data layout (v1)(current): | ||||
| * Request: [ ipfw_obj_header ipfw_obj_data [ uint64_t ]] | * Request: [ ipfw_obj_header ipfw_obj_data [ uint64_t ]] | ||||
| * Reply: [ ipfw_obj_header ipfw_obj_data [ | * Reply: [ ipfw_obj_header ipfw_obj_data [ | ||||
| * ipfw_nat64lsn_stg_v1 ipfw_nat64lsn_state_v1 x N] ] | * ipfw_nat64lsn_stg_v1 ipfw_nat64lsn_state_v1 x N] ] | ||||
| * | * | ||||
| * Returns 0 on success | * Returns 0 on success | ||||
| */ | */ | ||||
| static int | static int | ||||
| nat64lsn_states_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | nat64lsn_states(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | ||||
| struct sockopt_data *sd) | struct sockopt_data *sd) | ||||
| { | { | ||||
| ipfw_obj_header *oh; | ipfw_obj_header *oh; | ||||
| ipfw_obj_data *od; | ipfw_obj_data *od; | ||||
| ipfw_nat64lsn_stg_v1 *stg; | ipfw_nat64lsn_stg_v1 *stg; | ||||
| struct nat64lsn_instance *i; | |||||
| struct nat64lsn_cfg *cfg; | struct nat64lsn_cfg *cfg; | ||||
| struct nat64lsn_pg *pg; | struct nat64lsn_pg *pg; | ||||
| union nat64lsn_pgidx idx; | union nat64lsn_pgidx idx; | ||||
| size_t sz; | size_t sz; | ||||
| uint32_t count, total; | uint32_t count, total; | ||||
| int ret; | int ret; | ||||
| sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_data) + | sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_data) + | ||||
| Show All 11 Lines | nat64lsn_states(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | ||||
| idx.index = *(uint64_t *)(od + 1); | idx.index = *(uint64_t *)(od + 1); | ||||
| if (idx.index != 0 && idx.proto != IPPROTO_ICMP && | if (idx.index != 0 && idx.proto != IPPROTO_ICMP && | ||||
| idx.proto != IPPROTO_TCP && idx.proto != IPPROTO_UDP) | idx.proto != IPPROTO_TCP && idx.proto != IPPROTO_UDP) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| if (idx.index == LAST_IDX) | if (idx.index == LAST_IDX) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| IPFW_UH_RLOCK(ch); | IPFW_UH_RLOCK(ch); | ||||
| cfg = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); | i = nat64lsn_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set); | ||||
| if (cfg == NULL) { | if (i == NULL) { | ||||
| IPFW_UH_RUNLOCK(ch); | IPFW_UH_RUNLOCK(ch); | ||||
| return (ENOENT); | return (ENOENT); | ||||
| } | } | ||||
| cfg = i->cfg; | |||||
| if (idx.index == 0) { /* Fill in starting point */ | if (idx.index == 0) { /* Fill in starting point */ | ||||
| idx.addr = cfg->prefix4; | idx.addr = cfg->prefix4; | ||||
| idx.proto = IPPROTO_ICMP; | idx.proto = IPPROTO_ICMP; | ||||
| idx.port = NAT64_MIN_PORT; | idx.port = NAT64_MIN_PORT; | ||||
| } | } | ||||
| if (idx.addr < cfg->prefix4 || idx.addr > cfg->pmask4 || | if (idx.addr < cfg->prefix4 || idx.addr > cfg->pmask4 || | ||||
| idx.port < NAT64_MIN_PORT) { | idx.port < NAT64_MIN_PORT) { | ||||
| IPFW_UH_RUNLOCK(ch); | IPFW_UH_RUNLOCK(ch); | ||||
| Show All 17 Lines | nat64lsn_states(struct ip_fw_chain *ch, ip_fw3_opheader *op3, | ||||
| * Thus states, hosts and PGs will not expire while we hold it. | * Thus states, hosts and PGs will not expire while we hold it. | ||||
| */ | */ | ||||
| CALLOUT_LOCK(cfg); | CALLOUT_LOCK(cfg); | ||||
| ret = 0; | ret = 0; | ||||
| do { | do { | ||||
| pg = nat64lsn_get_pg_byidx(cfg, &idx); | pg = nat64lsn_get_pg_byidx(cfg, &idx); | ||||
| if (pg != NULL) { | if (pg != NULL) { | ||||
| count = 0; | count = 0; | ||||
| ret = nat64lsn_export_states_v1(cfg, &idx, pg, | ret = nat64lsn_export_states(cfg, &idx, pg, | ||||
| sd, &count); | sd, &count); | ||||
| if (ret != 0) | if (ret != 0) | ||||
| break; | break; | ||||
| if (count > 0) { | if (count > 0) { | ||||
| stg->count += count; | stg->count += count; | ||||
| total += count; | total += count; | ||||
| /* Update total size of reply */ | /* Update total size of reply */ | ||||
| od->head.length += | od->head.length += | ||||
| Show All 30 Lines | do { | ||||
| stg->next.index = idx.index; | stg->next.index = idx.index; | ||||
| } while (ret == 0); | } while (ret == 0); | ||||
| CALLOUT_UNLOCK(cfg); | CALLOUT_UNLOCK(cfg); | ||||
| IPFW_UH_RUNLOCK(ch); | IPFW_UH_RUNLOCK(ch); | ||||
| return ((total > 0 || idx.index == LAST_IDX) ? 0: ret); | return ((total > 0 || idx.index == LAST_IDX) ? 0: ret); | ||||
| } | } | ||||
| static struct ipfw_sopt_handler scodes[] = { | static struct ipfw_sopt_handler scodes[] = { | ||||
| { IP_FW_NAT64LSN_CREATE, 0, HDIR_BOTH, nat64lsn_create }, | { IP_FW_NAT64LSN_CREATE, IP_FW3_OPVER, HDIR_BOTH, nat64lsn_create }, | ||||
| { IP_FW_NAT64LSN_DESTROY,0, HDIR_SET, nat64lsn_destroy }, | { IP_FW_NAT64LSN_DESTROY, IP_FW3_OPVER, HDIR_SET, nat64lsn_destroy }, | ||||
| { IP_FW_NAT64LSN_CONFIG, 0, HDIR_BOTH, nat64lsn_config }, | { IP_FW_NAT64LSN_CONFIG, IP_FW3_OPVER, HDIR_BOTH, nat64lsn_config }, | ||||
| { IP_FW_NAT64LSN_LIST, 0, HDIR_GET, nat64lsn_list }, | { IP_FW_NAT64LSN_LIST, IP_FW3_OPVER, HDIR_GET, nat64lsn_list }, | ||||
| { IP_FW_NAT64LSN_STATS, 0, HDIR_GET, nat64lsn_stats }, | { IP_FW_NAT64LSN_STATS, IP_FW3_OPVER, HDIR_GET, nat64lsn_stats }, | ||||
| { IP_FW_NAT64LSN_RESET_STATS,0, HDIR_SET, nat64lsn_reset_stats }, | { IP_FW_NAT64LSN_RESET_STATS, IP_FW3_OPVER, HDIR_SET, nat64lsn_reset_stats }, | ||||
| { IP_FW_NAT64LSN_LIST_STATES,0, HDIR_GET, nat64lsn_states_v0 }, | { IP_FW_NAT64LSN_LIST_STATES, IP_FW3_OPVER, HDIR_GET, nat64lsn_states }, | ||||
| { IP_FW_NAT64LSN_LIST_STATES,1, HDIR_GET, nat64lsn_states_v1 }, | |||||
| }; | }; | ||||
| #define NAT64LSN_ARE_EQUAL(v) (cfg0->v == cfg1->v) | |||||
| static int | static int | ||||
| nat64lsn_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) | nat64lsn_cmp_configs(struct nat64lsn_cfg *cfg0, struct nat64lsn_cfg *cfg1) | ||||
| { | { | ||||
| ipfw_insn *icmd; | |||||
| icmd = cmd - 1; | if ((cfg0->base.flags & cfg1->base.flags & NAT64LSN_ALLOW_SWAPCONF) && | ||||
| if (icmd->opcode != O_EXTERNAL_ACTION || | NAT64LSN_ARE_EQUAL(prefix4) && | ||||
| icmd->arg1 != V_nat64lsn_eid) | NAT64LSN_ARE_EQUAL(pmask4) && | ||||
| return (1); | NAT64LSN_ARE_EQUAL(plen4) && | ||||
| NAT64LSN_ARE_EQUAL(base.plat_plen) && | |||||
| *puidx = cmd->arg1; | IN6_ARE_ADDR_EQUAL(&cfg0->base.plat_prefix, | ||||
| *ptype = 0; | &cfg1->base.plat_prefix)) | ||||
| return (0); | return (0); | ||||
| return (1); | |||||
| } | } | ||||
| #undef NAT64LSN_ARE_EQUAL | |||||
| static void | static void | ||||
| nat64lsn_update_arg1(ipfw_insn *cmd, uint16_t idx) | nat64lsn_swap_configs(struct nat64lsn_instance *i0, | ||||
| struct nat64lsn_instance *i1) | |||||
| { | { | ||||
| struct nat64lsn_cfg *cfg; | |||||
| cmd->arg1 = idx; | cfg = i0->cfg; | ||||
| i0->cfg = i1->cfg; | |||||
| i1->cfg = cfg; | |||||
| } | } | ||||
| /* | |||||
| * NAT64LSN sets swap handler. | |||||
| * | |||||
| * When two sets have NAT64LSN instance with the same name, we check | |||||
| * most important configuration parameters, and if there are no difference, | |||||
| * and both instances have NAT64LSN_ALLOW_SWAPCONF flag, we will exchange | |||||
| * configs between instances. This allows to keep NAT64 states when ipfw's | |||||
| * rules are reloaded using new set. | |||||
| * | |||||
| * XXX: since manage_sets caller doesn't hold IPFW_WLOCK(), it is possible | |||||
| * that some states will be created during switching, because set of rules | |||||
| * is changed a bit earley than named objects. | |||||
| */ | |||||
| static int | static int | ||||
| nat64lsn_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, | nat64lsn_swap_sets_cb(struct namedobj_instance *ni, struct named_object *no, | ||||
| struct named_object **pno) | void *arg) | ||||
| { | { | ||||
| int err; | struct nat64lsn_instance *i0, *i1; | ||||
| uint8_t *sets; | |||||
| err = ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti, | sets = arg; | ||||
| IPFW_TLV_NAT64LSN_NAME, pno); | if (no->set == sets[0]) { | ||||
| return (err); | /* | ||||
| * Check if we have instance in new set with the same | |||||
| * config that is sets aware and ready to swap configs. | |||||
| */ | |||||
| i0 = __containerof(no, struct nat64lsn_instance, no); | |||||
| if ((i0->cfg->base.flags & NAT64LSN_ALLOW_SWAPCONF) && | |||||
| (i1 = nat64lsn_find(ni, no->name, sets[1])) != NULL) { | |||||
| /* Compare configs */ | |||||
| if (nat64lsn_cmp_configs(i0->cfg, i1->cfg) == 0) { | |||||
| IPFW_UH_WLOCK_ASSERT(&V_layer3_chain); | |||||
| IPFW_WLOCK(&V_layer3_chain); | |||||
| nat64lsn_swap_configs(i0, i1); | |||||
| IPFW_WUNLOCK(&V_layer3_chain); | |||||
| } | } | ||||
| static struct named_object * | |||||
| nat64lsn_findbykidx(struct ip_fw_chain *ch, uint16_t idx) | |||||
| { | |||||
| struct namedobj_instance *ni; | |||||
| struct named_object *no; | |||||
| IPFW_UH_WLOCK_ASSERT(ch); | |||||
| ni = CHAIN_TO_SRV(ch); | |||||
| no = ipfw_objhash_lookup_kidx(ni, idx); | |||||
| KASSERT(no != NULL, ("NAT64LSN with index %d not found", idx)); | |||||
| return (no); | |||||
| } | } | ||||
| } | |||||
| return (0); | |||||
| } | |||||
| static int | static int | ||||
| nat64lsn_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, | nat64lsn_manage_sets(struct ip_fw_chain *ch, uint32_t set, uint8_t new_set, | ||||
| enum ipfw_sets_cmd cmd) | enum ipfw_sets_cmd cmd) | ||||
| { | { | ||||
| uint8_t sets[2]; | |||||
| if (cmd == SWAP_ALL) { | |||||
| sets[0] = (uint8_t)set; | |||||
| sets[1] = new_set; | |||||
| ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), | |||||
| nat64lsn_swap_sets_cb, &sets, IPFW_TLV_NAT64LSN_NAME); | |||||
| } | |||||
| return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NAT64LSN_NAME, | return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NAT64LSN_NAME, | ||||
| set, new_set, cmd)); | set, new_set, cmd)); | ||||
| } | } | ||||
| NAT64_DEFINE_OPCODE_REWRITER(nat64lsn, NAT64LSN, opcodes); | |||||
| static struct opcode_obj_rewrite opcodes[] = { | |||||
| { | |||||
| .opcode = O_EXTERNAL_INSTANCE, | |||||
| .etlv = IPFW_TLV_EACTION /* just show it isn't table */, | |||||
| .classifier = nat64lsn_classify, | |||||
| .update = nat64lsn_update_arg1, | |||||
| .find_byname = nat64lsn_findbyname, | |||||
| .find_bykidx = nat64lsn_findbykidx, | |||||
| .manage_sets = nat64lsn_manage_sets, | |||||
| }, | |||||
| }; | |||||
| static int | static int | ||||
| destroy_config_cb(struct namedobj_instance *ni, struct named_object *no, | destroy_config_cb(struct namedobj_instance *ni, struct named_object *no, | ||||
| void *arg) | void *arg) | ||||
| { | { | ||||
| struct nat64lsn_cfg *cfg; | struct nat64lsn_instance *i; | ||||
| struct ip_fw_chain *ch; | struct ip_fw_chain *ch; | ||||
| ch = (struct ip_fw_chain *)arg; | ch = (struct ip_fw_chain *)arg; | ||||
| cfg = (struct nat64lsn_cfg *)SRV_OBJECT(ch, no->kidx); | i = (struct nat64lsn_instance *)SRV_OBJECT(ch, no->kidx); | ||||
| SRV_OBJECT(ch, no->kidx) = NULL; | nat64lsn_detach_instance(ch, i); | ||||
| nat64lsn_detach_config(ch, cfg); | nat64lsn_destroy_config(i->cfg); | ||||
| nat64lsn_destroy_instance(cfg); | free(i, M_NAT64LSN); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| int | int | ||||
| nat64lsn_init(struct ip_fw_chain *ch, int first) | nat64lsn_init(struct ip_fw_chain *ch, int first) | ||||
| { | { | ||||
| if (first != 0) | if (first != 0) | ||||
| Show All 31 Lines | |||||