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
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/ipfw/; revision=268009
@ -137,15 +137,15 @@ altq_qid_to_name(u_int32_t qid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
print_altq_cmd(ipfw_insn_altq *altqptr)
|
print_altq_cmd(struct buf_pr *bp, ipfw_insn_altq *altqptr)
|
||||||
{
|
{
|
||||||
if (altqptr) {
|
if (altqptr) {
|
||||||
const char *qname;
|
const char *qname;
|
||||||
|
|
||||||
qname = altq_qid_to_name(altqptr->qid);
|
qname = altq_qid_to_name(altqptr->qid);
|
||||||
if (qname == NULL)
|
if (qname == NULL)
|
||||||
printf(" altq ?<%u>", altqptr->qid);
|
bprintf(bp, " altq ?<%u>", altqptr->qid);
|
||||||
else
|
else
|
||||||
printf(" altq %s", qname);
|
bprintf(bp, " altq %s", qname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,48 +174,44 @@ print_header(struct ipfw_flow_id *id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
list_flow(struct dn_flow *ni, int *print)
|
list_flow(struct buf_pr *bp, struct dn_flow *ni)
|
||||||
{
|
{
|
||||||
char buff[255];
|
char buff[255];
|
||||||
struct protoent *pe = NULL;
|
struct protoent *pe = NULL;
|
||||||
struct in_addr ina;
|
struct in_addr ina;
|
||||||
struct ipfw_flow_id *id = &ni->fid;
|
struct ipfw_flow_id *id = &ni->fid;
|
||||||
|
|
||||||
if (*print) {
|
|
||||||
print_header(&ni->fid);
|
|
||||||
*print = 0;
|
|
||||||
}
|
|
||||||
pe = getprotobynumber(id->proto);
|
pe = getprotobynumber(id->proto);
|
||||||
/* XXX: Should check for IPv4 flows */
|
/* XXX: Should check for IPv4 flows */
|
||||||
printf("%3u%c", (ni->oid.id) & 0xff,
|
bprintf(bp, "%3u%c", (ni->oid.id) & 0xff,
|
||||||
id->extra ? '*' : ' ');
|
id->extra ? '*' : ' ');
|
||||||
if (!IS_IP6_FLOW_ID(id)) {
|
if (!IS_IP6_FLOW_ID(id)) {
|
||||||
if (pe)
|
if (pe)
|
||||||
printf("%-4s ", pe->p_name);
|
bprintf(bp, "%-4s ", pe->p_name);
|
||||||
else
|
else
|
||||||
printf("%4u ", id->proto);
|
bprintf(bp, "%4u ", id->proto);
|
||||||
ina.s_addr = htonl(id->src_ip);
|
ina.s_addr = htonl(id->src_ip);
|
||||||
printf("%15s/%-5d ",
|
bprintf(bp, "%15s/%-5d ",
|
||||||
inet_ntoa(ina), id->src_port);
|
inet_ntoa(ina), id->src_port);
|
||||||
ina.s_addr = htonl(id->dst_ip);
|
ina.s_addr = htonl(id->dst_ip);
|
||||||
printf("%15s/%-5d ",
|
bprintf(bp, "%15s/%-5d ",
|
||||||
inet_ntoa(ina), id->dst_port);
|
inet_ntoa(ina), id->dst_port);
|
||||||
} else {
|
} else {
|
||||||
/* Print IPv6 flows */
|
/* Print IPv6 flows */
|
||||||
if (pe != NULL)
|
if (pe != NULL)
|
||||||
printf("%9s ", pe->p_name);
|
bprintf(bp, "%9s ", pe->p_name);
|
||||||
else
|
else
|
||||||
printf("%9u ", id->proto);
|
bprintf(bp, "%9u ", id->proto);
|
||||||
printf("%7d %39s/%-5d ", id->flow_id6,
|
bprintf(bp, "%7d %39s/%-5d ", id->flow_id6,
|
||||||
inet_ntop(AF_INET6, &(id->src_ip6), buff, sizeof(buff)),
|
inet_ntop(AF_INET6, &(id->src_ip6), buff, sizeof(buff)),
|
||||||
id->src_port);
|
id->src_port);
|
||||||
printf(" %39s/%-5d ",
|
bprintf(bp, " %39s/%-5d ",
|
||||||
inet_ntop(AF_INET6, &(id->dst_ip6), buff, sizeof(buff)),
|
inet_ntop(AF_INET6, &(id->dst_ip6), buff, sizeof(buff)),
|
||||||
id->dst_port);
|
id->dst_port);
|
||||||
}
|
}
|
||||||
pr_u64(&ni->tot_pkts, 4);
|
pr_u64(bp, &ni->tot_pkts, 4);
|
||||||
pr_u64(&ni->tot_bytes, 8);
|
pr_u64(bp, &ni->tot_bytes, 8);
|
||||||
printf("%2u %4u %3u\n",
|
bprintf(bp, "%2u %4u %3u",
|
||||||
ni->length, ni->len_bytes, ni->drops);
|
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 */
|
char buf[160]; /* pending buffer */
|
||||||
int toPrint = 1; /* print header */
|
int toPrint = 1; /* print header */
|
||||||
|
struct buf_pr bp;
|
||||||
|
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
|
bp_alloc(&bp, 4096);
|
||||||
for (; oid != end; oid = O_NEXT(oid, oid->len)) {
|
for (; oid != end; oid = O_NEXT(oid, oid->len)) {
|
||||||
if (oid->len < sizeof(*oid))
|
if (oid->len < sizeof(*oid))
|
||||||
errx(1, "invalid oid len %d\n", oid->len);
|
errx(1, "invalid oid len %d\n", oid->len);
|
||||||
@ -346,7 +344,12 @@ list_pipes(struct dn_id *oid, struct dn_id *end)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DN_FLOW:
|
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;
|
break;
|
||||||
|
|
||||||
case DN_LINK: {
|
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 ?
|
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 NEED(_p, msg) {if (!_p) errx(EX_USAGE, msg);}
|
||||||
#define NEED1(msg) {if (!(*av)) 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 */
|
/* memory allocation support */
|
||||||
void *safe_calloc(size_t number, size_t size);
|
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 */
|
/* altq.c */
|
||||||
void altq_set_enabled(int enabled);
|
void altq_set_enabled(int enabled);
|
||||||
u_int32_t altq_name_to_qid(const char *name);
|
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
|
#else
|
||||||
#define NO_ALTQ
|
#define NO_ALTQ
|
||||||
#endif
|
#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_unreach6_code(u_short *codep, char *str);
|
||||||
void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av, int cblen);
|
void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av, int cblen);
|
||||||
int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
|
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)
|
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->head.length = sizeof(ipfw_obj_ntlv);
|
||||||
ntlv->idx = uidx;
|
ntlv->idx = uidx;
|
||||||
strlcpy(ntlv->name, name, sizeof(ntlv->name));
|
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_XFLUSH 94 /* flush table data */
|
||||||
#define IP_FW_TABLE_XCREATE 95 /* create new table */
|
#define IP_FW_TABLE_XCREATE 95 /* create new table */
|
||||||
#define IP_FW_TABLE_XMODIFY 96 /* modify existing table */
|
#define IP_FW_TABLE_XMODIFY 96 /* modify existing table */
|
||||||
|
#define IP_FW_XGET 97 /* Retrieve configuration */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Usage guidelines:
|
* Usage guidelines:
|
||||||
@ -681,18 +682,30 @@ typedef struct _ipfw_xtable {
|
|||||||
|
|
||||||
typedef struct _ipfw_obj_tlv {
|
typedef struct _ipfw_obj_tlv {
|
||||||
uint16_t type; /* TLV type */
|
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;
|
} 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 */
|
/* Object name TLV */
|
||||||
typedef struct _ipfw_obj_ntlv {
|
typedef struct _ipfw_obj_ntlv {
|
||||||
ipfw_obj_tlv head; /* TLV header */
|
ipfw_obj_tlv head; /* TLV header */
|
||||||
uint16_t idx; /* Name index */
|
uint16_t idx; /* Name index */
|
||||||
uint16_t spare; /* unused */
|
uint16_t spare0; /* unused */
|
||||||
char name[64]; /* Null-terminated name */
|
uint32_t spare1; /* unused */
|
||||||
|
char name[64]; /* Null-terminated name */
|
||||||
} ipfw_obj_ntlv;
|
} 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 {
|
typedef struct _ipfw_xtable_info {
|
||||||
uint8_t type; /* table type (cidr,iface,..) */
|
uint8_t type; /* table type (cidr,iface,..) */
|
||||||
uint8_t ftype; /* table value format type */
|
uint8_t ftype; /* table value format type */
|
||||||
@ -725,4 +738,15 @@ typedef struct _ipfw_obj_lheader {
|
|||||||
uint32_t objsize; /* Size of one object */
|
uint32_t objsize; /* Size of one object */
|
||||||
} ipfw_obj_lheader;
|
} 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 */
|
#endif /* _IPFW2_H */
|
||||||
|
@ -1454,6 +1454,74 @@ ipfw_dyn_len(void)
|
|||||||
(DYN_COUNT * sizeof(ipfw_dyn_rule));
|
(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.
|
* Fill given buffer with dynamic states.
|
||||||
* IPFW_UH_RLOCK has to be held while calling.
|
* 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) {
|
if (bp + sizeof *p <= ep) {
|
||||||
ipfw_dyn_rule *dst =
|
ipfw_dyn_rule *dst =
|
||||||
(ipfw_dyn_rule *)bp;
|
(ipfw_dyn_rule *)bp;
|
||||||
bcopy(p, dst, sizeof *p);
|
|
||||||
bcopy(&(p->rule->rulenum), &(dst->rule),
|
export_dyn_rule(p, dst);
|
||||||
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));
|
|
||||||
last = dst;
|
last = dst;
|
||||||
dst->expire =
|
|
||||||
TIME_LEQ(dst->expire, time_uptime) ?
|
|
||||||
0 : dst->expire - time_uptime ;
|
|
||||||
bp += sizeof(ipfw_dyn_rule);
|
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.
|
* Eventually we may implement it with a callback on the function.
|
||||||
*/
|
*/
|
||||||
struct ip_fw_chain;
|
struct ip_fw_chain;
|
||||||
|
struct sockopt_data;
|
||||||
void ipfw_expire_dyn_rules(struct ip_fw_chain *, struct ip_fw *, int);
|
void ipfw_expire_dyn_rules(struct ip_fw_chain *, struct ip_fw *, int);
|
||||||
void ipfw_dyn_unlock(ipfw_dyn_rule *q);
|
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);
|
int *match_direction, struct tcphdr *tcp);
|
||||||
void ipfw_remove_dyn_children(struct ip_fw *rule);
|
void ipfw_remove_dyn_children(struct ip_fw *rule);
|
||||||
void ipfw_get_dynamic(struct ip_fw_chain *chain, char **bp, const char *ep);
|
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_init(struct ip_fw_chain *); /* per-vnet initialization */
|
||||||
void ipfw_dyn_uninit(int); /* per-vnet deinitialization */
|
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_OPLENGTH(x) ((x)->sopt_valsize - sizeof(ip_fw3_opheader))
|
||||||
#define IP_FW3_OPTBUF 4096 /* page-size */
|
#define IP_FW3_OPTBUF 4096 /* page-size */
|
||||||
/**
|
/**
|
||||||
@ -1101,6 +1273,10 @@ ipfw_ctl(struct sockopt *sopt)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IP_FW_XGET: /* IP_FW3 */
|
||||||
|
error = dump_config(chain, &sdata);
|
||||||
|
break;
|
||||||
|
|
||||||
case IP_FW_FLUSH:
|
case IP_FW_FLUSH:
|
||||||
/* locking is done within del_entry() */
|
/* locking is done within del_entry() */
|
||||||
error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */
|
error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */
|
||||||
|
@ -27,16 +27,15 @@
|
|||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lookup table support for ipfw
|
* Lookup table support for ipfw.
|
||||||
*
|
*
|
||||||
* Lookup tables are implemented (at the moment) using the radix
|
* This file containg handlers for all generic tables operations:
|
||||||
* tree used for routing tables. Tables store key-value entries, where
|
* add/del/flush entries, list/dump tables etc..
|
||||||
* 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).
|
|
||||||
*
|
*
|
||||||
* The table is protected by the IPFW lock even for manipulation coming
|
* Table data modification is protected by both UH and runtimg lock
|
||||||
* from userland, because operations are typically fast.
|
* 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"
|
#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;
|
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
|
static void
|
||||||
export_table_info(struct table_config *tc, ipfw_xtable_info *i)
|
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) {
|
for (; pa < pe; pa += l) {
|
||||||
ntlv = (ipfw_obj_ntlv *)pa;
|
ntlv = (ipfw_obj_ntlv *)pa;
|
||||||
l = ntlv->head.length;
|
l = ntlv->head.length;
|
||||||
if (ntlv->head.type != IPFW_TLV_NAME)
|
if (ntlv->head.type != IPFW_TLV_TBL_NAME)
|
||||||
continue;
|
continue;
|
||||||
if (ntlv->idx != uidx)
|
if (ntlv->idx != uidx)
|
||||||
continue;
|
continue;
|
||||||
@ -1515,6 +1539,40 @@ ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule)
|
|||||||
return (0);
|
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.
|
* 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,
|
int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain,
|
||||||
struct rule_check_info *ci);
|
struct rule_check_info *ci);
|
||||||
int ipfw_rewrite_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule);
|
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_rule(struct ip_fw_chain *chain, struct ip_fw *rule);
|
||||||
void ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head);
|
void ipfw_unbind_table_list(struct ip_fw_chain *chain, struct ip_fw *head);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user