mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-29 08:08:37 +00:00
Add ability to request listing and deleting only for dynamic states.
This can be useful, when net.inet.ip.fw.dyn_keep_states is enabled, but after rules reloading some state must be deleted. Added new flag '-D' for such purpose. Retire '-e' flag, since there can not be expired states in the meaning that this flag historically had. Also add "verbose" mode for listing of dynamic states, it can be enabled with '-v' flag and adds additional information to states list. This can be useful for debugging. Obtained from: Yandex LLC MFC after: 2 months Sponsored by: Yandex LLC
This commit is contained in:
parent
cefe3d67e2
commit
d66f9c86fa
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=341472
@ -1,7 +1,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd November 13, 2018
|
||||
.Dd December 4, 2018
|
||||
.Dt IPFW 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -310,10 +310,9 @@ i.e., omitting the "ip from any to any" string
|
||||
when this does not carry any additional information.
|
||||
.It Fl d
|
||||
When listing, show dynamic rules in addition to static ones.
|
||||
.It Fl e
|
||||
When listing and
|
||||
.Fl d
|
||||
is specified, also show expired dynamic rules.
|
||||
.It Fl D
|
||||
When listing, show only dynamic states.
|
||||
When deleting, delete only dynamic states.
|
||||
.It Fl f
|
||||
Run without prompting for confirmation for commands that can cause problems if misused,
|
||||
i.e.,
|
||||
|
@ -2247,10 +2247,9 @@ show_dyn_state(struct cmdline_opts *co, struct format_opts *fo,
|
||||
uint16_t rulenum;
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
|
||||
if (!co->do_expired) {
|
||||
if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT))
|
||||
return;
|
||||
}
|
||||
if (d->expire == 0 && d->dyn_type != O_LIMIT_PARENT)
|
||||
return;
|
||||
|
||||
bcopy(&d->rule, &rulenum, sizeof(rulenum));
|
||||
bprintf(bp, "%05d", rulenum);
|
||||
if (fo->pcwidth > 0 || fo->bcwidth > 0) {
|
||||
@ -2292,6 +2291,33 @@ show_dyn_state(struct cmdline_opts *co, struct format_opts *fo,
|
||||
if (d->kidx != 0)
|
||||
bprintf(bp, " :%s", object_search_ctlv(fo->tstate,
|
||||
d->kidx, IPFW_TLV_STATE_NAME));
|
||||
|
||||
#define BOTH_SYN (TH_SYN | (TH_SYN << 8))
|
||||
#define BOTH_FIN (TH_FIN | (TH_FIN << 8))
|
||||
if (co->verbose) {
|
||||
bprintf(bp, " state 0x%08x%s", d->state,
|
||||
d->state ? " ": ",");
|
||||
if (d->state & IPFW_DYN_ORPHANED)
|
||||
bprintf(bp, "ORPHANED,");
|
||||
if ((d->state & BOTH_SYN) == BOTH_SYN)
|
||||
bprintf(bp, "BOTH_SYN,");
|
||||
else {
|
||||
if (d->state & TH_SYN)
|
||||
bprintf(bp, "F_SYN,");
|
||||
if (d->state & (TH_SYN << 8))
|
||||
bprintf(bp, "R_SYN,");
|
||||
}
|
||||
if ((d->state & BOTH_FIN) == BOTH_FIN)
|
||||
bprintf(bp, "BOTH_FIN,");
|
||||
else {
|
||||
if (d->state & TH_FIN)
|
||||
bprintf(bp, "F_FIN,");
|
||||
if (d->state & (TH_FIN << 8))
|
||||
bprintf(bp, "R_FIN,");
|
||||
}
|
||||
bprintf(bp, " f_ack 0x%x, r_ack 0x%x", d->ack_fwd,
|
||||
d->ack_rev);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2695,7 +2721,8 @@ ipfw_list(int ac, char *av[], int show_counters)
|
||||
cfg = NULL;
|
||||
sfo.show_counters = show_counters;
|
||||
sfo.show_time = co.do_time;
|
||||
sfo.flags = IPFW_CFG_GET_STATIC;
|
||||
if (co.do_dynamic != 2)
|
||||
sfo.flags |= IPFW_CFG_GET_STATIC;
|
||||
if (co.do_dynamic != 0)
|
||||
sfo.flags |= IPFW_CFG_GET_STATES;
|
||||
if ((sfo.show_counters | sfo.show_time) != 0)
|
||||
@ -2740,17 +2767,15 @@ ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo,
|
||||
fo->set_mask = cfg->set_mask;
|
||||
|
||||
ctlv = (ipfw_obj_ctlv *)(cfg + 1);
|
||||
if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
|
||||
object_sort_ctlv(ctlv);
|
||||
fo->tstate = ctlv;
|
||||
readsz += ctlv->head.length;
|
||||
ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
|
||||
}
|
||||
|
||||
if (cfg->flags & IPFW_CFG_GET_STATIC) {
|
||||
/* We've requested static rules */
|
||||
if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
|
||||
object_sort_ctlv(ctlv);
|
||||
fo->tstate = ctlv;
|
||||
readsz += ctlv->head.length;
|
||||
ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv +
|
||||
ctlv->head.length);
|
||||
}
|
||||
|
||||
if (ctlv->head.type == IPFW_TLV_RULE_LIST) {
|
||||
rbase = (ipfw_obj_tlv *)(ctlv + 1);
|
||||
rcnt = ctlv->count;
|
||||
@ -2777,10 +2802,12 @@ ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo,
|
||||
if (ac == 0) {
|
||||
fo->first = 0;
|
||||
fo->last = IPFW_DEFAULT_RULE;
|
||||
list_static_range(co, fo, &bp, rbase, rcnt);
|
||||
if (cfg->flags & IPFW_CFG_GET_STATIC)
|
||||
list_static_range(co, fo, &bp, rbase, rcnt);
|
||||
|
||||
if (co->do_dynamic && dynsz > 0) {
|
||||
printf("## Dynamic rules (%d %zu):\n", fo->dcnt, dynsz);
|
||||
printf("## Dynamic rules (%d %zu):\n", fo->dcnt,
|
||||
dynsz);
|
||||
list_dyn_range(co, fo, &bp, dynbase, dynsz);
|
||||
}
|
||||
|
||||
@ -2800,6 +2827,9 @@ ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo,
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((cfg->flags & IPFW_CFG_GET_STATIC) == 0)
|
||||
continue;
|
||||
|
||||
if (list_static_range(co, fo, &bp, rbase, rcnt) == 0) {
|
||||
/* give precedence to other error(s) */
|
||||
if (exitval == EX_OK)
|
||||
@ -3313,6 +3343,8 @@ ipfw_delete(char *av[])
|
||||
rt.flags |= IPFW_RCFLAG_SET;
|
||||
}
|
||||
}
|
||||
if (co.do_dynamic == 2)
|
||||
rt.flags |= IPFW_RCFLAG_DYNAMIC;
|
||||
i = do_range_cmd(IP_FW_XDEL, &rt);
|
||||
if (i != 0) {
|
||||
exitval = EX_UNAVAILABLE;
|
||||
@ -3320,7 +3352,8 @@ ipfw_delete(char *av[])
|
||||
continue;
|
||||
warn("rule %u: setsockopt(IP_FW_XDEL)",
|
||||
rt.start_rule);
|
||||
} else if (rt.new_set == 0 && do_set == 0) {
|
||||
} else if (rt.new_set == 0 && do_set == 0 &&
|
||||
co.do_dynamic != 2) {
|
||||
exitval = EX_UNAVAILABLE;
|
||||
if (co.do_quiet)
|
||||
continue;
|
||||
|
@ -37,8 +37,6 @@ struct cmdline_opts {
|
||||
int do_quiet; /* Be quiet in add and flush */
|
||||
int do_pipe; /* this cmd refers to a pipe/queue/sched */
|
||||
int do_nat; /* this cmd refers to a nat config */
|
||||
int do_dynamic; /* display dynamic rules */
|
||||
int do_expired; /* display expired dynamic rules */
|
||||
int do_compact; /* show rules in compact mode */
|
||||
int do_force; /* do not ask for confirmation */
|
||||
int show_sets; /* display the set each rule belongs to */
|
||||
@ -48,6 +46,8 @@ struct cmdline_opts {
|
||||
|
||||
/* The options below can have multiple values. */
|
||||
|
||||
int do_dynamic; /* 1 - display dynamic rules */
|
||||
/* 2 - display/delete only dynamic rules */
|
||||
int do_sort; /* field to sort results (0 = no) */
|
||||
/* valid fields are 1 and above */
|
||||
|
||||
|
@ -262,7 +262,7 @@ ipfw_main(int oldac, char **oldav)
|
||||
save_av = av;
|
||||
|
||||
optind = optreset = 1; /* restart getopt() */
|
||||
while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtv")) != -1)
|
||||
while ((ch = getopt(ac, av, "abcdDefhinNp:qs:STtv")) != -1)
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
do_acct = 1;
|
||||
@ -281,8 +281,12 @@ ipfw_main(int oldac, char **oldav)
|
||||
co.do_dynamic = 1;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
co.do_dynamic = 2;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
co.do_expired = 1;
|
||||
/* nop for compatibility */
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
|
@ -708,6 +708,7 @@ struct _ipfw_dyn_rule {
|
||||
u_int32_t state; /* state of this rule (typically a
|
||||
* combination of TCP flags)
|
||||
*/
|
||||
#define IPFW_DYN_ORPHANED 0x40000 /* state's parent rule was deleted */
|
||||
u_int32_t ack_fwd; /* most recent ACKs in forward */
|
||||
u_int32_t ack_rev; /* and reverse directions (used */
|
||||
/* to generate keepalives) */
|
||||
@ -938,9 +939,10 @@ typedef struct _ipfw_range_tlv {
|
||||
#define IPFW_RCFLAG_RANGE 0x01 /* rule range is set */
|
||||
#define IPFW_RCFLAG_ALL 0x02 /* match ALL rules */
|
||||
#define IPFW_RCFLAG_SET 0x04 /* match rules in given set */
|
||||
#define IPFW_RCFLAG_DYNAMIC 0x08 /* match only dynamic states */
|
||||
/* User-settable flags */
|
||||
#define IPFW_RCFLAG_USER (IPFW_RCFLAG_RANGE | IPFW_RCFLAG_ALL | \
|
||||
IPFW_RCFLAG_SET)
|
||||
IPFW_RCFLAG_SET | IPFW_RCFLAG_DYNAMIC)
|
||||
/* Internally used flags */
|
||||
#define IPFW_RCFLAG_DEFAULT 0x0100 /* Do not skip defaul rule */
|
||||
|
||||
|
@ -2110,7 +2110,11 @@ dyn_free_states(struct ip_fw_chain *chain)
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 when state is matched by specified range, otherwise returns 0.
|
||||
* Returns:
|
||||
* 0 when state is not matched by specified range;
|
||||
* 1 when state is matched by specified range;
|
||||
* 2 when state is matched by specified range and requested deletion of
|
||||
* dynamic states.
|
||||
*/
|
||||
static int
|
||||
dyn_match_range(uint16_t rulenum, uint8_t set, const ipfw_range_tlv *rt)
|
||||
@ -2118,13 +2122,18 @@ dyn_match_range(uint16_t rulenum, uint8_t set, const ipfw_range_tlv *rt)
|
||||
|
||||
MPASS(rt != NULL);
|
||||
/* flush all states */
|
||||
if (rt->flags & IPFW_RCFLAG_ALL)
|
||||
if (rt->flags & IPFW_RCFLAG_ALL) {
|
||||
if (rt->flags & IPFW_RCFLAG_DYNAMIC)
|
||||
return (2); /* forced */
|
||||
return (1);
|
||||
}
|
||||
if ((rt->flags & IPFW_RCFLAG_SET) != 0 && set != rt->set)
|
||||
return (0);
|
||||
if ((rt->flags & IPFW_RCFLAG_RANGE) != 0 &&
|
||||
(rulenum < rt->start_rule || rulenum > rt->end_rule))
|
||||
return (0);
|
||||
if (rt->flags & IPFW_RCFLAG_DYNAMIC)
|
||||
return (2);
|
||||
return (1);
|
||||
}
|
||||
|
||||
@ -2194,7 +2203,7 @@ dyn_match_ipv4_state(struct ip_fw_chain *ch, struct dyn_ipv4_state *s,
|
||||
s->limit->set, rt));
|
||||
|
||||
ret = dyn_match_range(s->data->rulenum, s->data->set, rt);
|
||||
if (ret == 0 || V_dyn_keep_states == 0)
|
||||
if (ret == 0 || V_dyn_keep_states == 0 || ret > 1)
|
||||
return (ret);
|
||||
|
||||
rule = s->data->parent;
|
||||
@ -2217,7 +2226,7 @@ dyn_match_ipv6_state(struct ip_fw_chain *ch, struct dyn_ipv6_state *s,
|
||||
s->limit->set, rt));
|
||||
|
||||
ret = dyn_match_range(s->data->rulenum, s->data->set, rt);
|
||||
if (ret == 0 || V_dyn_keep_states == 0)
|
||||
if (ret == 0 || V_dyn_keep_states == 0 || ret > 1)
|
||||
return (ret);
|
||||
|
||||
rule = s->data->parent;
|
||||
@ -2939,9 +2948,12 @@ dyn_export_data(const struct dyn_data *data, uint16_t kidx, uint8_t type,
|
||||
memcpy((char *)&dst->rule + sizeof(data->rulenum), &data->set,
|
||||
sizeof(data->set));
|
||||
|
||||
dst->state = data->state;
|
||||
if (data->flags & DYN_REFERENCED)
|
||||
dst->state |= IPFW_DYN_ORPHANED;
|
||||
|
||||
/* unused fields */
|
||||
dst->parent = NULL;
|
||||
dst->state = data->state;
|
||||
dst->ack_fwd = data->ack_fwd;
|
||||
dst->ack_rev = data->ack_rev;
|
||||
dst->count = 0;
|
||||
|
@ -1033,6 +1033,16 @@ delete_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int *ndel)
|
||||
end = ipfw_find_rule(chain, rt->end_rule, UINT32_MAX);
|
||||
}
|
||||
|
||||
if (rt->flags & IPFW_RCFLAG_DYNAMIC) {
|
||||
/*
|
||||
* Requested deleting only for dynamic states.
|
||||
*/
|
||||
*ndel = 0;
|
||||
ipfw_expire_dyn_states(chain, rt);
|
||||
IPFW_UH_WUNLOCK(chain);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Allocate new map of the same size */
|
||||
map = get_map(chain, 0, 1 /* locked */);
|
||||
if (map == NULL) {
|
||||
@ -2402,7 +2412,6 @@ dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
|
||||
da.bmask = bmask = malloc(
|
||||
sizeof(uint32_t) * IPFW_TABLES_MAX * 2 / 32, M_TEMP,
|
||||
M_WAITOK | M_ZERO);
|
||||
|
||||
IPFW_UH_RLOCK(chain);
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user