Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F95995105
D29557.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
27 KB
Referenced Files
None
Subscribers
None
D29557.diff
View Options
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -4525,6 +4525,7 @@
netpfil/pf/pf_ioctl.c optional pf inet
netpfil/pf/pf_lb.c optional pf inet
netpfil/pf/pf_norm.c optional pf inet
+netpfil/pf/pf_nv.c optional pf inet
netpfil/pf/pf_osfp.c optional pf inet
netpfil/pf/pf_ruleset.c optional pf inet
netpfil/pf/pf_table.c optional pf inet
diff --git a/sys/modules/pf/Makefile b/sys/modules/pf/Makefile
--- a/sys/modules/pf/Makefile
+++ b/sys/modules/pf/Makefile
@@ -4,7 +4,7 @@
KMOD= pf
SRCS= pf.c pf_if.c pf_lb.c pf_osfp.c pf_ioctl.c pf_norm.c pf_table.c \
- pf_ruleset.c in4_cksum.c \
+ pf_ruleset.c pf_nv.c in4_cksum.c \
bus_if.h device_if.h \
opt_pf.h opt_inet.h opt_inet6.h opt_bpf.h opt_sctp.h opt_global.h
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1230,6 +1230,7 @@
#define DIOCSTART _IO ('D', 1)
#define DIOCSTOP _IO ('D', 2)
#define DIOCADDRULE _IOWR('D', 4, struct pfioc_rule)
+#define DIOCADDRULENV _IOWR('D', 4, struct pfioc_nv)
#define DIOCGETRULES _IOWR('D', 6, struct pfioc_rule)
#define DIOCGETRULE _IOWR('D', 7, struct pfioc_rule)
/* XXX cut 8 - 17 */
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -187,6 +187,12 @@
#define PF_TABLE_NAME_SIZE 32
#define PF_QNAME_SIZE 64
+struct pfioc_nv {
+ void *data;
+ size_t len; /* The length of the nvlist data. */
+ size_t size; /* The total size of the data buffer. */
+};
+
struct pf_rule;
/* keep synced with pfi_kif, used in RB_FIND */
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -61,6 +61,7 @@
#include <sys/lock.h>
#include <sys/mbuf.h>
#include <sys/module.h>
+#include <sys/nv.h>
#include <sys/proc.h>
#include <sys/smp.h>
#include <sys/socket.h>
@@ -82,6 +83,7 @@
#include <netinet/ip_var.h>
#include <netinet6/ip6_var.h>
#include <netinet/ip_icmp.h>
+#include <netpfil/pf/pf_nv.h>
#ifdef INET6
#include <netinet/ip6.h>
@@ -1622,6 +1624,294 @@
return (0);
}
+static int
+pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *paddr)
+{
+ return (pf_nvbinary(nvl, "addr", paddr, sizeof(*paddr)));
+}
+
+static int
+pf_nvpool_to_pool(const nvlist_t *nvl, struct pf_kpool *kpool)
+{
+ int error = 0;
+
+ bzero(kpool, sizeof(*kpool));
+
+ PFNV_CHK(pf_nvbinary(nvl, "key", &kpool->key, sizeof(kpool->key)));
+
+ if (nvlist_exists_nvlist(nvl, "counter")) {
+ PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "counter"),
+ &kpool->counter));
+ }
+
+ PFNV_CHK(pf_nvint(nvl, "tblidx", &kpool->tblidx));
+ PFNV_CHK(pf_nvuint16_array(nvl, "proxy_port", kpool->proxy_port, 2,
+ NULL));
+ PFNV_CHK(pf_nvuint8(nvl, "opts", &kpool->opts));
+
+errout:
+ return (error);
+}
+
+static int
+pf_nvaddr_wrap_to_addr_wrap(const nvlist_t *nvl, struct pf_addr_wrap *addr)
+{
+ int error = 0;
+
+ bzero(addr, sizeof(*addr));
+
+ PFNV_CHK(pf_nvuint8(nvl, "type", &addr->type));
+ PFNV_CHK(pf_nvuint8(nvl, "iflags", &addr->iflags));
+ PFNV_CHK(pf_nvstring(nvl, "ifname", addr->v.ifname,
+ sizeof(addr->v.ifname)));
+ PFNV_CHK(pf_nvstring(nvl, "tblname", addr->v.tblname,
+ sizeof(addr->v.tblname)));
+
+ if (! nvlist_exists_nvlist(nvl, "addr"))
+ return (EINVAL);
+ PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"),
+ &addr->v.a.addr));
+
+ if (! nvlist_exists_nvlist(nvl, "mask"))
+ return (EINVAL);
+ PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "mask"),
+ &addr->v.a.mask));
+
+ switch (addr->type) {
+ case PF_ADDR_DYNIFTL:
+ case PF_ADDR_TABLE:
+ case PF_ADDR_RANGE:
+ case PF_ADDR_ADDRMASK:
+ case PF_ADDR_NOROUTE:
+ case PF_ADDR_URPFFAILED:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+errout:
+ return (error);
+}
+
+static int
+pf_validate_op(uint8_t op)
+{
+ switch (op) {
+ case PF_OP_NONE:
+ case PF_OP_IRG:
+ case PF_OP_EQ:
+ case PF_OP_NE:
+ case PF_OP_LT:
+ case PF_OP_LE:
+ case PF_OP_GT:
+ case PF_OP_GE:
+ case PF_OP_XRG:
+ case PF_OP_RRG:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static int
+pf_nvrule_addr_to_rule_addr(const nvlist_t *nvl, struct pf_rule_addr *addr)
+{
+ int error = 0;
+
+ if (! nvlist_exists_nvlist(nvl, "addr"))
+ return (EINVAL);
+
+ PFNV_CHK(pf_nvaddr_wrap_to_addr_wrap(nvlist_get_nvlist(nvl, "addr"),
+ &addr->addr));
+ PFNV_CHK(pf_nvuint16_array(nvl, "port", addr->port, 2, NULL));
+ PFNV_CHK(pf_nvuint8(nvl, "neg", &addr->neg));
+ PFNV_CHK(pf_nvuint8(nvl, "port_op", &addr->port_op));
+
+ PFNV_CHK(pf_validate_op(addr->port_op));
+
+errout:
+ return (error);
+}
+
+static int
+pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
+{
+ int error = 0;
+
+ bzero(uid, sizeof(*uid));
+
+ PFNV_CHK(pf_nvuint32_array(nvl, "uid", uid->uid, 2, NULL));
+ PFNV_CHK(pf_nvuint8(nvl, "op", &uid->op));
+
+ PFNV_CHK(pf_validate_op(uid->op));
+
+errout:
+ return (error);
+}
+
+static int
+pf_nvrule_gid_to_rule_gid(const nvlist_t *nvl, struct pf_rule_gid *gid)
+{
+ /* Cheat a little. These stucts are the same, other than the name of
+ * the first field. */
+ return (pf_nvrule_uid_to_rule_uid(nvl, (struct pf_rule_uid *)gid));
+}
+
+static int
+pf_nvrule_to_krule(const nvlist_t *nvl, struct pf_krule **prule)
+{
+ struct pf_krule *rule;
+ int error = 0;
+
+ rule = malloc(sizeof(*rule), M_PFRULE, M_WAITOK | M_ZERO);
+
+ PFNV_CHK(pf_nvuint32(nvl, "nr", &rule->nr));
+
+ if (! nvlist_exists_nvlist(nvl, "src")) {
+ error = EINVAL;
+ goto errout;
+ }
+ error = pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"),
+ &rule->src);
+ if (error != 0)
+ goto errout;
+
+ if (! nvlist_exists_nvlist(nvl, "dst")) {
+ error = EINVAL;
+ goto errout;
+ }
+ PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
+ &rule->dst));
+
+ PFNV_CHK(pf_nvstring(nvl, "label", rule->label, sizeof(rule->label)));
+ PFNV_CHK(pf_nvstring(nvl, "ifname", rule->ifname,
+ sizeof(rule->ifname)));
+ PFNV_CHK(pf_nvstring(nvl, "qname", rule->qname, sizeof(rule->qname)));
+ PFNV_CHK(pf_nvstring(nvl, "pqname", rule->pqname,
+ sizeof(rule->pqname)));
+ PFNV_CHK(pf_nvstring(nvl, "tagname", rule->tagname,
+ sizeof(rule->tagname)));
+ PFNV_CHK(pf_nvstring(nvl, "match_tagname", rule->match_tagname,
+ sizeof(rule->match_tagname)));
+ PFNV_CHK(pf_nvstring(nvl, "overload_tblname", rule->overload_tblname,
+ sizeof(rule->overload_tblname)));
+
+ if (! nvlist_exists_nvlist(nvl, "rpool")) {
+ error = EINVAL;
+ goto errout;
+ }
+ PFNV_CHK(pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"),
+ &rule->rpool));
+
+ PFNV_CHK(pf_nvuint32(nvl, "os_fingerprint", &rule->os_fingerprint));
+
+ PFNV_CHK(pf_nvint(nvl, "rtableid", &rule->rtableid));
+ PFNV_CHK(pf_nvuint32_array(nvl, "timeout", rule->timeout, PFTM_MAX, NULL));
+ PFNV_CHK(pf_nvuint32(nvl, "max_states", &rule->max_states));
+ PFNV_CHK(pf_nvuint32(nvl, "max_src_nodes", &rule->max_src_nodes));
+ PFNV_CHK(pf_nvuint32(nvl, "max_src_states", &rule->max_src_states));
+ PFNV_CHK(pf_nvuint32(nvl, "max_src_conn", &rule->max_src_conn));
+ PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.limit",
+ &rule->max_src_conn_rate.limit));
+ PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.seconds",
+ &rule->max_src_conn_rate.seconds));
+ PFNV_CHK(pf_nvuint32(nvl, "prob", &rule->prob));
+ PFNV_CHK(pf_nvuint32(nvl, "cuid", &rule->cuid));
+ PFNV_CHK(pf_nvuint32(nvl, "cpid", &rule->cpid));
+
+ PFNV_CHK(pf_nvuint16(nvl, "return_icmp", &rule->return_icmp));
+ PFNV_CHK(pf_nvuint16(nvl, "return_icmp6", &rule->return_icmp6));
+
+ PFNV_CHK(pf_nvuint16(nvl, "max_mss", &rule->max_mss));
+ PFNV_CHK(pf_nvuint16(nvl, "scrub_flags", &rule->scrub_flags));
+
+ if (! nvlist_exists_nvlist(nvl, "uid")) {
+ error = EINVAL;
+ goto errout;
+ }
+ PFNV_CHK(pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "uid"),
+ &rule->uid));
+
+ if (! nvlist_exists_nvlist(nvl, "gid")) {
+ error = EINVAL;
+ goto errout;
+ }
+ PFNV_CHK(pf_nvrule_gid_to_rule_gid(nvlist_get_nvlist(nvl, "gid"),
+ &rule->gid));
+
+ PFNV_CHK(pf_nvuint32(nvl, "rule_flag", &rule->rule_flag));
+ PFNV_CHK(pf_nvuint8(nvl, "action", &rule->action));
+ PFNV_CHK(pf_nvuint8(nvl, "direction", &rule->direction));
+ PFNV_CHK(pf_nvuint8(nvl, "log", &rule->log));
+ PFNV_CHK(pf_nvuint8(nvl, "logif", &rule->logif));
+ PFNV_CHK(pf_nvuint8(nvl, "quick", &rule->quick));
+ PFNV_CHK(pf_nvuint8(nvl, "ifnot", &rule->ifnot));
+ PFNV_CHK(pf_nvuint8(nvl, "match_tag_not", &rule->match_tag_not));
+ PFNV_CHK(pf_nvuint8(nvl, "natpass", &rule->natpass));
+
+ PFNV_CHK(pf_nvuint8(nvl, "keep_state", &rule->keep_state));
+ PFNV_CHK(pf_nvuint8(nvl, "af", &rule->af));
+ PFNV_CHK(pf_nvuint8(nvl, "proto", &rule->proto));
+ PFNV_CHK(pf_nvuint8(nvl, "type", &rule->type));
+ PFNV_CHK(pf_nvuint8(nvl, "code", &rule->code));
+ PFNV_CHK(pf_nvuint8(nvl, "flags", &rule->flags));
+ PFNV_CHK(pf_nvuint8(nvl, "flagset", &rule->flagset));
+ PFNV_CHK(pf_nvuint8(nvl, "min_ttl", &rule->min_ttl));
+ PFNV_CHK(pf_nvuint8(nvl, "allow_opts", &rule->allow_opts));
+ PFNV_CHK(pf_nvuint8(nvl, "rt", &rule->rt));
+ PFNV_CHK(pf_nvuint8(nvl, "return_ttl", &rule->return_ttl));
+ PFNV_CHK(pf_nvuint8(nvl, "tos", &rule->tos));
+ PFNV_CHK(pf_nvuint8(nvl, "set_tos", &rule->set_tos));
+ PFNV_CHK(pf_nvuint8(nvl, "anchor_relative", &rule->anchor_relative));
+ PFNV_CHK(pf_nvuint8(nvl, "anchor_wildcard", &rule->anchor_wildcard));
+
+ PFNV_CHK(pf_nvuint8(nvl, "flush", &rule->flush));
+ PFNV_CHK(pf_nvuint8(nvl, "prio", &rule->prio));
+
+ PFNV_CHK(pf_nvuint8_array(nvl, "set_prio", &rule->prio, 2, NULL));
+
+ if (nvlist_exists_nvlist(nvl, "divert")) {
+ const nvlist_t *nvldivert = nvlist_get_nvlist(nvl, "divert");
+
+ if (! nvlist_exists_nvlist(nvldivert, "addr")) {
+ error = EINVAL;
+ goto errout;
+ }
+ PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvldivert, "addr"),
+ &rule->divert.addr));
+ PFNV_CHK(pf_nvuint16(nvldivert, "port", &rule->divert.port));
+ }
+
+ /* Validation */
+#ifndef INET
+ if (rule->af == AF_INET) {
+ error = EAFNOSUPPORT;
+ goto errout;
+ }
+#endif /* INET */
+#ifndef INET6
+ if (rule->af == AF_INET6) {
+ error = EAFNOSUPPORT;
+ goto errout;
+ }
+#endif /* INET6 */
+
+ PFNV_CHK(pf_check_rule_addr(&rule->src));
+ PFNV_CHK(pf_check_rule_addr(&rule->dst));
+
+ *prule = rule;
+
+ return (0);
+
+errout:
+ pf_krule_free(rule);
+ *prule = NULL;
+
+ return (error);
+}
+
static int
pf_rule_to_krule(const struct pf_rule *rule, struct pf_krule *krule)
{
@@ -1730,6 +2020,163 @@
return (0);
}
+static int
+pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
+ uint32_t pool_ticket, const char *anchor, const char *anchor_call,
+ struct thread *td)
+{
+ struct pf_kruleset *ruleset;
+ struct pf_krule *tail;
+ struct pf_kpooladdr *pa;
+ struct pfi_kkif *kif = NULL;
+ int rs_num;
+ int error = 0;
+
+ if ((rule->return_icmp >> 8) > ICMP_MAXTYPE) {
+ error = EINVAL;
+ goto errout_unlocked;
+ }
+
+#define ERROUT(x) { error = (x); goto errout; }
+
+ 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);
+ }
+ rule->states_cur = counter_u64_alloc(M_WAITOK);
+ rule->states_tot = counter_u64_alloc(M_WAITOK);
+ rule->src_nodes = counter_u64_alloc(M_WAITOK);
+ rule->cuid = td->td_ucred->cr_ruid;
+ rule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
+ TAILQ_INIT(&rule->rpool.list);
+
+ PF_RULES_WLOCK();
+ ruleset = pf_find_kruleset(anchor);
+ if (ruleset == NULL)
+ ERROUT(EINVAL);
+ rs_num = pf_get_ruleset_number(rule->action);
+ if (rs_num >= PF_RULESET_MAX)
+ ERROUT(EINVAL);
+ if (ticket != ruleset->rules[rs_num].inactive.ticket) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("ticket: %d != [%d]%d\n", ticket, rs_num,
+ ruleset->rules[rs_num].inactive.ticket));
+ ERROUT(EBUSY);
+ }
+ if (pool_ticket != V_ticket_pabuf) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pool_ticket: %d != %d\n", pool_ticket,
+ V_ticket_pabuf));
+ ERROUT(EBUSY);
+ }
+
+ tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
+ pf_krulequeue);
+ if (tail)
+ rule->nr = tail->nr + 1;
+ else
+ rule->nr = 0;
+ if (rule->ifname[0]) {
+ rule->kif = pfi_kkif_attach(kif, rule->ifname);
+ pfi_kkif_ref(rule->kif);
+ } else
+ rule->kif = NULL;
+
+ if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs)
+ error = EBUSY;
+
+#ifdef ALTQ
+ /* set queue IDs */
+ if (rule->qname[0] != 0) {
+ if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
+ error = EBUSY;
+ else if (rule->pqname[0] != 0) {
+ if ((rule->pqid =
+ pf_qname2qid(rule->pqname)) == 0)
+ error = EBUSY;
+ } else
+ rule->pqid = rule->qid;
+ }
+#endif
+ if (rule->tagname[0])
+ if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
+ error = EBUSY;
+ if (rule->match_tagname[0])
+ if ((rule->match_tag =
+ pf_tagname2tag(rule->match_tagname)) == 0)
+ error = EBUSY;
+ if (rule->rt && !rule->direction)
+ error = EINVAL;
+ if (!rule->log)
+ rule->logif = 0;
+ if (rule->logif >= PFLOGIFS_MAX)
+ error = EINVAL;
+ if (pf_addr_setup(ruleset, &rule->src.addr, rule->af))
+ error = ENOMEM;
+ if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af))
+ error = ENOMEM;
+ if (pf_kanchor_setup(rule, ruleset, anchor_call))
+ error = EINVAL;
+ if (rule->scrub_flags & PFSTATE_SETPRIO &&
+ (rule->set_prio[0] > PF_PRIO_MAX ||
+ rule->set_prio[1] > PF_PRIO_MAX))
+ error = EINVAL;
+ TAILQ_FOREACH(pa, &V_pf_pabuf, entries)
+ if (pa->addr.type == PF_ADDR_TABLE) {
+ pa->addr.p.tbl = pfr_attach_table(ruleset,
+ pa->addr.v.tblname);
+ if (pa->addr.p.tbl == NULL)
+ error = ENOMEM;
+ }
+
+ rule->overload_tbl = NULL;
+ if (rule->overload_tblname[0]) {
+ if ((rule->overload_tbl = pfr_attach_table(ruleset,
+ rule->overload_tblname)) == NULL)
+ error = EINVAL;
+ else
+ rule->overload_tbl->pfrkt_flags |=
+ PFR_TFLAG_ACTIVE;
+ }
+
+ pf_mv_kpool(&V_pf_pabuf, &rule->rpool.list);
+ if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
+ (rule->action == PF_BINAT)) && rule->anchor == NULL) ||
+ (rule->rt > PF_NOPFROUTE)) &&
+ (TAILQ_FIRST(&rule->rpool.list) == NULL))
+ error = EINVAL;
+
+ if (error) {
+ pf_free_rule(rule);
+ rule = NULL;
+ ERROUT(error);
+ }
+
+ rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
+ counter_u64_zero(rule->evaluations);
+ for (int i = 0; i < 2; i++) {
+ counter_u64_zero(rule->packets[i]);
+ counter_u64_zero(rule->bytes[i]);
+ }
+ TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
+ rule, entries);
+ ruleset->rules[rs_num].inactive.rcount++;
+ PF_RULES_WUNLOCK();
+
+ return (0);
+
+#undef ERROUT
+errout:
+ PF_RULES_WUNLOCK();
+errout_unlocked:
+ pf_kkif_free(kif);
+ pf_krule_free(rule);
+ return (error);
+}
+
static int
pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
@@ -1880,161 +2327,83 @@
}
break;
- case DIOCADDRULE: {
- struct pfioc_rule *pr = (struct pfioc_rule *)addr;
- struct pf_kruleset *ruleset;
- struct pf_krule *rule, *tail;
- struct pf_kpooladdr *pa;
- struct pfi_kkif *kif = NULL;
- int rs_num;
+ case DIOCADDRULENV: {
+ struct pfioc_nv *nv = (struct pfioc_nv *)addr;
+ nvlist_t *nvl = NULL;
+ void *nvlpacked = NULL;
+ struct pf_krule *rule = NULL;
+ const char *anchor = "", *anchor_call = "";
+ uint32_t ticket = 0, pool_ticket = 0;
- if (pr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
- error = EINVAL;
- break;
- }
+#define ERROUT(x) do { error = (x); goto DIOCADDRULENV_error; } while (0)
- rule = malloc(sizeof(*rule), M_PFRULE, M_WAITOK);
- error = pf_rule_to_krule(&pr->rule, rule);
- if (error != 0) {
- free(rule, M_PFRULE);
- break;
- }
+ if (nv->len > pf_ioctl_maxcount)
+ ERROUT(ENOMEM);
- 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);
- }
- rule->states_cur = counter_u64_alloc(M_WAITOK);
- rule->states_tot = counter_u64_alloc(M_WAITOK);
- rule->src_nodes = counter_u64_alloc(M_WAITOK);
- rule->cuid = td->td_ucred->cr_ruid;
- rule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
- TAILQ_INIT(&rule->rpool.list);
-#define ERROUT(x) { error = (x); goto DIOCADDRULE_error; }
+ nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK);
+ error = copyin(nv->data, nvlpacked, nv->len);
+ if (error)
+ ERROUT(error);
- PF_RULES_WLOCK();
- pr->anchor[sizeof(pr->anchor) - 1] = 0;
- ruleset = pf_find_kruleset(pr->anchor);
- if (ruleset == NULL)
+ nvl = nvlist_unpack(nvlpacked, nv->len, 0);
+ if (nvl == NULL)
+ ERROUT(EBADMSG);
+
+ if (! nvlist_exists_number(nvl, "ticket"))
ERROUT(EINVAL);
- rs_num = pf_get_ruleset_number(pr->rule.action);
- if (rs_num >= PF_RULESET_MAX)
+ ticket = nvlist_get_number(nvl, "ticket");
+
+ if (! nvlist_exists_number(nvl, "pool_ticket"))
ERROUT(EINVAL);
- if (pr->ticket != ruleset->rules[rs_num].inactive.ticket) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("ticket: %d != [%d]%d\n", pr->ticket, rs_num,
- ruleset->rules[rs_num].inactive.ticket));
- ERROUT(EBUSY);
- }
- if (pr->pool_ticket != V_ticket_pabuf) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pool_ticket: %d != %d\n", pr->pool_ticket,
- V_ticket_pabuf));
- ERROUT(EBUSY);
- }
+ pool_ticket = nvlist_get_number(nvl, "pool_ticket");
- tail = TAILQ_LAST(ruleset->rules[rs_num].inactive.ptr,
- pf_krulequeue);
- if (tail)
- rule->nr = tail->nr + 1;
- else
- rule->nr = 0;
- if (rule->ifname[0]) {
- rule->kif = pfi_kkif_attach(kif, rule->ifname);
- pfi_kkif_ref(rule->kif);
- } else
- rule->kif = NULL;
+ if (! nvlist_exists_nvlist(nvl, "rule"))
+ ERROUT(EINVAL);
- if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs)
- error = EBUSY;
+ error = pf_nvrule_to_krule(nvlist_get_nvlist(nvl, "rule"),
+ &rule);
+ if (error)
+ ERROUT(error);
-#ifdef ALTQ
- /* set queue IDs */
- if (rule->qname[0] != 0) {
- if ((rule->qid = pf_qname2qid(rule->qname)) == 0)
- error = EBUSY;
- else if (rule->pqname[0] != 0) {
- if ((rule->pqid =
- pf_qname2qid(rule->pqname)) == 0)
- error = EBUSY;
- } else
- rule->pqid = rule->qid;
- }
-#endif
- if (rule->tagname[0])
- if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
- error = EBUSY;
- if (rule->match_tagname[0])
- if ((rule->match_tag =
- pf_tagname2tag(rule->match_tagname)) == 0)
- error = EBUSY;
- if (rule->rt && !rule->direction)
- error = EINVAL;
- if (!rule->log)
- rule->logif = 0;
- if (rule->logif >= PFLOGIFS_MAX)
- error = EINVAL;
- if (pf_addr_setup(ruleset, &rule->src.addr, rule->af))
- error = ENOMEM;
- if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af))
- error = ENOMEM;
- if (pf_kanchor_setup(rule, ruleset, pr->anchor_call))
- error = EINVAL;
- if (rule->scrub_flags & PFSTATE_SETPRIO &&
- (rule->set_prio[0] > PF_PRIO_MAX ||
- rule->set_prio[1] > PF_PRIO_MAX))
- error = EINVAL;
- TAILQ_FOREACH(pa, &V_pf_pabuf, entries)
- if (pa->addr.type == PF_ADDR_TABLE) {
- pa->addr.p.tbl = pfr_attach_table(ruleset,
- pa->addr.v.tblname);
- if (pa->addr.p.tbl == NULL)
- error = ENOMEM;
- }
+ if (nvlist_exists_string(nvl, "anchor"))
+ anchor = nvlist_get_string(nvl, "anchor");
+ if (nvlist_exists_string(nvl, "anchor_call"))
+ anchor_call = nvlist_get_string(nvl, "anchor_call");
- rule->overload_tbl = NULL;
- if (rule->overload_tblname[0]) {
- if ((rule->overload_tbl = pfr_attach_table(ruleset,
- rule->overload_tblname)) == NULL)
- error = EINVAL;
- else
- rule->overload_tbl->pfrkt_flags |=
- PFR_TFLAG_ACTIVE;
- }
+ if ((error = nvlist_error(nvl)))
+ ERROUT(error);
- pf_mv_kpool(&V_pf_pabuf, &rule->rpool.list);
- if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) ||
- (rule->action == PF_BINAT)) && rule->anchor == NULL) ||
- (rule->rt > PF_NOPFROUTE)) &&
- (TAILQ_FIRST(&rule->rpool.list) == NULL))
- error = EINVAL;
+ /* Frees rule on error */
+ error = pf_ioctl_addrule(rule, ticket, pool_ticket, anchor,
+ anchor_call, td);
- if (error) {
- pf_free_rule(rule);
- PF_RULES_WUNLOCK();
+ nvlist_destroy(nvl);
+ free(nvlpacked, M_TEMP);
+ break;
+#undef ERROUT
+DIOCADDRULENV_error:
+ pf_krule_free(rule);
+ nvlist_destroy(nvl);
+ free(nvlpacked, M_TEMP);
+
+ break;
+ }
+ case DIOCADDRULE: {
+ struct pfioc_rule *pr = (struct pfioc_rule *)addr;
+ struct pf_krule *rule;
+
+ rule = malloc(sizeof(*rule), M_PFRULE, M_WAITOK);
+ error = pf_rule_to_krule(&pr->rule, rule);
+ if (error != 0) {
+ free(rule, M_PFRULE);
break;
}
- rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list);
- counter_u64_zero(rule->evaluations);
- for (int i = 0; i < 2; i++) {
- counter_u64_zero(rule->packets[i]);
- counter_u64_zero(rule->bytes[i]);
- }
- TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
- rule, entries);
- ruleset->rules[rs_num].inactive.rcount++;
- PF_RULES_WUNLOCK();
- break;
+ pr->anchor[sizeof(pr->anchor) - 1] = 0;
-#undef ERROUT
-DIOCADDRULE_error:
- PF_RULES_WUNLOCK();
- pf_krule_free(rule);
- pf_kkif_free(kif);
+ /* Frees rule on error */
+ error = pf_ioctl_addrule(rule, pr->ticket, pr->pool_ticket,
+ pr->anchor, pr->anchor_call, td);
break;
}
diff --git a/sys/netpfil/pf/pf_nv.h b/sys/netpfil/pf/pf_nv.h
new file mode 100644
--- /dev/null
+++ b/sys/netpfil/pf/pf_nv.h
@@ -0,0 +1,53 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Rubicon Communications, LLC (Netgate)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#ifndef _PF_NV_H_
+#define _PF_NV_H_
+
+#include <sys/types.h>
+#include <sys/nv.h>
+
+int pf_nvbinary(const nvlist_t *, const char *, void *, size_t);
+int pf_nvint(const nvlist_t *, const char *, int *);
+int pf_nvuint8(const nvlist_t *, const char *, uint8_t *);
+int pf_nvuint8_array(const nvlist_t *, const char *, uint8_t *,
+ size_t, size_t *);
+int pf_nvuint16(const nvlist_t *, const char *, uint16_t *);
+int pf_nvuint16_array(const nvlist_t *, const char *, uint16_t *,
+ size_t, size_t *);
+int pf_nvuint32(const nvlist_t *, const char *, uint32_t *);
+int pf_nvuint32_array(const nvlist_t *, const char *, uint32_t *,
+ size_t, size_t *);
+int pf_nvstring(const nvlist_t *, const char *, char *, size_t);
+
+#define PFNV_CHK(x) do { \
+ error = (x); \
+ if (error != 0) \
+ goto errout; \
+ } while (0)
+
+#endif
diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c
new file mode 100644
--- /dev/null
+++ b/sys/netpfil/pf/pf_nv.c
@@ -0,0 +1,127 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Rubicon Communications, LLC (Netgate)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/limits.h>
+#include <sys/systm.h>
+
+#include <netpfil/pf/pf_nv.h>
+
+#define PV_NV_IMPL_UINT(fnname, type, max) \
+ int \
+ fnname(const nvlist_t *nvl, const char *name, type *val) \
+ { \
+ uint64_t raw; \
+ if (! nvlist_exists_number(nvl, name)) \
+ return (EINVAL); \
+ raw = nvlist_get_number(nvl, name); \
+ if (raw > max) \
+ return (ERANGE); \
+ *val = (type)raw; \
+ return (0); \
+ } \
+ int \
+ fnname ## _array(const nvlist_t *nvl, const char *name, type *array, \
+ size_t maxelems, size_t *nelems) \
+ { \
+ const uint64_t *n; \
+ size_t nitems; \
+ bzero(array, sizeof(type) * maxelems); \
+ if (! nvlist_exists_number_array(nvl, name)) \
+ return (EINVAL); \
+ n = nvlist_get_number_array(nvl, name, &nitems); \
+ if (nitems != maxelems) \
+ return (E2BIG); \
+ if (nelems != NULL) \
+ *nelems = nitems; \
+ for (size_t i = 0; i < nitems; i++) { \
+ if (n[i] > max) \
+ return (ERANGE); \
+ array[i] = (type)n[i]; \
+ } \
+ return (0); \
+ }
+int
+pf_nvbinary(const nvlist_t *nvl, const char *name, void *data,
+ size_t expected_size)
+{
+ const uint8_t *nvdata;
+ size_t len;
+
+ bzero(data, expected_size);
+
+ if (! nvlist_exists_binary(nvl, name))
+ return (EINVAL);
+
+ nvdata = (const uint8_t *)nvlist_get_binary(nvl, name, &len);
+ if (len > expected_size)
+ return (EINVAL);
+
+ memcpy(data, nvdata, len);
+
+ return (0);
+}
+
+PV_NV_IMPL_UINT(pf_nvuint8, uint8_t, UINT8_MAX)
+PV_NV_IMPL_UINT(pf_nvuint16, uint16_t, UINT16_MAX);
+PV_NV_IMPL_UINT(pf_nvuint32, uint32_t, UINT32_MAX)
+
+int
+pf_nvint(const nvlist_t *nvl, const char *name, int *val)
+{
+ int64_t raw;
+
+ if (! nvlist_exists_number(nvl, name))
+ return (EINVAL);
+
+ raw = nvlist_get_number(nvl, name);
+ if (raw > INT_MAX || raw < INT_MIN)
+ return (ERANGE);
+
+ *val = (int)raw;
+
+ return (0);
+}
+
+int
+pf_nvstring(const nvlist_t *nvl, const char *name, char *str, size_t maxlen)
+{
+ int ret;
+
+ if (! nvlist_exists_string(nvl, name))
+ return (EINVAL);
+
+ ret = strlcpy(str, nvlist_get_string(nvl, name), maxlen);
+ if (ret >= maxlen)
+ return (EINVAL);
+
+ return (0);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Sep 24, 7:10 AM (1 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
12528076
Default Alt Text
D29557.diff (27 KB)
Attached To
Mode
D29557: pf: Introduce nvlist variant of DIOCADDRULE
Attached
Detach File
Event Timeline
Log In to Comment