diff options
Diffstat (limited to 'sys/netpfil')
| -rw-r--r-- | sys/netpfil/ipfw/pmod/tcpmod.c | 25 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_if.c | 2 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_ioctl.c | 2 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_nl.c | 44 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_nl.h | 2 | ||||
| -rw-r--r-- | sys/netpfil/pf/pf_table.c | 10 | 
6 files changed, 71 insertions, 14 deletions
diff --git a/sys/netpfil/ipfw/pmod/tcpmod.c b/sys/netpfil/ipfw/pmod/tcpmod.c index 0338dc792c64..50074ee98cca 100644 --- a/sys/netpfil/ipfw/pmod/tcpmod.c +++ b/sys/netpfil/ipfw/pmod/tcpmod.c @@ -57,7 +57,8 @@ VNET_DEFINE_STATIC(uint32_t, tcpmod_setmss_eid) = 0;  #define	V_tcpmod_setmss_eid	VNET(tcpmod_setmss_eid)  static int -tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss) +tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss, +    int *done)  {  	struct mbuf *m;  	u_char *cp; @@ -72,8 +73,10 @@ tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss)  		 * TCP header with options.  		 */  		*mp = m = m_pullup(m, m->m_pkthdr.len); -		if (m == NULL) +		if (m == NULL) { +			*done = 1;  			return (ret); +		}  	}  	/* Parse TCP options. */  	for (tlen -= sizeof(struct tcphdr), cp = (u_char *)(tcp + 1); @@ -114,7 +117,7 @@ tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss)  #ifdef INET6  static int -tcpmod_ipv6_setmss(struct mbuf **mp, uint16_t mss) +tcpmod_ipv6_setmss(struct mbuf **mp, uint16_t mss, int *done)  {  	struct ip6_hdr *ip6;  	struct ip6_hbh *hbh; @@ -142,13 +145,13 @@ tcpmod_ipv6_setmss(struct mbuf **mp, uint16_t mss)  	/* We must have TCP options and enough data in a packet. */  	if (hlen <= sizeof(struct tcphdr) || hlen > plen)  		return (IP_FW_DENY); -	return (tcpmod_setmss(mp, tcp, hlen, mss)); +	return (tcpmod_setmss(mp, tcp, hlen, mss, done));  }  #endif /* INET6 */  #ifdef INET  static int -tcpmod_ipv4_setmss(struct mbuf **mp, uint16_t mss) +tcpmod_ipv4_setmss(struct mbuf **mp, uint16_t mss, int *done)  {  	struct tcphdr *tcp;  	struct ip *ip; @@ -162,7 +165,7 @@ tcpmod_ipv4_setmss(struct mbuf **mp, uint16_t mss)  	/* We must have TCP options and enough data in a packet. */  	if (hlen <= sizeof(struct tcphdr) || hlen > plen)  		return (IP_FW_DENY); -	return (tcpmod_setmss(mp, tcp, hlen, mss)); +	return (tcpmod_setmss(mp, tcp, hlen, mss, done));  }  #endif /* INET */ @@ -206,19 +209,23 @@ ipfw_tcpmod(struct ip_fw_chain *chain, struct ip_fw_args *args,  	switch (args->f_id.addr_type) {  #ifdef INET  		case 4: -			ret = tcpmod_ipv4_setmss(&args->m, htons(icmd->arg1)); +			ret = tcpmod_ipv4_setmss(&args->m, htons(icmd->arg1), +			    done);  			break;  #endif  #ifdef INET6  		case 6: -			ret = tcpmod_ipv6_setmss(&args->m, htons(icmd->arg1)); +			ret = tcpmod_ipv6_setmss(&args->m, htons(icmd->arg1), +			    done);  			break;  #endif  	}  	/*  	 * We return zero in both @ret and @done on success, and ipfw_chk()  	 * will update rule counters. Otherwise a packet will not be matched -	 * by rule. +	 * by rule. We passed @done around above in case we hit a fatal error +	 * somewhere, we'll return non-zero but signal that rule processing +	 * cannot succeed.  	 */  	return (ret);  } diff --git a/sys/netpfil/pf/pf_if.c b/sys/netpfil/pf/pf_if.c index f3be036ef745..6f41d453a7d1 100644 --- a/sys/netpfil/pf/pf_if.c +++ b/sys/netpfil/pf/pf_if.c @@ -702,7 +702,7 @@ pfi_table_update(struct pfr_ktable *kt, struct pfi_kkif *kif, uint8_t net,  	}  	if ((e = pfr_set_addrs(&kt->pfrkt_t, V_pfi_buffer, V_pfi_buffer_cnt, &size2, -	    NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK))) +	    NULL, NULL, NULL, PFR_FLAG_START | PFR_FLAG_DONE, PFR_TFLAG_ALLMASK)))  		printf("%s: cannot set %d new addresses into table %s: %d\n",  		    __func__, V_pfi_buffer_cnt, kt->pfrkt_name, e);  } diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index 703ecf446fad..5ec67021068b 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -5142,7 +5142,7 @@ DIOCCHANGEADDR_error:  		error = pfr_set_addrs(&io->pfrio_table, pfras,  		    io->pfrio_size, &io->pfrio_size2, &io->pfrio_nadd,  		    &io->pfrio_ndel, &io->pfrio_nchange, io->pfrio_flags | -		    PFR_FLAG_USERIOCTL, 0); +		    PFR_FLAG_START | PFR_FLAG_DONE | PFR_FLAG_USERIOCTL, 0);  		PF_RULES_WUNLOCK();  		if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK)  			error = copyout(pfras, io->pfrio_buffer, totlen); diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c index 082b9b565153..21d4db1b8478 100644 --- a/sys/netpfil/pf/pf_nl.c +++ b/sys/netpfil/pf/pf_nl.c @@ -2100,6 +2100,7 @@ struct nl_parsed_table_addrs {  	size_t addr_count;  	int nadd;  	int ndel; +	int nchange;  };  #define _OUT(_field)	offsetof(struct pfr_addr, _field)  static const struct nlattr_parser nla_p_pfr_addr[] = { @@ -2209,6 +2210,42 @@ pf_handle_table_del_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)  	return (error);  } +static int +pf_handle_table_set_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ +	struct nl_parsed_table_addrs attrs = { 0 }; +	struct nl_writer *nw = npt->nw; +	struct genlmsghdr *ghdr_new; +	int error; + +	error = nl_parse_nlmsg(hdr, &table_addr_parser, npt, &attrs); +	if (error != 0) +		return  (error); + +	PF_RULES_WLOCK(); +	error = pfr_set_addrs(&attrs.table, &attrs.addrs[0], +	    attrs.addr_count, NULL, &attrs.nadd, &attrs.ndel, &attrs.nchange, +	    attrs.flags | PFR_FLAG_USERIOCTL, 0); +	PF_RULES_WUNLOCK(); + +	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) +		return (ENOMEM); + +	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); +	ghdr_new->cmd = PFNL_CMD_TABLE_DEL_ADDR; +	ghdr_new->version = 0; +	ghdr_new->reserved = 0; + +	nlattr_add_u32(nw, PF_TA_NBR_ADDED, attrs.nadd); +	nlattr_add_u32(nw, PF_TA_NBR_DELETED, attrs.ndel); +	nlattr_add_u32(nw, PF_TA_NBR_CHANGED, attrs.nchange); + +	if (!nlmsg_end(nw)) +		return (ENOMEM); + +	return (error); +} +  static const struct nlhdr_parser *all_parsers[] = {  	&state_parser,  	&addrule_parser, @@ -2460,6 +2497,13 @@ static const struct genl_cmd pf_cmds[] = {  		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,  		.cmd_priv = PRIV_NETINET_PF,  	}, +	{ +		.cmd_num = PFNL_CMD_TABLE_SET_ADDR, +		.cmd_name = "TABLE_SET_ADDRS", +		.cmd_cb = pf_handle_table_set_addrs, +		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL, +		.cmd_priv = PRIV_NETINET_PF, +	},  };  void diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h index c46c8f2b2592..d1538ab4ff5b 100644 --- a/sys/netpfil/pf/pf_nl.h +++ b/sys/netpfil/pf/pf_nl.h @@ -69,6 +69,7 @@ enum {  	PFNL_CMD_CLR_ADDRS = 31,  	PFNL_CMD_TABLE_ADD_ADDR = 32,  	PFNL_CMD_TABLE_DEL_ADDR = 33, +	PFNL_CMD_TABLE_SET_ADDR = 34,  	__PFNL_CMD_MAX,  };  #define PFNL_CMD_MAX (__PFNL_CMD_MAX -1) @@ -483,6 +484,7 @@ enum pf_table_addrs_t {  	PF_TA_FLAGS		= 3, /* u32 */  	PF_TA_NBR_ADDED		= 4, /* u32 */  	PF_TA_NBR_DELETED	= 5, /* u32 */ +	PF_TA_NBR_CHANGED	= 6, /* u32 */  };  #ifdef _KERNEL diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c index cf752ce0de18..0e2b9fe1cac8 100644 --- a/sys/netpfil/pf/pf_table.c +++ b/sys/netpfil/pf/pf_table.c @@ -399,7 +399,8 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,  	PF_RULES_WASSERT(); -	ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK); +	ACCEPT_FLAGS(flags, PFR_FLAG_START | PFR_FLAG_DONE | +	    PFR_FLAG_DUMMY | PFR_FLAG_FEEDBACK);  	if (pfr_validate_table(tbl, ignore_pfrt_flags, flags &  	    PFR_FLAG_USERIOCTL))  		return (EINVAL); @@ -411,7 +412,8 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,  	tmpkt = pfr_create_ktable(&V_pfr_nulltable, 0, 0);  	if (tmpkt == NULL)  		return (ENOMEM); -	pfr_mark_addrs(kt); +	if (flags & PFR_FLAG_START) +		pfr_mark_addrs(kt);  	SLIST_INIT(&addq);  	SLIST_INIT(&delq);  	SLIST_INIT(&changeq); @@ -444,6 +446,7 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,  			}  			p = pfr_create_kentry(&ad,  			    (kt->pfrkt_flags & PFR_TFLAG_COUNTERS) != 0); +			p->pfrke_mark = PFR_FB_ADDED;  			if (p == NULL)  				senderr(ENOMEM);  			if (pfr_route_kentry(tmpkt, p)) { @@ -459,7 +462,8 @@ _skip:  		if (flags & PFR_FLAG_FEEDBACK)  			bcopy(&ad, addr + i, sizeof(ad));  	} -	pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY); +	if (flags & PFR_FLAG_DONE) +		pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY);  	if ((flags & PFR_FLAG_FEEDBACK) && *size2) {  		if (*size2 < size+xdel) {  			*size2 = size+xdel;  | 
