static int table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh) { ipfw_obj_lheader req, *olh; size_t sz; memset(&req, 0, sizeof(req)); sz = sizeof(req); if (do_get3(opcode, &req.opheader, &sz) != 0) if (errno != ENOMEM) return (errno); sz = req.size; if ((olh = calloc(1, sz)) == NULL) return (ENOMEM); olh->size = sz; if (do_get3(opcode, &olh->opheader, &sz) != 0) { free(olh); return (errno); } *polh = olh; return (0); }
/* * Retrieves all entries for given table @i in * eXtended format. Allocate buffer large enough * to store result. Called needs to free it later. * * Returns 0 on success. */ static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh) { ipfw_obj_header *oh; size_t sz; int c; sz = 0; oh = NULL; for (c = 0; c < 8; c++) { if (sz < i->size) sz = i->size + 44; if (oh != NULL) free(oh); if ((oh = calloc(1, sz)) == NULL) continue; table_fill_objheader(oh, i); oh->opheader.version = 1; /* Current version */ if (do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz) == 0) { *poh = oh; return (0); } if (errno != ENOMEM) break; } free(oh); return (errno); }
static int table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, ipfw_obj_tentry *xtent) { char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; ipfw_obj_tentry *tent; uint8_t type; uint32_t vmask; size_t sz; memcpy(xbuf, oh, sizeof(*oh)); oh = (ipfw_obj_header *)xbuf; tent = (ipfw_obj_tentry *)(oh + 1); memset(tent, 0, sizeof(*tent)); tent->head.length = sizeof(*tent); tent->idx = 1; tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi); oh->ntlv.type = type; sz = sizeof(xbuf); if (do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz) != 0) return (errno); if (sz < sizeof(xbuf)) return (EINVAL); *xtent = *tent; return (0); }
static int table_do_modify_record(int cmd, ipfw_obj_header *oh, ipfw_obj_tentry *tent, int count, int atomic) { ipfw_obj_ctlv *ctlv; ipfw_obj_tentry *tent_base; caddr_t pbuf; char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; int error, i; size_t sz; sz = sizeof(*ctlv) + sizeof(*tent) * count; if (count == 1) { memset(xbuf, 0, sizeof(xbuf)); pbuf = xbuf; } else { if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL) return (ENOMEM); } memcpy(pbuf, oh, sizeof(*oh)); oh = (ipfw_obj_header *)pbuf; oh->opheader.version = 1; ctlv = (ipfw_obj_ctlv *)(oh + 1); ctlv->count = count; ctlv->head.length = sz; if (atomic != 0) ctlv->flags |= IPFW_CTF_ATOMIC; tent_base = tent; memcpy(ctlv + 1, tent, sizeof(*tent) * count); tent = (ipfw_obj_tentry *)(ctlv + 1); for (i = 0; i < count; i++, tent++) { tent->head.length = sizeof(ipfw_obj_tentry); tent->idx = oh->idx; } sz += sizeof(*oh); error = do_get3(cmd, &oh->opheader, &sz); tent = (ipfw_obj_tentry *)(ctlv + 1); /* Copy result back to provided buffer */ memcpy(tent_base, ctlv + 1, sizeof(*tent) * count); if (pbuf != xbuf) free(pbuf); return (error); }
/* * Get NPTv6 instance statistics. * Request: [ ipfw_obj_header ] * Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ] ] */ static int nptv6_get_stats(const char *name, uint8_t set, struct ipfw_nptv6_stats *stats) { ipfw_obj_header *oh; ipfw_obj_ctlv *oc; size_t sz; sz = sizeof(*oh) + sizeof(*oc) + sizeof(*stats); oh = calloc(1, sz); nptv6_fill_ntlv(&oh->ntlv, name, set); if (do_get3(IP_FW_NPTV6_STATS, &oh->opheader, &sz) == 0) { oc = (ipfw_obj_ctlv *)(oh + 1); memcpy(stats, oc + 1, sizeof(*stats)); free(oh); return (0); } free(oh); return (-1); }
/* * Retrieves table in given table specified by @oh->ntlv. * it inside @i. * Returns 0 on success. */ static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) { char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; size_t sz; sz = sizeof(tbuf); memset(tbuf, 0, sizeof(tbuf)); memcpy(tbuf, oh, sizeof(*oh)); oh = (ipfw_obj_header *)tbuf; if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) != 0) return (errno); if (sz < sizeof(tbuf)) return (EINVAL); *i = *(ipfw_xtable_info *)(oh + 1); return (0); }
/* * Retrieves table list from kernel, * optionally sorts it and calls requested function for each table. * Returns 0 on success. */ static int tables_foreach(table_cb_t *f, void *arg, int sort) { ipfw_obj_lheader *olh; ipfw_xtable_info *info; size_t sz; int i, error; /* Start with reasonable default */ sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info); for (;;) { if ((olh = calloc(1, sz)) == NULL) return (ENOMEM); olh->size = sz; if (do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz) != 0) { sz = olh->size; free(olh); if (errno != ENOMEM) return (errno); continue; } if (sort != 0) qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); info = (ipfw_xtable_info *)(olh + 1); for (i = 0; i < olh->count; i++) { error = f(info, arg); /* Ignore errors for now */ info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); } free(olh); break; } return (0); }
/* * Retrieves nat64lsn instance list from kernel, * optionally sorts it and calls requested function for each instance. * * Request: [ ipfw_obj_lheader ] * Reply: [ ipfw_obj_lheader ipfw_nat64lsn_cfg x N ] */ static int nat64lsn_foreach(nat64lsn_cb_t *f, const char *name, uint8_t set, int sort) { ipfw_obj_lheader *olh; ipfw_nat64lsn_cfg *cfg; size_t sz; int i, error; /* Start with reasonable default */ sz = sizeof(*olh) + 16 * sizeof(ipfw_nat64lsn_cfg); for (;;) { if ((olh = calloc(1, sz)) == NULL) return (ENOMEM); olh->size = sz; if (do_get3(IP_FW_NAT64LSN_LIST, &olh->opheader, &sz) != 0) { sz = olh->size; free(olh); if (errno != ENOMEM) return (errno); continue; } if (sort != 0) qsort(olh + 1, olh->count, olh->objsize, nat64name_cmp); cfg = (ipfw_nat64lsn_cfg *)(olh + 1); for (i = 0; i < olh->count; i++) { error = f(cfg, name, set); /* Ignore errors for now */ cfg = (ipfw_nat64lsn_cfg *)((caddr_t)cfg + olh->objsize); } free(olh); break; } return (0); }
static int nat64lsn_states_cb(ipfw_nat64lsn_cfg *cfg, const char *name, uint8_t set) { ipfw_obj_header *oh; ipfw_obj_data *od; void *buf; uint64_t next_idx; size_t sz; if (name != NULL && strcmp(cfg->name, name) != 0) return (ESRCH); if (set != 0 && cfg->set != set) return (ESRCH); next_idx = 0; sz = 4096; if ((buf = calloc(1, sz)) == NULL) err(EX_OSERR, NULL); do { oh = (ipfw_obj_header *)buf; od = (ipfw_obj_data *)(oh + 1); nat64lsn_fill_ntlv(&oh->ntlv, cfg->name, set); od->head.type = IPFW_TLV_OBJDATA; od->head.length = sizeof(*od) + sizeof(next_idx); *((uint64_t *)(od + 1)) = next_idx; if (do_get3(IP_FW_NAT64LSN_LIST_STATES, &oh->opheader, &sz)) err(EX_OSERR, "Error reading nat64lsn states"); next_idx = nat64lsn_print_states(buf); sz = 4096; memset(buf, 0, sz); } while (next_idx != 0xFF); free(buf); return (0); }
/* * Configures existing nat64clat instance * ipfw nat64clat <NAME> config <options> * Request: [ ipfw_obj_header ipfw_nat64clat_cfg ] */ static void nat64clat_config(const char *name, uint8_t set, int ac, char **av) { char buf[sizeof(ipfw_obj_header) + sizeof(ipfw_nat64clat_cfg)]; ipfw_nat64clat_cfg *cfg; ipfw_obj_header *oh; char *opt; char *p; size_t sz; int tcmd; struct in6_addr prefix; uint8_t plen; if (ac == 0) errx(EX_USAGE, "config options required"); memset(&buf, 0, sizeof(buf)); oh = (ipfw_obj_header *)buf; cfg = (ipfw_nat64clat_cfg *)(oh + 1); sz = sizeof(buf); nat64clat_fill_ntlv(&oh->ntlv, name, set); if (do_get3(IP_FW_NAT64CLAT_CONFIG, &oh->opheader, &sz) != 0) err(EX_OSERR, "failed to get config for instance %s", name); while (ac > 0) { tcmd = get_token(nat64newcmds, *av, "option"); opt = *av; ac--; av++; switch (tcmd) { case TOK_PLAT_PREFIX: case TOK_CLAT_PREFIX: if (tcmd == TOK_PLAT_PREFIX) { NEED1("IPv6 plat_prefix required"); } else { NEED1("IPv6 clat_prefix required"); } if ((p = strchr(*av, '/')) != NULL) *p++ = '\0'; if (inet_pton(AF_INET6, *av, &prefix) != 1) errx(EX_USAGE, "Bad prefix: %s", *av); plen = strtol(p, NULL, 10); if (ipfw_check_nat64prefix(&prefix, plen) != 0) errx(EX_USAGE, "Bad prefix length: %s", p); if (tcmd == TOK_PLAT_PREFIX) { cfg->plat_prefix = prefix; cfg->plat_plen = plen; } else { cfg->clat_prefix = prefix; cfg->clat_plen = plen; } ac--; av++; break; case TOK_LOG: cfg->flags |= NAT64_LOG; break; case TOK_LOGOFF: cfg->flags &= ~NAT64_LOG; break; case TOK_PRIVATE: cfg->flags |= NAT64_ALLOW_PRIVATE; break; case TOK_PRIVATEOFF: cfg->flags &= ~NAT64_ALLOW_PRIVATE; break; default: errx(EX_USAGE, "Can't change %s option", opt); } } if (do_set3(IP_FW_NAT64CLAT_CONFIG, &oh->opheader, sizeof(buf)) != 0) err(EX_OSERR, "nat64clat instance configuration failed"); }
/* * Configures existing nat64lsn instance * ipfw nat64lsn <NAME> config <options> * Request: [ ipfw_obj_header ipfw_nat64lsn_cfg ] */ static void nat64lsn_config(const char *name, uint8_t set, int ac, char **av) { char buf[sizeof(ipfw_obj_header) + sizeof(ipfw_nat64lsn_cfg)]; ipfw_nat64lsn_cfg *cfg; ipfw_obj_header *oh; size_t sz; char *opt; int tcmd; if (ac == 0) errx(EX_USAGE, "config options required"); memset(&buf, 0, sizeof(buf)); oh = (ipfw_obj_header *)buf; cfg = (ipfw_nat64lsn_cfg *)(oh + 1); sz = sizeof(buf); nat64lsn_fill_ntlv(&oh->ntlv, name, set); if (do_get3(IP_FW_NAT64LSN_CONFIG, &oh->opheader, &sz) != 0) err(EX_OSERR, "failed to get config for instance %s", name); while (ac > 0) { tcmd = get_token(nat64newcmds, *av, "option"); opt = *av; ac--; av++; switch (tcmd) { case TOK_MAX_PORTS: NEED1("Max per-user ports required"); cfg->max_ports = nat64lsn_parse_int(*av, opt); ac--; av++; break; case TOK_JMAXLEN: NEED1("job queue length required"); cfg->jmaxlen = nat64lsn_parse_int(*av, opt); ac--; av++; break; case TOK_HOST_DEL_AGE: NEED1("host delete delay required"); cfg->nh_delete_delay = (uint16_t)nat64lsn_parse_int( *av, opt); ac--; av++; break; case TOK_PG_DEL_AGE: NEED1("portgroup delete delay required"); cfg->pg_delete_delay = (uint16_t)nat64lsn_parse_int( *av, opt); ac--; av++; break; case TOK_TCP_SYN_AGE: NEED1("tcp syn age required"); cfg->st_syn_ttl = (uint16_t)nat64lsn_parse_int( *av, opt); ac--; av++; break; case TOK_TCP_CLOSE_AGE: NEED1("tcp close age required"); cfg->st_close_ttl = (uint16_t)nat64lsn_parse_int( *av, opt); ac--; av++; break; case TOK_TCP_EST_AGE: NEED1("tcp est age required"); cfg->st_estab_ttl = (uint16_t)nat64lsn_parse_int( *av, opt); ac--; av++; break; case TOK_UDP_AGE: NEED1("udp age required"); cfg->st_udp_ttl = (uint16_t)nat64lsn_parse_int( *av, opt); ac--; av++; break; case TOK_ICMP_AGE: NEED1("icmp age required"); cfg->st_icmp_ttl = (uint16_t)nat64lsn_parse_int( *av, opt); ac--; av++; break; case TOK_LOG: cfg->flags |= NAT64_LOG; break; case TOK_LOGOFF: cfg->flags &= ~NAT64_LOG; break; default: errx(EX_USAGE, "Can't change %s option", opt); } } if (do_set3(IP_FW_NAT64LSN_CONFIG, &oh->opheader, sizeof(buf)) != 0) err(EX_OSERR, "nat64lsn instance configuration failed"); }