Date: Tue, 4 Dec 2018 16:12:43 +0000 (UTC) From: "Andrey V. Elsukov" <ae@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r341472 - in head: sbin/ipfw sys/netinet sys/netpfil/ipfw Message-ID: <201812041612.wB4GCh78010128@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ae Date: Tue Dec 4 16:12:43 2018 New Revision: 341472 URL: https://svnweb.freebsd.org/changeset/base/341472 Log: 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 Modified: head/sbin/ipfw/ipfw.8 head/sbin/ipfw/ipfw2.c head/sbin/ipfw/ipfw2.h head/sbin/ipfw/main.c head/sys/netinet/ip_fw.h head/sys/netpfil/ipfw/ip_fw_dynamic.c head/sys/netpfil/ipfw/ip_fw_sockopt.c Modified: head/sbin/ipfw/ipfw.8 ============================================================================== --- head/sbin/ipfw/ipfw.8 Tue Dec 4 16:01:25 2018 (r341471) +++ head/sbin/ipfw/ipfw.8 Tue Dec 4 16:12:43 2018 (r341472) @@ -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., Modified: head/sbin/ipfw/ipfw2.c ============================================================================== --- head/sbin/ipfw/ipfw2.c Tue Dec 4 16:01:25 2018 (r341471) +++ head/sbin/ipfw/ipfw2.c Tue Dec 4 16:12:43 2018 (r341472) @@ -2247,10 +2247,9 @@ show_dyn_state(struct cmdline_opts *co, struct format_ 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_ 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 forma 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 forma 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 forma 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; Modified: head/sbin/ipfw/ipfw2.h ============================================================================== --- head/sbin/ipfw/ipfw2.h Tue Dec 4 16:01:25 2018 (r341471) +++ head/sbin/ipfw/ipfw2.h Tue Dec 4 16:12:43 2018 (r341472) @@ -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 */ Modified: head/sbin/ipfw/main.c ============================================================================== --- head/sbin/ipfw/main.c Tue Dec 4 16:01:25 2018 (r341471) +++ head/sbin/ipfw/main.c Tue Dec 4 16:12:43 2018 (r341472) @@ -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': Modified: head/sys/netinet/ip_fw.h ============================================================================== --- head/sys/netinet/ip_fw.h Tue Dec 4 16:01:25 2018 (r341471) +++ head/sys/netinet/ip_fw.h Tue Dec 4 16:12:43 2018 (r341472) @@ -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 */ Modified: head/sys/netpfil/ipfw/ip_fw_dynamic.c ============================================================================== --- head/sys/netpfil/ipfw/ip_fw_dynamic.c Tue Dec 4 16:01:25 2018 (r341471) +++ head/sys/netpfil/ipfw/ip_fw_dynamic.c Tue Dec 4 16:12:43 2018 (r341472) @@ -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 i 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 dy 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 dy 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 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; Modified: head/sys/netpfil/ipfw/ip_fw_sockopt.c ============================================================================== --- head/sys/netpfil/ipfw/ip_fw_sockopt.c Tue Dec 4 16:01:25 2018 (r341471) +++ head/sys/netpfil/ipfw/ip_fw_sockopt.c Tue Dec 4 16:12:43 2018 (r341472) @@ -1033,6 +1033,16 @@ delete_range(struct ip_fw_chain *chain, ipfw_range_tlv 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 da.bmask = bmask = malloc( sizeof(uint32_t) * IPFW_TABLES_MAX * 2 / 32, M_TEMP, M_WAITOK | M_ZERO); - IPFW_UH_RLOCK(chain); /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201812041612.wB4GCh78010128>