summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Smith <mgsmith@netgate.com>2015-11-18 10:28:57 -0600
committerMatt Smith <mgsmith@netgate.com>2015-11-18 10:28:57 -0600
commit999db7254ad92d567efd568383eb4842bd7b409b (patch)
treedaedd86a27848d397699d4a7a5faf1ed1e592768
parent1ee1795dcad82d0fde682259cbccd7be677d013d (diff)
downloadFreeBSD-src-999db7254ad92d567efd568383eb4842bd7b409b.zip
FreeBSD-src-999db7254ad92d567efd568383eb4842bd7b409b.tar.gz
Importing pfSense patch CP_speedup.diff
-rw-r--r--sbin/ipfw/ipfw2.c172
-rw-r--r--sys/net/if_ethersubr.c8
-rw-r--r--sys/netinet/ip_fw.h15
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c113
-rw-r--r--sys/netpfil/ipfw/ip_fw_pfil.c16
-rw-r--r--sys/netpfil/ipfw/ip_fw_private.h16
-rw-r--r--sys/netpfil/ipfw/ip_fw_sockopt.c52
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.c241
8 files changed, 555 insertions, 78 deletions
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 98b25b3..1d0d0ec 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -4122,8 +4122,9 @@ ipfw_flush(int force)
}
+static void table_list_entry(ipfw_table_xentry *);
static void table_list(uint16_t num, int need_header);
-static void table_fill_xentry(char *arg, ipfw_table_xentry *xent);
+static void table_fill_xentry(int ac, char *av[], ipfw_table_xentry *xent);
/*
* Retrieve maximum number of tables supported by ipfw(4) module.
@@ -4194,29 +4195,9 @@ ipfw_table_handler(int ac, char *av[])
if (_substrcmp(*av, "add") == 0 ||
_substrcmp(*av, "delete") == 0) {
do_add = **av == 'a';
- ac--; av++;
- if (!ac)
- errx(EX_USAGE, "address required");
- table_fill_xentry(*av, &xent);
+ table_fill_xentry(ac, av, &xent);
- ac--; av++;
- if (do_add && ac) {
- unsigned int tval;
- /* isdigit is a bit of a hack here.. */
- if (strchr(*av, (int)'.') == NULL && isdigit(**av)) {
- xent.value = strtoul(*av, NULL, 0);
- } else {
- if (lookup_host(*av, (struct in_addr *)&tval) == 0) {
- /* The value must be stored in host order *
- * so that the values < 65k can be distinguished */
- xent.value = ntohl(tval);
- } else {
- errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
- }
- }
- } else
- xent.value = 0;
if (do_setcmd3(do_add ? IP_FW_TABLE_XADD : IP_FW_TABLE_XDEL,
&xent, xent.len) < 0) {
/* If running silent, don't bomb out on these errors. */
@@ -4243,19 +4224,41 @@ ipfw_table_handler(int ac, char *av[])
do {
table_list(xent.tbl, is_all);
} while (++xent.tbl < a);
+ } else if (_substrcmp(*av, "entrystats") == 0) {
+ table_fill_xentry(ac, av, &xent);
+
+ if (do_setcmd3(IP_FW_TABLE_XLISTENTRY, &xent, xent.len) < 0) {
+ /* If running silent, don't bomb out on these errors. */
+ if (!(co.do_quiet))
+ err(EX_OSERR, "setsockopt(IP_FW_TABLE_XLISTENTRY)");
+ } else
+ table_list_entry(&xent);
+ } else if (_substrcmp(*av, "entryzerostats") == 0) {
+ table_fill_xentry(ac, av, &xent);
+
+ if (do_setcmd3(IP_FW_TABLE_XZEROENTRY, &xent, xent.len) < 0) {
+ /* If running silent, don't bomb out on these errors. */
+ if (!(co.do_quiet))
+ err(EX_OSERR, "setsockopt(IP_FW_TABLE_XZEROENTRY)");
+ }
} else
errx(EX_USAGE, "invalid table command %s", *av);
}
static void
-table_fill_xentry(char *arg, ipfw_table_xentry *xent)
+table_fill_xentry(int ac, char *av[], ipfw_table_xentry *xent)
{
- int addrlen, mask, masklen, type;
+ int addrlen, mask, masklen, type, do_add;
struct in6_addr *paddr;
uint32_t *pkey;
- char *p;
+ char *p, *arg;
uint32_t key;
+ do_add = **av == 'a';
+ ac--; av++;
+ if (!ac)
+ errx(EX_USAGE, "address required");
+
mask = 0;
type = 0;
addrlen = 0;
@@ -4270,7 +4273,20 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
* 4) port, uid/gid or other u32 key (base 10 format)
* 5) hostname
*/
- paddr = &xent->k.addr6;
+ if (ac > 1 && av && _substrcmp(*av, "mac") == 0) {
+ uint8_t _mask[8];
+
+ type = IPFW_TABLE_MIX;
+ get_mac_addr_mask(av[1], (uint8_t *)xent->mac_addr, _mask);
+ ac-=2; av+=2;
+ if (ac <= 0)
+ errx(EX_DATAERR, "wrong argument passed.");
+
+ paddr = (struct in6_addr *)&xent->k.addr6;
+ } else
+ paddr = &xent->k.addr6;
+
+ arg = *av;
if (ishexnumber(*arg) != 0 || *arg == ':') {
/* Remove / if exists */
if ((p = strchr(arg, '/')) != NULL) {
@@ -4283,9 +4299,11 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
errx(EX_DATAERR, "bad IPv4 mask width: %s",
p + 1);
- type = IPFW_TABLE_CIDR;
+ if (type == 0)
+ type = IPFW_TABLE_CIDR;
masklen = p ? mask : 32;
addrlen = sizeof(struct in_addr);
+ xent->flags = IPFW_TCF_INET;
} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
if (IN6_IS_ADDR_V4COMPAT(paddr))
errx(EX_DATAERR,
@@ -4294,10 +4312,14 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
errx(EX_DATAERR, "bad IPv6 mask width: %s",
p + 1);
- type = IPFW_TABLE_CIDR;
+ if (type == 0)
+ type = IPFW_TABLE_CIDR;
masklen = p ? mask : 128;
addrlen = sizeof(struct in6_addr);
} else {
+ if (type != 0 && type != IPFW_TABLE_MIX)
+ errx(EX_DATAERR, "Wrong value passed as address");
+
/* Port or any other key */
/* Skip non-base 10 entries like 'fa1' */
key = strtol(arg, &p, 10);
@@ -4338,11 +4360,88 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
masklen = 32;
type = IPFW_TABLE_CIDR;
addrlen = sizeof(struct in_addr);
+ xent->flags = IPFW_TCF_INET;
}
+ ac--; av++;
+ if (ac > 1 && av) {
+ if (_substrcmp(*av, "mac") == 0) {
+ uint8_t _mask[8];
+
+ if (type == 0)
+ type = IPFW_TABLE_CIDR;
+ get_mac_addr_mask(av[1], (uint8_t *)&xent->mac_addr, _mask);
+ ac-=2; av+=2;
+ }
+ }
+
+ if (do_add && ac > 0) {
+ unsigned int tval;
+ /* isdigit is a bit of a hack here.. */
+ if (strchr(*av, (int)'.') == NULL && isdigit(**av)) {
+ xent->value = strtoul(*av, NULL, 0);
+ } else {
+ if (lookup_host(*av, (struct in_addr *)&tval) == 0) {
+ /* The value must be stored in host order *
+ * so that the values < 65k can be distinguished */
+ xent->value = ntohl(tval);
+ } else {
+ errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
+ }
+ }
+ } else
+ xent->value = 0;
+
xent->type = type;
xent->masklen = masklen;
- xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
+ if (type == IPFW_TABLE_MIX)
+ xent->len = offsetof(ipfw_table_xentry, k) + addrlen + ETHER_ADDR_LEN;
+ else
+ xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
+}
+
+static void
+table_list_entry(ipfw_table_xentry *xent)
+{
+ struct in6_addr *addr6;
+ uint32_t tval;
+ char tbuf[128];
+
+ switch (xent->type) {
+ case IPFW_TABLE_CIDR:
+ /* IPv4 or IPv6 prefixes */
+ tval = xent->value;
+ addr6 = &xent->k.addr6;
+
+ if ((xent->flags & IPFW_TCF_INET) != 0) {
+ /* IPv4 address */
+ inet_ntop(AF_INET, (in_addr_t *)&addr6->s6_addr32[0], tbuf, sizeof(tbuf));
+ } else {
+ /* IPv6 address */
+ inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf));
+ }
+
+ if (co.do_value_as_ip) {
+ tval = htonl(tval);
+ printf("%s/%u %s %d %d %u\n", tbuf, xent->masklen,
+ inet_ntoa(*(struct in_addr *)&tval), pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
+ } else
+ printf("%s/%u %u %d %d %u\n", tbuf, xent->masklen, tval,
+ pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
+ break;
+ case IPFW_TABLE_INTERFACE:
+ /* Interface names */
+ tval = xent->value;
+ if (co.do_value_as_ip) {
+ tval = htonl(tval);
+ printf("%s %u %s %d %d %u\n", xent->k.iface, xent->masklen,
+ inet_ntoa(*(struct in_addr *)&tval), pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
+ } else
+ printf("%s %u %u %d %d %u\n", xent->k.iface, xent->masklen, tval,
+ pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
+
+ break;
+ }
}
static void
@@ -4388,21 +4487,24 @@ table_list(uint16_t num, int need_header)
tval = xent->value;
addr6 = &xent->k.addr6;
-
- if (IN6_IS_ADDR_V4COMPAT(addr6)) {
+ if ((xent->flags & IPFW_TCF_INET) != 0) {
/* IPv4 address */
- inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, sizeof(tbuf));
+ inet_ntop(AF_INET, &addr6->s6_addr32[0], tbuf, sizeof(tbuf));
} else {
/* IPv6 address */
inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf));
}
+ printf("%s/%u", tbuf, xent->masklen);
+ if (xent->mac_addr)
+ printf(" mac %s", ether_ntoa((struct ether_addr *)&xent->mac_addr));
+
if (co.do_value_as_ip) {
tval = htonl(tval);
- printf("%s/%u %s\n", tbuf, xent->masklen,
+ printf(" %s\n",
inet_ntoa(*(struct in_addr *)&tval));
} else
- printf("%s/%u %u\n", tbuf, xent->masklen, tval);
+ printf(" %u\n", tval);
break;
case IPFW_TABLE_INTERFACE:
/* Interface names */
@@ -4413,6 +4515,8 @@ table_list(uint16_t num, int need_header)
inet_ntoa(*(struct in_addr *)&tval));
} else
printf("%s %u\n", xent->k.iface, tval);
+
+ break;
}
if (sz < xent->len)
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 5e2499d..20689a8 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -742,7 +742,11 @@ ether_demux(struct ifnet *ifp, struct mbuf *m)
if (i != 0 || m == NULL)
return;
- }
+
+ /* M_PROTO2 is for M_IP[6]_NEXTHOP */
+ i = m->m_flags & (M_FASTFWD_OURS|M_PROTO2);
+ } else
+ i = 0;
eh = mtod(m, struct ether_header *);
ether_type = ntohs(eh->ether_type);
@@ -781,6 +785,8 @@ ether_demux(struct ifnet *ifp, struct mbuf *m)
*/
m->m_flags &= ~M_VLANTAG;
m_clrprotoflags(m);
+ if (i)
+ m->m_flags |= M_FASTFWD_OURS|M_PROTO2;
m_adj(m, ETHER_HDR_LEN);
/*
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index 14b08f5..9b48430 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -74,6 +74,8 @@ typedef struct _ip_fw3_opheader {
#define IP_FW_TABLE_XDEL 87 /* delete entry */
#define IP_FW_TABLE_XGETSIZE 88 /* get table size */
#define IP_FW_TABLE_XLIST 89 /* list table contents */
+#define IP_FW_TABLE_XLISTENTRY 90 /* list one table entry contents */
+#define IP_FW_TABLE_XZEROENTRY 91 /* zero one table entry stats */
/*
* The kernel representation of ipfw rules is made of a list of
@@ -600,11 +602,16 @@ struct _ipfw_dyn_rule {
#define IPFW_TABLE_CIDR 1 /* Table for holding IPv4/IPv6 prefixes */
#define IPFW_TABLE_INTERFACE 2 /* Table for holding interface names */
-#define IPFW_TABLE_MAXTYPE 2 /* Maximum valid number */
+#define IPFW_TABLE_MIX 3 /* Table for holding IPv4/mac entries */
+#define IPFW_TABLE_MAC 4 /* Table for holding mac entries */
+#define IPFW_TABLE_MAXTYPE 5 /* Maximum valid number */
typedef struct _ipfw_table_entry {
in_addr_t addr; /* network address */
u_int32_t value; /* value */
+ uint64_t mac_addr;
+ uint64_t bytes;
+ uint64_t packets;
u_int16_t tbl; /* table number */
u_int8_t masklen; /* mask length */
} ipfw_table_entry;
@@ -614,13 +621,19 @@ typedef struct _ipfw_table_xentry {
uint8_t type; /* entry type */
uint8_t masklen; /* mask length */
uint16_t tbl; /* table number */
+ uint16_t flags; /* record flags */
uint32_t value; /* value */
+ uint32_t timestamp;
+ uint64_t mac_addr;
+ uint64_t bytes;
+ uint64_t packets;
union {
/* Longest field needs to be aligned by 4-byte boundary */
struct in6_addr addr6; /* IPv6 address */
char iface[IF_NAMESIZE]; /* interface name */
} k;
} ipfw_table_xentry;
+#define IPFW_TCF_INET 0x01 /* CIDR flags: IPv4 record */
typedef struct _ipfw_table {
u_int32_t size; /* size of entries in bytes */
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index 764696c..5ec629b 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -358,8 +358,8 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, struct ip_fw_chain *chain, uin
/* Check by name or by IP address */
if (cmd->name[0] != '\0') { /* match by name */
if (cmd->name[0] == '\1') /* use tablearg to match */
- return ipfw_lookup_table_extended(chain, cmd->p.glob,
- ifp->if_xname, tablearg, IPFW_TABLE_INTERFACE);
+ return (ipfw_lookup_table_extended(chain, cmd->p.glob,
+ ifp->if_xname, tablearg, IPFW_TABLE_INTERFACE, NULL) != NULL);
/* Check name */
if (cmd->p.glob) {
if (fnmatch(cmd->name, ifp->if_xname, 0) == 0)
@@ -955,6 +955,7 @@ ipfw_chk(struct ip_fw_args *args)
int dyn_dir = MATCH_UNKNOWN;
ipfw_dyn_rule *q = NULL;
struct ip_fw_chain *chain = &V_layer3_chain;
+ void *tblent = NULL, *tblent2 = NULL;
/*
* We store in ulp a pointer to the upper layer protocol header.
@@ -1288,6 +1289,8 @@ do { \
continue;
skip_or = 0;
+ tblent = NULL;
+ tblent2 = NULL;
for (l = f->cmd_len, cmd = f->cmd ; l > 0 ;
l -= cmdlen, cmd += cmdlen) {
int match;
@@ -1402,7 +1405,7 @@ do { \
break;
case O_IN: /* "out" is "not in" */
- match = (oif == NULL);
+ match = (args->dir == DIR_IN);
break;
case O_LAYER2:
@@ -1438,11 +1441,18 @@ do { \
case O_IP_SRC_LOOKUP:
case O_IP_DST_LOOKUP:
if (is_ipv4) {
+ struct ether_addr *ea = NULL;
+
uint32_t key =
(cmd->opcode == O_IP_DST_LOOKUP) ?
dst_ip.s_addr : src_ip.s_addr;
uint32_t v = 0;
+ if (args->eh) {
+ ea = (struct ether_addr*)((cmd->opcode == O_IP_DST_LOOKUP) ?
+ args->eh->ether_dhost :
+ args->eh->ether_shost);
+ }
if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
/* generic lookup. The key must be
* in 32bit big-endian format.
@@ -1484,22 +1494,37 @@ do { \
} else
break;
}
- match = ipfw_lookup_table(chain,
- cmd->arg1, key, &v);
- if (!match)
+ tblent2 = ipfw_lookup_table(chain,
+ cmd->arg1, key, &v, ea);
+ if (tblent2 == NULL) {
+ match = 0;
break;
+ } else
+ match = 1;
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
match =
((ipfw_insn_u32 *)cmd)->d[0] == v;
- else
+ if (match)
tablearg = v;
} else if (is_ipv6) {
+ struct ether_addr *ea = NULL;
uint32_t v = 0;
+
+ if (args->eh) {
+ ea = (struct ether_addr*)((cmd->opcode == O_IP_DST_LOOKUP) ?
+ args->eh->ether_dhost :
+ args->eh->ether_shost);
+ }
void *pkey = (cmd->opcode == O_IP_DST_LOOKUP) ?
&args->f_id.dst_ip6: &args->f_id.src_ip6;
- match = ipfw_lookup_table_extended(chain,
+ tblent = ipfw_lookup_table_extended(chain,
cmd->arg1, pkey, &v,
- IPFW_TABLE_CIDR);
+ IPFW_TABLE_CIDR, ea);
+ if (tblent == NULL) {
+ match = 0;
+ break;
+ } else
+ match = 1;
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
if (match)
@@ -2314,8 +2339,7 @@ do { \
break;
case O_FORWARD_IP:
- if (args->eh) /* not valid on layer2 pkts */
- break;
+ if (!args->eh) {/* not valid on layer2 pkts */
if (q == NULL || q->rule != f ||
dyn_dir == MATCH_FORWARD) {
struct sockaddr_in *sa;
@@ -2330,6 +2354,48 @@ do { \
args->next_hop = sa;
}
}
+ } else if (args->eh) {
+ struct m_tag *fwd_tag;
+ struct sockaddr_in *sa;
+ u_short sum;
+
+ /*
+ * Checksum correct? (from ip_fastfwd.c)
+ */
+ if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED)
+ sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
+ else {
+ if (hlen == sizeof(struct ip))
+ sum = in_cksum_hdr(ip);
+ else
+ sum = in_cksum(m, hlen);
+ }
+ if (sum) {
+ IPSTAT_INC(ips_badsum);
+ retval = IP_FW_DENY;
+ break;
+ }
+
+ /*
+ * Remember that we have checked the IP header and found it valid.
+ */
+ m->m_pkthdr.csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID);
+
+ sa = &(((ipfw_insn_sa *)cmd)->sa);
+ fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
+ sizeof(struct sockaddr_in), M_NOWAIT);
+ if (fwd_tag == NULL)
+ retval = IP_FW_DENY;
+ else {
+ bcopy(sa, (fwd_tag+1), sizeof(struct sockaddr_in));
+ m_tag_prepend(m, fwd_tag);
+
+ if (in_localip(sa->sin_addr))
+ m->m_flags |= M_FASTFWD_OURS;
+ m->m_flags |= M_IP_NEXTHOP;
+ }
+ }
+
retval = IP_FW_PASS;
l = 0; /* exit inner loop */
done = 1; /* exit outer loop */
@@ -2337,8 +2403,7 @@ do { \
#ifdef INET6
case O_FORWARD_IP6:
- if (args->eh) /* not valid on layer2 pkts */
- break;
+ if (!args->eh) {/* not valid on layer2 pkts */
if (q == NULL || q->rule != f ||
dyn_dir == MATCH_FORWARD) {
struct sockaddr_in6 *sin6;
@@ -2346,6 +2411,24 @@ do { \
sin6 = &(((ipfw_insn_sa6 *)cmd)->sa);
args->next_hop6 = sin6;
}
+ } else if (args->eh) {
+ struct m_tag *fwd_tag;
+ struct sockaddr_in6 *sin6;
+
+ sin6 = &(((ipfw_insn_sa6 *)cmd)->sa);
+ fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
+ sizeof(struct sockaddr_in6), M_NOWAIT);
+ if (fwd_tag == NULL)
+ retval = IP_FW_DENY;
+ else {
+ bcopy(sin6, (fwd_tag+1), sizeof(struct sockaddr_in6));
+ m_tag_prepend(m, fwd_tag);
+
+ if (in6_localip(&sin6->sin6_addr))
+ m->m_flags |= M_FASTFWD_OURS;
+ m->m_flags |= M_IP6_NEXTHOP;
+ }
+ }
retval = IP_FW_PASS;
l = 0; /* exit inner loop */
done = 1; /* exit outer loop */
@@ -2502,6 +2585,10 @@ do { \
struct ip_fw *rule = chain->map[f_pos];
/* Update statistics */
IPFW_INC_RULE_COUNTER(rule, pktlen);
+ if (tblent != NULL)
+ ipfw_count_table_xentry_stats(tblent, pktlen);
+ if (tblent2 != NULL)
+ ipfw_count_table_entry_stats(tblent2, pktlen);
} else {
retval = IP_FW_DENY;
printf("ipfw: ouch!, skip past end of rules, denying packet\n");
diff --git a/sys/netpfil/ipfw/ip_fw_pfil.c b/sys/netpfil/ipfw/ip_fw_pfil.c
index d1202ff..bf225b8 100644
--- a/sys/netpfil/ipfw/ip_fw_pfil.c
+++ b/sys/netpfil/ipfw/ip_fw_pfil.c
@@ -143,8 +143,9 @@ again:
}
args.m = *m0;
- args.oif = dir == DIR_OUT ? ifp : NULL;
+ args.oif = ifp;
args.inp = inp;
+ args.dir = dir;
ipfw = ipfw_chk(&args);
*m0 = args.m;
@@ -314,9 +315,8 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *dst, int dir,
/* XXX can we free it after use ? */
mtag->m_tag_id = PACKET_TAG_NONE;
r = (struct ipfw_rule_ref *)(mtag + 1);
- if (r->info & IPFW_ONEPASS)
- return (0);
- args.rule = *r;
+ m_tag_delete(*m0, mtag);
+ return (0);
}
/* I need some amt of data to be contiguous */
@@ -333,12 +333,15 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *dst, int dir,
save_eh = *eh; /* save copy for restore below */
m_adj(m, ETHER_HDR_LEN); /* strip ethernet header */
+ dir = dir == PFIL_IN ? DIR_IN : DIR_OUT;
+
args.m = m; /* the packet we are looking at */
- args.oif = dir == PFIL_OUT ? dst: NULL; /* destination, if any */
+ args.oif = dst; /* destination, if any */
args.next_hop = NULL; /* we do not support forward yet */
args.next_hop6 = NULL; /* we do not support forward yet */
args.eh = &save_eh; /* MAC header for bridged/MAC packets */
args.inp = NULL; /* used by ipfw uid/gid/jail rules */
+ args.dir = dir; /* pfSense addition */
i = ipfw_chk(&args);
m = args.m;
if (m != NULL) {
@@ -369,13 +372,12 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *dst, int dir,
case IP_FW_DUMMYNET:
ret = EACCES;
- int dir;
if (ip_dn_io_ptr == NULL)
break; /* i.e. drop */
*m0 = NULL;
- dir = PROTO_LAYER2 | (dst ? DIR_OUT : DIR_IN);
+ dir = PROTO_LAYER2 | dir;
ip_dn_io_ptr(&m, dir, &args);
return 0;
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
index e4a2f31..4977dae 100644
--- a/sys/netpfil/ipfw/ip_fw_private.h
+++ b/sys/netpfil/ipfw/ip_fw_private.h
@@ -101,6 +101,7 @@ struct ip_fw_args {
struct ipfw_flow_id f_id; /* grabbed from IP header */
//uint32_t cookie; /* a cookie depending on rule action */
+ uint32_t dir; /* direction */
struct inpcb *inp;
struct _ip6dn_args dummypar; /* dummynet->ip6_output */
@@ -303,16 +304,21 @@ int ipfw_chk(struct ip_fw_args *args);
void ipfw_reap_rules(struct ip_fw *head);
/* In ip_fw_table.c */
+struct ether_addr;
struct radix_node;
-int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
- uint32_t *val);
-int ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
- uint32_t *val, int type);
+void *ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
+ uint32_t *val, struct ether_addr *);
+void *ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
+ uint32_t *val, int type, struct ether_addr *);
+void ipfw_count_table_entry_stats(void *, int);
+void ipfw_count_table_xentry_stats(void *, int);
+int ipfw_zero_table_xentry_stats(struct ip_fw_chain *, ipfw_table_xentry *);
+int ipfw_lookup_table_xentry(struct ip_fw_chain *, ipfw_table_xentry *);
int ipfw_init_tables(struct ip_fw_chain *ch);
void ipfw_destroy_tables(struct ip_fw_chain *ch);
int ipfw_flush_table(struct ip_fw_chain *ch, uint16_t tbl);
int ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
- uint8_t plen, uint8_t mlen, uint8_t type, uint32_t value);
+ uint8_t plen, uint8_t mlen, uint8_t type, u_int64_t mac_addr, uint32_t value);
int ipfw_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
uint8_t plen, uint8_t mlen, uint8_t type);
int ipfw_count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
index 3c342f7..229ef84 100644
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -1124,7 +1124,7 @@ ipfw_ctl(struct sockopt *sopt)
break;
error = ipfw_add_table_entry(chain, ent.tbl,
&ent.addr, sizeof(ent.addr), ent.masklen,
- IPFW_TABLE_CIDR, ent.value);
+ IPFW_TABLE_CIDR, ent.mac_addr, ent.value);
}
break;
@@ -1162,7 +1162,7 @@ ipfw_ctl(struct sockopt *sopt)
error = (opt == IP_FW_TABLE_XADD) ?
ipfw_add_table_entry(chain, xent->tbl, &xent->k,
- len, xent->masklen, xent->type, xent->value) :
+ len, xent->masklen, xent->type, xent->mac_addr, xent->value) :
ipfw_del_table_entry(chain, xent->tbl, &xent->k,
len, xent->masklen, xent->type);
}
@@ -1245,6 +1245,54 @@ ipfw_ctl(struct sockopt *sopt)
}
break;
+ case IP_FW_TABLE_XZEROENTRY: /* IP_FW3 */
+ {
+ ipfw_table_xentry *xent = (ipfw_table_xentry *)(op3 + 1);
+
+ /* Check minimum header size */
+ if (IP_FW3_OPLENGTH(sopt) < offsetof(ipfw_table_xentry, k)) {
+ error = EINVAL;
+ break;
+ }
+
+ /* Check if len field is valid */
+ if (xent->len > sizeof(ipfw_table_xentry)) {
+ error = EINVAL;
+ break;
+ }
+
+ error = ipfw_zero_table_xentry_stats(chain, xent);
+ if (!error) {
+ xent->timestamp += boottime.tv_sec;
+ error = sooptcopyout(sopt, xent, sizeof(*xent));
+ }
+ }
+ break;
+
+ case IP_FW_TABLE_XLISTENTRY: /* IP_FW3 */
+ {
+ ipfw_table_xentry *xent = (ipfw_table_xentry *)(op3 + 1);
+
+ /* Check minimum header size */
+ if (IP_FW3_OPLENGTH(sopt) < offsetof(ipfw_table_xentry, k)) {
+ error = EINVAL;
+ break;
+ }
+
+ /* Check if len field is valid */
+ if (xent->len > sizeof(ipfw_table_xentry)) {
+ error = EINVAL;
+ break;
+ }
+
+ error = ipfw_lookup_table_xentry(chain, xent);
+ if (!error) {
+ xent->timestamp += boottime.tv_sec;
+ error = sooptcopyout(sopt, xent, sizeof(*xent));
+ }
+ }
+ break;
+
case IP_FW_TABLE_XLIST: /* IP_FW3 */
{
ipfw_xtable *tbl;
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
index 31eebfe..37fec1d 100644
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <net/route.h>
#include <net/vnet.h>
+#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/ip_var.h> /* struct ipfw_rule_ref */
#include <netinet/ip_fw.h>
@@ -74,7 +75,11 @@ static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
struct table_entry {
struct radix_node rn[2];
struct sockaddr_in addr, mask;
+ u_int64_t mac_addr;
u_int32_t value;
+ u_int32_t timestamp;
+ u_int64_t bytes;
+ u_int64_t packets;
};
struct xaddr_iface {
@@ -97,7 +102,11 @@ struct table_xentry {
#endif
struct xaddr_iface ifmask;
} m;
+ u_int64_t mac_addr;
u_int32_t value;
+ u_int32_t timestamp;
+ u_int64_t bytes;
+ u_int64_t packets;
};
/*
@@ -137,7 +146,7 @@ ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
int
ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
- uint8_t plen, uint8_t mlen, uint8_t type, uint32_t value)
+ uint8_t plen, uint8_t mlen, uint8_t type, u_int64_t mac_addr, uint32_t value)
{
struct radix_node_head *rnh, **rnh_ptr;
struct table_entry *ent;
@@ -161,6 +170,7 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
return (EINVAL);
ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
ent->value = value;
+ ent->mac_addr = mac_addr;
/* Set 'total' structure length */
KEY_LEN(ent->addr) = KEY_LEN_INET;
KEY_LEN(ent->mask) = KEY_LEN_INET;
@@ -182,6 +192,7 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
return (EINVAL);
xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
xent->value = value;
+ xent->mac_addr = mac_addr;
/* Set 'total' structure length */
KEY_LEN(xent->a.addr6) = KEY_LEN_INET6;
KEY_LEN(xent->m.mask6) = KEY_LEN_INET6;
@@ -281,6 +292,28 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
IPFW_WUNLOCK(ch);
if (rn == NULL) {
+ if (type == IPFW_TABLE_CIDR) {
+ /* Just update if any new value needed */
+ if (plen == sizeof(in_addr_t)) {
+ ent = (struct table_entry *)(rnh->rnh_matchaddr(addr_ptr, rnh));
+ if (ent != NULL) {
+ if (ent->mac_addr) {
+ if (!bcmp(&mac_addr, &ent->mac_addr, ETHER_ADDR_LEN))
+ ent->value = value;
+ } else
+ ent->value = value;
+ }
+ } else {
+ xent = (struct table_xentry *)(rnh->rnh_matchaddr(addr_ptr, rnh));
+ if (xent != NULL) {
+ if (xent->mac_addr) {
+ if (!bcmp(&mac_addr, &xent->mac_addr, ETHER_ADDR_LEN))
+ xent->value = value;
+ } else
+ xent->value = value;
+ }
+ }
+ }
free(ent_ptr, M_IPFW_TBL);
return (EEXIST);
}
@@ -530,31 +563,194 @@ ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables)
return (0);
}
-int
+void *
ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
- uint32_t *val)
+ uint32_t *val, struct ether_addr *ea)
{
struct radix_node_head *rnh;
struct table_entry *ent;
struct sockaddr_in sa;
if (tbl >= V_fw_tables_max)
- return (0);
+ return (NULL);
if ((rnh = ch->tables[tbl]) == NULL)
- return (0);
+ return (NULL);
KEY_LEN(sa) = KEY_LEN_INET;
sa.sin_addr.s_addr = addr;
ent = (struct table_entry *)(rnh->rnh_matchaddr(&sa, rnh));
if (ent != NULL) {
- *val = ent->value;
- return (1);
+ if (ea && ent->mac_addr) {
+ if (bcmp((u_char *)&ent->mac_addr, ea->octet, ETHER_ADDR_LEN) != 0)
+ ent = NULL;
+ }
+ if (ent != NULL) {
+ *val = ent->value;
+ return (ent);
+ }
}
- return (0);
+ return (NULL);
+}
+
+void
+ipfw_count_table_entry_stats(void *arg, int pktlen)
+{
+ struct table_entry *xent = arg;
+
+ xent->packets++;
+ xent->bytes += pktlen;
+ xent->timestamp = time_uptime;
+}
+
+void
+ipfw_count_table_xentry_stats(void *arg, int pktlen)
+{
+ ipfw_table_xentry *xent= arg;
+
+ xent->packets++;
+ xent->bytes += pktlen;
+ xent->timestamp = time_uptime;
}
int
+ipfw_zero_table_xentry_stats(struct ip_fw_chain *ch, ipfw_table_xentry *arg)
+{
+ struct radix_node_head *rnh;
+ struct table_xentry *xent;
+ struct sockaddr_in6 sa6;
+ struct xaddr_iface iface;
+
+ if (arg->tbl >= V_fw_tables_max)
+ return (EINVAL);
+ if (ch->tables[arg->tbl] != NULL)
+ rnh = ch->tables[arg->tbl];
+ else if (ch->xtables[arg->tbl] != NULL)
+ rnh = ch->xtables[arg->tbl];
+ else
+ return (EINVAL);
+
+ switch (arg->type) {
+ case IPFW_TABLE_CIDR:
+ if (ch->tables[arg->tbl] != NULL) {
+ /* XXX: Maybe better by FreeBSD 11!! */
+ struct sockaddr_in sa;
+ struct table_entry *ent;
+
+ KEY_LEN(sa) = KEY_LEN_INET;
+ sa.sin_addr.s_addr = *((in_addr_t *)&arg->k.addr6);
+ ent = (struct table_entry *)(rnh->rnh_matchaddr(&sa, rnh));
+ if (ent == NULL)
+ return (EINVAL);
+
+ arg->bytes = 0;
+ arg->packets = 0;
+ arg->value = ent->value;
+ arg->timestamp = time_uptime;
+
+ return (0);
+ } else {
+ KEY_LEN(sa6) = KEY_LEN_INET6;
+ memcpy(&sa6.sin6_addr, &arg->k.addr6, sizeof(struct in6_addr));
+ xent = (struct table_xentry *)(rnh->rnh_matchaddr(&sa6, rnh));
+ }
+ break;
+
+ case IPFW_TABLE_INTERFACE:
+ KEY_LEN(iface) = KEY_LEN_IFACE +
+ strlcpy(iface.ifname, arg->k.iface, IF_NAMESIZE) + 1;
+ /* Assume direct match */
+ /* FIXME: Add interface pattern matching */
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&iface, NULL, rnh));
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ if (xent != NULL) {
+ xent->bytes = 0;
+ xent->packets = 0;
+ xent->timestamp = time_uptime;
+
+ return (0);
+ }
+ return (EINVAL);
+}
+
+int
+ipfw_lookup_table_xentry(struct ip_fw_chain *ch, ipfw_table_xentry *arg)
+{
+ struct radix_node_head *rnh;
+ struct table_xentry *xent;
+
+ if (arg->tbl >= V_fw_tables_max)
+ return (EINVAL);
+ if (ch->tables[arg->tbl] != NULL)
+ rnh = ch->tables[arg->tbl];
+ else if (ch->xtables[arg->tbl] != NULL)
+ rnh = ch->xtables[arg->tbl];
+ else
+ return (EINVAL);
+
+ switch (arg->type) {
+ case IPFW_TABLE_CIDR:
+ {
+ if (ch->tables[arg->tbl] != NULL) {
+ /* XXX: Maybe better by FreeBSD 11!! */
+ struct sockaddr_in sa;
+ struct table_entry *ent;
+
+ KEY_LEN(sa) = KEY_LEN_INET;
+ sa.sin_addr.s_addr = *((in_addr_t *)&arg->k.addr6);
+ ent = (struct table_entry *)(rnh->rnh_matchaddr(&sa, rnh));
+ if (ent == NULL)
+ return (EINVAL);
+
+ arg->bytes = ent->bytes;
+ arg->packets = ent->packets;
+ arg->value = ent->value;
+ arg->timestamp = ent->timestamp;
+ arg->mac_addr = ent->mac_addr;
+ return (0);
+ } else {
+ struct sockaddr_in6 sa6;
+ KEY_LEN(sa6) = KEY_LEN_INET6;
+ memcpy(&sa6.sin6_addr, &arg->k.addr6, sizeof(struct in6_addr));
+ xent = (struct table_xentry *)(rnh->rnh_matchaddr(&sa6, rnh));
+ }
+ }
+ break;
+
+ case IPFW_TABLE_INTERFACE:
+ {
+ struct xaddr_iface iface;
+
+ KEY_LEN(iface) = KEY_LEN_IFACE +
+ strlcpy(iface.ifname, arg->k.iface, IF_NAMESIZE) + 1;
+ /* Assume direct match */
+ /* FIXME: Add interface pattern matching */
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&iface, NULL, rnh));
+ }
+ break;
+
+ default:
+ return (0);
+ }
+
+ if (xent != NULL) {
+ arg->bytes = xent->bytes;
+ arg->packets = xent->packets;
+ arg->value = xent->value;
+ arg->timestamp = xent->timestamp;
+ arg->mac_addr = xent->mac_addr;
+
+ return (0);
+ }
+ return (EINVAL);
+}
+
+void *
ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
- uint32_t *val, int type)
+ uint32_t *val, int type, struct ether_addr *ea)
{
struct radix_node_head *rnh;
struct table_xentry *xent;
@@ -562,15 +758,21 @@ ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
struct xaddr_iface iface;
if (tbl >= V_fw_tables_max)
- return (0);
+ return (NULL);
if ((rnh = ch->xtables[tbl]) == NULL)
- return (0);
+ return (NULL);
switch (type) {
case IPFW_TABLE_CIDR:
KEY_LEN(sa6) = KEY_LEN_INET6;
memcpy(&sa6.sin6_addr, paddr, sizeof(struct in6_addr));
xent = (struct table_xentry *)(rnh->rnh_matchaddr(&sa6, rnh));
+ if (xent != NULL) {
+ if (ea && xent->mac_addr) {
+ if (bcmp((u_char *)&xent->mac_addr, ea->octet, ETHER_ADDR_LEN) != 0)
+ xent = NULL;
+ }
+ }
break;
case IPFW_TABLE_INTERFACE:
@@ -582,14 +784,14 @@ ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
break;
default:
- return (0);
+ return (NULL);
}
if (xent != NULL) {
*val = xent->value;
- return (1);
+ return (xent);
}
- return (0);
+ return (NULL);
}
static int
@@ -696,8 +898,13 @@ dump_table_xentry_base(struct radix_node *rn, void *arg)
else
xent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr));
/* Save IPv4 address as deprecated IPv6 compatible */
- xent->k.addr6.s6_addr32[3] = n->addr.sin_addr.s_addr;
+ xent->k.addr6.s6_addr32[0] = n->addr.sin_addr.s_addr;
+ xent->flags = IPFW_TCF_INET;
xent->value = n->value;
+ xent->bytes = n->bytes;
+ xent->packets = n->packets;
+ xent->timestamp = n->timestamp;
+ xent->mac_addr = n->mac_addr;
tbl->cnt++;
return (0);
}
@@ -741,6 +948,10 @@ dump_table_xentry_extended(struct radix_node *rn, void *arg)
}
xent->value = n->value;
+ xent->bytes = n->bytes;
+ xent->packets = n->packets;
+ xent->timestamp = n->timestamp;
+ xent->mac_addr = n->mac_addr;
tbl->cnt++;
return (0);
}
OpenPOWER on IntegriCloud