Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 16 Jul 2021 11:53:58 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: e540d078793b - stable/13 - pf: add DIOCGETSTATESV2
Message-ID:  <202107161153.16GBrwLw016214@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=e540d078793bacd4a291b499c96a34e027b13d8a

commit e540d078793bacd4a291b499c96a34e027b13d8a
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2021-07-06 10:12:12 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2021-07-16 09:08:27 +0000

    pf: add DIOCGETSTATESV2
    
    Add a new version of the DIOCGETSTATES call, which extends the struct to
    include the original interface information.
    
    MFC after:      1 week
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D31097
    
    (cherry picked from commit c6bf20a2a46dc36bf881ac594454f71379828a9a)
---
 sys/net/pfvar.h           |  73 ++++++++++++++++++++++++++++
 sys/netpfil/pf/pf_ioctl.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 192 insertions(+)

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index df86ce4f92c2..b6a2045473ec 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -517,6 +517,65 @@ struct pf_state_cmp {
 #define	PFSTATE_SETPRIO		0x0200
 #define	PFSTATE_SETMASK   (PFSTATE_SETPRIO)
 
+struct pf_state_scrub_export {
+	uint16_t	pfss_flags;
+	uint8_t		pfss_ttl;	/* stashed TTL		*/
+#define PF_SCRUB_FLAG_VALID		0x01
+	uint8_t		scrub_flag;
+	uint32_t	pfss_ts_mod;	/* timestamp modulation	*/
+};
+
+struct pf_state_key_export {
+	struct pf_addr	 addr[2];
+	uint16_t	 port[2];
+};
+
+struct pf_state_peer_export {
+	struct pf_state_scrub_export	scrub;	/* state is scrubbed	*/
+	uint32_t	seqlo;		/* Max sequence number sent	*/
+	uint32_t	seqhi;		/* Max the other end ACKd + win	*/
+	uint32_t	seqdiff;	/* Sequence number modulator	*/
+	uint16_t	max_win;	/* largest window (pre scaling)	*/
+	uint16_t	mss;		/* Maximum segment size option	*/
+	uint8_t		state;		/* active state level		*/
+	uint8_t		wscale;		/* window scaling factor	*/
+	uint8_t		dummy[6];
+};
+_Static_assert(sizeof(struct pf_state_peer_export) == 32, "size incorrect");
+
+struct pf_state_export {
+	uint64_t	 version;
+#define	PF_STATE_VERSION	20210706
+	uint64_t	 id;
+	char		 ifname[IFNAMSIZ];
+	char		 orig_ifname[IFNAMSIZ];
+	struct pf_state_key_export	 key[2];
+	struct pf_state_peer_export	 src;
+	struct pf_state_peer_export	 dst;
+	struct pf_addr	 rt_addr;
+	uint32_t	 rule;
+	uint32_t	 anchor;
+	uint32_t	 nat_rule;
+	uint32_t	 creation;
+	uint32_t	 expire;
+	uint32_t	 spare0;
+	uint64_t	 packets[2];
+	uint64_t	 bytes[2];
+	uint32_t	 creatorid;
+	uint32_t	 spare1;
+	sa_family_t	 af;
+	uint8_t		 proto;
+	uint8_t		 direction;
+	uint8_t		 log;
+	uint8_t		 state_flags;
+	uint8_t		 timeout;
+	uint8_t		 sync_flags;
+	uint8_t		 updates;
+
+	uint8_t		 spare[112];
+};
+_Static_assert(sizeof(struct pf_state_export) == 384, "size incorrect");
+
 #ifdef _KERNEL
 struct pf_kstate {
 	u_int64_t		 id;
@@ -643,6 +702,8 @@ extern pfsync_detach_ifnet_t	*pfsync_detach_ifnet_ptr;
 
 void			pfsync_state_export(struct pfsync_state *,
 			    struct pf_kstate *);
+void			pf_state_export(struct pf_state_export *,
+			    struct pf_kstate *);
 
 /* pflog */
 struct pf_kruleset;
@@ -1184,6 +1245,17 @@ struct pfioc_states {
 #define ps_states	ps_u.psu_states
 };
 
+struct pfioc_states_v2 {
+	int		ps_len;
+	uint64_t	ps_req_version;
+	union {
+		caddr_t			 psu_buf;
+		struct pf_state_export	*psu_states;
+	} ps_u;
+#define ps_buf		ps_u.psu_buf
+#define ps_states	ps_u.psu_states
+};
+
 struct pfioc_src_nodes {
 	int	psn_len;
 	union {
@@ -1399,6 +1471,7 @@ struct pfioc_iface {
 #define	DIOCCLRIFFLAG	_IOWR('D', 90, struct pfioc_iface)
 #define	DIOCKILLSRCNODES	_IOWR('D', 91, struct pfioc_src_node_kill)
 #define	DIOCKEEPCOUNTERS	_IOWR('D', 92, struct pfioc_nv)
+#define DIOCGETSTATESV2	_IOWR('D', 93, struct pfioc_states_v2)
 
 struct pf_ifspeed_v0 {
 	char			ifname[IFNAMSIZ];
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index bed3e8b057d1..24e40c1c716c 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -2109,6 +2109,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
 		case DIOCNATLOOK:
 		case DIOCSETDEBUG:
 		case DIOCGETSTATES:
+		case DIOCGETSTATESV2:
 		case DIOCGETSTATESNV:
 		case DIOCGETTIMEOUT:
 		case DIOCCLRRULECTRS:
@@ -2162,6 +2163,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
 		case DIOCGETSTATENV:
 		case DIOCGETSTATUS:
 		case DIOCGETSTATES:
+		case DIOCGETSTATESV2:
 		case DIOCGETSTATESNV:
 		case DIOCGETTIMEOUT:
 		case DIOCGETLIMIT:
@@ -2872,6 +2874,60 @@ DIOCGETSTATES_full:
 		break;
 	}
 
+	case DIOCGETSTATESV2: {
+		struct pfioc_states_v2	*ps = (struct pfioc_states_v2 *)addr;
+		struct pf_kstate	*s;
+		struct pf_state_export	*pstore, *p;
+		int i, nr;
+
+		if (ps->ps_req_version > PF_STATE_VERSION) {
+			error = ENOTSUP;
+			break;
+		}
+
+		if (ps->ps_len <= 0) {
+			nr = uma_zone_get_cur(V_pf_state_z);
+			ps->ps_len = sizeof(struct pf_state_export) * nr;
+			break;
+		}
+
+		p = pstore = malloc(ps->ps_len, M_TEMP, M_WAITOK | M_ZERO);
+		nr = 0;
+
+		for (i = 0; i <= pf_hashmask; i++) {
+			struct pf_idhash *ih = &V_pf_idhash[i];
+
+			if (LIST_EMPTY(&ih->states))
+				continue;
+
+			PF_HASHROW_LOCK(ih);
+			LIST_FOREACH(s, &ih->states, entry) {
+				if (s->timeout == PFTM_UNLINKED)
+					continue;
+
+				if ((nr+1) * sizeof(*p) > ps->ps_len) {
+					PF_HASHROW_UNLOCK(ih);
+					goto DIOCGETSTATESV2_full;
+				}
+				pf_state_export(p, s);
+				p++;
+				nr++;
+			}
+			PF_HASHROW_UNLOCK(ih);
+		}
+DIOCGETSTATESV2_full:
+		error = copyout(pstore, ps->ps_states,
+		    sizeof(struct pf_state_export) * nr);
+		if (error) {
+			free(pstore, M_TEMP);
+			break;
+		}
+		ps->ps_len = sizeof(struct pf_state_export) * nr;
+		free(pstore, M_TEMP);
+
+		break;
+	}
+
 	case DIOCGETSTATESNV: {
 		error = pf_getstates((struct pfioc_nv *)addr);
 		break;
@@ -4595,7 +4651,70 @@ pfsync_state_export(struct pfsync_state *sp, struct pf_kstate *st)
 	pf_state_counter_hton(st->packets[1], sp->packets[1]);
 	pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
 	pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
+}
+
+void
+pf_state_export(struct pf_state_export *sp, struct pf_kstate *st)
+{
+	bzero(sp, sizeof(*sp));
+
+	sp->version = PF_STATE_VERSION;
+
+	/* copy from state key */
+	sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
+	sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
+	sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
+	sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
+	sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
+	sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
+	sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
+	sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
+	sp->proto = st->key[PF_SK_WIRE]->proto;
+	sp->af = st->key[PF_SK_WIRE]->af;
+
+	/* copy from state */
+	strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));
+	strlcpy(sp->orig_ifname, st->orig_kif->pfik_name,
+	    sizeof(sp->orig_ifname));
+	bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
+	sp->creation = htonl(time_uptime - st->creation);
+	sp->expire = pf_state_expires(st);
+	if (sp->expire <= time_uptime)
+		sp->expire = htonl(0);
+	else
+		sp->expire = htonl(sp->expire - time_uptime);
+
+	sp->direction = st->direction;
+	sp->log = st->log;
+	sp->timeout = st->timeout;
+	sp->state_flags = st->state_flags;
+	if (st->src_node)
+		sp->sync_flags |= PFSYNC_FLAG_SRCNODE;
+	if (st->nat_src_node)
+		sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE;
+
+	sp->id = st->id;
+	sp->creatorid = st->creatorid;
+	pf_state_peer_hton(&st->src, &sp->src);
+	pf_state_peer_hton(&st->dst, &sp->dst);
+
+	if (st->rule.ptr == NULL)
+		sp->rule = htonl(-1);
+	else
+		sp->rule = htonl(st->rule.ptr->nr);
+	if (st->anchor.ptr == NULL)
+		sp->anchor = htonl(-1);
+	else
+		sp->anchor = htonl(st->anchor.ptr->nr);
+	if (st->nat_rule.ptr == NULL)
+		sp->nat_rule = htonl(-1);
+	else
+		sp->nat_rule = htonl(st->nat_rule.ptr->nr);
 
+	sp->packets[0] = st->packets[0];
+	sp->packets[1] = st->packets[1];
+	sp->bytes[0] = st->bytes[0];
+	sp->bytes[1] = st->bytes[1];
 }
 
 static void



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202107161153.16GBrwLw016214>