Page MenuHomeFreeBSD

D31737.id94413.diff
No OneTemporary

D31737.id94413.diff

Index: sys/net/pfvar.h
===================================================================
--- sys/net/pfvar.h
+++ sys/net/pfvar.h
@@ -51,6 +51,7 @@
#include <sys/seqc.h>
#include <vm/uma.h>
+#include <net/ethernet.h>
#include <net/radix.h>
#include <netinet/in.h>
#ifdef _KERNEL
@@ -565,6 +566,61 @@
u_int32_t pqid;
};
+union pf_keth_rule_ptr {
+ struct pf_keth_rule *ptr;
+ uint32_t nr;
+};
+
+struct pf_keth_rule_addr {
+ uint8_t addr[ETHER_ADDR_LEN];
+ uint8_t neg;
+ uint8_t isset;
+};
+
+struct pf_keth_rule {
+#define PFE_SKIP_IFP 0
+#define PFE_SKIP_DIR 1
+#define PFE_SKIP_PROTO 2
+#define PFE_SKIP_SRC_ADDR 3
+#define PFE_SKIP_DST_ADDR 4
+#define PFE_SKIP_COUNT 5
+ union pf_keth_rule_ptr skip[PFE_SKIP_COUNT];
+
+ TAILQ_ENTRY(pf_keth_rule) entries;
+
+ uint32_t nr;
+
+ bool quick;
+
+ /* Filter */
+ char ifname[IFNAMSIZ];
+ struct pfi_kkif *kif;
+ uint8_t ifnot;
+ uint8_t direction;
+ uint16_t proto;
+ struct pf_keth_rule_addr src, dst;
+
+ /* Stats */
+ counter_u64_t evaluations;
+ counter_u64_t packets[2];
+ counter_u64_t bytes[2];
+
+ /* Action */
+ char qname[PF_QNAME_SIZE];
+ int qid;
+ char tagname[PF_TAG_NAME_SIZE];
+ uint16_t tag;
+ uint8_t action;
+};
+
+TAILQ_HEAD(pf_keth_rules, pf_keth_rule);
+
+struct pf_keth_settings {
+ struct pf_keth_rules rules;
+ uint32_t ticket;
+ int open;
+};
+
union pf_krule_ptr {
struct pf_krule *ptr;
u_int32_t nr;
@@ -1599,6 +1655,7 @@
#define PF_RULESET_ALTQ (PF_RULESET_MAX)
#define PF_RULESET_TABLE (PF_RULESET_MAX+1)
+#define PF_RULESET_ETH (PF_RULESET_MAX+2)
struct pfioc_trans {
int size; /* number of elements */
int esize; /* size of each element in bytes */
@@ -1735,6 +1792,9 @@
#define DIOCGETSTATESV2 _IOWR('D', 93, struct pfioc_states_v2)
#define DIOCGETSYNCOOKIES _IOWR('D', 94, struct pfioc_nv)
#define DIOCSETSYNCOOKIES _IOWR('D', 95, struct pfioc_nv)
+#define DIOCADDETHRULE _IOWR('D', 96, struct pfioc_nv)
+#define DIOCGETETHRULE _IOWR('D', 97, struct pfioc_nv)
+#define DIOCGETETHRULES _IOWR('D', 98, struct pfioc_nv)
struct pf_ifspeed_v0 {
char ifname[IFNAMSIZ];
@@ -1964,6 +2024,7 @@
u_int8_t);
void pf_free_rule(struct pf_krule *);
+int pf_test_eth(int, int, struct ifnet *, struct mbuf **, struct inpcb *);
#ifdef INET
int pf_test(int, int, struct ifnet *, struct mbuf **, struct inpcb *);
int pf_normalize_ip(struct mbuf **, int, struct pfi_kkif *, u_short *,
@@ -2127,7 +2188,13 @@
#define V_pf_main_anchor VNET(pf_main_anchor)
#define pf_main_ruleset V_pf_main_anchor.ruleset
+VNET_DECLARE(struct pf_keth_settings*, pf_keth);
+#define V_pf_keth VNET(pf_keth)
+VNET_DECLARE(struct pf_keth_settings*, pf_keth_inactive);
+#define V_pf_keth_inactive VNET(pf_keth_inactive)
+
void pf_init_kruleset(struct pf_kruleset *);
+void pf_init_keth(struct pf_keth_settings *);
int pf_kanchor_setup(struct pf_krule *,
const struct pf_kruleset *, const char *);
int pf_kanchor_nvcopyout(const struct pf_kruleset *,
Index: sys/netpfil/pf/pf.c
===================================================================
--- sys/netpfil/pf/pf.c
+++ sys/netpfil/pf/pf.c
@@ -262,6 +262,8 @@
static u_int32_t pf_tcp_iss(struct pf_pdesc *);
void pf_rule_to_actions(struct pf_krule *,
struct pf_rule_actions *);
+static int pf_test_eth_rule(int, struct pfi_kkif *,
+ struct mbuf *);
static int pf_test_rule(struct pf_krule **, struct pf_kstate **,
int, struct pfi_kkif *, struct mbuf *, int,
struct pf_pdesc *, struct pf_krule **,
@@ -3472,6 +3474,108 @@
#undef ISN_RANDOM_INCREMENT
}
+static bool
+pf_match_eth_addr(const uint8_t *a, const struct pf_keth_rule_addr *r)
+{
+ /* Always matches if not set */
+ if (! r->isset)
+ return (!r->neg);
+
+ if (memcmp(a, r->addr, ETHER_ADDR_LEN) == 0)
+ return (!r->neg);
+
+ return (r->neg);
+}
+
+static int
+pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf *m)
+{
+ struct ether_header *e;
+ struct pf_keth_rule *r, *rm;
+ struct pf_mtag *mtag;
+ uint8_t action;
+
+ PF_RULES_RLOCK_TRACKER;
+
+ MPASS(kif->pfik_ifp->if_vnet == curvnet);
+ NET_EPOCH_ASSERT();
+
+ e = mtod(m, struct ether_header *);
+
+ PF_RULES_RLOCK();
+
+ r = TAILQ_FIRST(&V_pf_keth->rules);
+ rm = NULL;
+
+ while (r != NULL) {
+ counter_u64_add(r->evaluations, 1);
+ if (pfi_kkif_match(r->kif, kif) == r->ifnot)
+ r = r->skip[PFE_SKIP_IFP].ptr;
+ else if (r->direction && r->direction != dir)
+ r = r->skip[PFE_SKIP_DIR].ptr;
+ else if (r->proto && r->proto != ntohs(e->ether_type))
+ r = r->skip[PFE_SKIP_PROTO].ptr;
+ else if (! pf_match_eth_addr(e->ether_shost, &r->src))
+ r = r->skip[PFE_SKIP_SRC_ADDR].ptr;
+ else if (! pf_match_eth_addr(e->ether_dhost, &r->dst)) {
+ r = TAILQ_NEXT(r, entries);
+ }
+ else {
+ /* Rule matches */
+ rm = r;
+
+ if (r->quick)
+ break;
+
+ r = TAILQ_NEXT(r, entries);
+ }
+ }
+
+ r = rm;
+
+ /* Default to pass. */
+ if (r == NULL) {
+ PF_RULES_RUNLOCK();
+ return (PF_PASS);
+ }
+
+ /* Execute action. */
+ counter_u64_add(r->packets[dir == PF_OUT], 1);
+ counter_u64_add(r->bytes[dir == PF_OUT], m_length(m, NULL));
+
+ /* Shortcut. Don't tag if we're just going to drop anyway. */
+ if (r->action == PF_DROP) {
+ PF_RULES_RUNLOCK();
+ return (PF_DROP);
+ }
+
+ if (r->tag > 0) {
+ mtag = pf_get_mtag(m);
+ if (mtag == NULL) {
+ counter_u64_add(V_pf_status.counters[PFRES_MEMORY], 1);
+ PF_RULES_RUNLOCK();
+ return (PF_DROP);
+ }
+ mtag->tag = r->tag;
+ }
+
+ if (r->qid != 0) {
+ mtag = pf_get_mtag(m);
+ if (mtag == NULL) {
+ counter_u64_add(V_pf_status.counters[PFRES_MEMORY], 1);
+ PF_RULES_RUNLOCK();
+ return (PF_DROP);
+ }
+ mtag->qid = r->qid;
+ }
+
+ action = r->action;
+
+ PF_RULES_RUNLOCK();
+
+ return (action);
+}
+
static int
pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm, int direction,
struct pfi_kkif *kif, struct mbuf *m, int off, struct pf_pdesc *pd,
@@ -6110,6 +6214,37 @@
return (0);
}
+int
+pf_test_eth(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
+ struct inpcb *inp)
+{
+ struct pfi_kkif *kif;
+ struct mbuf *m = *m0;
+
+ M_ASSERTPKTHDR(m);
+ MPASS(ifp->if_vnet == curvnet);
+ NET_EPOCH_ASSERT();
+
+ if (!V_pf_status.running)
+ return (PF_PASS);
+
+ kif = (struct pfi_kkif *)ifp->if_pf_kif;
+
+ if (kif == NULL) {
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
+ return (PF_DROP);
+ }
+ if (kif->pfik_flags & PFI_IFLAG_SKIP)
+ return (PF_PASS);
+
+ if (m->m_flags & M_SKIP_FIREWALL)
+ return (PF_PASS);
+
+ /* Stateless! */
+ return (pf_test_eth_rule(dir, kif, m));
+}
+
#ifdef INET
int
pf_test(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0, struct inpcb *inp)
Index: sys/netpfil/pf/pf_ioctl.c
===================================================================
--- sys/netpfil/pf/pf_ioctl.c
+++ sys/netpfil/pf/pf_ioctl.c
@@ -106,6 +106,10 @@
static void pf_empty_kpool(struct pf_kpalist *);
static int pfioctl(struct cdev *, u_long, caddr_t, int,
struct thread *);
+static int pf_begin_eth(uint32_t *);
+static int pf_rollback_eth(uint32_t);
+static int pf_commit_eth(uint32_t);
+static void pf_free_eth_rule(struct pf_keth_rule *);
#ifdef ALTQ
static int pf_begin_altq(u_int32_t *);
static int pf_rollback_altq(u_int32_t);
@@ -218,6 +222,10 @@
/*
* Wrapper functions for pfil(9) hooks
*/
+static pfil_return_t pf_eth_check_in(struct mbuf **m, struct ifnet *ifp,
+ int flags, void *ruleset __unused, struct inpcb *inp);
+static pfil_return_t pf_eth_check_out(struct mbuf **m, struct ifnet *ifp,
+ int flags, void *ruleset __unused, struct inpcb *inp);
#ifdef INET
static pfil_return_t pf_check_in(struct mbuf **m, struct ifnet *ifp,
int flags, void *ruleset __unused, struct inpcb *inp);
@@ -306,6 +314,9 @@
RB_INIT(&V_pf_anchors);
pf_init_kruleset(&pf_main_ruleset);
+ pf_init_keth(V_pf_keth);
+ pf_init_keth(V_pf_keth_inactive);
+
/* default rule should never be garbage collected */
V_pf_default_rule.entries.tqe_prev = &V_pf_default_rule.entries.tqe_next;
#ifdef PF_DEFAULT_TO_DROP
@@ -473,6 +484,32 @@
PF_UNLNKDRULES_UNLOCK();
}
+static void
+pf_free_eth_rule(struct pf_keth_rule *rule)
+{
+ PF_RULES_WASSERT();
+
+ if (rule == NULL)
+ return;
+
+ if (rule->tag)
+ tag_unref(&V_pf_tags, rule->tag);
+#ifdef ALTQ
+ pf_qid_unref(rule->qid);
+#endif
+
+ if (rule->kif)
+ pfi_kkif_unref(rule->kif);
+
+ counter_u64_free(rule->evaluations);
+ for (int i = 0; i < 2; i++) {
+ counter_u64_free(rule->packets[i]);
+ counter_u64_free(rule->bytes[i]);
+ }
+
+ free(rule, M_PFRULE);
+}
+
void
pf_free_rule(struct pf_krule *rule)
{
@@ -659,6 +696,103 @@
return (tagname2tag(&V_pf_tags, tagname));
}
+static int
+pf_begin_eth(uint32_t *ticket)
+{
+ struct pf_keth_rule *rule, *tmp;
+
+ PF_RULES_WASSERT();
+
+ /* Purge old inactive rules. */
+ TAILQ_FOREACH_SAFE(rule, &V_pf_keth_inactive->rules, entries, tmp) {
+ TAILQ_REMOVE(&V_pf_keth_inactive->rules, rule, entries);
+ pf_free_eth_rule(rule);
+ }
+
+ *ticket = ++V_pf_keth_inactive->ticket;
+ V_pf_keth_inactive->open = 1;
+
+ return (0);
+}
+
+static int
+pf_rollback_eth(uint32_t ticket)
+{
+ struct pf_keth_rule *rule, *tmp;
+
+ PF_RULES_WASSERT();
+
+ if (!V_pf_keth_inactive->open || ticket != V_pf_keth_inactive->ticket)
+ return (0);
+
+ /* Purge old inactive rules. */
+ TAILQ_FOREACH_SAFE(rule, &V_pf_keth_inactive->rules, entries, tmp) {
+ TAILQ_REMOVE(&V_pf_keth_inactive->rules, rule, entries);
+ pf_free_eth_rule(rule);
+ }
+
+ V_pf_keth_inactive->open = 0;
+
+ return (0);
+}
+
+#define PF_SET_SKIP_STEPS(i) \
+ do { \
+ while (head[i] != cur) { \
+ head[i]->skip[i].ptr = cur; \
+ head[i] = TAILQ_NEXT(head[i], entries); \
+ } \
+ } while (0)
+
+static void
+pf_eth_calc_skip_steps(struct pf_keth_rules *rules)
+{
+ struct pf_keth_rule *cur, *prev, *head[PFE_SKIP_COUNT];
+ int i;
+
+ cur = TAILQ_FIRST(rules);
+ prev = cur;
+ for (i = 0; i < PFE_SKIP_COUNT; ++i)
+ head[i] = cur;
+ while (cur != NULL) {
+ if (cur->kif != prev->kif || cur->ifnot != prev->ifnot)
+ PF_SET_SKIP_STEPS(PFE_SKIP_IFP);
+ if (cur->direction != prev->direction)
+ PF_SET_SKIP_STEPS(PFE_SKIP_DIR);
+ if (cur->proto != prev->proto)
+ PF_SET_SKIP_STEPS(PFE_SKIP_PROTO);
+ if (memcmp(&cur->src, &prev->src, sizeof(cur->src)) != 0)
+ PF_SET_SKIP_STEPS(PFE_SKIP_SRC_ADDR);
+ if (memcmp(&cur->dst, &prev->dst, sizeof(cur->dst)) != 0)
+ PF_SET_SKIP_STEPS(PFE_SKIP_DST_ADDR);
+
+ prev = cur;
+ cur = TAILQ_NEXT(cur, entries);
+ }
+ for (i = 0; i < PFE_SKIP_COUNT; ++i)
+ PF_SET_SKIP_STEPS(i);
+}
+
+static int
+pf_commit_eth(uint32_t ticket)
+{
+ struct pf_keth_settings *settings;
+
+ if (!V_pf_keth_inactive->open ||
+ ticket != V_pf_keth_inactive->ticket)
+ return (EBUSY);
+
+ pf_eth_calc_skip_steps(&V_pf_keth_inactive->rules);
+
+ settings = V_pf_keth;
+ V_pf_keth = V_pf_keth_inactive;
+ V_pf_keth_inactive = settings;
+ V_pf_keth_inactive->ticket = V_pf_keth->ticket;
+
+ /* Clean up inactive rules. */
+ return (pf_rollback_eth(ticket));
+}
+
#ifdef ALTQ
static u_int32_t
pf_qname2qid(const char *qname)
@@ -2217,6 +2351,8 @@
case DIOCGIFSPEEDV1:
case DIOCSETIFFLAG:
case DIOCCLRIFFLAG:
+ case DIOCGETETHRULES:
+ case DIOCGETETHRULE:
break;
case DIOCRCLRTABLES:
case DIOCRADDTABLES:
@@ -2264,6 +2400,8 @@
case DIOCGIFSPEEDV1:
case DIOCGIFSPEEDV0:
case DIOCGETRULENV:
+ case DIOCGETETHRULES:
+ case DIOCGETETHRULE:
break;
case DIOCRCLRTABLES:
case DIOCRADDTABLES:
@@ -2322,6 +2460,213 @@
}
break;
+ case DIOCGETETHRULES: {
+ struct pfioc_nv *nv = (struct pfioc_nv *)addr;
+ nvlist_t *nvl;
+ void *packed;
+ struct pf_keth_rule *tail;
+ u_int32_t ticket, nr;
+
+ nvl = NULL;
+ packed = NULL;
+
+#define ERROUT(x) do { error = (x); goto DIOCGETETHRULES_error; } while (0)
+
+ nvl = nvlist_create(0);
+ if (nvl == NULL)
+ ERROUT(ENOMEM);
+
+ PF_RULES_RLOCK();
+
+ ticket = V_pf_keth->ticket;
+ tail = TAILQ_LAST(&V_pf_keth->rules, pf_keth_rules);
+ if (tail)
+ nr = tail->nr + 1;
+ else
+ nr = 0;
+
+ PF_RULES_RUNLOCK();
+
+ nvlist_add_number(nvl, "ticket", ticket);
+ nvlist_add_number(nvl, "nr", nr);
+
+ packed = nvlist_pack(nvl, &nv->len);
+ if (packed == NULL)
+ ERROUT(ENOMEM);
+
+ if (nv->size == 0)
+ ERROUT(0);
+ else if (nv->size < nv->len)
+ ERROUT(ENOSPC);
+
+ error = copyout(packed, nv->data, nv->len);
+
+#undef ERROUT
+DIOCGETETHRULES_error:
+ free(packed, M_TEMP);
+ nvlist_destroy(nvl);
+ break;
+ }
+
+ case DIOCGETETHRULE: {
+ struct epoch_tracker et;
+ struct pfioc_nv *nv = (struct pfioc_nv *)addr;
+ nvlist_t *nvl = NULL;
+ void *nvlpacked = NULL;
+ struct pf_keth_rule *rule = NULL;
+ u_int32_t ticket, nr;
+
+#define ERROUT(x) do { error = (x); goto DIOCGETETHRULE_error; } while (0)
+
+ nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK);
+ if (nvlpacked == NULL)
+ ERROUT(ENOMEM);
+
+ error = copyin(nv->data, nvlpacked, nv->len);
+ if (error)
+ ERROUT(error);
+
+ nvl = nvlist_unpack(nvlpacked, nv->len, 0);
+ if (! nvlist_exists_number(nvl, "ticket"))
+ ERROUT(EBADMSG);
+ ticket = nvlist_get_number(nvl, "ticket");
+
+ if (! nvlist_exists_number(nvl, "nr"))
+ ERROUT(EBADMSG);
+ nr = nvlist_get_number(nvl, "nr");
+
+ nvlist_destroy(nvl);
+ nvl = NULL;
+ free(nvlpacked, M_TEMP);
+ nvlpacked = NULL;
+
+ nvl = nvlist_create(0);
+
+ PF_RULES_RLOCK();
+ if (ticket != V_pf_keth->ticket) {
+ PF_RULES_RUNLOCK();
+ ERROUT(EBUSY);
+ }
+ rule = TAILQ_FIRST(&V_pf_keth->rules);
+ while ((rule != NULL) && (rule->nr != nr))
+ rule = TAILQ_NEXT(rule, entries);
+ if (rule == NULL) {
+ PF_RULES_RUNLOCK();
+ ERROUT(ENOENT);
+ }
+ /* Make sure rule can't go away. */
+ NET_EPOCH_ENTER(et);
+ PF_RULES_RUNLOCK();
+ nvl = pf_keth_rule_to_nvl(rule);
+ NET_EPOCH_EXIT(et);
+ if (nvl == NULL)
+ ERROUT(ENOMEM);
+
+ nvlpacked = nvlist_pack(nvl, &nv->len);
+ if (nvlpacked == NULL)
+ ERROUT(ENOMEM);
+
+ if (nv->size == 0)
+ ERROUT(0);
+ else if (nv->size < nv->len)
+ ERROUT(ENOSPC);
+
+ error = copyout(nvlpacked, nv->data, nv->len);
+
+#undef ERROUT
+DIOCGETETHRULE_error:
+ free(nvlpacked, M_TEMP);
+ nvlist_destroy(nvl);
+ break;
+ }
+
+ case DIOCADDETHRULE: {
+ struct pfioc_nv *nv = (struct pfioc_nv *)addr;
+ nvlist_t *nvl = NULL;
+ void *nvlpacked = NULL;
+ struct pf_keth_rule *rule = NULL;
+ struct pfi_kkif *kif = NULL;
+
+#define ERROUT(x) do { error = (x); goto DIOCADDETHRULE_error; } while (0)
+
+ nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK);
+ if (nvlpacked == NULL)
+ ERROUT(ENOMEM);
+
+ error = copyin(nv->data, nvlpacked, nv->len);
+ if (error)
+ ERROUT(error);
+
+ nvl = nvlist_unpack(nvlpacked, nv->len, 0);
+ if (nvl == NULL)
+ ERROUT(EBADMSG);
+
+ if (! nvlist_exists_number(nvl, "ticket"))
+ ERROUT(EBADMSG);
+
+ if (nvlist_get_number(nvl, "ticket") !=
+ V_pf_keth_inactive->ticket) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("ticket: %d != %d\n",
+ (u_int32_t)nvlist_get_number(nvl, "ticket"),
+ V_pf_keth_inactive->ticket));
+ ERROUT(EBUSY);
+ }
+
+ rule = malloc(sizeof(*rule), M_PFRULE, M_WAITOK);
+ if (rule == NULL)
+ ERROUT(ENOMEM);
+
+ error = pf_nvl_to_keth_rule(nvl, rule);
+ if (error != 0)
+ ERROUT(error);
+
+ if (rule->ifname[0])
+ kif = pf_kkif_create(M_WAITOK);
+ rule->evaluations = counter_u64_alloc(M_WAITOK);
+ for (int i = 0; i < 2; i++) {
+ rule->packets[i] = counter_u64_alloc(M_WAITOK);
+ rule->bytes[i] = counter_u64_alloc(M_WAITOK);
+ }
+
+ PF_RULES_WLOCK();
+
+ if (rule->ifname[0]) {
+ rule->kif = pfi_kkif_attach(kif, rule->ifname);
+ pfi_kkif_ref(rule->kif);
+ } else
+ rule->kif = NULL;
+
+#ifdef ALTQ
+ /* set queue IDs */
+ if (rule->qname[0] != 0) {
+ if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
+ error = EBUSY;
+ else
+ rule->qid = rule->qid;
+ }
+#endif
+ if (rule->tagname[0])
+ if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
+ error = EBUSY;
+
+ if (error) {
+ pf_free_eth_rule(rule);
+ PF_RULES_WUNLOCK();
+ ERROUT(error);
+ }
+
+ TAILQ_INSERT_TAIL(&V_pf_keth_inactive->rules, rule, entries);
+
+ PF_RULES_WUNLOCK();
+
+#undef ERROUT
+DIOCADDETHRULE_error:
+ nvlist_destroy(nvl);
+ free(nvlpacked, M_TEMP);
+ break;
+ }
+
case DIOCADDRULENV: {
struct pfioc_nv *nv = (struct pfioc_nv *)addr;
nvlist_t *nvl = NULL;
@@ -4362,6 +4707,19 @@
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
switch (ioe->rs_num) {
+ case PF_RULESET_ETH:
+ if (ioe->anchor[0]) {
+ PF_RULES_WUNLOCK();
+ free(ioes, M_TEMP);
+ error = EINVAL;
+ goto fail;
+ }
+ if ((error = pf_begin_eth(&ioe->ticket))) {
+ PF_RULES_WUNLOCK();
+ free(ioes, M_TEMP);
+ goto fail;
+ }
+ break;
#ifdef ALTQ
case PF_RULESET_ALTQ:
if (ioe->anchor[0]) {
@@ -4436,6 +4794,19 @@
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
ioe->anchor[sizeof(ioe->anchor) - 1] = '\0';
switch (ioe->rs_num) {
+ case PF_RULESET_ETH:
+ if (ioe->anchor[0]) {
+ PF_RULES_WUNLOCK();
+ free(ioes, M_TEMP);
+ error = EINVAL;
+ goto fail;
+ }
+ if ((error = pf_rollback_eth(ioe->ticket))) {
+ PF_RULES_WUNLOCK();
+ free(ioes, M_TEMP);
+ goto fail; /* really bad */
+ }
+ break;
#ifdef ALTQ
case PF_RULESET_ALTQ:
if (ioe->anchor[0]) {
@@ -4513,6 +4884,21 @@
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
ioe->anchor[sizeof(ioe->anchor) - 1] = 0;
switch (ioe->rs_num) {
+ case PF_RULESET_ETH:
+ if (ioe->anchor[0]) {
+ PF_RULES_WUNLOCK();
+ free(ioes, M_TEMP);
+ error = EINVAL;
+ goto fail;
+ }
+ if (!V_pf_keth_inactive->ticket ||
+ ioe->ticket != V_pf_keth_inactive->ticket) {
+ PF_RULES_WUNLOCK();
+ free(ioes, M_TEMP);
+ error = EBUSY;
+ goto fail;
+ }
+ break;
#ifdef ALTQ
case PF_RULESET_ALTQ:
if (ioe->anchor[0]) {
@@ -4564,6 +4950,13 @@
/* Now do the commit - no errors should happen here. */
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
switch (ioe->rs_num) {
+ case PF_RULESET_ETH:
+ if ((error = pf_commit_eth(ioe->ticket))) {
+ PF_RULES_WUNLOCK();
+ free(ioes, M_TEMP);
+ goto fail; /* really bad */
+ }
+ break;
#ifdef ALTQ
case PF_RULESET_ALTQ:
if ((error = pf_commit_altq(ioe->ticket))) {
@@ -5499,6 +5892,12 @@
if ((error = pf_clear_tables()) != 0)
break;
+ if ((error = pf_begin_eth(&t[0])) != 0) {
+ DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: eth\n"));
+ break;
+ }
+ pf_commit_eth(t[0]);
+
#ifdef ALTQ
if ((error = pf_begin_altq(&t[0])) != 0) {
DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n"));
@@ -5538,6 +5937,28 @@
}
}
+static pfil_return_t
+pf_eth_check_in(struct mbuf **m, struct ifnet *ifp, int flags,
+ void *ruleset __unused, struct inpcb *inp)
+{
+ int chk;
+
+ chk = pf_test_eth(PF_IN, flags, ifp, m, inp);
+
+ return (pf_check_return(chk, m));
+}
+
+static pfil_return_t
+pf_eth_check_out(struct mbuf **m, struct ifnet *ifp, int flags,
+ void *ruleset __unused, struct inpcb *inp)
+{
+ int chk;
+
+ chk = pf_test_eth(PF_OUT, flags, ifp, m, inp);
+
+ return (pf_check_return(chk, m));
+}
+
#ifdef INET
static pfil_return_t
pf_check_in(struct mbuf **m, struct ifnet *ifp, int flags,
@@ -5595,6 +6016,11 @@
}
#endif /* INET6 */
+VNET_DEFINE_STATIC(pfil_hook_t, pf_eth_in_hook);
+VNET_DEFINE_STATIC(pfil_hook_t, pf_eth_out_hook);
+#define V_pf_eth_in_hook VNET(pf_eth_in_hook)
+#define V_pf_eth_out_hook VNET(pf_eth_out_hook)
+
#ifdef INET
VNET_DEFINE_STATIC(pfil_hook_t, pf_ip4_in_hook);
VNET_DEFINE_STATIC(pfil_hook_t, pf_ip4_out_hook);
@@ -5624,6 +6050,24 @@
pla.pa_version = PFIL_VERSION;
+ pha.pa_type = PFIL_TYPE_ETHERNET;
+ pha.pa_func = pf_eth_check_in;
+ pha.pa_flags = PFIL_IN;
+ pha.pa_rulname = "eth-in";
+ V_pf_eth_in_hook = pfil_add_hook(&pha);
+ pla.pa_flags = PFIL_IN | PFIL_HEADPTR | PFIL_HOOKPTR;
+ pla.pa_head = V_link_pfil_head;
+ pla.pa_hook = V_pf_eth_in_hook;
+ (void)pfil_link(&pla);
+ pha.pa_func = pf_eth_check_out;
+ pha.pa_flags = PFIL_OUT;
+ pha.pa_rulname = "eth-out";
+ V_pf_eth_out_hook = pfil_add_hook(&pha);
+ pla.pa_flags = PFIL_OUT | PFIL_HEADPTR | PFIL_HOOKPTR;
+ pla.pa_head = V_link_pfil_head;
+ pla.pa_hook = V_pf_eth_out_hook;
+ (void)pfil_link(&pla);
+
#ifdef INET
pha.pa_type = PFIL_TYPE_IP4;
pha.pa_func = pf_check_in;
@@ -5677,6 +6121,9 @@
if (V_pf_pfil_hooked == 0)
return;
+ pfil_remove_hook(V_pf_eth_in_hook);
+ pfil_remove_hook(V_pf_eth_out_hook);
+
#ifdef INET
pfil_remove_hook(V_pf_ip4_in_hook);
pfil_remove_hook(V_pf_ip4_out_hook);
@@ -5702,6 +6149,10 @@
PF_QUEUE_TAG_HASH_SIZE_DEFAULT);
#endif
+ V_pf_keth = malloc(sizeof(*V_pf_keth), M_PFRULE, M_WAITOK);
+ V_pf_keth_inactive = malloc(sizeof(*V_pf_keth_inactive),
+ M_PFRULE, M_WAITOK);
+
pfattach_vnet();
V_pf_vnet_active = 1;
}
@@ -5811,6 +6262,9 @@
pf_counter_u64_deinit(&V_pf_status.fcounters[i]);
for (int i = 0; i < SCNT_MAX; i++)
counter_u64_free(V_pf_status.scounters[i]);
+
+ free(V_pf_keth, M_PFRULE);
+ free(V_pf_keth_inactive, M_PFRULE);
}
static void
Index: sys/netpfil/pf/pf_nv.h
===================================================================
--- sys/netpfil/pf/pf_nv.h
+++ sys/netpfil/pf/pf_nv.h
@@ -83,4 +83,6 @@
struct pf_kstate_kill *);
nvlist_t *pf_state_to_nvstate(const struct pf_kstate *);
+nvlist_t *pf_keth_rule_to_nvl(const struct pf_keth_rule *);
+int pf_nvl_to_keth_rule(const nvlist_t *, struct pf_keth_rule *);
#endif
Index: sys/netpfil/pf/pf_nv.c
===================================================================
--- sys/netpfil/pf/pf_nv.c
+++ sys/netpfil/pf/pf_nv.c
@@ -972,3 +972,149 @@
nvlist_destroy(nvl);
return (NULL);
}
+
+static int
+pf_nvl_addr_to_keth_rule_addr(const nvlist_t *nvl,
+ struct pf_keth_rule_addr *krule)
+{
+ static const u_int8_t EMPTY_MAC[ETHER_ADDR_LEN] = { 0 };
+ size_t len;
+
+ if (nvlist_exists_binary(nvl, "addr")) {
+ (void)nvlist_get_binary(nvl, "addr", &len);
+ if (len != ETHER_ADDR_LEN)
+ return (EINVAL);
+
+ memcpy(&krule->addr, nvlist_get_binary(nvl, "addr", &len),
+ sizeof(krule->addr));
+ }
+
+ if (nvlist_exists_bool(nvl, "neg"))
+ krule->neg = nvlist_get_bool(nvl, "neg");
+
+ /* To make checks for 'is this address set?' easier. */
+ if (memcmp(krule->addr, EMPTY_MAC, ETHER_ADDR_LEN) != 0)
+ krule->isset = 1;
+
+ return (0);
+}
+
+static nvlist_t*
+pf_keth_rule_addr_to_nvl(const struct pf_keth_rule_addr *krule)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ if (nvl == NULL)
+ return (NULL);
+
+ nvlist_add_binary(nvl, "addr", &krule->addr, sizeof(krule->addr));
+ nvlist_add_bool(nvl, "neg", krule->neg);
+
+ return (nvl);
+}
+
+nvlist_t*
+pf_keth_rule_to_nvl(const struct pf_keth_rule *krule)
+{
+ nvlist_t *nvl, *addr;
+
+ nvl = nvlist_create(0);
+ if (nvl == NULL)
+ return (NULL);
+
+ nvlist_add_number(nvl, "nr", krule->nr);
+ nvlist_add_bool(nvl, "quick", krule->quick);
+ nvlist_add_string(nvl, "ifname", krule->ifname);
+ nvlist_add_bool(nvl, "ifnot", krule->ifnot);
+ nvlist_add_number(nvl, "direction", krule->direction);
+ nvlist_add_number(nvl, "proto", krule->proto);
+
+ addr = pf_keth_rule_addr_to_nvl(&krule->src);
+ if (addr == NULL) {
+ nvlist_destroy(nvl);
+ return (NULL);
+ }
+ nvlist_add_nvlist(nvl, "src", addr);
+
+ addr = pf_keth_rule_addr_to_nvl(&krule->dst);
+ if (addr == NULL) {
+ nvlist_destroy(nvl);
+ return (NULL);
+ }
+ nvlist_add_nvlist(nvl, "dst", addr);
+
+ nvlist_add_number(nvl, "evaluations",
+ counter_u64_fetch(krule->evaluations));
+ nvlist_add_number(nvl, "packets-in",
+ counter_u64_fetch(krule->packets[0]));
+ nvlist_add_number(nvl, "packets-out",
+ counter_u64_fetch(krule->packets[1]));
+ nvlist_add_number(nvl, "bytes-in",
+ counter_u64_fetch(krule->bytes[0]));
+ nvlist_add_number(nvl, "bytes-out",
+ counter_u64_fetch(krule->bytes[1]));
+
+ nvlist_add_string(nvl, "qname", krule->qname);
+ nvlist_add_string(nvl, "tagname", krule->tagname);
+
+ nvlist_add_number(nvl, "action", krule->action);
+
+ return (nvl);
+}
+
+int
+pf_nvl_to_keth_rule(const nvlist_t *nvl,
+ struct pf_keth_rule *krule)
+{
+ int error;
+
+ bzero(krule, sizeof(*krule));
+
+ if (! nvlist_exists_number(nvl, "nr"))
+ return (EBADMSG);
+ krule->nr = nvlist_get_number(nvl, "nr");
+
+ if (nvlist_exists_bool(nvl, "quick"))
+ krule->quick = nvlist_get_bool(nvl, "quick");
+
+ if (nvlist_exists_string(nvl, "ifname"))
+ strlcpy(krule->ifname, nvlist_get_string(nvl, "ifname"),
+ sizeof(krule->ifname));
+
+ if (nvlist_exists_bool(nvl, "ifnot"))
+ krule->ifnot = nvlist_get_bool(nvl, "ifnot");
+
+ if (nvlist_exists_number(nvl, "direction"))
+ krule->direction = nvlist_get_number(nvl, "direction");
+
+ if (nvlist_exists_number(nvl, "proto"))
+ krule->proto = nvlist_get_number(nvl, "proto");
+
+ if (nvlist_exists_nvlist(nvl, "src")) {
+ error = pf_nvl_addr_to_keth_rule_addr(nvlist_get_nvlist(nvl,
+ "src"), &krule->src);
+ if (error)
+ return (error);
+ }
+ if (nvlist_exists_nvlist(nvl, "dst")) {
+ error = pf_nvl_addr_to_keth_rule_addr(nvlist_get_nvlist(nvl,
+ "dst"), &krule->dst);
+ if (error)
+ return (error);
+ }
+
+ if (nvlist_exists(nvl, "qname"))
+ strlcpy(krule->qname, nvlist_get_string(nvl, "qname"),
+ PF_QNAME_SIZE);
+
+ if (nvlist_exists_string(nvl, "tagname"))
+ strlcpy(krule->tagname, nvlist_get_string(nvl, "tagname"),
+ PF_TAG_NAME_SIZE);
+
+ if (! nvlist_exists_number(nvl, "action"))
+ return (EBADMSG);
+ krule->action = nvlist_get_number(nvl, "action");
+
+ return (0);
+}
Index: sys/netpfil/pf/pf_ruleset.c
===================================================================
--- sys/netpfil/pf/pf_ruleset.c
+++ sys/netpfil/pf/pf_ruleset.c
@@ -70,6 +70,8 @@
VNET_DEFINE(struct pf_kanchor_global, pf_anchors);
VNET_DEFINE(struct pf_kanchor, pf_main_anchor);
+VNET_DEFINE(struct pf_keth_settings*, pf_keth);
+VNET_DEFINE(struct pf_keth_settings*, pf_keth_inactive);
static __inline int pf_kanchor_compare(struct pf_kanchor *,
struct pf_kanchor *);
@@ -145,6 +147,15 @@
}
}
+void
+pf_init_keth(struct pf_keth_settings *settings)
+{
+
+ TAILQ_INIT(&settings->rules);
+ settings->ticket = 0;
+ settings->open = 0;
+}
+
struct pf_kruleset *
pf_find_kruleset(const char *path)
{

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 9, 3:10 AM (8 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28529484
Default Alt Text
D31737.id94413.diff (25 KB)

Event Timeline