Suppord showing named tables in ipfw(8) rule listing.
Kernel changes: * change base TLV header to be u64 (so size can be u32). * Introduce ipfw_obj_ctlv generc container TLV. * Add IP_FW_XGET opcode which is now used for atomic configuration retrieval. One can specify needed configuration pieces to retrieve via flags field. Currently supported are IPFW_CFG_GET_STATIC (static rules) and IPFW_CFG_GET_STATES (dynamic states). Other configuration pieces (tables, pipes, etc..) support is planned. Userland changes: * Switch ipfw(8) to use new IP_FW_XGET for rule listing. * Split rule listing code get and show pieces. * Make several steps forward towards libipfw: permit printing states and rules(paritally) to supplied buffer. do not die on malloc/kernel failure inside given printing functions. stop assuming cmdline_opts is global symbol.
This commit is contained in:
parent
2d99a3497d
commit
563b5ab132
@ -137,15 +137,15 @@ altq_qid_to_name(u_int32_t qid)
|
||||
}
|
||||
|
||||
void
|
||||
print_altq_cmd(ipfw_insn_altq *altqptr)
|
||||
print_altq_cmd(struct buf_pr *bp, ipfw_insn_altq *altqptr)
|
||||
{
|
||||
if (altqptr) {
|
||||
const char *qname;
|
||||
|
||||
qname = altq_qid_to_name(altqptr->qid);
|
||||
if (qname == NULL)
|
||||
printf(" altq ?<%u>", altqptr->qid);
|
||||
bprintf(bp, " altq ?<%u>", altqptr->qid);
|
||||
else
|
||||
printf(" altq %s", qname);
|
||||
bprintf(bp, " altq %s", qname);
|
||||
}
|
||||
}
|
||||
|
@ -174,48 +174,44 @@ print_header(struct ipfw_flow_id *id)
|
||||
}
|
||||
|
||||
static void
|
||||
list_flow(struct dn_flow *ni, int *print)
|
||||
list_flow(struct buf_pr *bp, struct dn_flow *ni)
|
||||
{
|
||||
char buff[255];
|
||||
struct protoent *pe = NULL;
|
||||
struct in_addr ina;
|
||||
struct ipfw_flow_id *id = &ni->fid;
|
||||
|
||||
if (*print) {
|
||||
print_header(&ni->fid);
|
||||
*print = 0;
|
||||
}
|
||||
pe = getprotobynumber(id->proto);
|
||||
/* XXX: Should check for IPv4 flows */
|
||||
printf("%3u%c", (ni->oid.id) & 0xff,
|
||||
bprintf(bp, "%3u%c", (ni->oid.id) & 0xff,
|
||||
id->extra ? '*' : ' ');
|
||||
if (!IS_IP6_FLOW_ID(id)) {
|
||||
if (pe)
|
||||
printf("%-4s ", pe->p_name);
|
||||
bprintf(bp, "%-4s ", pe->p_name);
|
||||
else
|
||||
printf("%4u ", id->proto);
|
||||
bprintf(bp, "%4u ", id->proto);
|
||||
ina.s_addr = htonl(id->src_ip);
|
||||
printf("%15s/%-5d ",
|
||||
bprintf(bp, "%15s/%-5d ",
|
||||
inet_ntoa(ina), id->src_port);
|
||||
ina.s_addr = htonl(id->dst_ip);
|
||||
printf("%15s/%-5d ",
|
||||
bprintf(bp, "%15s/%-5d ",
|
||||
inet_ntoa(ina), id->dst_port);
|
||||
} else {
|
||||
/* Print IPv6 flows */
|
||||
if (pe != NULL)
|
||||
printf("%9s ", pe->p_name);
|
||||
bprintf(bp, "%9s ", pe->p_name);
|
||||
else
|
||||
printf("%9u ", id->proto);
|
||||
printf("%7d %39s/%-5d ", id->flow_id6,
|
||||
bprintf(bp, "%9u ", id->proto);
|
||||
bprintf(bp, "%7d %39s/%-5d ", id->flow_id6,
|
||||
inet_ntop(AF_INET6, &(id->src_ip6), buff, sizeof(buff)),
|
||||
id->src_port);
|
||||
printf(" %39s/%-5d ",
|
||||
bprintf(bp, " %39s/%-5d ",
|
||||
inet_ntop(AF_INET6, &(id->dst_ip6), buff, sizeof(buff)),
|
||||
id->dst_port);
|
||||
}
|
||||
pr_u64(&ni->tot_pkts, 4);
|
||||
pr_u64(&ni->tot_bytes, 8);
|
||||
printf("%2u %4u %3u\n",
|
||||
pr_u64(bp, &ni->tot_pkts, 4);
|
||||
pr_u64(bp, &ni->tot_bytes, 8);
|
||||
bprintf(bp, "%2u %4u %3u",
|
||||
ni->length, ni->len_bytes, ni->drops);
|
||||
}
|
||||
|
||||
@ -303,8 +299,10 @@ list_pipes(struct dn_id *oid, struct dn_id *end)
|
||||
{
|
||||
char buf[160]; /* pending buffer */
|
||||
int toPrint = 1; /* print header */
|
||||
struct buf_pr bp;
|
||||
|
||||
buf[0] = '\0';
|
||||
bp_alloc(&bp, 4096);
|
||||
for (; oid != end; oid = O_NEXT(oid, oid->len)) {
|
||||
if (oid->len < sizeof(*oid))
|
||||
errx(1, "invalid oid len %d\n", oid->len);
|
||||
@ -346,7 +344,12 @@ list_pipes(struct dn_id *oid, struct dn_id *end)
|
||||
break;
|
||||
|
||||
case DN_FLOW:
|
||||
list_flow((struct dn_flow *)oid, &toPrint);
|
||||
if (toPrint != 0) {
|
||||
print_header(&((struct dn_flow *)oid)->fid);
|
||||
toPrint = 0;
|
||||
}
|
||||
list_flow(&bp, (struct dn_flow *)oid);
|
||||
printf("%s\n", bp.buf);
|
||||
break;
|
||||
|
||||
case DN_LINK: {
|
||||
@ -384,6 +387,8 @@ list_pipes(struct dn_id *oid, struct dn_id *end)
|
||||
}
|
||||
flush_buf(buf); // XXX does it really go here ?
|
||||
}
|
||||
|
||||
bp_free(&bp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -213,7 +213,19 @@ enum tokens {
|
||||
#define NEED(_p, msg) {if (!_p) errx(EX_USAGE, msg);}
|
||||
#define NEED1(msg) {if (!(*av)) errx(EX_USAGE, msg);}
|
||||
|
||||
int pr_u64(uint64_t *pd, int width);
|
||||
struct buf_pr {
|
||||
char *buf; /* allocated buffer */
|
||||
char *ptr; /* current pointer */
|
||||
size_t size; /* total buffer size */
|
||||
size_t avail; /* available storage */
|
||||
size_t needed; /* length needed */
|
||||
};
|
||||
|
||||
int pr_u64(struct buf_pr *bp, uint64_t *pd, int width);
|
||||
int bp_alloc(struct buf_pr *b, size_t size);
|
||||
void bp_free(struct buf_pr *b);
|
||||
int bprintf(struct buf_pr *b, char *format, ...);
|
||||
|
||||
|
||||
/* memory allocation support */
|
||||
void *safe_calloc(size_t number, size_t size);
|
||||
@ -274,7 +286,7 @@ void ipfw_list(int ac, char *av[], int show_counters);
|
||||
/* altq.c */
|
||||
void altq_set_enabled(int enabled);
|
||||
u_int32_t altq_name_to_qid(const char *name);
|
||||
void print_altq_cmd(struct _ipfw_insn_altq *altqptr);
|
||||
void print_altq_cmd(struct buf_pr *bp, struct _ipfw_insn_altq *altqptr);
|
||||
#else
|
||||
#define NO_ALTQ
|
||||
#endif
|
||||
@ -298,3 +310,8 @@ void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av, int cblen);
|
||||
void fill_unreach6_code(u_short *codep, char *str);
|
||||
void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av, int cblen);
|
||||
int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
|
||||
|
||||
/* tables.c */
|
||||
struct _ipfw_obj_ctlv;
|
||||
char *table_search_ctlv(struct _ipfw_obj_ctlv *ctlv, uint16_t idx);
|
||||
|
||||
|
@ -305,7 +305,7 @@ static void
|
||||
table_fill_ntlv(ipfw_obj_ntlv *ntlv, char *name, uint16_t uidx)
|
||||
{
|
||||
|
||||
ntlv->head.type = IPFW_TLV_NAME;
|
||||
ntlv->head.type = IPFW_TLV_TBL_NAME;
|
||||
ntlv->head.length = sizeof(ipfw_obj_ntlv);
|
||||
ntlv->idx = uidx;
|
||||
strlcpy(ntlv->name, name, sizeof(ntlv->name));
|
||||
@ -593,3 +593,43 @@ table_show_list(ipfw_obj_header *oh, int need_header)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
compare_ntlv(const void *k, const void *v)
|
||||
{
|
||||
ipfw_obj_ntlv *ntlv;
|
||||
uint16_t key;
|
||||
|
||||
key = *((uint16_t *)k);
|
||||
ntlv = (ipfw_obj_ntlv *)v;
|
||||
|
||||
if (key < ntlv->idx)
|
||||
return (-1);
|
||||
else if (key > ntlv->idx)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds table name in @ctlv by @idx.
|
||||
* Uses the following facts:
|
||||
* 1) All TLVs are the same size
|
||||
* 2) Kernel implementation provides already sorted list.
|
||||
*
|
||||
* Returns table name or NULL.
|
||||
*/
|
||||
char *
|
||||
table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
|
||||
{
|
||||
ipfw_obj_ntlv *ntlv;
|
||||
|
||||
ntlv = bsearch(&idx, (ctlv + 1), ctlv->count, ctlv->objsize,
|
||||
compare_ntlv);
|
||||
|
||||
if (ntlv != 0)
|
||||
return (ntlv->name);
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,7 @@ typedef struct _ip_fw3_opheader {
|
||||
#define IP_FW_TABLE_XFLUSH 94 /* flush table data */
|
||||
#define IP_FW_TABLE_XCREATE 95 /* create new table */
|
||||
#define IP_FW_TABLE_XMODIFY 96 /* modify existing table */
|
||||
#define IP_FW_XGET 97 /* Retrieve configuration */
|
||||
|
||||
/*
|
||||
* Usage guidelines:
|
||||
@ -681,18 +682,30 @@ typedef struct _ipfw_xtable {
|
||||
|
||||
typedef struct _ipfw_obj_tlv {
|
||||
uint16_t type; /* TLV type */
|
||||
uint16_t length; /* Total length, aligned to u32 */
|
||||
uint16_t flags; /* unused */
|
||||
uint32_t length; /* Total length, aligned to u64 */
|
||||
} ipfw_obj_tlv;
|
||||
#define IPFW_TLV_TBL_NAME 1
|
||||
#define IPFW_TLV_TBLNAME_LIST 2
|
||||
#define IPFW_TLV_RULE_LIST 3
|
||||
#define IPFW_TLV_STATE_LIST 4
|
||||
|
||||
#define IPFW_TLV_NAME 1
|
||||
/* Object name TLV */
|
||||
typedef struct _ipfw_obj_ntlv {
|
||||
ipfw_obj_tlv head; /* TLV header */
|
||||
uint16_t idx; /* Name index */
|
||||
uint16_t spare; /* unused */
|
||||
char name[64]; /* Null-terminated name */
|
||||
ipfw_obj_tlv head; /* TLV header */
|
||||
uint16_t idx; /* Name index */
|
||||
uint16_t spare0; /* unused */
|
||||
uint32_t spare1; /* unused */
|
||||
char name[64]; /* Null-terminated name */
|
||||
} ipfw_obj_ntlv;
|
||||
|
||||
/* Containter TLVs */
|
||||
typedef struct _ipfw_obj_ctlv {
|
||||
ipfw_obj_tlv head; /* TLV header */
|
||||
uint32_t count; /* Number of sub-TLVs */
|
||||
uint32_t objsize; /* Single object size */
|
||||
} ipfw_obj_ctlv;
|
||||
|
||||
typedef struct _ipfw_xtable_info {
|
||||
uint8_t type; /* table type (cidr,iface,..) */
|
||||
uint8_t ftype; /* table value format type */
|
||||
@ -725,4 +738,15 @@ typedef struct _ipfw_obj_lheader {
|
||||
uint32_t objsize; /* Size of one object */
|
||||
} ipfw_obj_lheader;
|
||||
|
||||
#define IPFW_CFG_GET_STATIC 1
|
||||
#define IPFW_CFG_GET_STATES 2
|
||||
typedef struct _ipfw_cfg_lheader {
|
||||
ip_fw3_opheader opheader; /* IP_FW3 opcode */
|
||||
uint32_t set_mask; /* disabled set mask */
|
||||
uint32_t flags; /* Request flags */
|
||||
uint32_t size; /* neded buffer size */
|
||||
uint32_t start_rule;
|
||||
uint32_t end_rule;
|
||||
} ipfw_cfg_lheader;
|
||||
|
||||
#endif /* _IPFW2_H */
|
||||
|
@ -1454,6 +1454,74 @@ ipfw_dyn_len(void)
|
||||
(DYN_COUNT * sizeof(ipfw_dyn_rule));
|
||||
}
|
||||
|
||||
static void
|
||||
export_dyn_rule(ipfw_dyn_rule *src, ipfw_dyn_rule *dst)
|
||||
{
|
||||
|
||||
memcpy(dst, src, sizeof(*src));
|
||||
memcpy(&(dst->rule), &(src->rule->rulenum), sizeof(src->rule->rulenum));
|
||||
/*
|
||||
* store set number into high word of
|
||||
* dst->rule pointer.
|
||||
*/
|
||||
memcpy((char *)&dst->rule + sizeof(src->rule->rulenum),
|
||||
&(src->rule->set), sizeof(src->rule->set));
|
||||
/*
|
||||
* store a non-null value in "next".
|
||||
* The userland code will interpret a
|
||||
* NULL here as a marker
|
||||
* for the last dynamic rule.
|
||||
*/
|
||||
memcpy(&dst->next, &dst, sizeof(dst));
|
||||
dst->expire =
|
||||
TIME_LEQ(dst->expire, time_uptime) ? 0 : dst->expire - time_uptime;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills int buffer given by @sd with dynamic states.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
int
|
||||
ipfw_dump_states(struct ip_fw_chain *chain, struct sockopt_data *sd)
|
||||
{
|
||||
ipfw_dyn_rule *p, *dst, *last = NULL;
|
||||
ipfw_obj_ctlv *ctlv;
|
||||
int i;
|
||||
|
||||
if (V_ipfw_dyn_v == NULL)
|
||||
return (0);
|
||||
|
||||
IPFW_UH_RLOCK_ASSERT(chain);
|
||||
|
||||
ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
|
||||
if (ctlv == NULL)
|
||||
return (ENOMEM);
|
||||
ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
|
||||
ctlv->objsize = sizeof(ipfw_dyn_rule);
|
||||
|
||||
for (i = 0 ; i < V_curr_dyn_buckets; i++) {
|
||||
IPFW_BUCK_LOCK(i);
|
||||
for (p = V_ipfw_dyn_v[i].head ; p != NULL; p = p->next) {
|
||||
dst = (ipfw_dyn_rule *)ipfw_get_sopt_space(sd,
|
||||
sizeof(*dst));
|
||||
if (dst == NULL) {
|
||||
IPFW_BUCK_UNLOCK(i);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
export_dyn_rule(p, dst);
|
||||
last = dst;
|
||||
}
|
||||
IPFW_BUCK_UNLOCK(i);
|
||||
}
|
||||
|
||||
if (last != NULL) /* mark last dynamic rule */
|
||||
bzero(&last->next, sizeof(last));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill given buffer with dynamic states.
|
||||
* IPFW_UH_RLOCK has to be held while calling.
|
||||
@ -1477,28 +1545,9 @@ ipfw_get_dynamic(struct ip_fw_chain *chain, char **pbp, const char *ep)
|
||||
if (bp + sizeof *p <= ep) {
|
||||
ipfw_dyn_rule *dst =
|
||||
(ipfw_dyn_rule *)bp;
|
||||
bcopy(p, dst, sizeof *p);
|
||||
bcopy(&(p->rule->rulenum), &(dst->rule),
|
||||
sizeof(p->rule->rulenum));
|
||||
/*
|
||||
* store set number into high word of
|
||||
* dst->rule pointer.
|
||||
*/
|
||||
bcopy(&(p->rule->set),
|
||||
(char *)&dst->rule +
|
||||
sizeof(p->rule->rulenum),
|
||||
sizeof(p->rule->set));
|
||||
/*
|
||||
* store a non-null value in "next".
|
||||
* The userland code will interpret a
|
||||
* NULL here as a marker
|
||||
* for the last dynamic rule.
|
||||
*/
|
||||
bcopy(&dst, &dst->next, sizeof(dst));
|
||||
|
||||
export_dyn_rule(p, dst);
|
||||
last = dst;
|
||||
dst->expire =
|
||||
TIME_LEQ(dst->expire, time_uptime) ?
|
||||
0 : dst->expire - time_uptime ;
|
||||
bp += sizeof(ipfw_dyn_rule);
|
||||
}
|
||||
}
|
||||
|
@ -176,6 +176,7 @@ enum { /* result for matching dynamic rules */
|
||||
* Eventually we may implement it with a callback on the function.
|
||||
*/
|
||||
struct ip_fw_chain;
|
||||
struct sockopt_data;
|
||||
void ipfw_expire_dyn_rules(struct ip_fw_chain *, struct ip_fw *, int);
|
||||
void ipfw_dyn_unlock(ipfw_dyn_rule *q);
|
||||
|
||||
@ -188,6 +189,7 @@ ipfw_dyn_rule *ipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt,
|
||||
int *match_direction, struct tcphdr *tcp);
|
||||
void ipfw_remove_dyn_children(struct ip_fw *rule);
|
||||
void ipfw_get_dynamic(struct ip_fw_chain *chain, char **bp, const char *ep);
|
||||
int ipfw_dump_states(struct ip_fw_chain *chain, struct sockopt_data *sd);
|
||||
|
||||
void ipfw_dyn_init(struct ip_fw_chain *); /* per-vnet initialization */
|
||||
void ipfw_dyn_uninit(int); /* per-vnet deinitialization */
|
||||
|
@ -989,6 +989,178 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
|
||||
}
|
||||
|
||||
|
||||
struct dump_args {
|
||||
uint32_t b; /* start rule */
|
||||
uint32_t e; /* end rule */
|
||||
uint32_t rcount; /* number of rules */
|
||||
uint32_t rsize; /* rules size */
|
||||
uint32_t tcount; /* number of tables */
|
||||
};
|
||||
|
||||
/*
|
||||
* Dumps static rules with table TLVs in buffer @sd.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
static int
|
||||
dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da,
|
||||
uint32_t *bmask, struct sockopt_data *sd)
|
||||
{
|
||||
int error;
|
||||
int i, l;
|
||||
uint32_t tcount;
|
||||
ipfw_obj_ctlv *ctlv;
|
||||
struct ip_fw *dst, *rule;
|
||||
time_t boot_seconds;
|
||||
|
||||
/* Dump table names first (if any) */
|
||||
if (da->tcount > 0) {
|
||||
/* Header first */
|
||||
ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
|
||||
if (ctlv == NULL)
|
||||
return (ENOMEM);
|
||||
ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
|
||||
ctlv->head.length = da->tcount * sizeof(ipfw_obj_ntlv) +
|
||||
sizeof(*ctlv);
|
||||
ctlv->count = da->tcount;
|
||||
ctlv->objsize = sizeof(ipfw_obj_ntlv);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
tcount = da->tcount;
|
||||
while (tcount > 0) {
|
||||
if ((bmask[i / 32] & (1 << (i % 32))) == 0) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((error = ipfw_export_table_ntlv(chain, i, sd)) != 0)
|
||||
return (error);
|
||||
|
||||
i++;
|
||||
tcount--;
|
||||
}
|
||||
|
||||
/* Dump rules */
|
||||
ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
|
||||
if (ctlv == NULL)
|
||||
return (ENOMEM);
|
||||
ctlv->head.type = IPFW_TLV_RULE_LIST;
|
||||
ctlv->head.length = da->rsize + sizeof(*ctlv);
|
||||
ctlv->count = da->rcount;
|
||||
|
||||
boot_seconds = boottime.tv_sec;
|
||||
for (i = da->b; i < da->e; i++) {
|
||||
rule = chain->map[i];
|
||||
|
||||
l = RULESIZE(rule);
|
||||
/* XXX: align to u64 */
|
||||
dst = (struct ip_fw *)ipfw_get_sopt_space(sd, l);
|
||||
if (rule == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
bcopy(rule, dst, l);
|
||||
if (dst->timestamp != 0)
|
||||
dst->timestamp += boot_seconds;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dumps requested objects data
|
||||
* Data layout (version 0)(current):
|
||||
* Request: [ ipfw_cfg_lheader ] + IPFW_CFG_GET_* flags
|
||||
* size = ipfw_cfg_lheader.size
|
||||
* Reply: [ ipfw_rules_lheader
|
||||
* [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
|
||||
* [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] (optional)
|
||||
* [ ipfw_obj_ctlv(IPFW_TLV_STATE_LIST) ipfw_dyn_rule x N ] (optional)
|
||||
* ]
|
||||
* * NOTE IPFW_TLV_STATE_LIST has the single valid field: objsize.
|
||||
* The rest (size, count) are set to zero and needs to be ignored.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
*/
|
||||
static int
|
||||
dump_config(struct ip_fw_chain *chain, struct sockopt_data *sd)
|
||||
{
|
||||
ipfw_cfg_lheader *hdr;
|
||||
struct ip_fw *rule;
|
||||
uint32_t sz;
|
||||
int error, i;
|
||||
struct dump_args da;
|
||||
uint32_t *bmask;
|
||||
|
||||
hdr = (ipfw_cfg_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
|
||||
if (hdr == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
/* Allocate needed state */
|
||||
error = 0;
|
||||
bmask = NULL;
|
||||
if (hdr->flags & IPFW_CFG_GET_STATIC)
|
||||
bmask = malloc(IPFW_TABLES_MAX / 8, M_TEMP, M_WAITOK | M_ZERO);
|
||||
|
||||
IPFW_UH_RLOCK(chain);
|
||||
|
||||
/*
|
||||
* STAGE 1: Determine size/count for objects in range.
|
||||
* Prepare used tables bitmask.
|
||||
*/
|
||||
sz = 0;
|
||||
memset(&da, 0, sizeof(da));
|
||||
|
||||
da.b = 0;
|
||||
da.e = chain->n_rules;
|
||||
|
||||
if (hdr->flags & IPFW_CFG_GET_STATIC) {
|
||||
for (i = da.b; i < da.e; i++) {
|
||||
rule = chain->map[i];
|
||||
da.rsize += RULESIZE(rule);
|
||||
da.rcount++;
|
||||
da.tcount += ipfw_mark_table_kidx(chain, rule, bmask);
|
||||
}
|
||||
|
||||
if (da.tcount > 0)
|
||||
sz += da.tcount * sizeof(ipfw_obj_ntlv) +
|
||||
sizeof(ipfw_obj_ctlv);
|
||||
sz += da.rsize + sizeof(ipfw_obj_ctlv);
|
||||
}
|
||||
|
||||
if (hdr->flags & IPFW_CFG_GET_STATES) {
|
||||
sz += ipfw_dyn_len();
|
||||
}
|
||||
|
||||
/* Fill header anyway */
|
||||
hdr->size = sz;
|
||||
hdr->set_mask = V_set_disable;
|
||||
|
||||
if (sd->valsize < sz) {
|
||||
IPFW_UH_RUNLOCK(chain);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
/* STAGE2: Store actual data */
|
||||
if (hdr->flags & IPFW_CFG_GET_STATIC) {
|
||||
error = dump_static_rules(chain, &da, bmask, sd);
|
||||
if (error != 0) {
|
||||
IPFW_UH_RUNLOCK(chain);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
if (hdr->flags & IPFW_CFG_GET_STATES)
|
||||
error = ipfw_dump_states(chain, sd);
|
||||
|
||||
IPFW_UH_RUNLOCK(chain);
|
||||
|
||||
if (bmask != NULL)
|
||||
free(bmask, M_TEMP);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
#define IP_FW3_OPLENGTH(x) ((x)->sopt_valsize - sizeof(ip_fw3_opheader))
|
||||
#define IP_FW3_OPTBUF 4096 /* page-size */
|
||||
/**
|
||||
@ -1101,6 +1273,10 @@ ipfw_ctl(struct sockopt *sopt)
|
||||
}
|
||||
break;
|
||||
|
||||
case IP_FW_XGET: /* IP_FW3 */
|
||||
error = dump_config(chain, &sdata);
|
||||
break;
|
||||
|
||||
case IP_FW_FLUSH:
|
||||
/* locking is done within del_entry() */
|
||||
error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */
|
||||
|
@ -27,16 +27,15 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/*
|
||||
* Lookup table support for ipfw
|
||||
* Lookup table support for ipfw.
|
||||
*
|
||||
* Lookup tables are implemented (at the moment) using the radix
|
||||
* tree used for routing tables. Tables store key-value entries, where
|
||||
* keys are network prefixes (addr/masklen), and values are integers.
|
||||
* As a degenerate case we can interpret keys as 32-bit integers
|
||||
* (with a /32 mask).
|
||||
* This file containg handlers for all generic tables operations:
|
||||
* add/del/flush entries, list/dump tables etc..
|
||||
*
|
||||
* The table is protected by the IPFW lock even for manipulation coming
|
||||
* from userland, because operations are typically fast.
|
||||
* Table data modification is protected by both UH and runtimg lock
|
||||
* while reading configuration/data is protected by UH lock.
|
||||
*
|
||||
* Lookup algorithms for all table types are located in ip_fw_table_algo.c
|
||||
*/
|
||||
|
||||
#include "opt_ipfw.h"
|
||||
@ -901,6 +900,31 @@ objheader_to_ti(struct _ipfw_obj_header *oh, struct tid_info *ti)
|
||||
ti->tlen = oh->ntlv.head.length;
|
||||
}
|
||||
|
||||
int
|
||||
ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx,
|
||||
struct sockopt_data *sd)
|
||||
{
|
||||
struct namedobj_instance *ni;
|
||||
struct named_object *no;
|
||||
ipfw_obj_ntlv *ntlv;
|
||||
|
||||
ni = CHAIN_TO_NI(ch);
|
||||
|
||||
no = ipfw_objhash_lookup_idx(ni, 0, kidx);
|
||||
KASSERT(no != NULL, ("invalid table kidx passed"));
|
||||
|
||||
ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
|
||||
if (ntlv == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
ntlv->head.type = IPFW_TLV_TBL_NAME;
|
||||
ntlv->head.length = sizeof(*ntlv);
|
||||
ntlv->idx = no->kidx;
|
||||
strlcpy(ntlv->name, no->name, sizeof(ntlv->name));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
export_table_info(struct table_config *tc, ipfw_xtable_info *i)
|
||||
{
|
||||
@ -1253,7 +1277,7 @@ find_name_tlv(void *tlvs, int len, uint16_t uidx)
|
||||
for (; pa < pe; pa += l) {
|
||||
ntlv = (ipfw_obj_ntlv *)pa;
|
||||
l = ntlv->head.length;
|
||||
if (ntlv->head.type != IPFW_TLV_NAME)
|
||||
if (ntlv->head.type != IPFW_TLV_TBL_NAME)
|
||||
continue;
|
||||
if (ntlv->idx != uidx)
|
||||
continue;
|
||||
@ -1515,6 +1539,40 @@ ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets every table kidx in @bmask which is used in rule @rule.
|
||||
*
|
||||
* Returns number of newly-referenced tables.
|
||||
*/
|
||||
int
|
||||
ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule,
|
||||
uint32_t *bmask)
|
||||
{
|
||||
int cmdlen, l, count;
|
||||
ipfw_insn *cmd;
|
||||
uint16_t kidx;
|
||||
uint8_t type;
|
||||
|
||||
l = rule->cmd_len;
|
||||
cmd = rule->cmd;
|
||||
cmdlen = 0;
|
||||
count = 0;
|
||||
for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
|
||||
cmdlen = F_LEN(cmd);
|
||||
|
||||
if (classify_table_opcode(cmd, &kidx, &type) != 0)
|
||||
continue;
|
||||
|
||||
if ((bmask[kidx / 32] & (1 << (kidx % 32))) == 0)
|
||||
count++;
|
||||
|
||||
bmask[kidx / 32] |= 1 << (kidx % 32);
|
||||
}
|
||||
|
||||
return (count);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Checks is opcode is referencing table of appropriate type.
|
||||
|
@ -111,6 +111,10 @@ int ipfw_del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti,
|
||||
int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
|
||||
struct rule_check_info *ci);
|
||||
int ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule);
|
||||
int ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule,
|
||||
uint32_t *bmask);
|
||||
int ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx,
|
||||
struct sockopt_data *sd);
|
||||
void ipfw_unbind_table_rule(struct ip_fw_chain *chain, struct ip_fw *rule);
|
||||
void ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user