summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormlaier <mlaier@FreeBSD.org>2004-06-16 23:39:33 +0000
committermlaier <mlaier@FreeBSD.org>2004-06-16 23:39:33 +0000
commitf60cf9b58b8456f06fbe5d6619f1b317c6f8020e (patch)
treef5ef8788feb494dffb0267e964fb6ac0d1e2cbfa
parenta5725614a74c5e7e57dee0cda1a81ab91810a418 (diff)
downloadFreeBSD-src-f60cf9b58b8456f06fbe5d6619f1b317c6f8020e.zip
FreeBSD-src-f60cf9b58b8456f06fbe5d6619f1b317c6f8020e.tar.gz
Commit userland part of pf version 3.5 from OpenBSD (OPENBSD_3_5_BASE).
-rw-r--r--contrib/pf/authpf/authpf.c138
-rw-r--r--contrib/pf/ftp-proxy/ftp-proxy.845
-rw-r--r--contrib/pf/ftp-proxy/ftp-proxy.c19
-rw-r--r--contrib/pf/man/pf.4228
-rw-r--r--contrib/pf/man/pflog.415
-rw-r--r--contrib/pf/man/pfsync.4166
-rw-r--r--contrib/pf/pfctl/parse.y966
-rw-r--r--contrib/pf/pfctl/pf_print_state.c9
-rw-r--r--contrib/pf/pfctl/pfctl.c562
-rw-r--r--contrib/pf/pfctl/pfctl.h17
-rw-r--r--contrib/pf/pfctl/pfctl_altq.c44
-rw-r--r--contrib/pf/pfctl/pfctl_parser.c404
-rw-r--r--contrib/pf/pfctl/pfctl_parser.h33
-rw-r--r--contrib/pf/pfctl/pfctl_qstats.c33
-rw-r--r--contrib/pf/pfctl/pfctl_table.c122
-rw-r--r--contrib/pf/pflogd/pflogd.c466
-rw-r--r--contrib/pf/pflogd/privsep.c16
-rw-r--r--sbin/pfctl/Makefile5
-rw-r--r--sbin/pflogd/Makefile2
-rw-r--r--usr.bin/kdump/mkioctls1
20 files changed, 2449 insertions, 842 deletions
diff --git a/contrib/pf/authpf/authpf.c b/contrib/pf/authpf/authpf.c
index c14bcf7..097e8f0 100644
--- a/contrib/pf/authpf/authpf.c
+++ b/contrib/pf/authpf/authpf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: authpf.c,v 1.68 2003/08/21 19:13:23 frantzen Exp $ */
+/* $OpenBSD: authpf.c,v 1.75 2004/01/29 01:55:10 deraadt Exp $ */
/*
* Copyright (C) 1998 - 2002 Bob Beck (beck@openbsd.org).
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <pfctl_parser.h>
+#include <pfctl.h>
#include "pathnames.h"
@@ -98,12 +99,6 @@ main(int argc, char *argv[])
char *cp;
uid_t uid;
- if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld",
- (long)getpid())) < 0 || n >= sizeof(rulesetname)) {
- syslog(LOG_ERR, "pid too large for ruleset name");
- exit(1);
- }
-
config = fopen(PATH_CONFFILE, "r");
if ((cp = getenv("SSH_TTY")) == NULL) {
@@ -131,7 +126,6 @@ main(int argc, char *argv[])
"cannot determine IP from SSH_CLIENT %s", ipsrc);
exit(1);
}
-
/* open the pf device */
dev = open(PATH_DEVFILE, O_RDWR);
if (dev == -1) {
@@ -160,6 +154,18 @@ main(int argc, char *argv[])
goto die;
}
+ if ((n = snprintf(rulesetname, sizeof(rulesetname), "%s(%ld)",
+ luser, (long)getpid())) < 0 || n >= sizeof(rulesetname)) {
+ syslog(LOG_INFO, "%s(%ld) too large, ruleset name will be %ld",
+ luser, (long)getpid(), (long)getpid());
+ if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld",
+ (long)getpid())) < 0 || n >= sizeof(rulesetname)) {
+ syslog(LOG_ERR, "pid too large for ruleset name");
+ goto die;
+ }
+ }
+
+
/* Make our entry in /var/authpf as /var/authpf/ipaddr */
n = snprintf(pidfile, sizeof(pidfile), "%s/%s", PATH_PIDFILE, ipsrc);
if (n < 0 || (u_int)n >= sizeof(pidfile)) {
@@ -242,15 +248,22 @@ main(int argc, char *argv[])
seteuid(getuid());
setuid(getuid());
- if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser))
+ openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON);
+
+ if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) {
+ syslog(LOG_INFO, "user %s prohibited", luser);
do_death(0);
+ }
- openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON);
- if (config == NULL || read_config(config))
+ if (config == NULL || read_config(config)) {
+ syslog(LOG_INFO, "bad or nonexistent %s", PATH_CONFFILE);
do_death(0);
+ }
- if (remove_stale_rulesets())
+ if (remove_stale_rulesets()) {
+ syslog(LOG_INFO, "error removing stale rulesets");
do_death(0);
+ }
/* We appear to be making headway, so actually mark our pid */
rewind(pidfp);
@@ -260,7 +273,7 @@ main(int argc, char *argv[])
if (change_filter(1, luser, ipsrc) == -1) {
printf("Unable to modify filters\r\n");
- do_death(1);
+ do_death(0);
}
signal(SIGTERM, need_death);
@@ -545,15 +558,20 @@ remove_stale_rulesets(void)
mnr = prs.nr;
nr = 0;
while (nr < mnr) {
- char *s;
+ char *s, *t;
pid_t pid;
prs.nr = nr;
if (ioctl(dev, DIOCGETRULESET, &prs))
return (1);
errno = 0;
- pid = strtoul(prs.name, &s, 10);
- if (!prs.name[0] || errno || *s)
+ if ((t = strchr(prs.name, '(')) == NULL)
+ t = prs.name;
+ else
+ t++;
+ pid = strtoul(t, &s, 10);
+ if (!prs.name[0] || errno ||
+ (*s && (t == prs.name || *s != ')')))
return (1);
if (kill(pid, 0) && errno != EPERM) {
int i;
@@ -585,14 +603,11 @@ change_filter(int add, const char *luser, const char *ipsrc)
{
char fn[MAXPATHLEN];
FILE *f = NULL;
- const int action[PF_RULESET_MAX] = { PF_SCRUB,
- PF_PASS, PF_NAT, PF_BINAT, PF_RDR };
struct pfctl pf;
- struct pfioc_rule pr[PF_RULESET_MAX];
+ struct pfr_buffer t;
int i;
- if (luser == NULL || !luser[0] || strlen(luser) >=
- PF_RULESET_NAME_SIZE || ipsrc == NULL || !ipsrc[0]) {
+ if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) {
syslog(LOG_ERR, "invalid luser/ipsrc");
goto error;
}
@@ -624,18 +639,18 @@ change_filter(int add, const char *luser, const char *ipsrc)
syslog(LOG_ERR, "unable to load kernel's OS fingerprints");
goto error;
}
-
+ bzero(&t, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
memset(&pf, 0, sizeof(pf));
for (i = 0; i < PF_RULESET_MAX; ++i) {
- memset(&pr[i], 0, sizeof(pr[i]));
- pr[i].rule.action = action[i];
- strlcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor));
- strlcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset));
- if (ioctl(dev, DIOCBEGINRULES, &pr[i])) {
- syslog(LOG_ERR, "DIOCBEGINRULES %m");
+ if (pfctl_add_trans(&t, i, anchorname, rulesetname)) {
+ syslog(LOG_ERR, "pfctl_add_trans %m");
goto error;
}
- pf.prule[i] = &pr[i];
+ }
+ if (pfctl_trans(dev, &t, DIOCXBEGIN, 0)) {
+ syslog(LOG_ERR, "DIOCXBEGIN (%s) %m", add?"add":"remove");
+ goto error;
}
if (add) {
@@ -646,6 +661,10 @@ change_filter(int add, const char *luser, const char *ipsrc)
}
pf.dev = dev;
+ pf.trans = &t;
+ pf.anchor = anchorname;
+ pf.ruleset = rulesetname;
+
infile = fn;
if (parse_rules(f, &pf) < 0) {
syslog(LOG_ERR, "syntax error in rule file: "
@@ -658,16 +677,10 @@ change_filter(int add, const char *luser, const char *ipsrc)
f = NULL;
}
- for (i = 0; i < PF_RULESET_MAX; ++i)
- /*
- * ignore EINVAL on removal, it means the anchor was
- * already automatically removed by the kernel.
- */
- if (ioctl(dev, DIOCCOMMITRULES, &pr[i]) &&
- (add || errno != EINVAL)) {
- syslog(LOG_ERR, "DIOCCOMMITRULES %m");
- goto error;
- }
+ if (pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) {
+ syslog(LOG_ERR, "DIOCXCOMMIT (%s) %m", add?"add":"remove");
+ goto error;
+ }
if (add) {
gettimeofday(&Tstart, NULL);
@@ -682,6 +695,8 @@ change_filter(int add, const char *luser, const char *ipsrc)
error:
if (f != NULL)
fclose(f);
+ if (pfctl_trans(dev, &t, DIOCXROLLBACK, 0))
+ syslog(LOG_ERR, "DIOCXROLLBACK (%s) %m", add?"add":"remove");
infile = NULL;
return (-1);
@@ -761,37 +776,44 @@ do_death(int active)
int
pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
{
- struct pfioc_rule *pr;
+ u_int8_t rs_num;
+ struct pfioc_rule pr;
switch (r->action) {
case PF_PASS:
case PF_DROP:
- pr = pf->prule[PF_RULESET_FILTER];
+ rs_num = PF_RULESET_FILTER;
break;
case PF_SCRUB:
- pr = pf->prule[PF_RULESET_SCRUB];
+ rs_num = PF_RULESET_SCRUB;
break;
case PF_NAT:
case PF_NONAT:
- pr = pf->prule[PF_RULESET_NAT];
+ rs_num = PF_RULESET_NAT;
break;
case PF_RDR:
case PF_NORDR:
- pr = pf->prule[PF_RULESET_RDR];
+ rs_num = PF_RULESET_RDR;
break;
case PF_BINAT:
case PF_NOBINAT:
- pr = pf->prule[PF_RULESET_BINAT];
+ rs_num = PF_RULESET_BINAT;
break;
default:
syslog(LOG_ERR, "invalid rule action %d", r->action);
return (1);
}
+
+ bzero(&pr, sizeof(pr));
+ strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor));
+ strlcpy(pr.ruleset, pf->ruleset, sizeof(pr.ruleset));
if (pfctl_add_pool(pf, &r->rpool, r->af))
return (1);
- pr->pool_ticket = pf->paddr.ticket;
- memcpy(&pr->rule, r, sizeof(pr->rule));
- if (ioctl(pf->dev, DIOCADDRULE, pr)) {
+ pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor,
+ pf->ruleset);
+ pr.pool_ticket = pf->paddr.ticket;
+ memcpy(&pr.rule, r, sizeof(pr.rule));
+ if (ioctl(pf->dev, DIOCADDRULE, &pr)) {
syslog(LOG_ERR, "DIOCADDRULE %m");
return (1);
}
@@ -852,6 +874,13 @@ pfctl_set_logif(struct pfctl *pf, char *ifname)
}
int
+pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
+{
+ fprintf(stderr, "set hostid not supported in authpf\n");
+ return (1);
+}
+
+int
pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
{
fprintf(stderr, "set timeout not supported in authpf\n");
@@ -866,6 +895,13 @@ pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
}
int
+pfctl_set_debug(struct pfctl *pf, char *d)
+{
+ fprintf(stderr, "set debug not supported in authpf\n");
+ return (1);
+}
+
+int
pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
const char *ruleset, struct pfr_buffer *ab, u_int32_t ticket)
{
@@ -875,10 +911,14 @@ pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
int
pfctl_rules(int dev, char *filename, int opts, char *anchorname,
- char *rulesetname)
+ char *rulesetname, struct pfr_buffer *t)
{
/* never called, no anchors inside anchors, but we need the stub */
fprintf(stderr, "load anchor not supported from authpf\n");
return (1);
}
+void
+pfctl_print_title(char *title)
+{
+}
diff --git a/contrib/pf/ftp-proxy/ftp-proxy.8 b/contrib/pf/ftp-proxy/ftp-proxy.8
index 3fb0c4d..db043cd 100644
--- a/contrib/pf/ftp-proxy/ftp-proxy.8
+++ b/contrib/pf/ftp-proxy/ftp-proxy.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ftp-proxy.8,v 1.37 2003/09/05 12:27:47 jmc Exp $
+.\" $OpenBSD: ftp-proxy.8,v 1.40 2004/03/16 08:50:07 jmc Exp $
.\"
.\" Copyright (c) 1996-2001
.\" Obtuse Systems Corporation, All rights reserved.
@@ -38,10 +38,11 @@
.Sh SYNOPSIS
.Nm ftp-proxy
.Op Fl AnrVw
+.Op Fl a Ar address
.Op Fl D Ar debuglevel
.Op Fl g Ar group
-.Op Fl m Ar minport
.Op Fl M Ar maxport
+.Op Fl m Ar minport
.Op Fl t Ar timeout
.Op Fl u Ar user
.Sh DESCRIPTION
@@ -67,6 +68,26 @@ or
.Qq anonymous
only.
Any attempt to log in as another user will be blocked by the proxy.
+.It Fl a Ar address
+Specify the local IP address to use in
+.Xr bind 2
+as the source for connections made by
+.Nm ftp-proxy
+when connecting to destination FTP servers.
+This may be necessary if the interface address of
+your default route is not reachable from the destinations
+.Nm
+is attempting connections to, or this address is different from the one
+connections are being NATed to.
+In the usual case this means that
+.Ar address
+should be a publicly visible IP address assigned to one of
+the interfaces on the machine running
+.Nm
+and should be the same address to which you are translating traffic
+if you are using the
+.Fl n
+option.
.It Fl D Ar debuglevel
Specify a debug level, where the proxy emits verbose debug output
into
@@ -82,14 +103,6 @@ lookups which require root.
By default,
.Nm
uses the default group of the user it drops privilege to.
-.It Fl m Ar minport
-Specify the lower end of the port range the proxy will use for all
-data connections it establishes.
-The default is
-.Dv IPPORT_HIFIRSTAUTO
-defined in
-.Aq Pa netinet/in.h
-as 49152.
.It Fl M Ar maxport
Specify the upper end of the port range the proxy will use for the
data connections it establishes.
@@ -98,6 +111,14 @@ The default is
defined in
.Aq Pa netinet/in.h
as 65535.
+.It Fl m Ar minport
+Specify the lower end of the port range the proxy will use for all
+data connections it establishes.
+The default is
+.Dv IPPORT_HIFIRSTAUTO
+defined in
+.Aq Pa netinet/in.h
+as 49152.
.It Fl n
Activate network address translation
.Pq NAT
@@ -175,8 +196,8 @@ A typical way to do this would be to use a
.Xr pf.conf 5
rule such as
.Bd -literal -offset 2n
-int_if = xl0
-rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
+int_if = \&"xl0\&"
+rdr pass on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
.Ed
.Pp
.Xr inetd 8
diff --git a/contrib/pf/ftp-proxy/ftp-proxy.c b/contrib/pf/ftp-proxy/ftp-proxy.c
index 87e9a65..344ca27 100644
--- a/contrib/pf/ftp-proxy/ftp-proxy.c
+++ b/contrib/pf/ftp-proxy/ftp-proxy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ftp-proxy.c,v 1.33 2003/08/22 21:50:34 david Exp $ */
+/* $OpenBSD: ftp-proxy.c,v 1.35 2004/03/14 21:51:44 dhartmei Exp $ */
/*
* Copyright (c) 1996-2001
@@ -151,6 +151,7 @@ char *Group;
extern int Debug_Level;
extern int Use_Rdns;
+extern in_addr_t Bind_Addr;
extern char *__progname;
typedef enum {
@@ -174,9 +175,8 @@ static void
usage(void)
{
syslog(LOG_NOTICE,
- "usage: %s [-AnrVw] [-D debuglevel] [-g group] %s %s",
- __progname, "[-m minport] [-M maxport] [-t timeout]",
- "[-u user]");
+ "usage: %s [-AnrVw] [-a address] [-D debuglevel [-g group]"
+ " [-M maxport] [-m minport] [-t timeout] [-u user]", __progname);
exit(EX_USAGE);
}
@@ -976,9 +976,18 @@ main(int argc, char *argv[])
int use_tcpwrapper = 0;
#endif /* LIBWRAP */
- while ((ch = getopt(argc, argv, "D:g:m:M:t:u:AnVwr")) != -1) {
+ while ((ch = getopt(argc, argv, "a:D:g:m:M:t:u:AnVwr")) != -1) {
char *p;
switch (ch) {
+ case 'a':
+ if (!*optarg)
+ usage();
+ if ((Bind_Addr = inet_addr(optarg)) == INADDR_NONE) {
+ syslog(LOG_NOTICE,
+ "%s: invalid address", optarg);
+ usage();
+ }
+ break;
case 'A':
AnonFtpOnly = 1; /* restrict to anon usernames only */
break;
diff --git a/contrib/pf/man/pf.4 b/contrib/pf/man/pf.4
index 0717013..053da27 100644
--- a/contrib/pf/man/pf.4
+++ b/contrib/pf/man/pf.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pf.4,v 1.37 2003/08/28 09:41:22 jmc Exp $
+.\" $OpenBSD: pf.4,v 1.48 2004/03/27 17:15:30 henning Exp $
.\"
.\" Copyright (C) 2001, Kjell Wooding. All rights reserved.
.\"
@@ -75,11 +75,7 @@ Stops the packet filter.
Starts the ALTQ bandwidth control system.
.It Dv DIOCSTOPALTQ
Stops the ALTQ bandwidth control system.
-.It Dv DIOCBEGINADDRS Fa "u_int32_t"
-Clears the buffer address pool
-and returns a ticket for subsequent DIOCADDADDR, DIOCADDRULE and
-DIOCCHANGERULE calls.
-.It Dv DIOCADDADDR Fa "struct pfioc_pooladdr"
+.It Dv DIOCBEGINADDRS Fa "struct pfioc_pooladdr"
.Bd -literal
struct pfioc_pooladdr {
u_int32_t action;
@@ -95,16 +91,17 @@ struct pfioc_pooladdr {
};
.Ed
.Pp
+Clears the buffer address pool
+and returns a
+.Va ticket
+for subsequent DIOCADDADDR, DIOCADDRULE and DIOCCHANGERULE calls.
+.It Dv DIOCADDADDR Fa "struct pfioc_pooladdr"
+.Pp
Adds pool address
.Va addr
to the buffer address pool to be used in the following
DIOCADDRULE or DIOCCHANGERULE call.
All other members of the structure are ignored.
-.It Dv DIOCBEGINRULES Fa "u_int32_t"
-Clears the inactive ruleset for the type of rule indicated by
-.Va rule.action
-and returns a ticket for subsequent
-DIOCADDRULE and DIOCCOMMITRULES calls.
.It Dv DIOCADDRULE Fa "struct pfioc_rule"
.Bd -literal
struct pfioc_rule {
@@ -123,7 +120,7 @@ Adds
at the end of the inactive ruleset.
Requires
.Va ticket
-obtained through preceding DIOCBEGINRULES call, and
+obtained through preceding DIOCXBEGIN call, and
.Va pool_ticket
obtained through DIOCBEGINADDRS call.
DIOCADDADDR must also be called if any pool addresses are required.
@@ -136,26 +133,16 @@ names indicate the anchor and ruleset in which to append the rule.
and
.Va action
are ignored.
-.It Dv DIOCCOMMITRULES Fa "u_int32_t"
-Switch inactive to active filter ruleset.
-Requires
-.Va ticket .
-.It Dv DIOCBEGINALTQS Fa "u_int32_t"
-Clears the inactive list of queues and returns a ticket for subsequent
-DIOCADDALTQ and DIOCCOMMITALTQS calls.
.It Dv DIOCADDALTQ Fa "struct pfioc_altq"
Adds
.Bd -literal
struct pfioc_altq {
+ u_int32_t action;
u_int32_t ticket;
u_int32_t nr;
struct pf_altq altq;
};
.Ed
-.It Dv DIOCCOMMITALTQS Fa "u_int32_t"
-Switch inactive to active list of queues.
-Requires
-.Va ticket .
.It Dv DIOCGETRULES Fa "struct pfioc_rule"
Returns
.Va ticket
@@ -227,8 +214,6 @@ of length
.Va nbytes
for the queue specified by
.Va nr .
-.It Dv DIOCCLRSTATES
-Clears the state table.
.It Dv DIOCADDSTATE Fa "struct pfioc_state"
Adds a state entry.
.It Dv DIOCGETSTATE Fa "struct pfioc_state"
@@ -249,8 +234,16 @@ struct pfioc_state_kill {
int psk_proto;
struct pf_rule_addr psk_src;
struct pf_rule_addr psk_dst;
+ char psk_ifname[IFNAMSIZ];
};
.Ed
+.It Dv DIOCCLRSTATES Fa "struct pfioc_state_kill"
+Clears all states.
+It works like
+.Dv DIOCKILLSTATES ,
+but ignores the psk_af, psk_proto, psk_src and psk_dst fields of the
+.Fa pfioc_state_kill
+structure.
.It Dv DIOCSETSTATUSIF Fa "struct pfioc_if"
.Bd -literal
struct pfioc_if {
@@ -262,14 +255,19 @@ Specifies the interface for which statistics are accumulated.
.It Dv DIOCGETSTATUS Fa "struct pf_status"
.Bd -literal
struct pf_status {
- u_int64_t counters[PFRES_MAX];
- u_int64_t fcounters[FCNT_MAX];
- u_int64_t pcounters[2][2][3];
- u_int64_t bcounters[2][2];
- u_int32_t running;
- u_int32_t states;
- u_int32_t since;
- u_int32_t debug;
+ u_int64_t counters[PFRES_MAX];
+ u_int64_t fcounters[FCNT_MAX];
+ u_int64_t scounters[SCNT_MAX];
+ u_int64_t pcounters[2][2][3];
+ u_int64_t bcounters[2][2];
+ u_int64_t stateid;
+ u_int32_t running;
+ u_int32_t states;
+ u_int32_t src_nodes;
+ u_int32_t since;
+ u_int32_t debug;
+ u_int32_t hostid;
+ char ifname[IFNAMSIZ];
};
.Ed
.Pp
@@ -288,7 +286,7 @@ struct pfioc_natlook {
u_int16_t dport;
u_int16_t rsport;
u_int16_t rdport;
- u_int8_t af;
+ sa_family_t af;
u_int8_t proto;
u_int8_t direction;
};
@@ -528,19 +526,6 @@ or deleted by the kernel.
Yes, tables can be deleted if one removes the
.Va persist
flag of an unreferenced table.
-.It Dv DIOCRINABEGIN Fa "struct pfioc_table"
-Starts a transaction with the inactive set of tables.
-Cleans up any leftover from a previously aborted transaction, and returns
-a new ticket.
-On exit, pfrio_ndel contains the number of leftover table deleted, and
-pfrio_ticket contains a valid ticket to use for the following two IOCTLs.
-.It Dv DIOCRINACOMMIT Fa "struct pfioc_table"
-Commit the inactive set of tables into the active set.
-While copying the addresses, do a best effort to keep statistics for
-addresses present before and after the commit.
-On entry, io->pfrio_ticket takes a valid ticket.
-On exit, io->pfrio_nadd and io->pfrio_nchange contain the number of tables
-added and altered by the commit operation.
.It Dv DIOCRINADEFINE Fa "struct pfioc_table"
Defines a table in the inactive set.
On entry, pfrio_table contains the table id and pfrio_buffer[pfrio_size]
@@ -549,6 +534,46 @@ A valid ticket must also be supplied to pfrio_ticket.
On exit, pfrio_nadd contains 0 if the table was already defined in the
inactive list, or 1 if a new table has been created.
pfrio_naddr contains the number of addresses effectively put in the table.
+.It Dv DIOCXBEGIN Fa "struct pfioc_trans"
+.Bd -literal
+#define PF_RULESET_ALTQ (PF_RULESET_MAX)
+#define PF_RULESET_TABLE (PF_RULESET_MAX+1)
+struct pfioc_trans {
+ int size; /* number of elements */
+ int esize; /* size of each element in bytes */
+ struct pfioc_trans_e {
+ int rs_num;
+ char anchor[PF_ANCHOR_NAME_SIZE];
+ char ruleset[PF_RULESET_NAME_SIZE];
+ u_int32_t ticket;
+ } *array;
+};
+.Ed
+.Pp
+Clears all the inactive rulesets specified in the
+.Fa "struct pfioc_trans_e"
+array.
+For each ruleset, a ticket is returned for subsequent "add rule" IOCTLs,
+as well as for the
+.Dv DIOCXCOMMIT
+and
+.Dv DIOCXROLLBACK
+calls.
+.It Dv DIOCXCOMMIT Fa "struct pfioc_trans"
+Atomically switch a vector of inactive rulesets to the active rulesets.
+Implemented as a standard 2-phase commit, which will either fail for all
+rulesets or completely succeed.
+All tickets need to be valid.
+Returns
+.Dv EBUSY
+if a concurrent process is trying to update some of the same rulesets
+concurrently.
+.It Dv DIOCXROLLBACK Fa "struct pfioc_trans"
+Clean up the kernel by undoing all changes that have taken place on the
+inactive rulesets since the last
+.Dv DIOCXBEGIN .
+.Dv DIOCXROLLBACK
+will silently ignore rulesets for which the ticket is invalid.
.It Dv DIOCFPFLUSH
Flush the passive OS fingerprint table.
.It Dv DIOCFPADD Fa "struct pf_osfp_ioctl"
@@ -626,6 +651,115 @@ The rest of the structure members will come back filled.
Get the whole list by repeatedly incrementing the
.Va fp_getnum
number until the ioctl returns EBUSY.
+.It Dv DIOCGETSRCNODES Fa "struct pfioc_src_nodes"
+.Bd -literal
+struct pfioc_src_nodes {
+ int psn_len;
+ union {
+ caddr_t psu_buf;
+ struct pf_src_node *psu_src_nodes;
+ } psn_u;
+#define psn_buf psn_u.psu_buf
+#define psn_src_nodes psn_u.psu_src_nodes
+};
+.Ed
+.Pp
+Get the list of source nodes kept by the
+.Ar sticky-address
+and
+.Ar source-track
+options.
+The ioctl must be called once with
+.Va psn_len
+set to 0.
+If the ioctl returns without error,
+.Va psn_len
+will be set to the size of the buffer required to hold all the
+.Va pf_src_node
+structures held in the table.
+A buffer of this size should then be allocated, and a pointer to this buffer
+placed in
+.Va psn_buf .
+The ioctl must then be called again to fill this buffer with the actual
+source node data.
+After the ioctl call
+.Va psn_len
+will be set to the length of the buffer actually used.
+.It Dv DIOCCLRSRCNODES Fa "struct pfioc_table"
+Clear the tree of source tracking nodes.
+.It Dv DIOCIGETIFACES Fa "struct pfioc_iface"
+Gets the list of interfaces and interface drivers known to
+.Nm .
+All the IOCTLs that manipulate interfaces
+use the same structure described below:
+.Bd -literal
+struct pfioc_iface {
+ char pfiio_name[IFNAMSIZ];
+ void *pfiio_buffer;
+ int pfiio_esize;
+ int pfiio_size;
+ int pfiio_nzero;
+ int pfiio_flags;
+};
+
+#define PFI_FLAG_GROUP 0x0001 /* gets groups of interfaces */
+#define PFI_FLAG_INSTANCE 0x0002 /* gets single interfaces */
+#define PFI_FLAG_ALLMASK 0x0003
+.Ed
+.Pp
+If not empty,
+.Va pfiio_name
+can be used to restrict the search to a specific interface or driver.
+.Va pfiio_buffer[pfiio_size]
+is the user-supplied buffer for returning the data.
+On entry,
+.Va pfiio_size
+represents the number of
+.Va pfi_if
+entries that can fit into the buffer.
+The kernel will replace this value by the real number of entries it wants
+to return.
+.Va pfiio_esize
+should be set to sizeof(struct pfi_if).
+.Va pfiio_flags
+should be set to
+.Dv PFI_FLAG_GROUP , PFI_FLAG_INSTANCE ,
+or both to tell the kernel to return a group of interfaces
+(drivers, like "fxp"), real interface instances (like "fxp1") or both.
+The data is returned in the
+.Va pfi_if
+structure described below:
+.Bd -literal
+struct pfi_if {
+ char pfif_name[IFNAMSIZ];
+ u_int64_t pfif_packets[2][2][2];
+ u_int64_t pfif_bytes[2][2][2];
+ u_int64_t pfif_addcnt;
+ u_int64_t pfif_delcnt;
+ long pfif_tzero;
+ int pfif_states;
+ int pfif_rules;
+ int pfif_flags;
+};
+
+#define PFI_IFLAG_GROUP 0x0001 /* group of interfaces */
+#define PFI_IFLAG_INSTANCE 0x0002 /* single instance */
+#define PFI_IFLAG_CLONABLE 0x0010 /* clonable group */
+#define PFI_IFLAG_DYNAMIC 0x0020 /* dynamic group */
+#define PFI_IFLAG_ATTACHED 0x0040 /* interface attached */
+#define PFI_IFLAG_REFERENCED 0x0080 /* referenced by rules */
+.Ed
+.It Dv DIOCICLRISTATS Fa "struct pfioc_iface"
+Clear the statistics counters of one or more interfaces.
+.Va pfiio_name
+and
+.Va pfrio_flags
+can be used to select which interfaces need to be cleared.
+The filtering process is the same as for
+.Dv DIOCIGETIFACES .
+.Va pfiio_nzero
+will be set by the kernel to the number of interfaces and drivers
+that have been cleared.
.El
.Sh EXAMPLES
The following example demonstrates how to use the DIOCNATLOOK command
diff --git a/contrib/pf/man/pflog.4 b/contrib/pf/man/pflog.4
index c3f7173..6fc278e 100644
--- a/contrib/pf/man/pflog.4
+++ b/contrib/pf/man/pflog.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pflog.4,v 1.4 2003/09/22 04:53:15 jmc Exp $
+.\" $OpenBSD: pflog.4,v 1.7 2004/03/21 19:47:59 miod Exp $
.\"
.\" Copyright (c) 2001 Tobias Weingartner
.\" All rights reserved.
@@ -32,19 +32,20 @@
.Nm pflog
.Nd packet filter logging interface
.Sh SYNOPSIS
-.Sy device pflog
+.Cd "device pflog"
.Sh DESCRIPTION
The
.Nm pflog
-interface is the interface the packet filter,
-.Xr pf 4 ,
-copies all the packets to which it has been configured to log.
-In this way, all logged packets can easily be monitored in real
+interface is a pseudo-device which makes visible all packets logged by
+the packet filter,
+.Xr pf 4 .
+Logged packets can easily be monitored in real
time by invoking
.Xr tcpdump 8
on the
.Nm
-interface.
+interface, or stored to disk using
+.Xr pflogd 8 .
.Pp
Each packet retrieved on this interface has a header associated
with it of length
diff --git a/contrib/pf/man/pfsync.4 b/contrib/pf/man/pfsync.4
index 9b22f57..5375a52 100644
--- a/contrib/pf/man/pfsync.4
+++ b/contrib/pf/man/pfsync.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pfsync.4,v 1.6 2003/06/06 10:29:41 jmc Exp $
+.\" $OpenBSD: pfsync.4,v 1.16 2004/03/22 21:04:36 jmc Exp $
.\"
.\" Copyright (c) 2002 Michael Shalayeff
.\" All rights reserved.
@@ -32,19 +32,48 @@
.Nm pfsync
.Nd packet filter states table logging interface
.Sh SYNOPSIS
-.Sy device pfsync
+.Cd "device pfsync"
.Sh DESCRIPTION
The
-.Nm pfsync
-interface is the interface to the packet filter,
-.Xr pf 4 ,
-exposing all the changes to the state table.
-This allows for both debugging of rulesets and monitoring
-for changes in the table by invoking
+.Nm
+interface is a pseudo-device which exposes certain changes to the state
+table used by
+.Xr pf 4 .
+State changes can be viewed by invoking
.Xr tcpdump 8
on the
.Nm
interface.
+If configured with a physical synchronisation interface,
+.Nm
+will also send state changes out on that interface using IP multicast,
+and insert state changes received on that interface from other systems
+into the state table.
+.Pp
+By default, all local changes to the state table are exposed via
+.Nm .
+However, state changes from packets received by
+.Nm
+over the network are not rebroadcast.
+States created by a rule marked with the
+.Ar no-sync
+keyword are omitted from the
+.Nm
+interface (see
+.Xr pf.conf 5
+for details).
+.Pp
+The
+.Nm
+interface will attempt to collapse multiple updates of the same
+state into one message where possible.
+The maximum number of times this can be done before the update is sent out
+is controlled by the
+.Ar maxupd
+to ifconfig.
+(see
+.Xr ifconfig 8
+and the example below for more details)
.Pp
Each packet retrieved on this interface has a header associated
with it of length
@@ -63,16 +92,133 @@ struct pfsync_header {
u_int8_t count;
};
.Ed
+.Sh NETWORK SYNCHRONISATION
+States can be synchronised between two or more firewalls using this
+interface, by specifying a synchronisation interface using
+.Xr ifconfig 8 .
+For example, the following command sets fxp0 as the synchronisation
+interface.
+.Bd -literal -offset indent
+# ifconfig pfsync0 syncif fxp0
+.Ed
+.Pp
+State change messages are sent out on the synchronisation
+interface using IP multicast packets.
+The protocol is IP protocol 240, PFSYNC, and the multicast group
+used is 224.0.0.240.
+.Pp
+It is important that the synchronisation interface be on a trusted
+network as there is no authentication on the protocol and it would
+be trivial to spoof packets which create states, bypassing the pf ruleset.
+Ideally, this is a network dedicated to pfsync messages,
+i.e. a crossover cable between two firewalls.
+.Pp
+There is a one-to-one correspondence between packets seen by
+.Xr bpf 4
+on the
+.Nm
+interface, and packets sent out on the synchronisation interface, i.e.\&
+a packet with 4 state deletion messages on
+.Nm
+means that the same 4 deletions were sent out on the synchronisation
+interface.
+However, the actual packet contents may differ as the messages
+sent over the network are "compressed" where possible, containing
+only the necessary information.
.Sh EXAMPLES
+.Nm
+and
+.Xr carp 4
+can be used together to provide automatic failover of a pair of firewalls
+configured in parallel.
+One firewall handles all traffic \- if it dies or
+is shut down, the second firewall takes over automatically.
+.Pp
+Both firewalls in this example have three
+.Xr sis 4
+interfaces.
+sis0 is the external interface, on the 10.0.0.0/24 subnet, sis1 is the
+internal interface, on the 192.168.0.0/24 subnet, and sis2 is the
+.Nm
+interface, using the 192.168.254.0/24 subnet.
+A crossover cable connects the two firewalls via their sis2 interfaces.
+On all three interfaces, firewall A uses the .254 address, while firewall B
+uses .253.
+The interfaces are configured as follows (firewall A unless otherwise
+indicated):
+.Pp
+.Pa /etc/hostname.sis0 :
+.Bd -literal -offset indent
+inet 10.0.0.254 255.255.255.0 NONE
+.Ed
+.Pp
+.Pa /etc/hostname.sis1 :
+.Bd -literal -offset indent
+inet 192.168.0.254 255.255.255.0 NONE
+.Ed
+.Pp
+.Pa /etc/hostname.sis2 :
+.Bd -literal -offset indent
+inet 192.168.254.254 255.255.255.0 NONE
+.Ed
+.Pp
+.Pa /etc/hostname.carp0 :
+.Bd -literal -offset indent
+inet 10.0.0.1 255.255.255.0 10.0.0.255 vhid 1 pass foo
+.Ed
+.Pp
+.Pa /etc/hostname.carp1 :
+.Bd -literal -offset indent
+inet 192.168.0.1 255.255.255.0 192.168.0.255 vhid 2 pass bar
+.Ed
+.Pp
+.Pa /etc/hostname.pfsync0 :
+.Bd -literal -offset indent
+up syncif sis2
+.Ed
+.Pp
+.Xr pf 4
+must also be configured to allow
+.Nm
+and
+.Xr carp 4
+traffic through.
+The following should be added to the top of
+.Pa /etc/pf.conf :
+.Bd -literal -offset indent
+pass quick on { sis2 } proto pfsync
+pass on { sis0 sis1 } proto carp keep state
+.Ed
+.Pp
+If it is preferable that one firewall handle the traffic,
+the
+.Ar advskew
+on the backup firewall's
+.Xr carp 4
+interfaces should be set to something higher than
+the primary's.
+For example, if firewall B is the backup, its
+.Pa /etc/hostname.carp1
+would look like this:
+.Bd -literal -offset indent
+inet 192.168.0.1 255.255.255.0 192.168.0.255 vhid 2 pass bar \e
+ advskew 100
+.Ed
+.Pp
+The following must also be added to
+.Pa /etc/sysctl.conf :
.Bd -literal -offset indent
-# ifconfig pfsync0 up
-# tcpdump -s1500 -evtni pfsync0
+net.inet.carp.preempt=1
.Ed
.Sh SEE ALSO
+.Xr bpf 4 ,
.Xr inet 4 ,
.Xr inet6 4 ,
.Xr netintro 4 ,
.Xr pf 4 ,
+.Xr hostname.if 5 ,
+.Xr pf.conf 5 ,
+.Xr protocols 5 ,
.Xr ifconfig 8 ,
.Xr tcpdump 8
.Sh HISTORY
diff --git a/contrib/pf/pfctl/parse.y b/contrib/pf/pfctl/parse.y
index 5a53bac..2c82bcd 100644
--- a/contrib/pf/pfctl/parse.y
+++ b/contrib/pf/pfctl/parse.y
@@ -1,8 +1,10 @@
-/* $OpenBSD: parse.y,v 1.415 2003/09/01 15:07:40 henning Exp $ */
+/* $OpenBSD: parse.y,v 1.449 2004/03/20 23:20:20 david Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
+ * Copyright (c) 2001 Theo de Raadt. All rights reserved.
+ * Copyright (c) 2002,2003 Henning Brauer. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -75,6 +77,7 @@ static u_int16_t returnicmp6default =
(ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
static int blockpolicy = PFRULE_DROP;
static int require_order = 1;
+static int default_statelock;
enum {
PFCTL_STATE_NONE,
@@ -120,11 +123,20 @@ struct node_icmp {
struct node_icmp *tail;
};
-enum { PF_STATE_OPT_MAX=0, PF_STATE_OPT_TIMEOUT=1 };
+enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
+ PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_NODES,
+ PF_STATE_OPT_STATELOCK, PF_STATE_OPT_TIMEOUT };
+
+enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
+
struct node_state_opt {
int type;
union {
u_int32_t max_states;
+ u_int32_t max_src_states;
+ u_int32_t max_src_nodes;
+ u_int8_t src_track;
+ u_int32_t statelock;
struct {
int number;
u_int32_t seconds;
@@ -159,6 +171,7 @@ struct filter_opts {
#define FOM_ICMP 0x02
#define FOM_TOS 0x04
#define FOM_KEEP 0x08
+#define FOM_SRCTRACK 0x10
struct node_uid *uid;
struct node_gid *gid;
struct {
@@ -219,23 +232,37 @@ struct table_opts {
struct node_tinithead init_nodes;
} table_opts;
+struct pool_opts {
+ int marker;
+#define POM_TYPE 0x01
+#define POM_STICKYADDRESS 0x02
+ u_int8_t opts;
+ int type;
+ int staticport;
+ struct pf_poolhashkey *key;
+
+} pool_opts;
+
+
struct node_hfsc_opts hfsc_opts;
int yyerror(const char *, ...);
int disallow_table(struct node_host *, const char *);
+int disallow_alias(struct node_host *, const char *);
int rule_consistent(struct pf_rule *);
int filter_consistent(struct pf_rule *);
int nat_consistent(struct pf_rule *);
int rdr_consistent(struct pf_rule *);
int process_tabledef(char *, struct table_opts *);
int yyparse(void);
-void expand_label_str(char *, const char *, const char *);
-void expand_label_if(const char *, char *, const char *);
-void expand_label_addr(const char *, char *, u_int8_t, struct node_host *);
-void expand_label_port(const char *, char *, struct node_port *);
-void expand_label_proto(const char *, char *, u_int8_t);
-void expand_label_nr(const char *, char *);
-void expand_label(char *, const char *, u_int8_t, struct node_host *,
+void expand_label_str(char *, size_t, const char *, const char *);
+void expand_label_if(const char *, char *, size_t, const char *);
+void expand_label_addr(const char *, char *, size_t, u_int8_t,
+ struct node_host *);
+void expand_label_port(const char *, char *, size_t, struct node_port *);
+void expand_label_proto(const char *, char *, size_t, u_int8_t);
+void expand_label_nr(const char *, char *, size_t);
+void expand_label(char *, size_t, const char *, u_int8_t, struct node_host *,
struct node_port *, struct node_host *, struct node_port *,
u_int8_t);
void expand_rule(struct pf_rule *, struct node_if *, struct node_host *,
@@ -276,8 +303,9 @@ void remove_invalid_hosts(struct node_host **, sa_family_t *);
int invalid_redirect(struct node_host *, sa_family_t);
u_int16_t parseicmpspec(char *, sa_family_t);
-TAILQ_HEAD(loadanchorshead, loadanchors) loadanchorshead =
- TAILQ_HEAD_INITIALIZER(loadanchorshead);
+TAILQ_HEAD(loadanchorshead, loadanchors)
+ loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
+
struct loadanchors {
TAILQ_ENTRY(loadanchors) entries;
char *anchorname;
@@ -315,7 +343,6 @@ typedef struct {
struct peer src, dst;
struct node_os *src_os;
} fromto;
- struct pf_poolhashkey *hashkey;
struct {
struct node_host *host;
u_int8_t rt;
@@ -328,10 +355,6 @@ typedef struct {
struct range rport;
} *redirection;
struct {
- int type;
- struct pf_poolhashkey *key;
- } pooltype;
- struct {
int action;
struct node_state_opt *options;
} keep_state;
@@ -339,6 +362,7 @@ typedef struct {
u_int8_t log;
u_int8_t quick;
} logquick;
+ struct pf_poolhashkey *hashkey;
struct node_queue *queue;
struct node_queue_opt queue_options;
struct node_queue_bw queue_bwspec;
@@ -348,6 +372,7 @@ typedef struct {
struct queue_opts queue_opts;
struct scrub_opts scrub_opts;
struct table_opts table_opts;
+ struct pool_opts pool_opts;
struct node_hfsc_opts hfsc_opts;
} v;
int lineno;
@@ -365,6 +390,10 @@ typedef struct {
} \
} while (0)
+#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
+ (!((addr).iflags & PFI_AFLAG_NOALIAS) || \
+ !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))
+
%}
%token PASS BLOCK SCRUB RETURN IN OS OUT LOG LOGALL QUICK ON FROM TO FLAGS
@@ -374,24 +403,24 @@ typedef struct {
%token NOROUTE FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
-%token REQUIREORDER SYNPROXY FINGERPRINTS
+%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG HOSTID
%token ANTISPOOF FOR
%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT
%token ALTQ CBQ PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
%token QUEUE PRIORITY QLIMIT
%token LOAD
-%token TAGGED TAG
+%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
+%token TAGGED TAG IFBOUND GRBOUND FLOATING STATEPOLICY
%token <v.string> STRING
%token <v.i> PORTBINARY
%type <v.interface> interface if_list if_item_not if_item
%type <v.number> number icmptype icmp6type uid gid
%type <v.number> tos not yesno natpass
-%type <v.i> no dir log af fragcache
-%type <v.i> staticport unaryop
+%type <v.i> no dir log af fragcache sourcetrack
+%type <v.i> unaryop statelock
%type <v.b> action nataction flags flag blockspec
%type <v.range> port rport
%type <v.hashkey> hashkey
-%type <v.pooltype> pooltype
%type <v.proto> proto proto_list proto_item
%type <v.icmp> icmpspec
%type <v.icmp> icmp_list icmp_item
@@ -424,6 +453,7 @@ typedef struct {
%type <v.queue_opts> queue_opts queue_opt queue_opts_l
%type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l
%type <v.table_opts> table_opts table_opt table_opts_l
+%type <v.pool_opts> pool_opts pool_opt pool_opts_l
%%
ruleset : /* empty */
@@ -444,26 +474,45 @@ ruleset : /* empty */
;
option : SET OPTIMIZATION STRING {
- if (check_rulestate(PFCTL_STATE_OPTION))
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
YYERROR;
+ }
if (pfctl_set_optimization(pf, $3) != 0) {
yyerror("unknown optimization %s", $3);
+ free($3);
YYERROR;
}
+ free ($3);
}
| SET TIMEOUT timeout_spec
| SET TIMEOUT '{' timeout_list '}'
| SET LIMIT limit_spec
| SET LIMIT '{' limit_list '}'
| SET LOGINTERFACE STRING {
- if (check_rulestate(PFCTL_STATE_OPTION))
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
YYERROR;
- if ((ifa_exists($3) == NULL) && strcmp($3, "none")) {
+ }
+ if ((ifa_exists($3, 0) == NULL) && strcmp($3, "none")) {
yyerror("interface %s doesn't exist", $3);
+ free($3);
YYERROR;
}
if (pfctl_set_logif(pf, $3) != 0) {
yyerror("error setting loginterface %s", $3);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | SET HOSTID number {
+ if ($3 == 0) {
+ yyerror("hostid must be non-zero");
+ YYERROR;
+ }
+ if (pfctl_set_hostid(pf, $3) != 0) {
+ yyerror("error setting loginterface %08x", $3);
YYERROR;
}
}
@@ -490,12 +539,44 @@ option : SET OPTIMIZATION STRING {
| SET FINGERPRINTS STRING {
if (pf->opts & PF_OPT_VERBOSE)
printf("fingerprints %s\n", $3);
- if (check_rulestate(PFCTL_STATE_OPTION))
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
YYERROR;
+ }
if (pfctl_file_fingerprints(pf->dev, pf->opts, $3)) {
yyerror("error loading fingerprints %s", $3);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | SET STATEPOLICY statelock {
+ if (pf->opts & PF_OPT_VERBOSE)
+ switch ($3) {
+ case 0:
+ printf("set state-policy floating\n");
+ break;
+ case PFRULE_IFBOUND:
+ printf("set state-policy if-bound\n");
+ break;
+ case PFRULE_GRBOUND:
+ printf("set state-policy "
+ "group-bound\n");
+ break;
+ }
+ default_statelock = $3;
+ }
+ | SET DEBUG STRING {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
+ YYERROR;
+ }
+ if (pfctl_set_debug(pf, $3) != 0) {
+ yyerror("error setting debuglevel %s", $3);
+ free($3);
YYERROR;
}
+ free($3);
}
;
@@ -513,19 +594,32 @@ varset : STRING '=' string {
printf("%s = \"%s\"\n", $1, $3);
if (symset($1, $3, 0) == -1)
err(1, "cannot store variable %s", $1);
+ free($1);
+ free($3);
}
;
-anchorrule : ANCHOR string dir interface af proto fromto {
+anchorrule : ANCHOR string dir interface af proto fromto filter_opts {
struct pf_rule r;
- if (check_rulestate(PFCTL_STATE_FILTER))
+ if (check_rulestate(PFCTL_STATE_FILTER)) {
+ free($2);
YYERROR;
+ }
PREPARE_ANCHOR_RULE(r, $2);
r.direction = $3;
r.af = $5;
+ if ($8.match_tag)
+ if (strlcpy(r.match_tagname, $8.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = $8.match_tag_not;
+
decide_address_family($7.src.host, &r.af);
decide_address_family($7.dst.host, &r.af);
@@ -536,10 +630,13 @@ anchorrule : ANCHOR string dir interface af proto fromto {
| NATANCHOR string interface af proto fromto {
struct pf_rule r;
- if (check_rulestate(PFCTL_STATE_NAT))
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free($2);
YYERROR;
+ }
PREPARE_ANCHOR_RULE(r, $2);
+ free($2);
r.action = PF_NAT;
r.af = $4;
@@ -553,10 +650,13 @@ anchorrule : ANCHOR string dir interface af proto fromto {
| RDRANCHOR string interface af proto fromto {
struct pf_rule r;
- if (check_rulestate(PFCTL_STATE_NAT))
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free($2);
YYERROR;
+ }
PREPARE_ANCHOR_RULE(r, $2);
+ free($2);
r.action = PF_RDR;
r.af = $4;
@@ -591,10 +691,13 @@ anchorrule : ANCHOR string dir interface af proto fromto {
| BINATANCHOR string interface af proto fromto {
struct pf_rule r;
- if (check_rulestate(PFCTL_STATE_NAT))
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free($2);
YYERROR;
+ }
PREPARE_ANCHOR_RULE(r, $2);
+ free($2);
r.action = PF_BINAT;
r.af = $4;
if ($5 != NULL) {
@@ -626,18 +729,21 @@ loadrule : LOAD ANCHOR string FROM string {
struct loadanchors *loadanchor;
t = strsep(&$3, ":");
- if (*t == '\0' || *$3 == '\0') {
+ if (*t == '\0' || $3 == NULL || *$3 == '\0') {
yyerror("anchor '%s' invalid\n", $3);
+ free(t);
YYERROR;
}
if (strlen(t) >= PF_ANCHOR_NAME_SIZE) {
yyerror("anchorname %s too long, max %u\n",
t, PF_ANCHOR_NAME_SIZE - 1);
+ free(t);
YYERROR;
}
if (strlen($3) >= PF_RULESET_NAME_SIZE) {
yyerror("rulesetname %s too long, max %u\n",
$3, PF_RULESET_NAME_SIZE - 1);
+ free(t);
YYERROR;
}
@@ -676,13 +782,6 @@ scrubrule : SCRUB dir logquick interface af proto fromto scrub_opts
YYERROR;
}
- if ($4) {
- if ($4->not) {
- yyerror("scrub rules do not support "
- "'! <if>'");
- YYERROR;
- }
- }
r.af = $5;
if ($8.nodf)
r.rule_flag |= PFRULE_NODF;
@@ -712,7 +811,7 @@ scrubrule : SCRUB dir logquick interface af proto fromto scrub_opts
scrub_opts : {
bzero(&scrub_opts, sizeof scrub_opts);
}
- scrub_opts_l
+ scrub_opts_l
{ $$ = scrub_opts; }
| /* empty */ {
bzero(&scrub_opts, sizeof scrub_opts);
@@ -764,8 +863,11 @@ scrub_opt : NODF {
scrub_opts.fragcache = $1;
}
| REASSEMBLE STRING {
- if (strcasecmp($2, "tcp") != 0)
+ if (strcasecmp($2, "tcp") != 0) {
+ free($2);
YYERROR;
+ }
+ free($2);
if (scrub_opts.reassemble_tcp) {
yyerror("reassemble tcp cannot be respecified");
YYERROR;
@@ -814,10 +916,11 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
YYERROR;
}
j->not = 1;
- h = ifa_lookup(j->ifname, PFCTL_IFLOOKUP_NET);
+ h = ifa_lookup(j->ifname, PFI_AFLAG_NETWORK);
- expand_rule(&r, j, NULL, NULL, NULL, h, NULL,
- NULL, NULL, NULL, NULL, NULL);
+ if (h != NULL)
+ expand_rule(&r, j, NULL, NULL, NULL, h,
+ NULL, NULL, NULL, NULL, NULL, NULL);
if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
bzero(&r, sizeof(r));
@@ -829,11 +932,11 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
r.af = $4;
if (rule_label(&r, $5.label))
YYERROR;
- h = ifa_lookup(i->ifname,
- PFCTL_IFLOOKUP_HOST);
- expand_rule(&r, NULL, NULL, NULL, NULL,
- h, NULL, NULL, NULL, NULL, NULL,
- NULL);
+ h = ifa_lookup(i->ifname, 0);
+ if (h != NULL)
+ expand_rule(&r, NULL, NULL,
+ NULL, NULL, h, NULL, NULL,
+ NULL, NULL, NULL, NULL);
}
}
free($5.label);
@@ -853,7 +956,7 @@ antispoof_iflst : if_item { $$ = $1; }
;
antispoof_opts : { bzero(&antispoof_opts, sizeof antispoof_opts); }
- antispoof_opts_l
+ antispoof_opts_l
{ $$ = antispoof_opts; }
| /* empty */ {
bzero(&antispoof_opts, sizeof antispoof_opts);
@@ -876,6 +979,7 @@ antispoof_opt : label {
not : '!' { $$ = 1; }
| /* empty */ { $$ = 0; }
+ ;
tabledef : TABLE '<' STRING '>' table_opts {
struct node_host *h, *nh;
@@ -884,11 +988,15 @@ tabledef : TABLE '<' STRING '>' table_opts {
if (strlen($3) >= PF_TABLE_NAME_SIZE) {
yyerror("table name too long, max %d chars",
PF_TABLE_NAME_SIZE - 1);
+ free($3);
YYERROR;
}
if (pf->loadopt & PFCTL_FLAG_TABLE)
- if (process_tabledef($3, &$5))
+ if (process_tabledef($3, &$5)) {
+ free($3);
YYERROR;
+ }
+ free($3);
for (ti = SIMPLEQ_FIRST(&$5.init_nodes);
ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) {
if (ti->file)
@@ -898,7 +1006,7 @@ tabledef : TABLE '<' STRING '>' table_opts {
free(h);
}
nti = SIMPLEQ_NEXT(ti, entries);
- free (ti);
+ free(ti);
}
}
;
@@ -907,7 +1015,7 @@ table_opts : {
bzero(&table_opts, sizeof table_opts);
SIMPLEQ_INIT(&table_opts.init_nodes);
}
- table_opts_l
+ table_opts_l
{ $$ = table_opts; }
| /* empty */
{
@@ -926,8 +1034,11 @@ table_opt : STRING {
table_opts.flags |= PFR_TFLAG_CONST;
else if (!strcmp($1, "persist"))
table_opts.flags |= PFR_TFLAG_PERSIST;
- else
+ else {
+ free($1);
YYERROR;
+ }
+ free($1);
}
| '{' '}' { table_opts.init_addr = 1; }
| '{' host_list '}' {
@@ -935,7 +1046,7 @@ table_opt : STRING {
struct node_tinit *ti;
for (n = $2; n != NULL; n = n->next) {
- switch(n->addr.type) {
+ switch (n->addr.type) {
case PF_ADDR_ADDRMASK:
continue; /* ok */
case PF_ADDR_DYNIFTL:
@@ -1001,8 +1112,10 @@ altqif : ALTQ interface queue_opts QUEUE qassign {
queuespec : QUEUE STRING interface queue_opts qassign {
struct pf_altq a;
- if (check_rulestate(PFCTL_STATE_QUEUE))
+ if (check_rulestate(PFCTL_STATE_QUEUE)) {
+ free($2);
YYERROR;
+ }
memset(&a, 0, sizeof(a));
@@ -1010,8 +1123,10 @@ queuespec : QUEUE STRING interface queue_opts qassign {
sizeof(a.qname)) {
yyerror("queue name too long (max "
"%d chars)", PF_QNAME_SIZE-1);
+ free($2);
YYERROR;
}
+ free($2);
if ($4.tbrsize) {
yyerror("cannot specify tbrsize for queue");
YYERROR;
@@ -1038,7 +1153,7 @@ queue_opts : {
queue_opts.scheduler.qtype = ALTQT_NONE;
queue_opts.queue_bwspec.bw_percent = 100;
}
- queue_opts_l
+ queue_opts_l
{ $$ = queue_opts; }
| /* empty */ {
bzero(&queue_opts, sizeof queue_opts);
@@ -1128,17 +1243,21 @@ bandwidth : STRING {
if (bps < 0 || bps > 100) {
yyerror("bandwidth spec "
"out of range");
+ free($1);
YYERROR;
}
$$.bw_percent = bps;
bps = 0;
} else {
yyerror("unknown unit %s", cp);
+ free($1);
YYERROR;
}
}
+ free($1);
$$.bw_absolute = (u_int32_t)bps;
}
+ ;
scheduler : CBQ {
$$.qtype = ALTQT_CBQ;
@@ -1184,8 +1303,10 @@ cbqflags_item : STRING {
$$ = CBQCLF_RIO;
else {
yyerror("unknown cbq flag \"%s\"", $1);
+ free($1);
YYERROR;
}
+ free($1);
}
;
@@ -1204,8 +1325,10 @@ priqflags_item : STRING {
$$ = PRCF_RIO;
else {
yyerror("unknown priq flag \"%s\"", $1);
+ free($1);
YYERROR;
}
+ free($1);
}
;
@@ -1213,7 +1336,7 @@ hfsc_opts : {
bzero(&hfsc_opts,
sizeof(struct node_hfsc_opts));
}
- hfscopts_list {
+ hfscopts_list {
$$ = hfsc_opts;
}
;
@@ -1287,8 +1410,10 @@ hfscopts_item : LINKSHARE bandwidth {
hfsc_opts.flags |= HFCF_RIO;
else {
yyerror("unknown hfsc flag \"%s\"", $1);
+ free($1);
YYERROR;
}
+ free($1);
}
;
@@ -1311,22 +1436,26 @@ qassign_item : STRING {
err(1, "qassign_item: calloc");
if (strlcpy($$->queue, $1, sizeof($$->queue)) >=
sizeof($$->queue)) {
- free($$);
yyerror("queue name '%s' too long (max "
"%d chars)", $1, sizeof($$->queue)-1);
+ free($1);
+ free($$);
YYERROR;
}
+ free($1);
$$->next = NULL;
$$->tail = $$;
}
;
pfrule : action dir logquick interface route af proto fromto
- filter_opts
+ filter_opts
{
struct pf_rule r;
struct node_state_opt *o;
struct node_proto *proto;
+ int srctrack = 0;
+ int statelock = 0;
if (check_rulestate(PFCTL_STATE_FILTER))
YYERROR;
@@ -1357,14 +1486,14 @@ pfrule : action dir logquick interface route af proto fromto
r.af = $6;
if ($9.tag)
if (strlcpy(r.tagname, $9.tag,
- PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) {
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
yyerror("tag too long, max %u chars",
PF_TAG_NAME_SIZE - 1);
YYERROR;
}
if ($9.match_tag)
if (strlcpy(r.match_tagname, $9.match_tag,
- PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) {
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
yyerror("tag too long, max %u chars",
PF_TAG_NAME_SIZE - 1);
YYERROR;
@@ -1394,7 +1523,7 @@ pfrule : action dir logquick interface route af proto fromto
if (($9.flags.b1 & parse_flags("S")) == 0 &&
$8.src_os) {
yyerror("OS fingerprinting requires "
- "the SYN TCP flag (flags S/SA)");
+ "the SYN TCP flag (flags S/SA)");
YYERROR;
}
#endif
@@ -1415,6 +1544,65 @@ pfrule : action dir logquick interface route af proto fromto
}
r.max_states = o->data.max_states;
break;
+ case PF_STATE_OPT_NOSYNC:
+ if (r.rule_flag & PFRULE_NOSYNC) {
+ yyerror("state option 'sync' "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_NOSYNC;
+ break;
+ case PF_STATE_OPT_SRCTRACK:
+ if (srctrack) {
+ yyerror("state option "
+ "'source-track' "
+ "multiple definitions");
+ YYERROR;
+ }
+ srctrack = o->data.src_track;
+ break;
+ case PF_STATE_OPT_MAX_SRC_STATES:
+ if (r.max_src_states) {
+ yyerror("state option "
+ "'max-src-states' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_nodes == 0) {
+ yyerror("'max-src-states' must "
+ "be > 0");
+ YYERROR;
+ }
+ r.max_src_states =
+ o->data.max_src_states;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_NODES:
+ if (r.max_src_nodes) {
+ yyerror("state option "
+ "'max-src-nodes' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_nodes == 0) {
+ yyerror("'max-src-nodes' must "
+ "be > 0");
+ YYERROR;
+ }
+ r.max_src_nodes =
+ o->data.max_src_nodes;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_STATELOCK:
+ if (statelock) {
+ yyerror("state locking option: "
+ "multiple definitions");
+ YYERROR;
+ }
+ statelock = 1;
+ r.rule_flag |= o->data.statelock;
+ break;
case PF_STATE_OPT_TIMEOUT:
if (r.timeout[o->data.timeout.number]) {
yyerror("state timeout %s "
@@ -1429,6 +1617,20 @@ pfrule : action dir logquick interface route af proto fromto
o = o->next;
free(p);
}
+ if (srctrack) {
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_nodes) {
+ yyerror("'max-src-nodes' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_SRCTRACK;
+ if (srctrack == PF_SRCTRACK_RULE)
+ r.rule_flag |= PFRULE_RULESRCTRACK;
+ }
+ if (r.keep_state && !statelock)
+ r.rule_flag |= default_statelock;
if ($9.fragment)
r.rule_flag |= PFRULE_FRAGMENT;
@@ -1457,17 +1659,24 @@ pfrule : action dir logquick interface route af proto fromto
"matching address family found.");
YYERROR;
}
- if (r.rpool.opts == PF_POOL_NONE && (
- $5.host->next != NULL ||
- $5.host->addr.type == PF_ADDR_TABLE))
- r.rpool.opts = PF_POOL_ROUNDROBIN;
- if (r.rpool.opts != PF_POOL_ROUNDROBIN)
- if (disallow_table($5.host, "tables "
- "are only supported in round-robin "
- "routing pools"))
- YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
+ PF_POOL_NONE && ($5.host->next != NULL ||
+ $5.host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR($5.host->addr)))
+ r.rpool.opts |= PF_POOL_ROUNDROBIN;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_table($5.host, "tables are only "
+ "supported in round-robin routing pools"))
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias($5.host, "interface (%s) "
+ "is only supported in round-robin "
+ "routing pools"))
+ YYERROR;
if ($5.host->next != NULL) {
- if (r.rpool.opts !=
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
PF_POOL_ROUNDROBIN) {
yyerror("r.rpool.opts must "
"be PF_POOL_ROUNDROBIN");
@@ -1501,7 +1710,7 @@ pfrule : action dir logquick interface route af proto fromto
;
filter_opts : { bzero(&filter_opts, sizeof filter_opts); }
- filter_opts_l
+ filter_opts_l
{ $$ = filter_opts; }
| /* empty */ {
bzero(&filter_opts, sizeof filter_opts);
@@ -1628,22 +1837,32 @@ blockspec : /* empty */ {
}
| RETURNICMP '(' STRING ')' {
$$.b2 = PFRULE_RETURNICMP;
- if (!($$.w = parseicmpspec($3, AF_INET)))
+ if (!($$.w = parseicmpspec($3, AF_INET))) {
+ free($3);
YYERROR;
+ }
+ free($3);
$$.w2 = returnicmp6default;
}
| RETURNICMP6 '(' STRING ')' {
$$.b2 = PFRULE_RETURNICMP;
$$.w = returnicmpdefault;
- if (!($$.w2 = parseicmpspec($3, AF_INET6)))
+ if (!($$.w2 = parseicmpspec($3, AF_INET6))) {
+ free($3);
YYERROR;
+ }
+ free($3);
}
| RETURNICMP '(' STRING comma STRING ')' {
$$.b2 = PFRULE_RETURNICMP;
- if (!($$.w = parseicmpspec($3, AF_INET)))
- YYERROR;
- if (!($$.w2 = parseicmpspec($5, AF_INET6)))
+ if (!($$.w = parseicmpspec($3, AF_INET)) ||
+ !($$.w2 = parseicmpspec($5, AF_INET6))) {
+ free($3);
+ free($5);
YYERROR;
+ }
+ free($3);
+ free($5);
}
| RETURN {
$$.b2 = PFRULE_RETURN;
@@ -1687,19 +1906,29 @@ if_item_not : not if_item { $$ = $2; $$->not = $1; }
if_item : STRING {
struct node_host *n;
- if ((n = ifa_exists($1)) == NULL) {
+ if ((n = ifa_exists($1, 1)) == NULL) {
+#ifndef __FreeBSD__
yyerror("unknown interface %s", $1);
+ free($1);
YYERROR;
+#endif
}
$$ = calloc(1, sizeof(struct node_if));
if ($$ == NULL)
err(1, "if_item: calloc");
if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >=
sizeof($$->ifname)) {
+ free($1);
free($$);
yyerror("interface name too long");
YYERROR;
}
+ free($1);
+#ifdef __FreeBSD__
+ if (n == NULL)
+ $$->ifa_flags = PF_IFA_FLAG_DYNAMIC;
+ else /* XXX ugly */
+#endif
$$->ifa_flags = n->ifa_flags;
$$->not = 0;
$$->next = NULL;
@@ -1710,6 +1939,7 @@ if_item : STRING {
af : /* empty */ { $$ = 0; }
| INET { $$ = AF_INET; }
| INET6 { $$ = AF_INET6; }
+ ;
proto : /* empty */ { $$ = NULL; }
| PROTO proto_item { $$ = $2; }
@@ -1731,6 +1961,7 @@ proto_item : STRING {
if (atoul($1, &ulval) == 0) {
if (ulval > 255) {
yyerror("protocol outside range");
+ free($1);
YYERROR;
}
pr = (u_int8_t)ulval;
@@ -1740,10 +1971,12 @@ proto_item : STRING {
p = getprotobyname($1);
if (p == NULL) {
yyerror("unknown protocol %s", $1);
+ free($1);
YYERROR;
}
pr = p->p_proto;
}
+ free($1);
if (pr == 0) {
yyerror("proto 0 cannot be used");
YYERROR;
@@ -1864,9 +2097,11 @@ xhost : not host {
host : STRING {
if (($$ = host($1)) == NULL) {
/* error. "any" is handled elsewhere */
+ free($1);
yyerror("could not parse host specification");
YYERROR;
}
+ free($1);
}
| STRING '/' number {
@@ -1874,6 +2109,7 @@ host : STRING {
if (asprintf(&buf, "%s/%u", $1, $3) == -1)
err(1, "host: asprintf");
+ free($1);
if (($$ = host(buf)) == NULL) {
/* error. "any" is handled elsewhere */
free(buf);
@@ -1892,7 +2128,8 @@ host : STRING {
}
| '<' STRING '>' {
if (strlen($2) >= PF_TABLE_NAME_SIZE) {
- yyerror("table name '%s' too long");
+ yyerror("table name '%s' too long", $2);
+ free($2);
YYERROR;
}
$$ = calloc(1, sizeof(struct node_host));
@@ -1903,6 +2140,7 @@ host : STRING {
sizeof($$->addr.v.tblname)) >=
sizeof($$->addr.v.tblname))
errx(1, "host: strlcpy");
+ free($2);
$$->next = NULL;
$$->tail = $$;
}
@@ -1913,16 +2151,48 @@ number : STRING {
if (atoul($1, &ulval) == -1) {
yyerror("%s is not a number", $1);
+ free($1);
YYERROR;
} else
$$ = ulval;
+ free($1);
}
;
dynaddr : '(' STRING ')' {
- if (ifa_exists($2) == NULL) {
+ int flags = 0;
+ char *p, *op;
+
+ op = $2;
+ while ((p = strrchr($2, ':')) != NULL) {
+ if (!strcmp(p+1, "network"))
+ flags |= PFI_AFLAG_NETWORK;
+ else if (!strcmp(p+1, "broadcast"))
+ flags |= PFI_AFLAG_BROADCAST;
+ else if (!strcmp(p+1, "peer"))
+ flags |= PFI_AFLAG_PEER;
+ else if (!strcmp(p+1, "0"))
+ flags |= PFI_AFLAG_NOALIAS;
+ else {
+ yyerror("interface %s has bad modifier",
+ $2);
+ free(op);
+ YYERROR;
+ }
+ *p = '\0';
+ }
+ if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
+ free(op);
+ yyerror("illegal combination of "
+ "interface modifiers");
+ YYERROR;
+ }
+ if (ifa_exists($2, 1) == NULL && strcmp($2, "self")) {
+#ifndef __FreeBSD__
yyerror("interface %s does not exist", $2);
+ free(op);
YYERROR;
+#endif
}
$$ = calloc(1, sizeof(struct node_host));
if ($$ == NULL)
@@ -1930,13 +2200,16 @@ dynaddr : '(' STRING ')' {
$$->af = 0;
set_ipmask($$, 128);
$$->addr.type = PF_ADDR_DYNIFTL;
+ $$->addr.iflags = flags;
if (strlcpy($$->addr.v.ifname, $2,
sizeof($$->addr.v.ifname)) >=
sizeof($$->addr.v.ifname)) {
+ free(op);
free($$);
yyerror("interface name too long");
YYERROR;
}
+ free(op);
$$->next = NULL;
$$->tail = $$;
}
@@ -2007,6 +2280,7 @@ port : STRING {
if (p == NULL) {
if (atoul($1, &ulval) == 0) {
if (ulval > 65535) {
+ free($1);
yyerror("illegal port value %d",
ulval);
YYERROR;
@@ -2018,6 +2292,7 @@ port : STRING {
s = getservbyname($1, "udp");
if (s == NULL) {
yyerror("unknown port %s", $1);
+ free($1);
YYERROR;
}
$$.a = s->s_port;
@@ -2029,12 +2304,15 @@ port : STRING {
*p++ = 0;
if ((port[0] = getservice($1)) == -1 ||
- (port[1] = getservice(p)) == -1)
+ (port[1] = getservice(p)) == -1) {
+ free($1);
YYERROR;
+ }
$$.a = port[0];
$$.b = port[1];
$$.t = PF_OP_RRG;
}
+ free($1);
}
;
@@ -2103,17 +2381,20 @@ uid : STRING {
if ((pw = getpwnam($1)) == NULL) {
yyerror("unknown user %s", $1);
+ free($1);
YYERROR;
}
$$ = pw->pw_uid;
}
} else {
if (ulval >= UID_MAX) {
+ free($1);
yyerror("illegal uid value %lu", ulval);
YYERROR;
}
$$ = ulval;
}
+ free($1);
}
;
@@ -2182,6 +2463,7 @@ gid : STRING {
if ((grp = getgrnam($1)) == NULL) {
yyerror("unknown group %s", $1);
+ free($1);
YYERROR;
}
$$ = grp->gr_gid;
@@ -2189,10 +2471,12 @@ gid : STRING {
} else {
if (ulval >= GID_MAX) {
yyerror("illegal gid value %lu", ulval);
+ free($1);
YYERROR;
}
$$ = ulval;
}
+ free($1);
}
;
@@ -2201,8 +2485,10 @@ flag : STRING {
if ((f = parse_flags($1)) < 0) {
yyerror("bad flags %s", $1);
+ free($1);
YYERROR;
}
+ free($1);
$$.b1 = f;
}
;
@@ -2249,6 +2535,7 @@ icmp_item : icmptype {
if (atoul($3, &ulval) == 0) {
if (ulval > 255) {
+ free($3);
yyerror("illegal icmp-code %d", ulval);
YYERROR;
}
@@ -2256,10 +2543,12 @@ icmp_item : icmptype {
if ((p = geticmpcodebyname($1-1, $3,
AF_INET)) == NULL) {
yyerror("unknown icmp-code %s", $3);
+ free($3);
YYERROR;
}
ulval = p->code;
}
+ free($3);
$$ = calloc(1, sizeof(struct node_icmp));
if ($$ == NULL)
err(1, "icmp_item: calloc");
@@ -2289,16 +2578,19 @@ icmp6_item : icmp6type {
if (ulval > 255) {
yyerror("illegal icmp6-code %ld",
ulval);
+ free($3);
YYERROR;
}
} else {
if ((p = geticmpcodebyname($1-1, $3,
AF_INET6)) == NULL) {
yyerror("unknown icmp6-code %s", $3);
+ free($3);
YYERROR;
}
ulval = p->code;
}
+ free($3);
$$ = calloc(1, sizeof(struct node_icmp));
if ($$ == NULL)
err(1, "icmp_item: calloc");
@@ -2317,6 +2609,7 @@ icmptype : STRING {
if (atoul($1, &ulval) == 0) {
if (ulval > 255) {
yyerror("illegal icmp-type %d", ulval);
+ free($1);
YYERROR;
}
$$ = ulval + 1;
@@ -2324,10 +2617,12 @@ icmptype : STRING {
if ((p = geticmptypebyname($1, AF_INET)) ==
NULL) {
yyerror("unknown icmp-type %s", $1);
+ free($1);
YYERROR;
}
$$ = p->type + 1;
}
+ free($1);
}
;
@@ -2338,6 +2633,7 @@ icmp6type : STRING {
if (atoul($1, &ulval) == 0) {
if (ulval > 255) {
yyerror("illegal icmp6-type %d", ulval);
+ free($1);
YYERROR;
}
$$ = ulval + 1;
@@ -2345,10 +2641,12 @@ icmp6type : STRING {
if ((p = geticmptypebyname($1, AF_INET6)) ==
NULL) {
yyerror("unknown icmp6-type %s", $1);
+ free($1);
YYERROR;
}
$$ = p->type + 1;
}
+ free($1);
}
;
@@ -2365,8 +2663,26 @@ tos : TOS STRING {
$$ = strtoul($2, NULL, 10);
if (!$$ || $$ > 255) {
yyerror("illegal tos value %s", $2);
+ free($2);
YYERROR;
}
+ free($2);
+ }
+ ;
+
+sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; }
+ | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; }
+ | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; }
+ ;
+
+statelock : IFBOUND {
+ $$ = PFRULE_IFBOUND;
+ }
+ | GRBOUND {
+ $$ = PFRULE_GRBOUND;
+ }
+ | FLOATING {
+ $$ = 0;
}
;
@@ -2374,7 +2690,7 @@ keep : KEEP STATE state_opt_spec {
$$.action = PF_STATE_NORMAL;
$$.options = $3;
}
- | MODULATE STATE state_opt_spec {
+ | MODULATE STATE state_opt_spec {
$$.action = PF_STATE_MODULATE;
$$.options = $3;
}
@@ -2405,6 +2721,50 @@ state_opt_item : MAXIMUM number {
$$->next = NULL;
$$->tail = $$;
}
+ | NOSYNC {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_NOSYNC;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | MAXSRCSTATES number {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_SRC_STATES;
+ $$->data.max_src_states = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | MAXSRCNODES number {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_SRC_NODES;
+ $$->data.max_src_nodes = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | sourcetrack {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_SRCTRACK;
+ $$->data.src_track = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | statelock {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_STATELOCK;
+ $$->data.statelock = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
| STRING number {
int i;
@@ -2413,12 +2773,15 @@ state_opt_item : MAXIMUM number {
; /* nothing */
if (!pf_timeouts[i].name) {
yyerror("illegal timeout name %s", $1);
+ free($1);
YYERROR;
}
if (strchr(pf_timeouts[i].name, '.') == NULL) {
yyerror("illegal state timeout %s", $1);
+ free($1);
YYERROR;
}
+ free($1);
$$ = calloc(1, sizeof(struct node_state_opt));
if ($$ == NULL)
err(1, "state_opt_item: calloc");
@@ -2431,23 +2794,19 @@ state_opt_item : MAXIMUM number {
;
label : LABEL STRING {
- if (($$ = strdup($2)) == NULL)
- err(1, "rule label strdup() failed");
+ $$ = $2;
}
;
qname : QUEUE STRING {
- if (($$.qname = strdup($2)) == NULL)
- err(1, "qname strdup() failed");
+ $$.qname = $2;
}
| QUEUE '(' STRING ')' {
- if (($$.qname = strdup($3)) == NULL)
- err(1, "qname strdup() failed");
+ $$.qname = $3;
}
| QUEUE '(' STRING comma STRING ')' {
- if (($$.qname = strdup($3)) == NULL ||
- ($$.pqname = strdup($5)) == NULL)
- err(1, "qname strdup() failed");
+ $$.qname = $3;
+ $$.pqname = $5;
}
;
@@ -2459,24 +2818,31 @@ rport : STRING {
char *p = strchr($1, ':');
if (p == NULL) {
- if (($$.a = getservice($1)) == -1)
+ if (($$.a = getservice($1)) == -1) {
+ free($1);
YYERROR;
+ }
$$.b = $$.t = 0;
} else if (!strcmp(p+1, "*")) {
*p = 0;
- if (($$.a = getservice($1)) == -1)
+ if (($$.a = getservice($1)) == -1) {
+ free($1);
YYERROR;
+ }
$$.b = 0;
$$.t = 1;
} else {
*p++ = 0;
if (($$.a = getservice($1)) == -1 ||
- ($$.b = getservice(p)) == -1)
+ ($$.b = getservice(p)) == -1) {
+ free($1);
YYERROR;
+ }
if ($$.a == $$.b)
$$.b = 0;
$$.t = 0;
}
+ free($1);
}
;
@@ -2523,6 +2889,7 @@ hashkey : /* empty */
{
if (!strncmp($1, "0x", 2)) {
if (strlen($1) != 34) {
+ free($1);
yyerror("hex key must be 128 bits "
"(32 hex digits) long");
YYERROR;
@@ -2535,6 +2902,7 @@ hashkey : /* empty */
&$$->key32[0], &$$->key32[1],
&$$->key32[2], &$$->key32[3]) != 4) {
free($$);
+ free($1);
yyerror("invalid hex key");
YYERROR;
}
@@ -2553,38 +2921,67 @@ hashkey : /* empty */
HTONL($$->key32[2]);
HTONL($$->key32[3]);
}
+ free($1);
}
;
-pooltype : /* empty */
- {
- $$.type = PF_POOL_NONE;
- $$.key = NULL;
+pool_opts : { bzero(&pool_opts, sizeof pool_opts); }
+ pool_opts_l
+ { $$ = pool_opts; }
+ | /* empty */ {
+ bzero(&pool_opts, sizeof pool_opts);
+ $$ = pool_opts;
}
- | BITMASK
- {
- $$.type = PF_POOL_BITMASK;
- $$.key = NULL;
+ ;
+
+pool_opts_l : pool_opts_l pool_opt
+ | pool_opt
+ ;
+
+pool_opt : BITMASK {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_BITMASK;
}
- | RANDOM
- {
- $$.type = PF_POOL_RANDOM;
- $$.key = NULL;
+ | RANDOM {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_RANDOM;
}
- | SOURCEHASH hashkey
- {
- $$.type = PF_POOL_SRCHASH;
- $$.key = $2;
+ | SOURCEHASH hashkey {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_SRCHASH;
+ pool_opts.key = $2;
}
- | ROUNDROBIN
- {
- $$.type = PF_POOL_ROUNDROBIN;
- $$.key = NULL;
+ | ROUNDROBIN {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_ROUNDROBIN;
+ }
+ | STATICPORT {
+ if (pool_opts.staticport) {
+ yyerror("static-port cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.staticport = 1;
+ }
+ | STICKYADDRESS {
+ if (filter_opts.marker & POM_STICKYADDRESS) {
+ yyerror("sticky-address cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.marker |= POM_STICKYADDRESS;
+ pool_opts.opts |= PF_POOL_STICKYADDR;
}
- ;
-
-staticport : /* empty */ { $$ = 0; }
- | STATICPORT { $$ = 1; }
;
redirection : /* empty */ { $$ = NULL; }
@@ -2626,8 +3023,7 @@ nataction : no NAT natpass {
}
;
-natrule : nataction interface af proto fromto tag redirpool pooltype
- staticport
+natrule : nataction interface af proto fromto tag redirpool pool_opts
{
struct pf_rule r;
@@ -2650,7 +3046,7 @@ natrule : nataction interface af proto fromto tag redirpool pooltype
}
if ($6 != NULL)
- if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >
+ if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >=
PF_TAG_NAME_SIZE) {
yyerror("tag too long, max %u chars",
PF_TAG_NAME_SIZE - 1);
@@ -2686,14 +3082,17 @@ natrule : nataction interface af proto fromto tag redirpool pooltype
$5.dst.port != NULL) {
r.rpool.proxy_port[1] =
ntohs($7->rport.a) +
- (ntohs($5.dst.port->port[1]) -
- ntohs($5.dst.port->port[0]));
+ (ntohs(
+ $5.dst.port->port[1]) -
+ ntohs(
+ $5.dst.port->port[0]));
} else
r.rpool.proxy_port[1] =
ntohs($7->rport.b);
break;
case PF_NAT:
- r.rpool.proxy_port[1] = ntohs($7->rport.b);
+ r.rpool.proxy_port[1] =
+ ntohs($7->rport.b);
if (!r.rpool.proxy_port[0] &&
!r.rpool.proxy_port[1]) {
r.rpool.proxy_port[0] =
@@ -2709,30 +3108,31 @@ natrule : nataction interface af proto fromto tag redirpool pooltype
}
r.rpool.opts = $8.type;
- if (r.rpool.opts == PF_POOL_NONE)
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
+ PF_POOL_NONE && ($7->host->next != NULL ||
+ $7->host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR($7->host->addr)))
r.rpool.opts = PF_POOL_ROUNDROBIN;
- if (r.rpool.opts != PF_POOL_ROUNDROBIN)
- if (disallow_table($7->host, "tables "
- "are only supported in round-robin "
- "redirection pools"))
- YYERROR;
- if ($7->host->next) {
- if (r.rpool.opts !=
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_table($7->host, "tables are only "
+ "supported in round-robin redirection "
+ "pools"))
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias($7->host, "interface (%s) "
+ "is only supported in round-robin "
+ "redirection pools"))
+ YYERROR;
+ if ($7->host->next != NULL) {
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
PF_POOL_ROUNDROBIN) {
yyerror("only round-robin "
"valid for multiple "
"redirection addresses");
YYERROR;
}
- } else {
- if ((r.af == AF_INET &&
- unmask(&$7->host->addr.v.a.mask,
- r.af) == 32) ||
- (r.af == AF_INET6 &&
- unmask(&$7->host->addr.v.a.mask,
- r.af) == 128)) {
- r.rpool.opts = PF_POOL_NONE;
- }
}
}
@@ -2740,7 +3140,10 @@ natrule : nataction interface af proto fromto tag redirpool pooltype
memcpy(&r.rpool.key, $8.key,
sizeof(struct pf_poolhashkey));
- if ($9 != 0) {
+ if ($8.opts)
+ r.rpool.opts |= $8.opts;
+
+ if ($8.staticport) {
if (r.action != PF_NAT) {
yyerror("the 'static-port' option is "
"only valid with nat rules");
@@ -2767,7 +3170,7 @@ natrule : nataction interface af proto fromto tag redirpool pooltype
;
binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag
- redirection
+ redirection
{
struct pf_rule binat;
struct pf_pooladdr *pa;
@@ -2798,11 +3201,12 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag
if ($4 != NULL) {
memcpy(binat.ifname, $4->ifname,
sizeof(binat.ifname));
+ binat.ifnot = $4->not;
free($4);
}
if ($11 != NULL)
if (strlcpy(binat.tagname, $11,
- PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) {
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
yyerror("tag too long, max %u chars",
PF_TAG_NAME_SIZE - 1);
YYERROR;
@@ -2816,10 +3220,18 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag
if ($8 != NULL && disallow_table($8, "invalid use of "
"table <%s> as the source address of a binat rule"))
YYERROR;
+ if ($8 != NULL && disallow_alias($8, "invalid use of "
+ "interface (%s) as the source address of a binat "
+ "rule"))
+ YYERROR;
if ($12 != NULL && $12->host != NULL && disallow_table(
$12->host, "invalid use of table <%s> as the "
"redirect address of a binat rule"))
YYERROR;
+ if ($12 != NULL && $12->host != NULL && disallow_alias(
+ $12->host, "invalid use of interface (%s) as the "
+ "redirect address of a binat rule"))
+ YYERROR;
if ($8 != NULL) {
if ($8->next) {
@@ -2906,18 +3318,18 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag
tag : /* empty */ { $$ = NULL; }
| TAG STRING { $$ = $2; }
+ ;
route_host : STRING {
- struct node_host *n;
-
$$ = calloc(1, sizeof(struct node_host));
if ($$ == NULL)
err(1, "route_host: calloc");
- if (($$->ifname = strdup($1)) == NULL)
- err(1, "routeto: strdup");
- if ((n = ifa_exists($$->ifname)) == NULL) {
+ $$->ifname = $1;
+ if (ifa_exists($$->ifname, 0) == NULL) {
yyerror("routeto: unknown interface %s",
$$->ifname);
+ free($1);
+ free($$);
YYERROR;
}
set_ipmask($$, 128);
@@ -2925,12 +3337,9 @@ route_host : STRING {
$$->tail = $$;
}
| '(' STRING host ')' {
- struct node_host *n;
-
$$ = $3;
- if (($$->ifname = strdup($2)) == NULL)
- err(1, "routeto: strdup");
- if ((n = ifa_exists($$->ifname)) == NULL) {
+ $$->ifname = $2;
+ if (ifa_exists($$->ifname, 0) == NULL) {
yyerror("routeto: unknown interface %s",
$$->ifname);
YYERROR;
@@ -2967,24 +3376,24 @@ route : /* empty */ {
$$.rt = PF_FASTROUTE;
$$.pool_opts = 0;
}
- | ROUTETO routespec pooltype {
+ | ROUTETO routespec pool_opts {
$$.host = $2;
$$.rt = PF_ROUTETO;
- $$.pool_opts = $3.type;
+ $$.pool_opts = $3.type | $3.opts;
if ($3.key != NULL)
$$.key = $3.key;
}
- | REPLYTO routespec pooltype {
+ | REPLYTO routespec pool_opts {
$$.host = $2;
$$.rt = PF_REPLYTO;
- $$.pool_opts = $3.type;
+ $$.pool_opts = $3.type | $3.opts;
if ($3.key != NULL)
$$.key = $3.key;
}
- | DUPTO routespec pooltype {
+ | DUPTO routespec pool_opts {
$$.host = $2;
$$.rt = PF_DUPTO;
- $$.pool_opts = $3.type;
+ $$.pool_opts = $3.type | $3.opts;
if ($3.key != NULL)
$$.key = $3.key;
}
@@ -2992,12 +3401,16 @@ route : /* empty */ {
timeout_spec : STRING number
{
- if (check_rulestate(PFCTL_STATE_OPTION))
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($1);
YYERROR;
+ }
if (pfctl_set_timeout(pf, $1, $2, 0) != 0) {
yyerror("unknown timeout %s", $1);
+ free($1);
YYERROR;
}
+ free($1);
}
;
@@ -3007,13 +3420,18 @@ timeout_list : timeout_list comma timeout_spec
limit_spec : STRING number
{
- if (check_rulestate(PFCTL_STATE_OPTION))
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($1);
YYERROR;
+ }
if (pfctl_set_limit(pf, $1, $2) != 0) {
yyerror("unable to set limit %s %u", $1, $2);
+ free($1);
YYERROR;
}
+ free($1);
}
+ ;
limit_list : limit_list comma limit_spec
| limit_spec
@@ -3027,9 +3445,13 @@ yesno : NO { $$ = 0; }
| STRING {
if (!strcmp($1, "yes"))
$$ = 1;
- else
+ else {
+ free($1);
YYERROR;
+ }
+ free($1);
}
+ ;
unaryop : '=' { $$ = PF_OP_EQ; }
| '!' '=' { $$ = PF_OP_NE; }
@@ -3068,6 +3490,17 @@ disallow_table(struct node_host *h, const char *fmt)
}
int
+disallow_alias(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (DYNIF_MULTIADDR(h->addr)) {
+ yyerror(fmt, h->addr.v.tblname);
+ return (1);
+ }
+ return (0);
+}
+
+int
rule_consistent(struct pf_rule *r)
{
int problems = 0;
@@ -3104,10 +3537,6 @@ filter_consistent(struct pf_rule *r)
yyerror("port only applies to tcp/udp");
problems++;
}
- if (r->src.port_op == PF_OP_RRG || r->dst.port_op == PF_OP_RRG) {
- yyerror("the ':' port operator only applies to rdr");
- problems++;
- }
if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
(r->type || r->code)) {
yyerror("icmp-type/code only applies to icmp");
@@ -3124,22 +3553,10 @@ filter_consistent(struct pf_rule *r)
r->af == AF_INET ? "inet" : "inet6");
problems++;
}
- if ((r->keep_state == PF_STATE_MODULATE || r->keep_state ==
- PF_STATE_SYNPROXY) && r->proto && r->proto != IPPROTO_TCP) {
- yyerror("modulate/synproxy state can only be applied to "
- "TCP rules");
- problems++;
- }
if (r->allow_opts && r->action != PF_PASS) {
yyerror("allow-opts can only be specified for pass rules");
problems++;
}
- if (!r->af && (r->src.addr.type == PF_ADDR_DYNIFTL ||
- r->dst.addr.type == PF_ADDR_DYNIFTL)) {
- yyerror("dynamic addresses require address family "
- "(inet/inet6)");
- problems++;
- }
if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
r->dst.port_op || r->flagset || r->type || r->code)) {
yyerror("fragments can be filtered only on IP header fields");
@@ -3149,12 +3566,16 @@ filter_consistent(struct pf_rule *r)
yyerror("return-rst can only be applied to TCP rules");
problems++;
}
+ if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) {
+ yyerror("max-src-nodes requires 'source-track rule'");
+ problems++;
+ }
if (r->action == PF_DROP && r->keep_state) {
yyerror("keep state on block rules doesn't make sense");
problems++;
}
if ((r->tagname[0] || r->match_tagname[0]) && !r->keep_state &&
- r->action == PF_PASS) {
+ r->action == PF_PASS && !r->anchorname[0]) {
yyerror("tags cannot be used without keep state");
problems++;
}
@@ -3164,31 +3585,13 @@ filter_consistent(struct pf_rule *r)
int
nat_consistent(struct pf_rule *r)
{
- int problems = 0;
- struct pf_pooladdr *pa;
-
- if (r->src.port_op == PF_OP_RRG || r->dst.port_op == PF_OP_RRG) {
- yyerror("the ':' port operator only applies to rdr");
- problems++;
- }
- if (!r->af) {
- TAILQ_FOREACH(pa, &r->rpool.list, entries) {
- if (pa->addr.type == PF_ADDR_DYNIFTL) {
- yyerror("dynamic addresses require "
- "address family (inet/inet6)");
- problems++;
- break;
- }
- }
- }
- return (-problems);
+ return (0); /* yeah! */
}
int
rdr_consistent(struct pf_rule *r)
{
int problems = 0;
- struct pf_pooladdr *pa;
if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) {
if (r->src.port_op) {
@@ -3209,28 +3612,6 @@ rdr_consistent(struct pf_rule *r)
yyerror("invalid port operator for rdr destination port");
problems++;
}
- if (r->src.port_op == PF_OP_RRG) {
- yyerror("the ':' port operator only applies to rdr "
- "destination port");
- problems++;
- }
- if (!r->af) {
- if (r->src.addr.type == PF_ADDR_DYNIFTL ||
- r->dst.addr.type == PF_ADDR_DYNIFTL) {
- yyerror("dynamic addresses require address family "
- "(inet/inet6)");
- problems++;
- } else {
- TAILQ_FOREACH(pa, &r->rpool.list, entries) {
- if (pa->addr.type == PF_ADDR_DYNIFTL) {
- yyerror("dynamic addresses require "
- "address family (inet/inet6)");
- problems++;
- break;
- }
- }
- }
- }
return (-problems);
}
@@ -3314,38 +3695,41 @@ struct keywords {
} while (0)
void
-expand_label_str(char *label, const char *srch, const char *repl)
+expand_label_str(char *label, size_t len, const char *srch, const char *repl)
{
- char tmp[PF_RULE_LABEL_SIZE] = "";
+ char *tmp;
char *p, *q;
+ if ((tmp = calloc(1, len)) == NULL)
+ err(1, "expand_label_str: calloc");
p = q = label;
while ((q = strstr(p, srch)) != NULL) {
*q = '\0';
- if ((strlcat(tmp, p, sizeof(tmp)) >= sizeof(tmp)) ||
- (strlcat(tmp, repl, sizeof(tmp)) >= sizeof(tmp)))
- err(1, "expand_label: label too long");
+ if ((strlcat(tmp, p, len) >= len) ||
+ (strlcat(tmp, repl, len) >= len))
+ errx(1, "expand_label: label too long");
q += strlen(srch);
p = q;
}
- if (strlcat(tmp, p, sizeof(tmp)) >= sizeof(tmp))
- err(1, "expand_label: label too long");
- strlcpy(label, tmp, PF_RULE_LABEL_SIZE); /* always fits */
+ if (strlcat(tmp, p, len) >= len)
+ errx(1, "expand_label: label too long");
+ strlcpy(label, tmp, len); /* always fits */
+ free(tmp);
}
void
-expand_label_if(const char *name, char *label, const char *ifname)
+expand_label_if(const char *name, char *label, size_t len, const char *ifname)
{
if (strstr(label, name) != NULL) {
if (!*ifname)
- expand_label_str(label, name, "any");
+ expand_label_str(label, len, name, "any");
else
- expand_label_str(label, name, ifname);
+ expand_label_str(label, len, name, ifname);
}
}
void
-expand_label_addr(const char *name, char *label, sa_family_t af,
+expand_label_addr(const char *name, char *label, size_t len, sa_family_t af,
struct node_host *h)
{
char tmp[64], tmp_not[66];
@@ -3377,7 +3761,7 @@ expand_label_addr(const char *name, char *label, sa_family_t af,
if ((af == AF_INET && bits < 32) ||
(af == AF_INET6 && bits < 128))
snprintf(tmp, sizeof(tmp),
- "%s/%d", a, bits);
+ "%s/%d", a, bits);
else
snprintf(tmp, sizeof(tmp),
"%s", a);
@@ -3391,14 +3775,15 @@ expand_label_addr(const char *name, char *label, sa_family_t af,
if (h->not) {
snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
- expand_label_str(label, name, tmp_not);
+ expand_label_str(label, len, name, tmp_not);
} else
- expand_label_str(label, name, tmp);
+ expand_label_str(label, len, name, tmp);
}
}
void
-expand_label_port(const char *name, char *label, struct node_port *port)
+expand_label_port(const char *name, char *label, size_t len,
+ struct node_port *port)
{
char a1[6], a2[6], op[13] = "";
@@ -3423,12 +3808,12 @@ expand_label_port(const char *name, char *label, struct node_port *port)
snprintf(op, sizeof(op), ">%s", a1);
else if (port->op == PF_OP_GE)
snprintf(op, sizeof(op), ">=%s", a1);
- expand_label_str(label, name, op);
+ expand_label_str(label, len, name, op);
}
}
void
-expand_label_proto(const char *name, char *label, u_int8_t proto)
+expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto)
{
struct protoent *pe;
char n[4];
@@ -3436,38 +3821,38 @@ expand_label_proto(const char *name, char *label, u_int8_t proto)
if (strstr(label, name) != NULL) {
pe = getprotobynumber(proto);
if (pe != NULL)
- expand_label_str(label, name, pe->p_name);
+ expand_label_str(label, len, name, pe->p_name);
else {
snprintf(n, sizeof(n), "%u", proto);
- expand_label_str(label, name, n);
+ expand_label_str(label, len, name, n);
}
}
}
void
-expand_label_nr(const char *name, char *label)
+expand_label_nr(const char *name, char *label, size_t len)
{
char n[11];
if (strstr(label, name) != NULL) {
snprintf(n, sizeof(n), "%u", pf->rule_nr);
- expand_label_str(label, name, n);
+ expand_label_str(label, len, name, n);
}
}
void
-expand_label(char *label, const char *ifname, sa_family_t af,
+expand_label(char *label, size_t len, const char *ifname, sa_family_t af,
struct node_host *src_host, struct node_port *src_port,
struct node_host *dst_host, struct node_port *dst_port,
u_int8_t proto)
{
- expand_label_if("$if", label, ifname);
- expand_label_addr("$srcaddr", label, af, src_host);
- expand_label_addr("$dstaddr", label, af, dst_host);
- expand_label_port("$srcport", label, src_port);
- expand_label_port("$dstport", label, dst_port);
- expand_label_proto("$proto", label, proto);
- expand_label_nr("$nr", label);
+ expand_label_if("$if", label, len, ifname);
+ expand_label_addr("$srcaddr", label, len, af, src_host);
+ expand_label_addr("$dstaddr", label, len, af, dst_host);
+ expand_label_port("$srcport", label, len, src_port);
+ expand_label_port("$dstport", label, len, dst_port);
+ expand_label_proto("$proto", label, len, proto);
+ expand_label_nr("$nr", label, len);
}
int
@@ -3733,14 +4118,22 @@ expand_rule(struct pf_rule *r,
int added = 0, error = 0;
char ifname[IF_NAMESIZE];
char label[PF_RULE_LABEL_SIZE];
+ char tagname[PF_TAG_NAME_SIZE];
+ char match_tagname[PF_TAG_NAME_SIZE];
struct pf_pooladdr *pa;
struct node_host *h;
- u_int8_t flags, flagset;
+ u_int8_t flags, flagset, keep_state;
if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
errx(1, "expand_rule: strlcpy");
+ if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
+ sizeof(match_tagname))
+ errx(1, "expand_rule: strlcpy");
flags = r->flags;
flagset = r->flagset;
+ keep_state = r->keep_state;
LOOP_THROUGH(struct node_if, interface, interfaces,
LOOP_THROUGH(struct node_proto, proto, protos,
@@ -3761,9 +4154,9 @@ expand_rule(struct pf_rule *r,
src_host->af != dst_host->af) ||
(src_host->ifindex && dst_host->ifindex &&
src_host->ifindex != dst_host->ifindex) ||
- (src_host->ifindex && if_nametoindex(interface->ifname) &&
+ (src_host->ifindex && *interface->ifname &&
src_host->ifindex != if_nametoindex(interface->ifname)) ||
- (dst_host->ifindex && if_nametoindex(interface->ifname) &&
+ (dst_host->ifindex && *interface->ifname &&
dst_host->ifindex != if_nametoindex(interface->ifname)))
continue;
if (!r->af && src_host->af)
@@ -3771,18 +4164,31 @@ expand_rule(struct pf_rule *r,
else if (!r->af && dst_host->af)
r->af = dst_host->af;
- if (if_indextoname(src_host->ifindex, ifname))
+ if (*interface->ifname)
+ memcpy(r->ifname, interface->ifname, sizeof(r->ifname));
+ else if (if_indextoname(src_host->ifindex, ifname))
memcpy(r->ifname, ifname, sizeof(r->ifname));
else if (if_indextoname(dst_host->ifindex, ifname))
memcpy(r->ifname, ifname, sizeof(r->ifname));
else
- memcpy(r->ifname, interface->ifname, sizeof(r->ifname));
+ memset(r->ifname, '\0', sizeof(r->ifname));
if (strlcpy(r->label, label, sizeof(r->label)) >=
sizeof(r->label))
errx(1, "expand_rule: strlcpy");
- expand_label(r->label, r->ifname, r->af, src_host, src_port,
- dst_host, dst_port, proto->proto);
+ if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
+ sizeof(r->tagname))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(r->match_tagname, match_tagname,
+ sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
+ errx(1, "expand_rule: strlcpy");
+ expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname,
+ r->af, src_host, src_port, dst_host, dst_port,
+ proto->proto);
error += check_netmask(src_host, r->af);
error += check_netmask(dst_host, r->af);
@@ -3808,6 +4214,13 @@ expand_rule(struct pf_rule *r,
r->type = icmp_type->type;
r->code = icmp_type->code;
+ if ((keep_state == PF_STATE_MODULATE ||
+ keep_state == PF_STATE_SYNPROXY) &&
+ r->proto && r->proto != IPPROTO_TCP)
+ r->keep_state = PF_STATE_NORMAL;
+ else
+ r->keep_state = keep_state;
+
if (r->proto && r->proto != IPPROTO_TCP) {
r->flags = 0;
r->flagset = 0;
@@ -3914,6 +4327,7 @@ lookup(char *s)
{ "cbq", CBQ},
{ "code", CODE},
{ "crop", FRAGCROP},
+ { "debug", DEBUG},
{ "drop", DROP},
{ "drop-ovl", FRAGDROP},
{ "dup-to", DUPTO},
@@ -3921,13 +4335,18 @@ lookup(char *s)
{ "file", FILENAME},
{ "fingerprints", FINGERPRINTS},
{ "flags", FLAGS},
+ { "floating", FLOATING},
{ "for", FOR},
{ "fragment", FRAGMENT},
{ "from", FROM},
+ { "global", GLOBAL},
{ "group", GROUP},
+ { "group-bound", GRBOUND},
{ "hfsc", HFSC},
+ { "hostid", HOSTID},
{ "icmp-type", ICMPTYPE},
{ "icmp6-type", ICMP6TYPE},
+ { "if-bound", IFBOUND},
{ "in", IN},
{ "inet", INET},
{ "inet6", INET6},
@@ -3941,6 +4360,8 @@ lookup(char *s)
{ "loginterface", LOGINTERFACE},
{ "max", MAXIMUM},
{ "max-mss", MAXMSS},
+ { "max-src-nodes", MAXSRCNODES},
+ { "max-src-states", MAXSRCSTATES},
{ "min-ttl", MINTTL},
{ "modulate", MODULATE},
{ "nat", NAT},
@@ -3948,6 +4369,7 @@ lookup(char *s)
{ "no", NO},
{ "no-df", NODF},
{ "no-route", NOROUTE},
+ { "no-sync", NOSYNC},
{ "on", ON},
{ "optimization", OPTIMIZATION},
{ "os", OS},
@@ -3974,11 +4396,15 @@ lookup(char *s)
{ "return-rst", RETURNRST},
{ "round-robin", ROUNDROBIN},
{ "route-to", ROUTETO},
+ { "rule", RULE},
{ "scrub", SCRUB},
{ "set", SET},
{ "source-hash", SOURCEHASH},
+ { "source-track", SOURCETRACK},
{ "state", STATE},
+ { "state-policy", STATEPOLICY},
{ "static-port", STATICPORT},
+ { "sticky-address", STICKYADDRESS},
{ "synproxy", SYNPROXY},
{ "table", TABLE},
{ "tag", TAG},
@@ -4202,10 +4628,9 @@ top:
} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
lungetc(c);
*p = '\0';
- token = lookup(buf);
- yylval.v.string = strdup(buf);
- if (yylval.v.string == NULL)
- err(1, "yylex: strdup");
+ if ((token = lookup(buf)) == STRING)
+ if ((yylval.v.string = strdup(buf)) == NULL)
+ err(1, "yylex: strdup");
return (token);
}
if (c == '\n') {
@@ -4220,7 +4645,7 @@ top:
int
parse_rules(FILE *input, struct pfctl *xpf)
{
- struct sym *sym;
+ struct sym *sym, *next;
fin = input;
pf = xpf;
@@ -4236,13 +4661,15 @@ parse_rules(FILE *input, struct pfctl *xpf)
yyparse();
/* Free macros and check which have not been used. */
- TAILQ_FOREACH(sym, &symhead, entries) {
+ for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
+ next = TAILQ_NEXT(sym, entries);
if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
fprintf(stderr, "warning: macro '%s' not "
"used\n", sym->nam);
free(sym->nam);
free(sym->val);
TAILQ_REMOVE(&symhead, sym, entries);
+ free(sym);
}
return (errors ? -1 : 0);
@@ -4380,9 +4807,10 @@ invalid_redirect(struct node_host *nh, sa_family_t af)
if (!af) {
struct node_host *n;
- /* only tables are ok without an address family */
+ /* tables and dyniftl are ok without an address family */
for (n = nh; n != NULL; n = n->next) {
- if (n->addr.type != PF_ADDR_TABLE) {
+ if (n->addr.type != PF_ADDR_TABLE &&
+ n->addr.type != PF_ADDR_DYNIFTL) {
yyerror("address family not given and "
"translation address expands to multiple "
"address families");
@@ -4479,7 +4907,7 @@ parseicmpspec(char *w, sa_family_t af)
}
int
-pfctl_load_anchors(int dev, int opts)
+pfctl_load_anchors(int dev, int opts, struct pfr_buffer *trans)
{
struct loadanchors *la;
@@ -4488,7 +4916,7 @@ pfctl_load_anchors(int dev, int opts)
fprintf(stderr, "\nLoading anchor %s:%s from %s\n",
la->anchorname, la->rulesetname, la->filename);
if (pfctl_rules(dev, la->filename, opts, la->anchorname,
- la->rulesetname) == -1)
+ la->rulesetname, trans) == -1)
return (-1);
}
diff --git a/contrib/pf/pfctl/pf_print_state.c b/contrib/pf/pfctl/pf_print_state.c
index b7cf5ca..318bde7 100644
--- a/contrib/pf/pfctl/pf_print_state.c
+++ b/contrib/pf/pfctl/pf_print_state.c
@@ -30,8 +30,12 @@
*
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/endian.h>
#include <net/if.h>
#define TCPSTATES
#include <netinet/tcp_fsm.h>
@@ -284,8 +288,13 @@ print_state(struct pf_state *s, int opts)
printf("\n");
}
if (opts & PF_OPT_VERBOSE2) {
+#ifdef __FreeBSD__
+ printf(" id: %016llx creatorid: %08x\n",
+ (long long)be64toh(s->id), ntohl(s->creatorid));
+#else
printf(" id: %016llx creatorid: %08x\n",
betoh64(s->id), ntohl(s->creatorid));
+#endif
}
}
diff --git a/contrib/pf/pfctl/pfctl.c b/contrib/pf/pfctl/pfctl.c
index 418b51f..6abbbec 100644
--- a/contrib/pf/pfctl/pfctl.c
+++ b/contrib/pf/pfctl/pfctl.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: pfctl.c,v 1.188 2003/08/29 21:47:36 cedric Exp $ */
+/* $OpenBSD: pfctl.c,v 1.213 2004/03/20 09:31:42 david Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
+ * Copyright (c) 2002,2003 Henning Brauer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -56,6 +57,10 @@ __FBSDID("$FreeBSD$");
#include "pfctl_parser.h"
#include "pfctl.h"
+#ifdef __FreeBSD__
+#define HTONL(x) (x) = htonl((__uint32_t)(x))
+#endif
+
void usage(void);
int pfctl_enable(int, int);
int pfctl_disable(int, int);
@@ -63,17 +68,19 @@ int pfctl_clear_stats(int, int);
int pfctl_clear_rules(int, int, char *, char *);
int pfctl_clear_nat(int, int, char *, char *);
int pfctl_clear_altq(int, int);
-int pfctl_clear_states(int, int);
-int pfctl_kill_states(int, int);
+int pfctl_clear_src_nodes(int, int);
+int pfctl_clear_states(int, const char *, int);
+int pfctl_kill_states(int, const char *, int);
int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
- char *, char *);
+ char *, char *);
void pfctl_print_rule_counters(struct pf_rule *, int);
int pfctl_show_rules(int, int, int, char *, char *);
int pfctl_show_nat(int, int, char *, char *);
-int pfctl_show_states(int, u_int8_t, int);
-int pfctl_show_status(int);
-int pfctl_show_timeouts(int);
-int pfctl_show_limits(int);
+int pfctl_show_src_nodes(int, int);
+int pfctl_show_states(int, const char *, int);
+int pfctl_show_status(int, int);
+int pfctl_show_timeouts(int, int);
+int pfctl_show_limits(int, int);
int pfctl_debug(int, u_int32_t, int);
int pfctl_clear_rule_counters(int, int);
int pfctl_test_altqsupport(int, int);
@@ -85,6 +92,8 @@ char *rulesopt;
const char *showopt;
const char *debugopt;
char *anchoropt;
+char *pf_device = "/dev/pf";
+char *ifaceopt;
char *tableopt;
const char *tblcmdopt;
int state_killers;
@@ -93,6 +102,8 @@ int loadopt;
int altqsupport;
int dev = -1;
+int first_title = 1;
+int labels = 0;
const char *infile;
@@ -101,6 +112,7 @@ static const struct {
int index;
} pf_limits[] = {
{ "states", PF_LIMIT_STATES },
+ { "src-nodes", PF_LIMIT_SRC_NODES },
{ "frags", PF_LIMIT_FRAGS },
{ NULL, 0 }
};
@@ -159,12 +171,14 @@ static const struct {
};
static const char *clearopt_list[] = {
- "nat", "queue", "rules", "state", "info", "Tables", "osfp", "all", NULL
+ "nat", "queue", "rules", "Sources",
+ "state", "info", "Tables", "osfp", "all", NULL
};
static const char *showopt_list[] = {
- "nat", "queue", "rules", "Anchors", "state", "info", "labels",
- "timeouts", "memory", "Tables", "osfp", "all", NULL
+ "nat", "queue", "rules", "Anchors", "Sources", "state", "info",
+ "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
+ "all", NULL
};
static const char *tblcmdopt_list[] = {
@@ -182,12 +196,14 @@ usage(void)
{
extern char *__progname;
- fprintf(stderr, "usage: %s [-AdeghnNqrROvz] ", __progname);
+ fprintf(stderr, "usage: %s [-AdeghNnOqRrvz] ", __progname);
fprintf(stderr, "[-a anchor[:ruleset]] [-D macro=value]\n");
fprintf(stderr, " ");
- fprintf(stderr, "[-f file] [-F modifier] [-k host] [-s modifier]\n");
+ fprintf(stderr, "[-F modifier] [-f file] [-i interface] ");
+ fprintf(stderr, "[-k host] [-p device]\n");
fprintf(stderr, " ");
- fprintf(stderr, "[-t table] [-T command [address ...]] [-x level]\n");
+ fprintf(stderr, "[-s modifier] [-T command [address ...]] ");
+ fprintf(stderr, "[-t table] [-x level]\n");
exit(1);
}
@@ -246,7 +262,7 @@ pfctl_clear_stats(int dev, int opts)
int
pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname)
{
- struct pfioc_rule pr;
+ struct pfr_buffer t;
if (*anchorname && !*rulesetname) {
struct pfioc_ruleset pr;
@@ -276,19 +292,13 @@ pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname)
fprintf(stderr, "rules cleared\n");
return (0);
}
- memset(&pr, 0, sizeof(pr));
- memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
- memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
- pr.rule.action = PF_SCRUB;
- if (ioctl(dev, DIOCBEGINRULES, &pr))
- err(1, "DIOCBEGINRULES");
- else if (ioctl(dev, DIOCCOMMITRULES, &pr))
- err(1, "DIOCCOMMITRULES");
- pr.rule.action = PF_PASS;
- if (ioctl(dev, DIOCBEGINRULES, &pr))
- err(1, "DIOCBEGINRULES");
- else if (ioctl(dev, DIOCCOMMITRULES, &pr))
- err(1, "DIOCCOMMITRULES");
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname, rulesetname) ||
+ pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname, rulesetname) ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_rules");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "rules cleared\n");
return (0);
@@ -297,7 +307,7 @@ pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname)
int
pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname)
{
- struct pfioc_rule pr;
+ struct pfr_buffer t;
if (*anchorname && !*rulesetname) {
struct pfioc_ruleset pr;
@@ -327,24 +337,14 @@ pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname)
fprintf(stderr, "nat cleared\n");
return (0);
}
- memset(&pr, 0, sizeof(pr));
- memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
- memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
- pr.rule.action = PF_NAT;
- if (ioctl(dev, DIOCBEGINRULES, &pr))
- err(1, "DIOCBEGINRULES");
- else if (ioctl(dev, DIOCCOMMITRULES, &pr))
- err(1, "DIOCCOMMITRULES");
- pr.rule.action = PF_BINAT;
- if (ioctl(dev, DIOCBEGINRULES, &pr))
- err(1, "DIOCBEGINRULES");
- else if (ioctl(dev, DIOCCOMMITRULES, &pr))
- err(1, "DIOCCOMMITRULES");
- pr.rule.action = PF_RDR;
- if (ioctl(dev, DIOCBEGINRULES, &pr))
- err(1, "DIOCBEGINRULES");
- else if (ioctl(dev, DIOCCOMMITRULES, &pr))
- err(1, "DIOCCOMMITRULES");
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname, rulesetname) ||
+ pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname, rulesetname) ||
+ pfctl_add_trans(&t, PF_RULESET_RDR, anchorname, rulesetname) ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_nat");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "nat cleared\n");
return (0);
@@ -353,32 +353,50 @@ pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname)
int
pfctl_clear_altq(int dev, int opts)
{
- struct pfioc_altq pa;
+ struct pfr_buffer t;
if (!altqsupport)
return (-1);
- memset(&pa, 0, sizeof(pa));
- if (ioctl(dev, DIOCBEGINALTQS, &pa.ticket))
- err(1, "DIOCBEGINALTQS");
- else if (ioctl(dev, DIOCCOMMITALTQS, &pa.ticket))
- err(1, "DIOCCOMMITALTQS");
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "", "") ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_altq");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "altq cleared\n");
return (0);
}
int
-pfctl_clear_states(int dev, int opts)
+pfctl_clear_src_nodes(int dev, int opts)
+{
+ if (ioctl(dev, DIOCCLRSRCNODES))
+ err(1, "DIOCCLRSRCNODES");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "source tracking entries cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_states(int dev, const char *iface, int opts)
{
- if (ioctl(dev, DIOCCLRSTATES))
+ struct pfioc_state_kill psk;
+
+ memset(&psk, 0, sizeof(psk));
+ if (iface != NULL && strlcpy(psk.psk_ifname, iface,
+ sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
+ errx(1, "invalid interface: %s", iface);
+
+ if (ioctl(dev, DIOCCLRSTATES, &psk))
err(1, "DIOCCLRSTATES");
if ((opts & PF_OPT_QUIET) == 0)
- fprintf(stderr, "states cleared\n");
+ fprintf(stderr, "%d states cleared\n", psk.psk_af);
return (0);
}
int
-pfctl_kill_states(int dev, int opts)
+pfctl_kill_states(int dev, const char *iface, int opts)
{
struct pfioc_state_kill psk;
struct addrinfo *res[2], *resp[2];
@@ -393,6 +411,9 @@ pfctl_kill_states(int dev, int opts)
sizeof(psk.psk_src.addr.v.a.mask));
memset(&last_src, 0xff, sizeof(last_src));
memset(&last_dst, 0xff, sizeof(last_dst));
+ if (iface != NULL && strlcpy(psk.psk_ifname, iface,
+ sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
+ errx(1, "invalid interface: %s", iface);
if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
@@ -426,7 +447,8 @@ pfctl_kill_states(int dev, int opts)
memset(&last_dst, 0xff, sizeof(last_dst));
if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
&res[1]))) {
- errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
+ errx(1, "getaddrinfo: %s",
+ gai_strerror(ret_ga));
/* NOTREACHED */
}
for (resp[1] = res[1]; resp[1];
@@ -557,12 +579,21 @@ pfctl_print_rule_counters(struct pf_rule *rule, int opts)
(unsigned long long)rule->bytes, rule->states);
}
+void
+pfctl_print_title(char *title)
+{
+ if (!first_title)
+ printf("\n");
+ first_title = 0;
+ printf("%s\n", title);
+}
+
int
pfctl_show_rules(int dev, int opts, int format, char *anchorname,
char *rulesetname)
{
struct pfioc_rule pr;
- u_int32_t nr, mnr;
+ u_int32_t nr, mnr, header = 0;
int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
if (*anchorname && !*rulesetname) {
@@ -579,6 +610,8 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname,
err(1, "DIOCGETRULESETS");
return (-1);
}
+ if (opts & PF_OPT_SHOWALL && pr.nr)
+ pfctl_print_title("FILTER RULES:");
mnr = pr.nr;
for (nr = 0; nr < mnr; ++nr) {
pr.nr = nr;
@@ -595,11 +628,25 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname,
memset(&pr, 0, sizeof(pr));
memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset));
+ if (opts & PF_OPT_SHOWALL) {
+ pr.rule.action = PF_PASS;
+ if (ioctl(dev, DIOCGETRULES, &pr)) {
+ warn("DIOCGETRULES");
+ return (-1);
+ }
+ header++;
+ }
pr.rule.action = PF_SCRUB;
if (ioctl(dev, DIOCGETRULES, &pr)) {
warn("DIOCGETRULES");
return (-1);
}
+ if (opts & PF_OPT_SHOWALL) {
+ if (format == 0 && (pr.nr > 0 || header))
+ pfctl_print_title("FILTER RULES:");
+ else if (format == 1 && labels)
+ pfctl_print_title("LABEL COUNTERS:");
+ }
mnr = pr.nr;
for (nr = 0; nr < mnr; ++nr) {
pr.nr = nr;
@@ -623,6 +670,8 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname,
}
break;
default:
+ if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
+ labels = 1;
print_rule(&pr.rule, rule_numbers);
pfctl_print_rule_counters(&pr.rule, opts);
}
@@ -656,6 +705,8 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname,
}
break;
default:
+ if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
+ labels = 1;
print_rule(&pr.rule, rule_numbers);
pfctl_print_rule_counters(&pr.rule, opts);
}
@@ -670,7 +721,7 @@ pfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname)
struct pfioc_rule pr;
u_int32_t mnr, nr;
static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
- int i;
+ int i, dotitle = opts & PF_OPT_SHOWALL;
if (*anchorname && !*rulesetname) {
struct pfioc_ruleset pr;
@@ -718,6 +769,10 @@ pfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname)
pr.ticket, nattype[i], anchorname,
rulesetname) != 0)
return (-1);
+ if (dotitle) {
+ pfctl_print_title("TRANSLATION RULES:");
+ dotitle = 0;
+ }
print_rule(&pr.rule, opts & PF_OPT_VERBOSE2);
pfctl_print_rule_counters(&pr.rule, opts);
pfctl_clear_pool(&pr.rule.rpool);
@@ -727,21 +782,64 @@ pfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname)
}
int
-pfctl_show_states(int dev, u_int8_t proto, int opts)
+pfctl_show_src_nodes(int dev, int opts)
+{
+ struct pfioc_src_nodes psn;
+ struct pf_src_node *p;
+ char *inbuf = NULL, *newinbuf = NULL;
+ unsigned len = 0;
+ int i;
+
+ memset(&psn, 0, sizeof(psn));
+ for (;;) {
+ psn.psn_len = len;
+ if (len) {
+ newinbuf = realloc(inbuf, len);
+ if (newinbuf == NULL)
+ err(1, "realloc");
+ psn.psn_buf = inbuf = newinbuf;
+ }
+ if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
+ warn("DIOCGETSRCNODES");
+ return (-1);
+ }
+ if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
+ break;
+ if (len == 0 && psn.psn_len == 0)
+ return (0);
+ if (len == 0 && psn.psn_len != 0)
+ len = psn.psn_len;
+ if (psn.psn_len == 0)
+ return (0); /* no src_nodes */
+ len *= 2;
+ }
+ p = psn.psn_src_nodes;
+ if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
+ pfctl_print_title("SOURCE TRACKING NODES:");
+ for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
+ print_src_node(p, opts);
+ p++;
+ }
+ return (0);
+}
+
+int
+pfctl_show_states(int dev, const char *iface, int opts)
{
struct pfioc_states ps;
struct pf_state *p;
- char *inbuf = NULL;
+ char *inbuf = NULL, *newinbuf = NULL;
unsigned len = 0;
- int i;
+ int i, dotitle = (opts & PF_OPT_SHOWALL);
memset(&ps, 0, sizeof(ps));
for (;;) {
ps.ps_len = len;
if (len) {
- ps.ps_buf = inbuf = realloc(inbuf, len);
- if (inbuf == NULL)
+ newinbuf = realloc(inbuf, len);
+ if (newinbuf == NULL)
err(1, "realloc");
+ ps.ps_buf = inbuf = newinbuf;
}
if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
warn("DIOCGETSTATES");
@@ -758,16 +856,20 @@ pfctl_show_states(int dev, u_int8_t proto, int opts)
len *= 2;
}
p = ps.ps_states;
- for (i = 0; i < ps.ps_len; i += sizeof(*p)) {
- if (!proto || (p->proto == proto))
- print_state(p, opts);
- p++;
+ for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
+ if (iface != NULL && strcmp(p->u.ifname, iface))
+ continue;
+ if (dotitle) {
+ pfctl_print_title("STATES:");
+ dotitle = 0;
+ }
+ print_state(p, opts);
}
return (0);
}
int
-pfctl_show_status(int dev)
+pfctl_show_status(int dev, int opts)
{
struct pf_status status;
@@ -775,16 +877,20 @@ pfctl_show_status(int dev)
warn("DIOCGETSTATUS");
return (-1);
}
- print_status(&status);
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("INFO:");
+ print_status(&status, opts);
return (0);
}
int
-pfctl_show_timeouts(int dev)
+pfctl_show_timeouts(int dev, int opts)
{
struct pfioc_tm pt;
int i;
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("TIMEOUTS:");
memset(&pt, 0, sizeof(pt));
for (i = 0; pf_timeouts[i].name; i++) {
pt.timeout = pf_timeouts[i].timeout;
@@ -802,14 +908,16 @@ pfctl_show_timeouts(int dev)
}
int
-pfctl_show_limits(int dev)
+pfctl_show_limits(int dev, int opts)
{
struct pfioc_limit pl;
int i;
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("LIMITS:");
memset(&pl, 0, sizeof(pl));
for (i = 0; pf_limits[i].name; i++) {
- pl.index = i;
+ pl.index = pf_limits[i].index;
if (ioctl(dev, DIOCGETLIMIT, &pl))
err(1, "DIOCGETLIMIT");
printf("%-10s ", pf_limits[i].name);
@@ -846,7 +954,8 @@ pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
int
pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
{
- u_int8_t rs_num;
+ u_int8_t rs_num;
+ struct pfioc_rule pr;
switch (r->action) {
case PF_SCRUB:
@@ -884,12 +993,19 @@ pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
}
if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ bzero(&pr, sizeof(pr));
+ if (strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor)) >=
+ sizeof(pr.anchor) ||
+ strlcpy(pr.ruleset, pf->ruleset, sizeof(pr.ruleset)) >=
+ sizeof(pr.ruleset))
+ errx(1, "pfctl_add_rule: strlcpy");
if (pfctl_add_pool(pf, &r->rpool, r->af))
return (1);
- memcpy(&pf->prule[rs_num]->rule, r,
- sizeof(pf->prule[rs_num]->rule));
- pf->prule[rs_num]->pool_ticket = pf->paddr.ticket;
- if (ioctl(pf->dev, DIOCADDRULE, pf->prule[rs_num]))
+ pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor,
+ pf->ruleset);
+ pr.pool_ticket = pf->paddr.ticket;
+ memcpy(&pr.rule, r, sizeof(pr.rule));
+ if (ioctl(pf->dev, DIOCADDRULE, &pr))
err(1, "DIOCADDRULE");
}
if (pf->opts & PF_OPT_VERBOSE)
@@ -922,26 +1038,31 @@ pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
int
pfctl_rules(int dev, char *filename, int opts, char *anchorname,
- char *rulesetname)
+ char *rulesetname, struct pfr_buffer *trans)
{
#define ERR(x) do { warn(x); goto _error; } while(0)
#define ERRX(x) do { warnx(x); goto _error; } while(0)
- FILE *fin;
- struct pfioc_rule pr[PF_RULESET_MAX];
- struct pfioc_altq pa;
- struct pfctl pf;
- struct pfr_table trs;
- int i;
+ FILE *fin;
+ struct pfr_buffer *t, buf;
+ struct pfioc_altq pa;
+ struct pfctl pf;
+ struct pfr_table trs;
+ int osize;
+
+ if (trans == NULL) {
+ bzero(&buf, sizeof(buf));
+ buf.pfrb_type = PFRB_TRANS;
+ t = &buf;
+ osize = 0;
+ } else {
+ t = trans;
+ osize = t->pfrb_size;
+ }
memset(&pa, 0, sizeof(pa));
memset(&pf, 0, sizeof(pf));
memset(&trs, 0, sizeof(trs));
- for (i = 0; i < PF_RULESET_MAX; i++) {
- memset(&pr[i], 0, sizeof(pr[i]));
- memcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor));
- memcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset));
- }
if (strlcpy(trs.pfrt_anchor, anchorname,
sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor) ||
strlcpy(trs.pfrt_ruleset, rulesetname,
@@ -957,46 +1078,53 @@ pfctl_rules(int dev, char *filename, int opts, char *anchorname,
}
infile = filename;
}
- if ((opts & PF_OPT_NOACTION) == 0) {
- if ((loadopt & PFCTL_FLAG_NAT) != 0) {
- pr[PF_RULESET_NAT].rule.action = PF_NAT;
- if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_NAT]))
- ERR("DIOCBEGINRULES");
- pr[PF_RULESET_RDR].rule.action = PF_RDR;
- if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_RDR]))
- ERR("DIOCBEGINRULES");
- pr[PF_RULESET_BINAT].rule.action = PF_BINAT;
- if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_BINAT]))
- ERR("DIOCBEGINRULES");
- }
- if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) &&
- ioctl(dev, DIOCBEGINALTQS, &pa.ticket)) {
- ERR("DIOCBEGINALTQS");
- }
- if ((loadopt & PFCTL_FLAG_FILTER) != 0) {
- pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB;
- if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_SCRUB]))
- ERR("DIOCBEGINRULES");
- pr[PF_RULESET_FILTER].rule.action = PF_PASS;
- if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_FILTER]))
- ERR("DIOCBEGINRULES");
- }
- if (loadopt & PFCTL_FLAG_TABLE) {
- if (pfr_ina_begin(&trs, &pf.tticket, NULL, 0) != 0)
- ERR("begin table");
- }
- }
- /* fill in callback data */
pf.dev = dev;
pf.opts = opts;
pf.loadopt = loadopt;
+ if (anchorname[0])
+ pf.loadopt &= ~PFCTL_FLAG_ALTQ;
pf.paltq = &pa;
- for (i = 0; i < PF_RULESET_MAX; i++) {
- pf.prule[i] = &pr[i];
- }
+ pf.trans = t;
pf.rule_nr = 0;
pf.anchor = anchorname;
pf.ruleset = rulesetname;
+
+ if ((opts & PF_OPT_NOACTION) == 0) {
+ if ((pf.loadopt & PFCTL_FLAG_NAT) != 0) {
+ if (pfctl_add_trans(t, PF_RULESET_NAT, anchorname,
+ rulesetname) ||
+ pfctl_add_trans(t, PF_RULESET_BINAT, anchorname,
+ rulesetname) ||
+ pfctl_add_trans(t, PF_RULESET_RDR, anchorname,
+ rulesetname))
+ ERR("pfctl_rules");
+ }
+ if (((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))) {
+ if (pfctl_add_trans(t, PF_RULESET_ALTQ, anchorname,
+ rulesetname))
+ ERR("pfctl_rules");
+ }
+ if ((pf.loadopt & PFCTL_FLAG_FILTER) != 0) {
+ if (pfctl_add_trans(t, PF_RULESET_SCRUB, anchorname,
+ rulesetname) ||
+ pfctl_add_trans(t, PF_RULESET_FILTER, anchorname,
+ rulesetname))
+ ERR("pfctl_rules");
+ }
+ if (pf.loadopt & PFCTL_FLAG_TABLE) {
+ if (pfctl_add_trans(t, PF_RULESET_TABLE, anchorname,
+ rulesetname))
+ ERR("pfctl_rules");
+ }
+ if (pfctl_trans(dev, t, DIOCXBEGIN, osize))
+ ERR("DIOCXBEGIN");
+ if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
+ pa.ticket = pfctl_get_ticket(t, PF_RULESET_ALTQ,
+ anchorname, rulesetname);
+ if (pf.loadopt & PFCTL_FLAG_TABLE)
+ pf.tticket = pfctl_get_ticket(t, PF_RULESET_TABLE,
+ anchorname, rulesetname);
+ }
if (parse_rules(fin, &pf) < 0) {
if ((opts & PF_OPT_NOACTION) == 0)
ERRX("Syntax error in config file: "
@@ -1004,57 +1132,30 @@ pfctl_rules(int dev, char *filename, int opts, char *anchorname,
else
goto _error;
}
- if ((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0))
+ if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
if (check_commit_altq(dev, opts) != 0)
ERRX("errors in altq config");
- if ((opts & PF_OPT_NOACTION) == 0) {
- if ((loadopt & PFCTL_FLAG_NAT) != 0) {
- pr[PF_RULESET_NAT].rule.action = PF_NAT;
- if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_NAT]) &&
- (errno != EINVAL || pf.rule_nr))
- ERR("DIOCCOMMITRULES NAT");
- pr[PF_RULESET_RDR].rule.action = PF_RDR;
- if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_RDR]) &&
- (errno != EINVAL || pf.rule_nr))
- ERR("DIOCCOMMITRULES RDR");
- pr[PF_RULESET_BINAT].rule.action = PF_BINAT;
- if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_BINAT]) &&
- (errno != EINVAL || pf.rule_nr))
- ERR("DIOCCOMMITRULES BINAT");
- }
- if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) &&
- ioctl(dev, DIOCCOMMITALTQS, &pa.ticket))
- ERR("DIOCCOMMITALTQS");
- if ((loadopt & PFCTL_FLAG_FILTER) != 0) {
- pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB;
- if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_SCRUB]) &&
- (errno != EINVAL || pf.rule_nr))
- ERR("DIOCCOMMITRULES SCRUB");
- pr[PF_RULESET_FILTER].rule.action = PF_PASS;
- if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_FILTER]) &&
- (errno != EINVAL || pf.rule_nr))
- ERR("DIOCCOMMITRULES FILTER");
- }
- if (loadopt & PFCTL_FLAG_TABLE) {
- if (pfr_ina_commit(&trs, pf.tticket, NULL, NULL, 0))
- ERR("commit table");
- pf.tdirty = 0;
- }
- }
if (fin != stdin)
fclose(fin);
/* process "load anchor" directives */
if (!anchorname[0] && !rulesetname[0])
- if (pfctl_load_anchors(dev, opts) == -1)
+ if (pfctl_load_anchors(dev, opts, t) == -1)
ERRX("load anchors");
+ if (trans == NULL && (opts & PF_OPT_NOACTION) == 0)
+ if (pfctl_trans(dev, t, DIOCXCOMMIT, 0))
+ ERR("DIOCXCOMMIT");
return (0);
_error:
- if (pf.tdirty) /* cleanup kernel leftover */
- pfr_ina_begin(&trs, NULL, NULL, 0);
- exit(1);
+ if (trans == NULL) { /* main ruleset */
+ if ((opts & PF_OPT_NOACTION) == 0)
+ if (pfctl_trans(dev, t, DIOCXROLLBACK, 0))
+ err(1, "DIOCXROLLBACK");
+ exit(1);
+ } else /* sub ruleset */
+ return (-1);
#undef ERR
#undef ERRX
@@ -1072,7 +1173,7 @@ pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
memset(&pl, 0, sizeof(pl));
for (i = 0; pf_limits[i].name; i++) {
if (strcasecmp(opt, pf_limits[i].name) == 0) {
- pl.index = i;
+ pl.index = pf_limits[i].index;
pl.limit = limit;
if ((pf->opts & PF_OPT_NOACTION) == 0) {
if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
@@ -1191,6 +1292,55 @@ pfctl_set_logif(struct pfctl *pf, char *ifname)
}
int
+pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
+{
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ HTONL(hostid);
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0)
+ if (ioctl(dev, DIOCSETHOSTID, &hostid))
+ err(1, "DIOCSETHOSTID");
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set hostid 0x%08x\n", ntohl(hostid));
+
+ return (0);
+}
+
+int
+pfctl_set_debug(struct pfctl *pf, char *d)
+{
+ u_int32_t level;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ if (!strcmp(d, "none"))
+ level = PF_DEBUG_NONE;
+ else if (!strcmp(d, "urgent"))
+ level = PF_DEBUG_URGENT;
+ else if (!strcmp(d, "misc"))
+ level = PF_DEBUG_MISC;
+ else if (!strcmp(d, "loud"))
+ level = PF_DEBUG_NOISY;
+ else {
+ warnx("unknown debug level \"%s\"", d);
+ return (-1);
+ }
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0)
+ if (ioctl(dev, DIOCSETDEBUG, &level))
+ err(1, "DIOCSETDEBUG");
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set debug %s\n", d);
+
+ return (0);
+}
+
+int
pfctl_debug(int dev, u_int32_t level, int opts)
{
if (ioctl(dev, DIOCSETDEBUG, &level))
@@ -1264,14 +1414,15 @@ pfctl_show_anchors(int dev, int opts, char *anchorname)
return (-1);
}
mnr = pa.nr;
- if (!(opts & PF_OPT_QUIET))
- printf("%u anchors:\n", mnr);
for (nr = 0; nr < mnr; ++nr) {
pa.nr = nr;
if (ioctl(dev, DIOCGETANCHOR, &pa)) {
warn("DIOCGETANCHOR");
return (-1);
}
+ if (!(opts & PF_OPT_VERBOSE) &&
+ !strcmp(pa.name, PF_RESERVED_ANCHOR))
+ continue;
printf(" %s\n", pa.name);
}
} else {
@@ -1288,8 +1439,6 @@ pfctl_show_anchors(int dev, int opts, char *anchorname)
return (-1);
}
mnr = pr.nr;
- if (!(opts & PF_OPT_QUIET))
- printf("%u rulesets in anchor %s:\n", mnr, anchorname);
for (nr = 0; nr < mnr; ++nr) {
pr.nr = nr;
if (ioctl(dev, DIOCGETRULESET, &pr))
@@ -1323,8 +1472,8 @@ main(int argc, char *argv[])
if (argc < 2)
usage();
- while ((ch = getopt(argc, argv, "a:AdD:eqf:F:ghk:nNOrRs:t:T:vx:z")) !=
- -1) {
+ while ((ch = getopt(argc, argv,
+ "a:AdD:eqf:F:ghi:k:nNOp:rRs:t:T:vx:z")) != -1) {
switch (ch) {
case 'a':
anchoropt = optarg;
@@ -1353,6 +1502,9 @@ main(int argc, char *argv[])
}
mode = O_RDWR;
break;
+ case 'i':
+ ifaceopt = optarg;
+ break;
case 'k':
if (state_killers >= 2) {
warnx("can only specify -k twice");
@@ -1387,6 +1539,9 @@ main(int argc, char *argv[])
case 'O':
loadopt |= PFCTL_FLAG_OPTION;
break;
+ case 'p':
+ pf_device = optarg;
+ break;
case 's':
showopt = pfctl_lookup_option(optarg, showopt_list);
if (showopt == NULL) {
@@ -1436,14 +1591,8 @@ main(int argc, char *argv[])
if (ch == 'l') {
loadopt |= PFCTL_FLAG_TABLE;
tblcmdopt = NULL;
- } else {
+ } else
mode = strchr("acdfkrz", ch) ? O_RDWR : O_RDONLY;
- if (opts & PF_OPT_NOACTION) {
- dev = open("/dev/pf", mode);
- if (dev >= 0)
- opts |= PF_OPT_DUMMYACTION;
- }
- }
} else if (argc != optind) {
warnx("unknown command line argument: %s ...", argv[optind]);
usage();
@@ -1482,11 +1631,14 @@ main(int argc, char *argv[])
}
if ((opts & PF_OPT_NOACTION) == 0) {
- dev = open("/dev/pf", mode);
+ dev = open(pf_device, mode);
if (dev == -1)
- err(1, "/dev/pf");
+ err(1, "%s", pf_device);
altqsupport = pfctl_test_altqsupport(dev, opts);
} else {
+ dev = open(pf_device, O_RDONLY);
+ if (dev >= 0)
+ opts |= PF_OPT_DUMMYACTION;
/* turn off options */
opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
clearopt = showopt = debugopt = NULL;
@@ -1521,32 +1673,38 @@ main(int argc, char *argv[])
pfctl_show_nat(dev, opts, anchorname, rulesetname);
break;
case 'q':
- pfctl_show_altq(dev, opts, opts & PF_OPT_VERBOSE2);
+ pfctl_show_altq(dev, ifaceopt, opts,
+ opts & PF_OPT_VERBOSE2);
break;
case 's':
- pfctl_show_states(dev, 0, opts);
+ pfctl_show_states(dev, ifaceopt, opts);
+ break;
+ case 'S':
+ pfctl_show_src_nodes(dev, opts);
break;
case 'i':
- pfctl_show_status(dev);
+ pfctl_show_status(dev, opts);
break;
case 't':
- pfctl_show_timeouts(dev);
+ pfctl_show_timeouts(dev, opts);
break;
case 'm':
- pfctl_show_limits(dev);
+ pfctl_show_limits(dev, opts);
break;
case 'a':
+ opts |= PF_OPT_SHOWALL;
pfctl_load_fingerprints(dev, opts);
+ pfctl_show_nat(dev, opts, anchorname, rulesetname);
pfctl_show_rules(dev, opts, 0, anchorname,
rulesetname);
- pfctl_show_nat(dev, opts, anchorname, rulesetname);
- pfctl_show_altq(dev, opts, 0);
- pfctl_show_states(dev, 0, opts);
- pfctl_show_status(dev);
+ pfctl_show_altq(dev, ifaceopt, opts, 0);
+ pfctl_show_states(dev, ifaceopt, opts);
+ pfctl_show_src_nodes(dev, opts);
+ pfctl_show_status(dev, opts);
pfctl_show_rules(dev, opts, 1, anchorname, rulesetname);
- pfctl_show_timeouts(dev);
- pfctl_show_limits(dev);
+ pfctl_show_timeouts(dev, opts);
+ pfctl_show_limits(dev, opts);
pfctl_show_tables(anchorname, rulesetname, opts);
pfctl_show_fingerprints(opts);
break;
@@ -1557,6 +1715,9 @@ main(int argc, char *argv[])
pfctl_load_fingerprints(dev, opts);
pfctl_show_fingerprints(opts);
break;
+ case 'I':
+ pfctl_show_ifaces(ifaceopt, opts);
+ break;
}
}
@@ -1572,7 +1733,10 @@ main(int argc, char *argv[])
pfctl_clear_altq(dev, opts);
break;
case 's':
- pfctl_clear_states(dev, opts);
+ pfctl_clear_states(dev, ifaceopt, opts);
+ break;
+ case 'S':
+ pfctl_clear_src_nodes(dev, opts);
break;
case 'i':
pfctl_clear_stats(dev, opts);
@@ -1580,11 +1744,14 @@ main(int argc, char *argv[])
case 'a':
pfctl_clear_rules(dev, opts, anchorname, rulesetname);
pfctl_clear_nat(dev, opts, anchorname, rulesetname);
- pfctl_clear_altq(dev, opts);
- pfctl_clear_states(dev, opts);
- pfctl_clear_stats(dev, opts);
pfctl_clear_tables(anchorname, rulesetname, opts);
- pfctl_clear_fingerprints(dev, opts);
+ if (!*anchorname && !*rulesetname) {
+ pfctl_clear_altq(dev, opts);
+ pfctl_clear_states(dev, ifaceopt, opts);
+ pfctl_clear_src_nodes(dev, opts);
+ pfctl_clear_stats(dev, opts);
+ pfctl_clear_fingerprints(dev, opts);
+ }
break;
case 'o':
pfctl_clear_fingerprints(dev, opts);
@@ -1595,7 +1762,7 @@ main(int argc, char *argv[])
}
}
if (state_killers)
- pfctl_kill_states(dev, opts);
+ pfctl_kill_states(dev, ifaceopt, opts);
if (tblcmdopt != NULL) {
error = pfctl_command_tables(argc, argv, tableopt,
@@ -1608,7 +1775,8 @@ main(int argc, char *argv[])
error = 1;
if (rulesopt != NULL) {
- if (pfctl_rules(dev, rulesopt, opts, anchorname, rulesetname))
+ if (pfctl_rules(dev, rulesopt, opts, anchorname, rulesetname,
+ NULL))
error = 1;
else if (!(opts & PF_OPT_NOACTION) &&
(loadopt & PFCTL_FLAG_TABLE))
diff --git a/contrib/pf/pfctl/pfctl.h b/contrib/pf/pfctl/pfctl.h
index 7ec0c3b..2776f5e 100644
--- a/contrib/pf/pfctl/pfctl.h
+++ b/contrib/pf/pfctl/pfctl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.h,v 1.25 2003/08/29 21:47:36 cedric Exp $ */
+/* $OpenBSD: pfctl.h,v 1.33 2004/02/19 21:37:01 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -34,7 +34,8 @@
#ifndef _PFCTL_H_
#define _PFCTL_H_
-enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS, PFRB_MAX };
+enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS,
+ PFRB_IFACES, PFRB_TRANS, PFRB_MAX };
struct pfr_buffer {
int pfrb_type; /* type of content, see enum above */
int pfrb_size; /* number of objects in buffer */
@@ -58,7 +59,7 @@ int pfr_clr_addrs(struct pfr_table *, int *, int);
int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
- int *, int *, int *, int);
+ int *, int *, int *, int);
int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int);
int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int);
int pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *, int);
@@ -75,13 +76,17 @@ int pfr_buf_grow(struct pfr_buffer *, int);
int pfr_buf_load(struct pfr_buffer *, char *, int,
int (*)(struct pfr_buffer *, char *, int));
char *pfr_strerror(int);
+int pfi_get_ifaces(const char *, struct pfi_if *, int *, int);
+int pfi_clr_istats(const char *, int *, int);
+void pfctl_print_title(char *);
int pfctl_clear_tables(const char *, const char *, int);
int pfctl_show_tables(const char *, const char *, int);
int pfctl_command_tables(int, char *[], char *, const char *, char *,
const char *, const char *, int);
-int pfctl_show_altq(int, int, int);
+int pfctl_show_altq(int, const char *, int, int);
void warn_namespace_collision(const char *);
+int pfctl_show_ifaces(const char *, int);
#ifdef __FreeBSD__
extern int altqsupport;
@@ -116,5 +121,9 @@ void print_state(struct pf_state *, int);
int unmask(struct pf_addr *, sa_family_t);
int pfctl_cmdline_symset(char *);
+int pfctl_add_trans(struct pfr_buffer *, int, const char *, const char *);
+u_int32_t
+ pfctl_get_ticket(struct pfr_buffer *, int, const char *, const char *);
+int pfctl_trans(int, struct pfr_buffer *, u_long, int);
#endif /* _PFCTL_H_ */
diff --git a/contrib/pf/pfctl/pfctl_altq.c b/contrib/pf/pfctl/pfctl_altq.c
index 534902b..eeed648 100644
--- a/contrib/pf/pfctl/pfctl_altq.c
+++ b/contrib/pf/pfctl/pfctl_altq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_altq.c,v 1.77 2003/08/22 21:50:34 david Exp $ */
+/* $OpenBSD: pfctl_altq.c,v 1.83 2004/03/14 21:51:44 dhartmei Exp $ */
/*
* Copyright (c) 2002
@@ -89,8 +89,6 @@ u_int32_t eval_bwspec(struct node_queue_bw *, u_int32_t);
void print_hfsc_sc(const char *, u_int, u_int, u_int,
const struct node_hfsc_sc *);
-static u_int32_t max_qid = 1;
-
void
pfaltq_store(struct pf_altq *a)
{
@@ -165,14 +163,14 @@ void
print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw,
struct node_queue_opt *qopts)
{
- if (a->qname[0] != '\0') {
+ if (a->qname[0] != 0) {
print_queue(a, level, bw, 0, qopts);
return;
}
printf("altq on %s ", a->ifname);
- switch(a->scheduler) {
+ switch (a->scheduler) {
case ALTQT_CBQ:
if (!print_cbq_opts(a))
printf("cbq ");
@@ -272,6 +270,8 @@ eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
else
size = 24;
size = size * getifmtu(pa->ifname);
+ if (size > 0xffff)
+ size = 0xffff;
pa->tbrsize = size;
}
return (errors);
@@ -421,8 +421,6 @@ eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa)
if (pa->parent[0] == 0)
opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR);
- else if (pa->qid == 0 && (opts->flags & CBQCLF_DEFCLASS) == 0)
- pa->qid = ++max_qid;
cbq_compute_idletime(pf, pa);
return (0);
@@ -496,9 +494,12 @@ cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa)
minidle = -((double)opts->maxpktsize * (double)nsPerByte);
/* scale parameters */
- maxidle = ((maxidle * 8.0) / nsPerByte) * pow(2.0, (double)RM_FILTER_GAIN);
- offtime = (offtime * 8.0) / nsPerByte * pow(2.0, (double)RM_FILTER_GAIN);
- minidle = ((minidle * 8.0) / nsPerByte) * pow(2.0, (double)RM_FILTER_GAIN);
+ maxidle = ((maxidle * 8.0) / nsPerByte) *
+ pow(2.0, (double)RM_FILTER_GAIN);
+ offtime = (offtime * 8.0) / nsPerByte *
+ pow(2.0, (double)RM_FILTER_GAIN);
+ minidle = ((minidle * 8.0) / nsPerByte) *
+ pow(2.0, (double)RM_FILTER_GAIN);
maxidle = maxidle / 1000.0;
offtime = offtime / 1000.0;
@@ -506,10 +507,10 @@ cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa)
opts->minburst = minburst;
opts->maxburst = maxburst;
- opts->ns_per_byte = (u_int) nsPerByte;
- opts->maxidle = (u_int) fabs(maxidle);
+ opts->ns_per_byte = (u_int)nsPerByte;
+ opts->maxidle = (u_int)fabs(maxidle);
opts->minidle = (int)minidle;
- opts->offtime = (u_int) fabs(offtime);
+ opts->offtime = (u_int)fabs(offtime);
return (0);
}
@@ -604,9 +605,6 @@ eval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa)
}
}
- if (pa->qid == 0)
- pa->qid = ++max_qid;
-
return (0);
}
@@ -676,13 +674,11 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
if (pa->parent[0] == 0) {
/* root queue */
- pa->qid = HFSC_ROOTCLASS_HANDLE;
opts->lssc_m1 = pa->ifbandwidth;
opts->lssc_m2 = pa->ifbandwidth;
opts->lssc_d = 0;
return (0);
- } else if (pa->qid == 0)
- pa->qid = ++max_qid;
+ }
LIST_INIT(&rtsc);
LIST_INIT(&lssc);
@@ -729,7 +725,7 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
/* if the class has a real-time service curve, add it. */
if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) {
sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1;
- sc.d = altq->pq_u.hfsc_opts.rtsc_d;
+ sc.d = altq->pq_u.hfsc_opts.rtsc_d;
sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2;
gsc_add_sc(&rtsc, &sc);
}
@@ -740,7 +736,7 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
/* if the class has a link-sharing service curve, add it. */
if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) {
sc.m1 = altq->pq_u.hfsc_opts.lssc_m1;
- sc.d = altq->pq_u.hfsc_opts.lssc_d;
+ sc.d = altq->pq_u.hfsc_opts.lssc_d;
sc.m2 = altq->pq_u.hfsc_opts.lssc_m2;
gsc_add_sc(&lssc, &sc);
}
@@ -749,7 +745,7 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
/* check the real-time service curve. reserve 20% of interface bw */
if (opts->rtsc_m2 != 0) {
sc.m1 = 0;
- sc.d = 0;
+ sc.d = 0;
sc.m2 = pa->ifbandwidth / 100 * 80;
if (!is_gsc_under_sc(&rtsc, &sc)) {
warnx("real-time sc exceeds the interface bandwidth");
@@ -760,7 +756,7 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
/* check the link-sharing service curve. */
if (opts->lssc_m2 != 0) {
sc.m1 = parent->pq_u.hfsc_opts.lssc_m1;
- sc.d = parent->pq_u.hfsc_opts.lssc_d;
+ sc.d = parent->pq_u.hfsc_opts.lssc_d;
sc.m2 = parent->pq_u.hfsc_opts.lssc_m2;
if (!is_gsc_under_sc(&lssc, &sc)) {
warnx("link-sharing sc exceeds parent's sc");
@@ -1020,7 +1016,7 @@ gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m)
else
x2 = x + d;
start = gsc_getentry(gsc, x);
- end = gsc_getentry(gsc, x2);
+ end = gsc_getentry(gsc, x2);
if (start == NULL || end == NULL)
return (-1);
diff --git a/contrib/pf/pfctl/pfctl_parser.c b/contrib/pf/pfctl/pfctl_parser.c
index 61b47f5..203ec7e 100644
--- a/contrib/pf/pfctl/pfctl_parser.c
+++ b/contrib/pf/pfctl/pfctl_parser.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: pfctl_parser.c,v 1.175 2003/09/18 20:27:58 cedric Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.194 2004/03/15 15:25:44 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
+ * Copyright (c) 2002,2003 Henning Brauer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,6 +35,7 @@
__FBSDID("$FreeBSD$");
#include <sys/types.h>
+#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -196,6 +198,7 @@ const struct pf_timeout pf_timeouts[] = {
{ "interval", PFTM_INTERVAL },
{ "adaptive.start", PFTM_ADAPTIVE_START },
{ "adaptive.end", PFTM_ADAPTIVE_END },
+ { "src.track", PFTM_SRC_NODE },
{ NULL, 0 }
};
@@ -255,7 +258,7 @@ geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af)
}
} else {
for (i=0; i < (sizeof (icmp6_code) /
- sizeof(icmp6_code[0])); i++) {
+ sizeof(icmp6_code[0])); i++) {
if (type == icmp6_code[i].type &&
code == icmp6_code[i].code)
return (&icmp6_code[i]);
@@ -462,23 +465,27 @@ print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2,
printf(" round-robin");
break;
}
+ if (pool->opts & PF_POOL_STICKYADDR)
+ printf(" sticky-address");
if (id == PF_NAT && p1 == 0 && p2 == 0)
printf(" static-port");
}
const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
+const char *pf_scounters[FCNT_MAX+1] = FCNT_NAMES;
void
-print_status(struct pf_status *s)
+print_status(struct pf_status *s, int opts)
{
- char statline[80];
+ char statline[80], *running;
time_t runtime;
int i;
runtime = time(NULL) - s->since;
+ running = s->running ? "Enabled" : "Disabled";
- if (s->running) {
+ if (s->since) {
unsigned sec, min, hrs, day = runtime;
sec = day % 60;
@@ -488,22 +495,26 @@ print_status(struct pf_status *s)
hrs = day % 24;
day /= 24;
snprintf(statline, sizeof(statline),
- "Status: Enabled for %u days %.2u:%.2u:%.2u",
- day, hrs, min, sec);
+ "Status: %s for %u days %.2u:%.2u:%.2u",
+ running, day, hrs, min, sec);
} else
- snprintf(statline, sizeof(statline), "Status: Disabled");
+ snprintf(statline, sizeof(statline), "Status: %s", running);
printf("%-44s", statline);
switch (s->debug) {
- case 0:
+ case PF_DEBUG_NONE:
printf("%15s\n\n", "Debug: None");
break;
- case 1:
+ case PF_DEBUG_URGENT:
printf("%15s\n\n", "Debug: Urgent");
break;
- case 2:
+ case PF_DEBUG_MISC:
printf("%15s\n\n", "Debug: Misc");
break;
+ case PF_DEBUG_NOISY:
+ printf("%15s\n\n", "Debug: Loud");
+ break;
}
+ printf("Hostid: 0x%08x\n\n", ntohl(s->hostid));
if (s->ifname[0] != 0) {
printf("Interface Stats for %-16s %5s %16s\n",
s->ifname, "IPv4", "IPv6");
@@ -539,6 +550,20 @@ print_status(struct pf_status *s)
else
printf("%14s\n", "");
}
+ if (opts & PF_OPT_VERBOSE) {
+ printf("Source Tracking Table\n");
+ printf(" %-25s %14u %14s\n", "current entries",
+ s->src_nodes, "");
+ for (i = 0; i < SCNT_MAX; i++) {
+ printf(" %-25s %14lld ", pf_scounters[i],
+ s->scounters[i]);
+ if (runtime > 0)
+ printf("%14.1f/s\n",
+ (double)s->scounters[i] / (double)runtime);
+ else
+ printf("%14s\n", "");
+ }
+ }
printf("Counters\n");
for (i = 0; i < PFRES_MAX; i++) {
printf(" %-25s %14llu ", pf_reasons[i],
@@ -552,6 +577,57 @@ print_status(struct pf_status *s)
}
void
+print_src_node(struct pf_src_node *sn, int opts)
+{
+ struct pf_addr_wrap aw;
+ int min, sec;
+
+ memset(&aw, 0, sizeof(aw));
+ if (sn->af == AF_INET)
+ aw.v.a.mask.addr32[0] = 0xffffffff;
+ else
+ memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask));
+
+ aw.v.a.addr = sn->addr;
+ print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2);
+ printf(" -> ");
+ aw.v.a.addr = sn->raddr;
+ print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2);
+ printf(" (%d states)\n", sn->states);
+ if (opts & PF_OPT_VERBOSE) {
+ sec = sn->creation % 60;
+ sn->creation /= 60;
+ min = sn->creation % 60;
+ sn->creation /= 60;
+ printf(" age %.2u:%.2u:%.2u", sn->creation, min, sec);
+ if (sn->states == 0) {
+ sec = sn->expire % 60;
+ sn->expire /= 60;
+ min = sn->expire % 60;
+ sn->expire /= 60;
+ printf(", expires in %.2u:%.2u:%.2u",
+ sn->expire, min, sec);
+ }
+ printf(", %u pkts, %u bytes", sn->packets, sn->bytes);
+ switch (sn->ruletype) {
+ case PF_NAT:
+ if (sn->rule.nr != -1)
+ printf(", nat rule %u", sn->rule.nr);
+ break;
+ case PF_RDR:
+ if (sn->rule.nr != -1)
+ printf(", rdr rule %u", sn->rule.nr);
+ break;
+ case PF_PASS:
+ if (sn->rule.nr != -1)
+ printf(", filter rule %u", sn->rule.nr);
+ break;
+ }
+ printf("\n");
+ }
+}
+
+void
print_rule(struct pf_rule *r, int verbose)
{
static const char *actiontypes[] = { "pass", "block", "scrub", "nat",
@@ -588,7 +664,7 @@ print_rule(struct pf_rule *r, int verbose)
ic6 = geticmpcodebynumber(r->return_icmp6 >> 8,
r->return_icmp6 & 255, AF_INET6);
- switch(r->af) {
+ switch (r->af) {
case AF_INET:
printf(" return-icmp");
if (ic == NULL)
@@ -707,7 +783,13 @@ print_rule(struct pf_rule *r, int verbose)
else if (r->keep_state == PF_STATE_SYNPROXY)
printf(" synproxy state");
opts = 0;
- if (r->max_states)
+ if (r->max_states || r->max_src_nodes || r->max_src_states)
+ opts = 1;
+ if (r->rule_flag & PFRULE_NOSYNC)
+ opts = 1;
+ if (r->rule_flag & PFRULE_SRCTRACK)
+ opts = 1;
+ if (r->rule_flag & (PFRULE_IFBOUND | PFRULE_GRBOUND))
opts = 1;
for (i = 0; !opts && i < PFTM_MAX; ++i)
if (r->timeout[i])
@@ -718,6 +800,46 @@ print_rule(struct pf_rule *r, int verbose)
printf("max %u", r->max_states);
opts = 0;
}
+ if (r->rule_flag & PFRULE_NOSYNC) {
+ if (!opts)
+ printf(", ");
+ printf("no-sync");
+ opts = 0;
+ }
+ if (r->rule_flag & PFRULE_SRCTRACK) {
+ if (!opts)
+ printf(", ");
+ printf("source-track");
+ if (r->rule_flag & PFRULE_RULESRCTRACK)
+ printf(" rule");
+ else
+ printf(" global");
+ opts = 0;
+ }
+ if (r->max_src_states) {
+ if (!opts)
+ printf(", ");
+ printf("max-src-states %u", r->max_src_states);
+ opts = 0;
+ }
+ if (r->max_src_nodes) {
+ if (!opts)
+ printf(", ");
+ printf("max-src-nodes %u", r->max_src_nodes);
+ opts = 0;
+ }
+ if (r->rule_flag & PFRULE_IFBOUND) {
+ if (!opts)
+ printf(", ");
+ printf("if-bound");
+ opts = 0;
+ }
+ if (r->rule_flag & PFRULE_GRBOUND) {
+ if (!opts)
+ printf(", ");
+ printf("group-bound");
+ opts = 0;
+ }
for (i = 0; i < PFTM_MAX; ++i)
if (r->timeout[i]) {
if (!opts)
@@ -885,6 +1007,8 @@ ifa_load(void)
{
struct ifaddrs *ifap, *ifa;
struct node_host *n = NULL, *h = NULL;
+ struct pfr_buffer b;
+ struct pfi_if *p;
if (getifaddrs(&ifap) < 0)
err(1, "getifaddrs");
@@ -903,7 +1027,8 @@ ifa_load(void)
if (n->af == AF_INET6 &&
IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)
ifa->ifa_addr)->sin6_addr) &&
- ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) {
+ ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id ==
+ 0) {
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
@@ -925,6 +1050,10 @@ ifa_load(void)
memcpy(&n->bcast, &((struct sockaddr_in *)
ifa->ifa_broadaddr)->sin_addr.s_addr,
sizeof(struct in_addr));
+ if (ifa->ifa_dstaddr != NULL)
+ memcpy(&n->peer, &((struct sockaddr_in *)
+ ifa->ifa_dstaddr)->sin_addr.s_addr,
+ sizeof(struct in_addr));
} else if (n->af == AF_INET6) {
memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *)
ifa->ifa_addr)->sin6_addr.s6_addr,
@@ -936,6 +1065,10 @@ ifa_load(void)
memcpy(&n->bcast, &((struct sockaddr_in6 *)
ifa->ifa_broadaddr)->sin6_addr.s6_addr,
sizeof(struct in6_addr));
+ if (ifa->ifa_dstaddr != NULL)
+ memcpy(&n->peer, &((struct sockaddr_in6 *)
+ ifa->ifa_dstaddr)->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
n->ifindex = ((struct sockaddr_in6 *)
ifa->ifa_addr)->sin6_scope_id;
}
@@ -950,15 +1083,58 @@ ifa_load(void)
h->tail = n;
}
}
+
+ /* add interface groups, including clonable and dynamic stuff */
+ bzero(&b, sizeof(b));
+ b.pfrb_type = PFRB_IFACES;
+ for (;;) {
+ if (pfr_buf_grow(&b, b.pfrb_size))
+ err(1, "ifa_load: pfr_buf_grow");
+ b.pfrb_size = b.pfrb_msize;
+ if (pfi_get_ifaces(NULL, b.pfrb_caddr, &b.pfrb_size,
+ PFI_FLAG_GROUP))
+ err(1, "ifa_load: pfi_get_ifaces");
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ }
+ PFRB_FOREACH(p, &b) {
+ n = calloc(1, sizeof(struct node_host));
+ if (n == NULL)
+ err(1, "address: calloc");
+ n->af = AF_LINK;
+ n->ifa_flags = PF_IFA_FLAG_GROUP;
+ if (p->pfif_flags & PFI_IFLAG_DYNAMIC)
+ n->ifa_flags |= PF_IFA_FLAG_DYNAMIC;
+ if (p->pfif_flags & PFI_IFLAG_CLONABLE)
+ n->ifa_flags |= PF_IFA_FLAG_CLONABLE;
+ if (!strcmp(p->pfif_name, "lo"))
+ n->ifa_flags |= IFF_LOOPBACK;
+ if ((n->ifname = strdup(p->pfif_name)) == NULL)
+ err(1, "ifa_load: strdup");
+ n->next = NULL;
+ n->tail = n;
+ if (h == NULL)
+ h = n;
+ else {
+ h->tail->next = n;
+ h->tail = n;
+ }
+ }
+
iftab = h;
freeifaddrs(ifap);
}
struct node_host *
-ifa_exists(const char *ifa_name)
+ifa_exists(const char *ifa_name, int group_ok)
{
struct node_host *n;
+ char *p, buf[IFNAMSIZ];
+ int group;
+ group = !isdigit(ifa_name[strlen(ifa_name) - 1]);
+ if (group && !group_ok)
+ return (NULL);
if (iftab == NULL)
ifa_load();
@@ -966,14 +1142,28 @@ ifa_exists(const char *ifa_name)
if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
return (n);
}
+ if (!group) {
+ /* look for clonable and/or dynamic interface */
+ strlcpy(buf, ifa_name, sizeof(buf));
+ for (p = buf + strlen(buf) - 1; p > buf && isdigit(*p); p--)
+ *p = '\0';
+ for (n = iftab; n != NULL; n = n->next)
+ if (n->af == AF_LINK &&
+ !strncmp(n->ifname, buf, IFNAMSIZ))
+ break;
+ if (n != NULL && n->ifa_flags &
+ (PF_IFA_FLAG_DYNAMIC | PF_IFA_FLAG_CLONABLE))
+ return (n); /* XXX */
+ }
return (NULL);
}
struct node_host *
-ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode)
+ifa_lookup(const char *ifa_name, int flags)
{
struct node_host *p = NULL, *h = NULL, *n = NULL;
- int return_all = 0;
+ int return_all = 0, got4 = 0, got6 = 0;
+ const char *last_if = NULL;
if (!strncmp(ifa_name, "self", IFNAMSIZ))
return_all = 1;
@@ -983,23 +1173,44 @@ ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode)
for (p = iftab; p; p = p->next) {
if (!((p->af == AF_INET || p->af == AF_INET6) &&
- (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all)))
+ (!strncmp(p->ifname, ifa_name, strlen(ifa_name)) ||
+ return_all)))
+ continue;
+ if ((flags & PFI_AFLAG_BROADCAST) && p->af != AF_INET)
+ continue;
+ if ((flags & PFI_AFLAG_BROADCAST) &&
+ !(p->ifa_flags & IFF_BROADCAST))
+ continue;
+ if ((flags & PFI_AFLAG_PEER) &&
+ !(p->ifa_flags & IFF_POINTOPOINT))
+ continue;
+ if ((flags & PFI_AFLAG_NETWORK) && p->ifindex > 0)
continue;
- if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET)
+ if (last_if == NULL || strcmp(last_if, p->ifname))
+ got4 = got6 = 0;
+ last_if = p->ifname;
+ if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET && got4)
continue;
- if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0)
+ if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET6 && got6)
continue;
+ if (p->af == AF_INET)
+ got4 = 1;
+ else
+ got6 = 1;
n = calloc(1, sizeof(struct node_host));
if (n == NULL)
err(1, "address: calloc");
n->af = p->af;
- if (mode == PFCTL_IFLOOKUP_BCAST)
+ if (flags & PFI_AFLAG_BROADCAST)
memcpy(&n->addr.v.a.addr, &p->bcast,
sizeof(struct pf_addr));
+ else if (flags & PFI_AFLAG_PEER)
+ memcpy(&n->addr.v.a.addr, &p->peer,
+ sizeof(struct pf_addr));
else
memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr,
sizeof(struct pf_addr));
- if (mode == PFCTL_IFLOOKUP_NET)
+ if (flags & PFI_AFLAG_NETWORK)
set_ipmask(n, unmask(&p->addr.v.a.mask, n->af));
else {
if (n->af == AF_INET) {
@@ -1024,9 +1235,6 @@ ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode)
h->tail = n;
}
}
- if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) {
- fprintf(stderr, "no IP address found for %s\n", ifa_name);
- }
return (h);
}
@@ -1084,29 +1292,39 @@ host_if(const char *s, int mask)
{
struct node_host *n, *h = NULL;
char *p, *ps;
- int mode = PFCTL_IFLOOKUP_HOST;
+ int flags = 0;
- if ((p = strrchr(s, ':')) != NULL &&
- (!strcmp(p+1, "network") || !strcmp(p+1, "broadcast"))) {
+ if ((ps = strdup(s)) == NULL)
+ err(1, "host_if: strdup");
+ while ((p = strrchr(ps, ':')) != NULL) {
if (!strcmp(p+1, "network"))
- mode = PFCTL_IFLOOKUP_NET;
- if (!strcmp(p+1, "broadcast"))
- mode = PFCTL_IFLOOKUP_BCAST;
- if (mask > -1) {
- fprintf(stderr, "network or broadcast lookup, but "
- "extra netmask given\n");
+ flags |= PFI_AFLAG_NETWORK;
+ else if (!strcmp(p+1, "broadcast"))
+ flags |= PFI_AFLAG_BROADCAST;
+ else if (!strcmp(p+1, "peer"))
+ flags |= PFI_AFLAG_PEER;
+ else if (!strcmp(p+1, "0"))
+ flags |= PFI_AFLAG_NOALIAS;
+ else {
+ free(ps);
return (NULL);
}
- if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
- err(1, "host: malloc");
- strlcpy(ps, s, strlen(s) - strlen(p) + 1);
- } else
- if ((ps = strdup(s)) == NULL)
- err(1, "host_if: strdup");
-
- if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) {
+ *p = '\0';
+ }
+ if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { /* Yep! */
+ fprintf(stderr, "illegal combination of interface modifiers\n");
+ free(ps);
+ return (NULL);
+ }
+ if ((flags & (PFI_AFLAG_NETWORK|PFI_AFLAG_BROADCAST)) && mask > -1) {
+ fprintf(stderr, "network or broadcast lookup, but "
+ "extra netmask given\n");
+ free(ps);
+ return (NULL);
+ }
+ if (ifa_exists(ps, 1) || !strncmp(ps, "self", IFNAMSIZ)) {
/* interface with this name exists */
- h = ifa_lookup(ps, mode);
+ h = ifa_lookup(ps, flags);
for (n = h; n != NULL && mask > -1; n = n->next)
set_ipmask(n, mask);
}
@@ -1120,27 +1338,27 @@ host_v4(const char *s, int mask)
{
struct node_host *h = NULL;
struct in_addr ina;
- int bits;
+ int bits = 32;
memset(&ina, 0, sizeof(struct in_addr));
- if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) > -1) {
- h = calloc(1, sizeof(struct node_host));
- if (h == NULL)
- err(1, "address: calloc");
- h->ifname = NULL;
- h->af = AF_INET;
- h->addr.v.a.addr.addr32[0] = ina.s_addr;
-#if defined(__FreeBSD__) && (__FreeBSD_version <= 501106)
- /* inet_net_pton acts strange w/ multicast addresses, RFC1112 */
- if (mask == -1 && h->addr.v.a.addr.addr8[0] >= 224 &&
- h->addr.v.a.addr.addr8[0] < 240)
- bits = 32;
-#endif
- set_ipmask(h, bits);
- h->next = NULL;
- h->tail = h;
+ if (strrchr(s, '/') != NULL) {
+ if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
+ return (NULL);
+ } else {
+ if (inet_pton(AF_INET, s, &ina) != 1)
+ return (NULL);
}
+ h = calloc(1, sizeof(struct node_host));
+ if (h == NULL)
+ err(1, "address: calloc");
+ h->ifname = NULL;
+ h->af = AF_INET;
+ h->addr.v.a.addr.addr32[0] = ina.s_addr;
+ set_ipmask(h, bits);
+ h->next = NULL;
+ h->tail = h;
+
return (h);
}
@@ -1179,12 +1397,20 @@ host_dns(const char *s, int v4mask, int v6mask)
{
struct addrinfo hints, *res0, *res;
struct node_host *n, *h = NULL;
- int error;
+ int error, noalias = 0;
+ int got4 = 0, got6 = 0;
+ char *p, *ps;
+ if ((ps = strdup(s)) == NULL)
+ err(1, "host_if: strdup");
+ if ((p = strrchr(ps, ':')) != NULL && !strcmp(p, ":0")) {
+ noalias = 1;
+ *p = '\0';
+ }
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; /* DUMMY */
- error = getaddrinfo(s, NULL, &hints, &res0);
+ error = getaddrinfo(ps, NULL, &hints, &res0);
if (error)
return (h);
@@ -1192,6 +1418,17 @@ host_dns(const char *s, int v4mask, int v6mask)
if (res->ai_family != AF_INET &&
res->ai_family != AF_INET6)
continue;
+ if (noalias) {
+ if (res->ai_family == AF_INET) {
+ if (got4)
+ continue;
+ got4 = 1;
+ } else {
+ if (got6)
+ continue;
+ got6 = 1;
+ }
+ }
n = calloc(1, sizeof(struct node_host));
if (n == NULL)
err(1, "host_dns: calloc");
@@ -1223,6 +1460,7 @@ host_dns(const char *s, int v4mask, int v6mask)
}
}
freeaddrinfo(res0);
+ free(ps);
return (h);
}
@@ -1296,3 +1534,45 @@ append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not)
return (0);
}
+
+int
+pfctl_add_trans(struct pfr_buffer *buf, int rs_num, const char *anchor,
+ const char *ruleset)
+{
+ struct pfioc_trans_e trans;
+
+ bzero(&trans, sizeof(trans));
+ trans.rs_num = rs_num;
+ if (strlcpy(trans.anchor, anchor,
+ sizeof(trans.anchor)) >= sizeof(trans.anchor) ||
+ strlcpy(trans.ruleset, ruleset,
+ sizeof(trans.ruleset)) >= sizeof(trans.ruleset))
+ errx(1, "pfctl_add_trans: strlcpy");
+
+ return pfr_buf_add(buf, &trans);
+}
+
+u_int32_t
+pfctl_get_ticket(struct pfr_buffer *buf, int rs_num, const char *anchor,
+ const char *ruleset)
+{
+ struct pfioc_trans_e *p;
+
+ PFRB_FOREACH(p, buf)
+ if (rs_num == p->rs_num && !strcmp(anchor, p->anchor) &&
+ !strcmp(ruleset, p->ruleset))
+ return (p->ticket);
+ errx(1, "pfr_get_ticket: assertion failed");
+}
+
+int
+pfctl_trans(int dev, struct pfr_buffer *buf, u_long cmd, int from)
+{
+ struct pfioc_trans trans;
+
+ bzero(&trans, sizeof(trans));
+ trans.size = buf->pfrb_size - from;
+ trans.esize = sizeof(struct pfioc_trans_e);
+ trans.array = ((struct pfioc_trans_e *)buf->pfrb_caddr) + from;
+ return ioctl(dev, cmd, &trans);
+}
diff --git a/contrib/pf/pfctl/pfctl_parser.h b/contrib/pf/pfctl/pfctl_parser.h
index 6911a47..0756cc8 100644
--- a/contrib/pf/pfctl/pfctl_parser.h
+++ b/contrib/pf/pfctl/pfctl_parser.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.h,v 1.67 2003/08/21 19:12:09 frantzen Exp $ */
+/* $OpenBSD: pfctl_parser.h,v 1.74 2004/02/10 22:26:56 dhartmei Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -46,6 +46,7 @@
#define PF_OPT_VERBOSE2 0x0080
#define PF_OPT_DUMMYACTION 0x0100
#define PF_OPT_DEBUG 0x0200
+#define PF_OPT_SHOWALL 0x0400
#define PF_TH_ALL 0xFF
@@ -67,19 +68,13 @@ struct pfctl {
int tdirty; /* kernel dirty */
u_int32_t rule_nr;
struct pfioc_pooladdr paddr;
- struct pfioc_rule *prule[PF_RULESET_MAX];
struct pfioc_altq *paltq;
struct pfioc_queue *pqueue;
+ struct pfr_buffer *trans;
const char *anchor;
const char *ruleset;
};
-enum pfctl_iflookup_mode {
- PFCTL_IFLOOKUP_HOST,
- PFCTL_IFLOOKUP_NET,
- PFCTL_IFLOOKUP_BCAST
-};
-
struct node_if {
char ifname[IFNAMSIZ];
u_int8_t not;
@@ -91,6 +86,7 @@ struct node_if {
struct node_host {
struct pf_addr_wrap addr;
struct pf_addr bcast;
+ struct pf_addr peer;
sa_family_t af;
u_int8_t not;
u_int32_t ifindex; /* link-local IPv6 addrs */
@@ -99,6 +95,10 @@ struct node_host {
struct node_host *next;
struct node_host *tail;
};
+/* special flags used by ifa_exists */
+#define PF_IFA_FLAG_GROUP 0x10000
+#define PF_IFA_FLAG_DYNAMIC 0x20000
+#define PF_IFA_FLAG_CLONABLE 0x40000
struct node_os {
char *os;
@@ -168,7 +168,7 @@ struct node_tinit { /* table initializer */
struct pfr_buffer; /* forward definition */
-int pfctl_rules(int, char *, int, char *, char *);
+int pfctl_rules(int, char *, int, char *, char *, struct pfr_buffer *);
int pfctl_add_rule(struct pfctl *, struct pf_rule *);
int pfctl_add_altq(struct pfctl *, struct pf_altq *);
@@ -179,15 +179,18 @@ int pfctl_set_timeout(struct pfctl *, const char *, int, int);
int pfctl_set_optimization(struct pfctl *, const char *);
int pfctl_set_limit(struct pfctl *, const char *, unsigned int);
int pfctl_set_logif(struct pfctl *, char *);
+int pfctl_set_hostid(struct pfctl *, u_int32_t);
+int pfctl_set_debug(struct pfctl *, char *);
int parse_rules(FILE *, struct pfctl *);
int parse_flags(char *);
-int pfctl_load_anchors(int, int);
+int pfctl_load_anchors(int, int, struct pfr_buffer *);
void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int);
+void print_src_node(struct pf_src_node *, int);
void print_rule(struct pf_rule *, int);
void print_tabledef(const char *, int, int, struct node_tinithead *);
-void print_status(struct pf_status *);
+void print_status(struct pf_status *, int);
int eval_pfaltq(struct pfctl *, struct pf_altq *, struct node_queue_bw *,
struct node_queue_opt *);
@@ -195,9 +198,9 @@ int eval_pfqueue(struct pfctl *, struct pf_altq *, struct node_queue_bw *,
struct node_queue_opt *);
void print_altq(const struct pf_altq *, unsigned, struct node_queue_bw *,
- struct node_queue_opt *);
+ struct node_queue_opt *);
void print_queue(const struct pf_altq *, unsigned, struct node_queue_bw *,
- int, struct node_queue_opt *);
+ int, struct node_queue_opt *);
int pfctl_define_table(char *, int, int, const char *, const char *,
struct pfr_buffer *, u_int32_t);
@@ -242,8 +245,8 @@ extern const struct pf_timeout pf_timeouts[];
void set_ipmask(struct node_host *, u_int8_t);
int check_netmask(struct node_host *, sa_family_t);
void ifa_load(void);
-struct node_host *ifa_exists(const char *);
-struct node_host *ifa_lookup(const char *, enum pfctl_iflookup_mode);
+struct node_host *ifa_exists(const char *, int);
+struct node_host *ifa_lookup(const char *, int);
struct node_host *host(const char *);
int append_addr(struct pfr_buffer *, char *, int);
diff --git a/contrib/pf/pfctl/pfctl_qstats.c b/contrib/pf/pfctl/pfctl_qstats.c
index 0e8b61f..a46603c 100644
--- a/contrib/pf/pfctl/pfctl_qstats.c
+++ b/contrib/pf/pfctl/pfctl_qstats.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_qstats.c,v 1.24 2003/07/31 09:46:08 kjc Exp $ */
+/* $OpenBSD: pfctl_qstats.c,v 1.29 2004/03/15 15:25:44 dhartmei Exp $ */
/*
* Copyright (c) Henning Brauer <henning@openbsd.org>
@@ -84,28 +84,40 @@ void pfctl_print_altq_nodestat(int,
void update_avg(struct pf_altq_node *);
int
-pfctl_show_altq(int dev, int opts, int verbose2)
+pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
{
struct pf_altq_node *root = NULL, *node;
+ int nodes, dotitle = (opts & PF_OPT_SHOWALL);
#ifdef __FreeBSD__
if (!altqsupport)
return (-1);
#endif
- if (pfctl_update_qstats(dev, &root))
+
+ if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
return (-1);
- for (node = root; node != NULL; node = node->next)
+ for (node = root; node != NULL; node = node->next) {
+ if (iface != NULL && strcmp(node->altq.ifname, iface))
+ continue;
+ if (dotitle) {
+ pfctl_print_title("ALTQ:");
+ dotitle = 0;
+ }
pfctl_print_altq_node(dev, node, 0, opts);
+ }
while (verbose2) {
printf("\n");
fflush(stdout);
sleep(STAT_INTERVAL);
- if (pfctl_update_qstats(dev, &root))
+ if (pfctl_update_qstats(dev, &root) == -1)
return (-1);
- for (node = root; node != NULL; node = node->next)
+ for (node = root; node != NULL; node = node->next) {
+ if (iface != NULL && strcmp(node->altq.ifname, iface))
+ continue;
pfctl_print_altq_node(dev, node, 0, opts);
+ }
}
pfctl_free_altq_node(root);
return (0);
@@ -162,7 +174,7 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root)
}
}
}
- return (0);
+ return (mnr);
}
void
@@ -252,12 +264,13 @@ pfctl_print_altq_node(int dev, const struct pf_altq_node *node, unsigned level,
pfctl_print_altq_nodestat(dev, node);
if (opts & PF_OPT_DEBUG)
- printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n", node->altq.qid,
- node->altq.ifname, rate2str((double)(node->altq.ifbandwidth)));
+ printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n",
+ node->altq.qid, node->altq.ifname,
+ rate2str((double)(node->altq.ifbandwidth)));
for (child = node->children; child != NULL;
child = child->next)
- pfctl_print_altq_node(dev, child, level+1, opts);
+ pfctl_print_altq_node(dev, child, level + 1, opts);
}
void
diff --git a/contrib/pf/pfctl/pfctl_table.c b/contrib/pf/pfctl/pfctl_table.c
index ad4d53a..4aa606d 100644
--- a/contrib/pf/pfctl/pfctl_table.c
+++ b/contrib/pf/pfctl/pfctl_table.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_table.c,v 1.50 2003/08/29 21:47:36 cedric Exp $ */
+/* $OpenBSD: pfctl_table.c,v 1.59 2004/03/15 15:25:44 dhartmei Exp $ */
/*
* Copyright (c) 2002 Cedric Berger
@@ -64,12 +64,19 @@ static void print_addrx(struct pfr_addr *, struct pfr_addr *, int);
static void print_astats(struct pfr_astats *, int);
static void radix_perror(void);
static void xprintf(int, const char *, ...);
+static void print_iface(struct pfi_if *, int);
+static void oprintf(int, int, const char *, int *, int);
static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = {
{ "In/Block:", "In/Pass:", "In/XPass:" },
{ "Out/Block:", "Out/Pass:", "Out/XPass:" }
};
+static const char *istats_text[2][2][2] = {
+ { { "In4/Pass:", "In4/Block:" }, { "Out4/Pass:", "Out4/Block:" } },
+ { { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } }
+};
+
#define RVTEST(fct) do { \
if ((!(opts & PF_OPT_NOACTION) || \
(opts & PF_OPT_DUMMYACTION)) && \
@@ -118,12 +125,12 @@ int
pfctl_table(int argc, char *argv[], char *tname, const char *command,
char *file, const char *anchor, const char *ruleset, int opts)
{
- struct pfr_table table;
- struct pfr_buffer b, b2;
- struct pfr_addr *a, *a2;
- int nadd = 0, ndel = 0, nchange = 0, nzero = 0;
- int rv = 0, flags = 0, nmatch = 0;
- void *p;
+ struct pfr_table table;
+ struct pfr_buffer b, b2;
+ struct pfr_addr *a, *a2;
+ int nadd = 0, ndel = 0, nchange = 0, nzero = 0;
+ int rv = 0, flags = 0, nmatch = 0;
+ void *p;
if (command == NULL)
usage();
@@ -168,6 +175,10 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
if (b.pfrb_size <= b.pfrb_msize)
break;
}
+
+ if (opts & PF_OPT_SHOWALL && b.pfrb_size > 0)
+ pfctl_print_title("TABLES:");
+
PFRB_FOREACH(p, &b)
if (opts & PF_OPT_VERBOSE2)
print_tstats(p, opts & PF_OPT_DEBUG);
@@ -246,7 +257,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
opts & PF_OPT_USEDNS);
} else if (!strcmp(command, "show")) {
b.pfrb_type = (opts & PF_OPT_VERBOSE) ?
- PFRB_ASTATS : PFRB_ADDRS;
+ PFRB_ASTATS : PFRB_ADDRS;
if (argc || file != NULL)
usage();
for (;;) {
@@ -328,9 +339,9 @@ print_table(struct pfr_table *ta, int verbose, int debug)
(ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-',
ta->pfrt_name);
if (ta->pfrt_anchor[0])
- printf("\t%s", ta->pfrt_anchor);
+ printf("\t%s", ta->pfrt_anchor);
if (ta->pfrt_ruleset[0])
- printf(":%s", ta->pfrt_ruleset);
+ printf(":%s", ta->pfrt_ruleset);
puts("");
} else
puts(ta->pfrt_name);
@@ -453,12 +464,11 @@ pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
struct pfr_table tbl;
bzero(&tbl, sizeof(tbl));
- if (strlcpy(tbl.pfrt_name, name,
- sizeof(tbl.pfrt_name)) >= sizeof(tbl.pfrt_name) ||
- strlcpy(tbl.pfrt_anchor, anchor,
+ if (strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)) >=
+ sizeof(tbl.pfrt_name) || strlcpy(tbl.pfrt_anchor, anchor,
sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor) ||
- strlcpy(tbl.pfrt_ruleset, ruleset,
- sizeof(tbl.pfrt_ruleset)) >= sizeof(tbl.pfrt_ruleset))
+ strlcpy(tbl.pfrt_ruleset, ruleset, sizeof(tbl.pfrt_ruleset)) >=
+ sizeof(tbl.pfrt_ruleset))
errx(1, "pfctl_define_table: strlcpy");
tbl.pfrt_flags = flags;
@@ -481,7 +491,7 @@ warn_namespace_collision(const char *filter)
b.pfrb_size = b.pfrb_msize;
if (pfr_get_tables(NULL, b.pfrb_caddr,
&b.pfrb_size, PFR_FLAG_ALLRSETS))
- err(1, "pfr_get_tables");
+ err(1, "pfr_get_tables");
if (b.pfrb_size <= b.pfrb_msize)
break;
}
@@ -526,3 +536,83 @@ xprintf(int opts, const char *fmt, ...)
else
fprintf(stderr, ".\n");
}
+
+
+/* interface stuff */
+
+int
+pfctl_show_ifaces(const char *filter, int opts)
+{
+ struct pfr_buffer b;
+ struct pfi_if *p;
+ int i = 0, f = PFI_FLAG_GROUP|PFI_FLAG_INSTANCE;
+
+ if (filter != NULL && *filter && !isdigit(filter[strlen(filter)-1]))
+ f &= ~PFI_FLAG_INSTANCE;
+ bzero(&b, sizeof(b));
+ b.pfrb_type = PFRB_IFACES;
+ for (;;) {
+ pfr_buf_grow(&b, b.pfrb_size);
+ b.pfrb_size = b.pfrb_msize;
+ if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size, f)) {
+ radix_perror();
+ return (1);
+ }
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ i++;
+ }
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("INTERFACES:");
+ PFRB_FOREACH(p, &b)
+ print_iface(p, opts);
+ return (0);
+}
+
+void
+print_iface(struct pfi_if *p, int opts)
+{
+ time_t tzero = p->pfif_tzero;
+ int flags = (opts & PF_OPT_VERBOSE) ? p->pfif_flags : 0;
+ int first = 1;
+ int i, af, dir, act;
+
+ printf("%s", p->pfif_name);
+ oprintf(flags, PFI_IFLAG_INSTANCE, "instance", &first, 0);
+ oprintf(flags, PFI_IFLAG_GROUP, "group", &first, 0);
+ oprintf(flags, PFI_IFLAG_CLONABLE, "clonable", &first, 0);
+ oprintf(flags, PFI_IFLAG_DYNAMIC, "dynamic", &first, 0);
+ oprintf(flags, PFI_IFLAG_ATTACHED, "attached", &first, 1);
+#ifdef __FreeBSD__
+ first = 1;
+ oprintf(flags, PFI_IFLAG_PLACEHOLDER, "placeholder", &first, 1);
+#endif
+ printf("\n");
+
+ if (!(opts & PF_OPT_VERBOSE2))
+ return;
+ printf("\tCleared: %s", ctime(&tzero));
+ printf("\tReferences: [ States: %-18d Rules: %-18d ]\n",
+ p->pfif_states, p->pfif_rules);
+ for (i = 0; i < 8; i++) {
+ af = (i>>2) & 1;
+ dir = (i>>1) &1;
+ act = i & 1;
+ printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
+ istats_text[af][dir][act],
+ (unsigned long long)p->pfif_packets[af][dir][act],
+ (unsigned long long)p->pfif_bytes[af][dir][act]);
+ }
+}
+
+void
+oprintf(int flags, int flag, const char *s, int *first, int last)
+{
+ if (flags & flag) {
+ printf(*first ? "\t(%s" : ", %s", s);
+ *first = 0;
+ }
+ if (last && !*first)
+ printf(")");
+}
+
diff --git a/contrib/pf/pflogd/pflogd.c b/contrib/pf/pflogd/pflogd.c
index e69c4ae..54a2572 100644
--- a/contrib/pf/pflogd/pflogd.c
+++ b/contrib/pf/pflogd/pflogd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pflogd.c,v 1.21 2003/08/22 21:50:34 david Exp $ */
+/* $OpenBSD: pflogd.c,v 1.27 2004/02/13 19:01:57 otto Exp $ */
/*
* Copyright (c) 2001 Theo de Raadt
@@ -34,6 +34,7 @@
__FBSDID("$FreeBSD$");
#include <sys/types.h>
+#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <stdio.h>
@@ -53,20 +54,14 @@ __FBSDID("$FreeBSD$");
#include <util.h>
#endif
-#define DEF_SNAPLEN 116 /* default plus allow for larger header of pflog */
-#define PCAP_TO_MS 500 /* pcap read timeout (ms) */
-#define PCAP_NUM_PKTS 1000 /* max number of packets to process at each loop */
-#define PCAP_OPT_FIL 0 /* filter optimization */
-#define FLUSH_DELAY 60 /* flush delay */
-
-#define PFLOGD_LOG_FILE "/var/log/pflog"
-#define PFLOGD_DEFAULT_IF "pflog0"
+#include "pflogd.h"
pcap_t *hpcap;
-pcap_dumper_t *dpcap;
+static FILE *dpcap;
int Debug = 0;
-int snaplen = DEF_SNAPLEN;
+static int snaplen = DEF_SNAPLEN;
+static int cur_snaplen = DEF_SNAPLEN;
volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup;
@@ -79,15 +74,43 @@ char errbuf[PCAP_ERRBUF_SIZE];
int log_debug = 0;
unsigned int delay = FLUSH_DELAY;
-char *copy_argv(char * const *argv);
+char *copy_argv(char * const *);
+void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
+void dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *);
+int flush_buffer(FILE *);
int init_pcap(void);
-void logmsg(int priority, const char *message, ...);
+void logmsg(int, const char *, ...);
+void purge_buffer(void);
int reset_dump(void);
+int scan_dump(FILE *, off_t);
+int set_snaplen(int);
+void set_suspended(int);
void sig_alrm(int);
void sig_close(int);
void sig_hup(int);
void usage(void);
+/* buffer must always be greater than snaplen */
+static int bufpkt = 0; /* number of packets in buffer */
+static int buflen = 0; /* allocated size of buffer */
+static char *buffer = NULL; /* packet buffer */
+static char *bufpos = NULL; /* position in buffer */
+static int bufleft = 0; /* bytes left in buffer */
+
+/* if error, stop logging but count dropped packets */
+static int suspended = -1;
+static long packets_dropped = 0;
+
+void
+set_suspended(int s)
+{
+ if (suspended == s)
+ return;
+
+ suspended = s;
+ setproctitle("[%s] -s %d -f %s",
+ suspended ? "suspended" : "running", cur_snaplen, filename);
+}
char *
copy_argv(char * const *argv)
@@ -136,7 +159,7 @@ __dead void
#endif
usage(void)
{
- fprintf(stderr, "usage: pflogd [-D] [-d delay] [-f filename] ");
+ fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename] ");
fprintf(stderr, "[-s snaplen] [expression]\n");
exit(1);
}
@@ -159,37 +182,64 @@ sig_alrm(int sig)
gotsig_alrm = 1;
}
-int
-init_pcap(void)
+void
+set_pcap_filter(void)
{
struct bpf_program bprog;
- pcap_t *oldhpcap = hpcap;
+ if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
+ logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
+ else {
+ if (pcap_setfilter(hpcap, &bprog) < 0)
+ logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
+ pcap_freecode(&bprog);
+ }
+}
+
+int
+init_pcap(void)
+{
hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
if (hpcap == NULL) {
logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
- hpcap = oldhpcap;
return (-1);
}
- if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
- logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
- else if (pcap_setfilter(hpcap, &bprog) < 0)
- logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
- if (filter != NULL)
- free(filter);
-
if (pcap_datalink(hpcap) != DLT_PFLOG) {
logmsg(LOG_ERR, "Invalid datalink type");
pcap_close(hpcap);
- hpcap = oldhpcap;
+ hpcap = NULL;
return (-1);
}
- if (oldhpcap)
- pcap_close(oldhpcap);
+ set_pcap_filter();
+
+ cur_snaplen = snaplen = pcap_snapshot(hpcap);
+
+#ifdef __FreeBSD__
+ /* We can not lock bpf devices ... yet */
+#else
+ /* lock */
+ if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
+ logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
+ return (-1);
+ }
+#endif
+
+ return (0);
+}
+
+int
+set_snaplen(int snap)
+{
+ if (priv_set_snaplen(snap))
+ return (1);
+
+ if (cur_snaplen > snap)
+ purge_buffer();
+
+ cur_snaplen = snap;
- snaplen = pcap_snapshot(hpcap);
return (0);
}
@@ -198,45 +248,51 @@ reset_dump(void)
{
struct pcap_file_header hdr;
struct stat st;
- int tmpsnap;
+ int fd;
FILE *fp;
if (hpcap == NULL)
- return (1);
+ return (-1);
+
if (dpcap) {
- pcap_dump_close(dpcap);
- dpcap = 0;
+ flush_buffer(dpcap);
+ fclose(dpcap);
+ dpcap = NULL;
}
/*
* Basically reimplement pcap_dump_open() because it truncates
* files and duplicates headers and such.
*/
- fp = fopen(filename, "a+");
+ fd = priv_open_log();
+ if (fd < 0)
+ return (1);
+
+ fp = fdopen(fd, "a+");
+
if (fp == NULL) {
- snprintf(hpcap->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
- filename, pcap_strerror(errno));
- logmsg(LOG_ERR, "Error: %s", pcap_geterr(hpcap));
+ logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
return (1);
}
if (fstat(fileno(fp), &st) == -1) {
- snprintf(hpcap->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
- filename, pcap_strerror(errno));
- logmsg(LOG_ERR, "Error: %s", pcap_geterr(hpcap));
+ logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
return (1);
}
- dpcap = (pcap_dumper_t *)fp;
+ /* set FILE unbuffered, we do our own buffering */
+ if (setvbuf(fp, NULL, _IONBF, 0)) {
+ logmsg(LOG_ERR, "Failed to set output buffers");
+ return (1);
+ }
#define TCPDUMP_MAGIC 0xa1b2c3d4
if (st.st_size == 0) {
- if (snaplen != pcap_snapshot(hpcap)) {
+ if (snaplen != cur_snaplen) {
logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
- if (init_pcap()) {
- logmsg(LOG_ERR, "Failed to initialize");
- if (hpcap == NULL) return (-1);
- logmsg(LOG_NOTICE, "Using old settings");
+ if (set_snaplen(snaplen)) {
+ logmsg(LOG_WARNING,
+ "Failed, using old settings");
}
}
hdr.magic = TCPDUMP_MAGIC;
@@ -248,58 +304,228 @@ reset_dump(void)
hdr.linktype = hpcap->linktype;
if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
- dpcap = NULL;
fclose(fp);
- return (-1);
+ return (1);
}
- return (0);
+ } else if (scan_dump(fp, st.st_size)) {
+ /* XXX move file and continue? */
+ fclose(fp);
+ return (1);
}
+ dpcap = fp;
+
+ set_suspended(0);
+ flush_buffer(fp);
+
+ return (0);
+}
+
+int
+scan_dump(FILE *fp, off_t size)
+{
+ struct pcap_file_header hdr;
+ struct pcap_pkthdr ph;
+ off_t pos;
+
/*
- * XXX Must read the file, compare the header against our new
+ * Must read the file, compare the header against our new
* options (in particular, snaplen) and adjust our options so
- * that we generate a correct file.
+ * that we generate a correct file. Furthermore, check the file
+ * for consistency so that we can append safely.
+ *
+ * XXX this may take a long time for large logs.
*/
(void) fseek(fp, 0L, SEEK_SET);
- if (fread((char *)&hdr, sizeof(hdr), 1, fp) == 1) {
- if (hdr.magic != TCPDUMP_MAGIC ||
- hdr.version_major != PCAP_VERSION_MAJOR ||
- hdr.version_minor != PCAP_VERSION_MINOR ||
- hdr.linktype != hpcap->linktype) {
- logmsg(LOG_ERR,
- "Invalid/incompatible log file, move it away");
- fclose(fp);
- return (1);
- }
- if (hdr.snaplen != snaplen) {
+
+ if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
+ logmsg(LOG_ERR, "Short file header");
+ return (1);
+ }
+
+ if (hdr.magic != TCPDUMP_MAGIC ||
+ hdr.version_major != PCAP_VERSION_MAJOR ||
+ hdr.version_minor != PCAP_VERSION_MINOR ||
+ hdr.linktype != hpcap->linktype ||
+ hdr.snaplen > PFLOGD_MAXSNAPLEN) {
+ logmsg(LOG_ERR, "Invalid/incompatible log file, move it away");
+ return (1);
+ }
+
+ pos = sizeof(hdr);
+
+ while (!feof(fp)) {
+ off_t len = fread((char *)&ph, 1, sizeof(ph), fp);
+ if (len == 0)
+ break;
+
+ if (len != sizeof(ph))
+ goto error;
+ if (ph.caplen > hdr.snaplen || ph.caplen > PFLOGD_MAXSNAPLEN)
+ goto error;
+ pos += sizeof(ph) + ph.caplen;
+ if (pos > size)
+ goto error;
+ fseek(fp, ph.caplen, SEEK_CUR);
+ }
+
+ if (pos != size)
+ goto error;
+
+ if (hdr.snaplen != cur_snaplen) {
+ logmsg(LOG_WARNING,
+ "Existing file has different snaplen %u, using it",
+ hdr.snaplen);
+ if (set_snaplen(hdr.snaplen)) {
logmsg(LOG_WARNING,
- "Existing file specifies a snaplen of %u, using it",
- hdr.snaplen);
- tmpsnap = snaplen;
- snaplen = hdr.snaplen;
- if (init_pcap()) {
- logmsg(LOG_ERR, "Failed to re-initialize");
- if (hpcap == 0)
- return (-1);
- logmsg(LOG_NOTICE,
- "Using old settings, offset: %llu",
- (unsigned long long)st.st_size);
- }
- snaplen = tmpsnap;
+ "Failed, using old settings, offset %llu",
+ (unsigned long long) size);
+ }
+ }
+
+ return (0);
+
+ error:
+ logmsg(LOG_ERR, "Corrupted log file.");
+ return (1);
+}
+
+/* dump a packet directly to the stream, which is unbuffered */
+void
+dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
+{
+ FILE *f = (FILE *)user;
+
+ if (suspended) {
+ packets_dropped++;
+ return;
+ }
+
+ if (fwrite((char *)h, sizeof(*h), 1, f) != 1) {
+ /* try to undo header to prevent corruption */
+ off_t pos = ftello(f);
+ if (pos < sizeof(*h) ||
+ ftruncate(fileno(f), pos - sizeof(*h))) {
+ logmsg(LOG_ERR, "Write failed, corrupted logfile!");
+ set_suspended(1);
+ gotsig_close = 1;
+ return;
}
+ goto error;
}
- (void) fseek(fp, 0L, SEEK_END);
+ if (fwrite((char *)sp, h->caplen, 1, f) != 1)
+ goto error;
+
+ return;
+
+error:
+ set_suspended(1);
+ packets_dropped ++;
+ logmsg(LOG_ERR, "Logging suspended: fwrite: %s", strerror(errno));
+}
+
+int
+flush_buffer(FILE *f)
+{
+ off_t offset;
+ int len = bufpos - buffer;
+
+ if (len <= 0)
+ return (0);
+
+ offset = ftello(f);
+ if (offset == (off_t)-1) {
+ set_suspended(1);
+ logmsg(LOG_ERR, "Logging suspended: ftello: %s",
+ strerror(errno));
+ return (1);
+ }
+
+ if (fwrite(buffer, len, 1, f) != 1) {
+ set_suspended(1);
+ logmsg(LOG_ERR, "Logging suspended: fwrite: %s",
+ strerror(errno));
+ ftruncate(fileno(f), offset);
+ return (1);
+ }
+
+ set_suspended(0);
+ bufpos = buffer;
+ bufleft = buflen;
+ bufpkt = 0;
+
return (0);
}
+void
+purge_buffer(void)
+{
+ packets_dropped += bufpkt;
+
+ set_suspended(0);
+ bufpos = buffer;
+ bufleft = buflen;
+ bufpkt = 0;
+}
+
+/* append packet to the buffer, flushing if necessary */
+void
+dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
+{
+ FILE *f = (FILE *)user;
+ size_t len = sizeof(*h) + h->caplen;
+
+ if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
+ logmsg(LOG_NOTICE, "invalid size %u (%u/%u), packet dropped",
+ len, cur_snaplen, snaplen);
+ packets_dropped++;
+ return;
+ }
+
+ if (len <= bufleft)
+ goto append;
+
+ if (suspended) {
+ packets_dropped++;
+ return;
+ }
+
+ if (flush_buffer(f)) {
+ packets_dropped++;
+ return;
+ }
+
+ if (len > bufleft) {
+ dump_packet_nobuf(user, h, sp);
+ return;
+ }
+
+ append:
+ memcpy(bufpos, h, sizeof(*h));
+ memcpy(bufpos + sizeof(*h), sp, h->caplen);
+
+ bufpos += len;
+ bufleft -= len;
+ bufpkt++;
+
+ return;
+}
+
int
main(int argc, char **argv)
{
struct pcap_stat pstat;
- int ch, np;
+ int ch, np, Xflag = 0;
+ pcap_handler phandler = dump_packet;
+
+#ifdef __FreeBSD__
+ /* another ?paranoid? safety measure we do not have */
+#else
+ closefrom(STDERR_FILENO + 1);
+#endif
- while ((ch = getopt(argc, argv, "Dd:s:f:")) != -1) {
+ while ((ch = getopt(argc, argv, "Dxd:s:f:")) != -1) {
switch (ch) {
case 'D':
Debug = 1;
@@ -316,6 +542,11 @@ main(int argc, char **argv)
snaplen = atoi(optarg);
if (snaplen <= 0)
snaplen = DEF_SNAPLEN;
+ if (snaplen > PFLOGD_MAXSNAPLEN)
+ snaplen = PFLOGD_MAXSNAPLEN;
+ break;
+ case 'x':
+ Xflag++;
break;
default:
usage();
@@ -338,32 +569,57 @@ main(int argc, char **argv)
(void)umask(S_IRWXG | S_IRWXO);
- signal(SIGTERM, sig_close);
- signal(SIGINT, sig_close);
- signal(SIGQUIT, sig_close);
- signal(SIGALRM, sig_alrm);
- signal(SIGHUP, sig_hup);
- alarm(delay);
-
+ /* filter will be used by the privileged process */
if (argc) {
filter = copy_argv(argv);
if (filter == NULL)
logmsg(LOG_NOTICE, "Failed to form filter expression");
}
+ /* initialize pcap before dropping privileges */
if (init_pcap()) {
logmsg(LOG_ERR, "Exiting, init failure");
exit(1);
}
- if (reset_dump()) {
- logmsg(LOG_ERR, "Failed to open log file %s", filename);
- pcap_close(hpcap);
+ /* Privilege separation begins here */
+ if (priv_init()) {
+ logmsg(LOG_ERR, "unable to privsep");
exit(1);
}
+ setproctitle("[initializing]");
+ /* Process is now unprivileged and inside a chroot */
+ signal(SIGTERM, sig_close);
+ signal(SIGINT, sig_close);
+ signal(SIGQUIT, sig_close);
+ signal(SIGALRM, sig_alrm);
+ signal(SIGHUP, sig_hup);
+ alarm(delay);
+
+ buffer = malloc(PFLOGD_BUFSIZE);
+
+ if (buffer == NULL) {
+ logmsg(LOG_WARNING, "Failed to allocate output buffer");
+ phandler = dump_packet_nobuf;
+ } else {
+ bufleft = buflen = PFLOGD_BUFSIZE;
+ bufpos = buffer;
+ bufpkt = 0;
+ }
+
+ if (reset_dump()) {
+ if (Xflag)
+ return (1);
+
+ logmsg(LOG_ERR, "Logging suspended: open error");
+ set_suspended(1);
+ } else if (Xflag)
+ return (0);
+
while (1) {
- np = pcap_dispatch(hpcap, PCAP_NUM_PKTS, pcap_dump, (u_char *)dpcap);
+ np = pcap_dispatch(hpcap, PCAP_NUM_PKTS,
+ dump_packet, (u_char *)dpcap);
if (np < 0)
logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
@@ -371,38 +627,34 @@ main(int argc, char **argv)
break;
if (gotsig_hup) {
if (reset_dump()) {
- logmsg(LOG_ERR, "Failed to open log file!");
- break;
+ logmsg(LOG_ERR,
+ "Logging suspended: open error");
+ set_suspended(1);
}
- logmsg(LOG_NOTICE, "Reopened logfile");
gotsig_hup = 0;
}
if (gotsig_alrm) {
- /* XXX pcap_dumper is an incomplete type which libpcap
- * casts to a FILE* currently. For now it is safe to
- * make the same assumption, however this may change
- * in the future.
- */
- if (dpcap) {
- if (fflush((FILE *)dpcap) == EOF) {
- break;
- }
- }
+ if (dpcap)
+ flush_buffer(dpcap);
gotsig_alrm = 0;
alarm(delay);
}
}
- logmsg(LOG_NOTICE, "Exiting due to signal");
- if (dpcap)
- pcap_dump_close(dpcap);
+ logmsg(LOG_NOTICE, "Exiting");
+ if (dpcap) {
+ flush_buffer(dpcap);
+ fclose(dpcap);
+ }
+ purge_buffer();
if (pcap_stats(hpcap, &pstat) < 0)
logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap));
else
- logmsg(LOG_NOTICE, "%u packets received, %u dropped",
- pstat.ps_recv, pstat.ps_drop);
+ logmsg(LOG_NOTICE,
+ "%u packets received, %u/%u dropped (kernel/pflogd)",
+ pstat.ps_recv, pstat.ps_drop, packets_dropped);
pcap_close(hpcap);
if (!Debug)
diff --git a/contrib/pf/pflogd/privsep.c b/contrib/pf/pflogd/privsep.c
index 50807ad..3dfba32 100644
--- a/contrib/pf/pflogd/privsep.c
+++ b/contrib/pf/pflogd/privsep.c
@@ -16,11 +16,13 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <sys/ioctl.h>
-#include <sys/types.h>
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h>
-#include <sys/ioctl.h>
#include <net/if.h>
#include <net/bpf.h>
@@ -28,13 +30,13 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
-#include <pcap.h>
-#include <pcap-int.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <pcap.h>
+#include <pcap-int.h>
#include <syslog.h>
#include <unistd.h>
#include "pflogd.h"
@@ -70,7 +72,11 @@ priv_init(void)
int snaplen, ret;
struct passwd *pw;
+#ifdef __FreeBSD__
+ for (i = 1; i < NSIG; i++)
+#else
for (i = 1; i < _NSIG; i++)
+#endif
signal(i, SIG_DFL);
/* Create sockets */
diff --git a/sbin/pfctl/Makefile b/sbin/pfctl/Makefile
index 3c40c93..3be4087 100644
--- a/sbin/pfctl/Makefile
+++ b/sbin/pfctl/Makefile
@@ -12,10 +12,11 @@ SRCS+= pfctl_osfp.c pfctl_radix.c pfctl_table.c pfctl_qstats.c
CFLAGS+= -Wall -Wmissing-prototypes -Wno-uninitialized
CFLAGS+= -Wstrict-prototypes -I${.CURDIR}/../../contrib/pf/pfctl
+CFLAGS+= -I${.CURDIR}/../../sys/contrib/pf
# XXX ALTQ
-#CFLAGS+= -DENABLE_ALTQ
-CFLAGS+= -I${.CURDIR}/missing
+CFLAGS+= -DENABLE_ALTQ
+#CFLAGS+= -I${.CURDIR}/missing
YFLAGS=
diff --git a/sbin/pflogd/Makefile b/sbin/pflogd/Makefile
index 0855e8c..285387a 100644
--- a/sbin/pflogd/Makefile
+++ b/sbin/pflogd/Makefile
@@ -3,7 +3,7 @@
.PATH: ${.CURDIR}/../../contrib/pf/pflogd
PROG= pflogd
-SRCS= pflogd.c pidfile.c
+SRCS= pflogd.c pidfile.c privsep.c privsep_fdpass.c
MAN= pflogd.8
CFLAGS+=-Wall -Werror -Wmissing-prototypes -Wshadow
diff --git a/usr.bin/kdump/mkioctls b/usr.bin/kdump/mkioctls
index ac132a3..cbe7515 100644
--- a/usr.bin/kdump/mkioctls
+++ b/usr.bin/kdump/mkioctls
@@ -41,6 +41,7 @@ BEGIN {
print "#include <net/ethernet.h>"
print "#include <net/if.h>"
print "#include <net/if_var.h>"
+ print "#include <net/pfvar.h>"
print "#include <net/route.h>"
print "#include <netatm/atm.h>"
print "#include <netatm/atm_if.h>"
OpenPOWER on IntegriCloud