aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2021-07-06 10:12:12 +0000
committerKristof Provost <kp@FreeBSD.org>2021-07-16 09:08:27 +0000
commite540d078793bacd4a291b499c96a34e027b13d8a (patch)
tree34bce35aaf78c9edfb703abdd9fdb8ec4f5b2832
parent6d6ad313081535416ca26da26dc2e0b57da6bf37 (diff)
downloadsrc-e540d078793bacd4a291b499c96a34e027b13d8a.tar.gz
src-e540d078793bacd4a291b499c96a34e027b13d8a.zip
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)
-rw-r--r--sys/net/pfvar.h73
-rw-r--r--sys/netpfil/pf/pf_ioctl.c119
2 files changed, 192 insertions, 0 deletions
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