Commit userland part of pf version 3.5 from OpenBSD (OPENBSD_3_5_BASE).

This commit is contained in:
Max Laier 2004-06-16 23:39:33 +00:00
parent 24b10b46ce
commit 22ac3ead26
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=130617
20 changed files with 2479 additions and 872 deletions

View File

@ -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))
do_death(0);
openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON);
if (config == NULL || read_config(config))
do_death(0);
if (remove_stale_rulesets())
if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) {
syslog(LOG_INFO, "user %s prohibited", luser);
do_death(0);
}
if (config == NULL || read_config(config)) {
syslog(LOG_INFO, "bad or nonexistent %s", PATH_CONFFILE);
do_death(0);
}
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);
}
@ -851,6 +873,13 @@ pfctl_set_logif(struct pfctl *pf, char *ifname)
return (1);
}
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)
{
@ -865,6 +894,13 @@ pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
return (1);
}
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)
{
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 EXAMPLES
.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 up
# tcpdump -s1500 -evtni pfsync0
# 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
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

File diff suppressed because it is too large Load Diff

View File

@ -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
}
}

View File

@ -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, DIOCCLRSTATES))
err(1, "DIOCCLRSTATES");
if (ioctl(dev, DIOCCLRSRCNODES))
err(1, "DIOCCLRSRCNODES");
if ((opts & PF_OPT_QUIET) == 0)
fprintf(stderr, "states cleared\n");
fprintf(stderr, "source tracking entries cleared\n");
return (0);
}
int
pfctl_kill_states(int dev, int opts)
pfctl_clear_states(int dev, const char *iface, int opts)
{
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, "%d states cleared\n", psk.psk_af);
return (0);
}
int
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)) {
@ -1190,6 +1291,55 @@ pfctl_set_logif(struct pfctl *pf, char *ifname)
return (0);
}
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)
{
@ -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))

View File

@ -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_ */

View File

@ -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);

View File

@ -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],
@ -551,6 +576,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)
{
@ -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 (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET)
if ((flags & PFI_AFLAG_BROADCAST) && p->af != AF_INET)
continue;
if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0)
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 (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 ((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);
}

View File

@ -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);

View File

@ -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

View File

@ -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(")");
}

View File

@ -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;
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);
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);
return (-1);
}
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 (0);
}
/*
* XXX 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.
*/
(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) {
}
} 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;
/*
* 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. 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) {
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);
}
}
(void) fseek(fp, 0L, SEEK_END);
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;
}
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;
while ((ch = getopt(argc, argv, "Dd:s:f:")) != -1) {
#ifdef __FreeBSD__
/* another ?paranoid? safety measure we do not have */
#else
closefrom(STDERR_FILENO + 1);
#endif
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,6 +569,27 @@ main(int argc, char **argv)
(void)umask(S_IRWXG | S_IRWXO);
/* 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);
}
/* 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);
@ -345,25 +597,29 @@ main(int argc, char **argv)
signal(SIGHUP, sig_hup);
alarm(delay);
if (argc) {
filter = copy_argv(argv);
if (filter == NULL)
logmsg(LOG_NOTICE, "Failed to form filter expression");
}
buffer = malloc(PFLOGD_BUFSIZE);
if (init_pcap()) {
logmsg(LOG_ERR, "Exiting, init failure");
exit(1);
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()) {
logmsg(LOG_ERR, "Failed to open log file %s", filename);
pcap_close(hpcap);
exit(1);
}
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)

View File

@ -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 */

View File

@ -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=

View File

@ -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

View File

@ -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>"