Import userland of pf 3.5 from OpenBSD (OPENBSD_3_5_BASE).
This commit is contained in:
parent
c9eda2a3d0
commit
6a32f6ec2e
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: authpf.8,v 1.30 2003/08/17 23:24:47 henning Exp $
|
||||
.\" $OpenBSD: authpf.8,v 1.31 2003/12/10 04:10:37 beck Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2002 Bob Beck (beck@openbsd.org>. All rights reserved.
|
||||
.\"
|
||||
@ -84,9 +84,9 @@ shared by all
|
||||
processes.
|
||||
By default, the
|
||||
.Pa anchor
|
||||
name "authpf" is used, and the ruleset names equal the PIDs of the
|
||||
name "authpf" is used, and the ruleset names equal the username and PID of the
|
||||
.Nm
|
||||
processes.
|
||||
processes as "username(pid)".
|
||||
The following rules need to be added to the main ruleset
|
||||
.Pa /etc/pf.conf
|
||||
in order to cause evaluation of any
|
||||
@ -263,7 +263,8 @@ by creating an appropriate
|
||||
.Pa /etc/authpf/authpf.conf
|
||||
file.
|
||||
.Sh EXAMPLES
|
||||
\fBControl Files\fP - To illustrate the user-specific access control
|
||||
.Sy Control Files
|
||||
\- To illustrate the user-specific access control
|
||||
mechanisms, let us consider a typical user named bob.
|
||||
Normally, as long as bob can authenticate himself, the
|
||||
.Nm
|
||||
@ -298,7 +299,8 @@ file.
|
||||
Though bob is listed in the allow file, he is prevented from using
|
||||
this gateway due to the existence of a ban file.
|
||||
.Pp
|
||||
\fBDistributed Authentication\fP - It is often desirable to interface with a
|
||||
.Sy Distributed Authentication
|
||||
\- It is often desirable to interface with a
|
||||
distributed password system rather than forcing the sysadmins to keep a large
|
||||
number of local password files in sync.
|
||||
The
|
||||
@ -332,7 +334,8 @@ Using a default password file, all users will get
|
||||
as their shell except for root who will get
|
||||
.Pa /bin/csh .
|
||||
.Pp
|
||||
\fBSSH Configuration\fP - As stated earlier,
|
||||
.Sy SSH Configuration
|
||||
\- As stated earlier,
|
||||
.Xr sshd 8
|
||||
must be properly configured to detect and defeat network attacks.
|
||||
To that end, the following options should be added to
|
||||
@ -346,7 +349,8 @@ ClientAliveCountMax 3
|
||||
This ensures that unresponsive or spoofed sessions are terminated within a
|
||||
minute, since a hijacker should not be able to spoof ssh keepalive messages.
|
||||
.Pp
|
||||
\fBBanners\fP - Once authenticated, the user is shown the contents of
|
||||
.Sy Banners
|
||||
\- Once authenticated, the user is shown the contents of
|
||||
.Pa /etc/authpf/authpf.message .
|
||||
This message may be a screen-full of the appropriate use policy, the contents
|
||||
of
|
||||
@ -366,7 +370,8 @@ problem so we can fix it, please phone 1-900-314-1597 or send
|
||||
an email to remove@bulkmailerz.net.
|
||||
.Ed
|
||||
.Pp
|
||||
\fBPacket Filter Rules\fP - In areas where this gateway is used to protect a
|
||||
.Sy Packet Filter Rules
|
||||
\- In areas where this gateway is used to protect a
|
||||
wireless network (a hub with several hundred ports), the default rule set as
|
||||
well as the per-user rules should probably allow very few things beyond
|
||||
encrypted protocols like
|
||||
@ -378,15 +383,14 @@ On a securely switched network, with plug-in jacks for visitors who are
|
||||
given authentication accounts, you might want to allow out everything.
|
||||
In this context, a secure switch is one that tries to prevent address table
|
||||
overflow attacks.
|
||||
The examples below assume a switched wired net.
|
||||
.Pp
|
||||
Example
|
||||
.Pa /etc/pf.conf :
|
||||
.Bd -literal
|
||||
# by default we allow internal clients to talk to us using
|
||||
# ssh and use us as a dns server.
|
||||
internal_if=\&"fxp1\&"
|
||||
gateway_addr=\&"10.0.1.1\&"
|
||||
internal_if="fxp1"
|
||||
gateway_addr="10.0.1.1"
|
||||
nat-anchor authpf
|
||||
rdr-anchor authpf
|
||||
binat-anchor authpf
|
||||
@ -398,26 +402,28 @@ pass in quick on $internal_if proto udp from any to $gateway_addr \e
|
||||
anchor authpf
|
||||
.Ed
|
||||
.Pp
|
||||
Example
|
||||
.Pa /etc/authpf/authpf.rules :
|
||||
.Sy For a switched, wired net
|
||||
\- This example
|
||||
.Pa /etc/authpf/authpf.rules
|
||||
makes no real restrictions; it turns the IP address on and off, logging
|
||||
TCP connections.
|
||||
.Bd -literal
|
||||
# no real restrictions here, basically turn the network jack off or on.
|
||||
|
||||
external_if = \&"xl0\&"
|
||||
internal_if = \&"fxp0\&"
|
||||
external_if = "xl0"
|
||||
internal_if = "fxp0"
|
||||
|
||||
pass in log quick on $internal_if proto tcp from $user_ip to any \e
|
||||
keep state
|
||||
pass in quick on $internal_if from $user_ip to any
|
||||
.Ed
|
||||
.Pp
|
||||
Another example
|
||||
.Sy For a wireless or shared net
|
||||
\- This example
|
||||
.Pa /etc/authpf/authpf.rules
|
||||
for an insecure network (such as a public wireless network) where
|
||||
could be used for an insecure network (such as a public wireless network) where
|
||||
we might need to be a bit more restrictive.
|
||||
.Bd -literal
|
||||
internal_if=\&"fxp1\&"
|
||||
ipsec_gw=\&"10.2.3.4\&"
|
||||
internal_if="fxp1"
|
||||
ipsec_gw="10.2.3.4"
|
||||
|
||||
# rdr ftp for proxying by ftp-proxy(8)
|
||||
rdr on $internal_if proto tcp from $user_ip to any port 21 \e
|
||||
@ -433,6 +439,32 @@ pass in quick proto udp from $user_ip to $ipsec_gw port = isakmp \e
|
||||
keep state
|
||||
pass in quick proto esp from $user_ip to $ipsec_gw
|
||||
.Ed
|
||||
.Pp
|
||||
.Sy Dealing with NAT
|
||||
\- The following
|
||||
.Pa /etc/authpf/authpf.rules
|
||||
shows how to deal with NAT, using tags:
|
||||
.Bd -literal
|
||||
ext_if = "fxp1"
|
||||
ext_addr = 129.128.11.10
|
||||
int_if = "fxp0"
|
||||
# nat and tag connections...
|
||||
nat on $ext_if from $user_ip to any tag $user_ip -> $ext_addr
|
||||
pass in quick on $int_if from $user_ip to any
|
||||
pass out log quick on $ext_if tagged $user_ip keep state
|
||||
.Ed
|
||||
.Pp
|
||||
With the above rules added by
|
||||
.Nm ,
|
||||
outbound connections corresponding to each users NAT'ed connections
|
||||
will be logged as in the example below, where the user may be identified
|
||||
from the ruleset name.
|
||||
.Bd -literal
|
||||
# tcpdump -n -e -ttt -i pflog0
|
||||
Oct 31 19:42:30.296553 rule 0.bbeck(20267).1/0(match): pass out on fxp1: \e
|
||||
129.128.11.10.60539 > 198.137.240.92.22: S 2131494121:2131494121(0) win \e
|
||||
16384 <mss 1460,nop,nop,sackOK> (DF)
|
||||
.Ed
|
||||
.Sh FILES
|
||||
.Bl -tag -width "/etc/authpf/authpf.conf" -compact
|
||||
.It Pa /etc/authpf/authpf.conf
|
||||
|
@ -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).
|
||||
@ -46,6 +46,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <pfctl_parser.h>
|
||||
#include <pfctl.h>
|
||||
|
||||
#include "pathnames.h"
|
||||
|
||||
@ -91,12 +92,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) {
|
||||
@ -124,7 +119,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) {
|
||||
@ -153,6 +147,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)) {
|
||||
@ -235,15 +241,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);
|
||||
@ -253,7 +266,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);
|
||||
@ -536,15 +549,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;
|
||||
@ -576,14 +594,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;
|
||||
}
|
||||
@ -615,18 +630,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) {
|
||||
@ -637,6 +652,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: "
|
||||
@ -649,14 +668,8 @@ 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");
|
||||
if (pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) {
|
||||
syslog(LOG_ERR, "DIOCXCOMMIT (%s) %m", add?"add":"remove");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -673,6 +686,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);
|
||||
@ -748,37 +763,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);
|
||||
}
|
||||
@ -838,6 +860,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)
|
||||
{
|
||||
@ -852,6 +881,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)
|
||||
@ -862,10 +898,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)
|
||||
{
|
||||
}
|
||||
|
@ -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.
|
||||
@ -36,10 +36,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
|
||||
@ -65,6 +66,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
|
||||
@ -80,14 +101,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.
|
||||
@ -96,6 +109,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
|
||||
@ -173,8 +194,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
|
||||
|
@ -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
|
||||
@ -67,7 +67,7 @@
|
||||
* - per-user rules perhaps.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
@ -148,6 +148,7 @@ char *Group;
|
||||
|
||||
extern int Debug_Level;
|
||||
extern int Use_Rdns;
|
||||
extern in_addr_t Bind_Addr;
|
||||
extern char *__progname;
|
||||
|
||||
typedef enum {
|
||||
@ -171,9 +172,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);
|
||||
}
|
||||
|
||||
@ -973,9 +973,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;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: util.c,v 1.16 2003/06/28 01:04:57 deraadt Exp $ */
|
||||
/* $OpenBSD: util.c,v 1.18 2004/01/22 16:10:30 beck Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996-2001
|
||||
@ -58,6 +58,7 @@
|
||||
|
||||
int Debug_Level;
|
||||
int Use_Rdns;
|
||||
in_addr_t Bind_Addr = INADDR_NONE;
|
||||
|
||||
void debuglog(int debug_level, const char *fmt, ...);
|
||||
|
||||
@ -77,7 +78,8 @@ get_proxy_env(int connected_fd, struct sockaddr_in *real_server_sa_ptr,
|
||||
struct sockaddr_in *client_sa_ptr)
|
||||
{
|
||||
struct pfioc_natlook natlook;
|
||||
int slen, fd;
|
||||
socklen_t slen;
|
||||
int fd;
|
||||
|
||||
slen = sizeof(*real_server_sa_ptr);
|
||||
if (getsockname(connected_fd, (struct sockaddr *)real_server_sa_ptr,
|
||||
@ -257,10 +259,13 @@ get_backchannel_socket(int type, int min_port, int max_port, int start_port,
|
||||
|
||||
bzero(&sa, sizeof sa);
|
||||
sa.sin_family = AF_INET;
|
||||
if (Bind_Addr == INADDR_NONE)
|
||||
if (sap == NULL)
|
||||
sa.sin_addr.s_addr = INADDR_ANY;
|
||||
else
|
||||
sa.sin_addr.s_addr = sap->sin_addr.s_addr;
|
||||
else
|
||||
sa.sin_addr.s_addr = Bind_Addr;
|
||||
|
||||
/*
|
||||
* Indicate that we want to reuse a port if it happens that the
|
||||
|
@ -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.
|
||||
.\"
|
||||
@ -33,7 +33,7 @@
|
||||
.Nm pf
|
||||
.Nd packet filter
|
||||
.Sh SYNOPSIS
|
||||
.Cd "pseudo-device pf 1"
|
||||
.Cd "pseudo-device pf"
|
||||
.Sh DESCRIPTION
|
||||
Packet filtering takes place in the kernel.
|
||||
A pseudo-device,
|
||||
@ -72,11 +72,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;
|
||||
@ -92,16 +88,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 {
|
||||
@ -120,7 +117,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.
|
||||
@ -133,26 +130,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
|
||||
@ -224,8 +211,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"
|
||||
@ -246,8 +231,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 {
|
||||
@ -261,12 +254,17 @@ Specifies the interface for which statistics are accumulated.
|
||||
struct pf_status {
|
||||
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
|
||||
@ -285,7 +283,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;
|
||||
};
|
||||
@ -525,19 +523,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]
|
||||
@ -546,6 +531,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"
|
||||
@ -623,6 +648,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
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: pf.conf.5,v 1.271 2003/09/02 18:37:08 jmc Exp $
|
||||
.\" $OpenBSD: pf.conf.5,v 1.292 2004/02/24 05:44:48 mcbride Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2002, Daniel Hartmeier
|
||||
.\" All rights reserved.
|
||||
@ -234,6 +234,9 @@ command.
|
||||
Interval between purging expired states and fragments.
|
||||
.It Ar frag
|
||||
Seconds before an unassembled fragment is expired.
|
||||
.It Ar src.track
|
||||
Length of time to retain a source tracking entry after the last state
|
||||
expires.
|
||||
.El
|
||||
.Pp
|
||||
When a packet matches a stateful connection, the seconds to live for the
|
||||
@ -366,10 +369,21 @@ sets the maximum number of entries in the memory pool used for fragment
|
||||
reassembly (generated by
|
||||
.Ar scrub
|
||||
rules) to 20000.
|
||||
Finally,
|
||||
.Bd -literal -offset indent
|
||||
set limit src-nodes 2000
|
||||
.Ed
|
||||
.Pp
|
||||
sets the maximum number of entries in the memory pool used for tracking
|
||||
source IP addresses (generated by the
|
||||
.Ar sticky-address
|
||||
and
|
||||
.Ar source-track
|
||||
options) to 2000.
|
||||
.Pp
|
||||
These can be combined:
|
||||
.Bd -literal -offset indent
|
||||
set limit { states 20000, frags 20000 }
|
||||
set limit { states 20000, frags 20000, src-nodes 2000 }
|
||||
.Ed
|
||||
.Pp
|
||||
.It Ar set optimization
|
||||
@ -420,6 +434,24 @@ For example:
|
||||
.Bd -literal -offset indent
|
||||
set block-policy return
|
||||
.Ed
|
||||
.It Ar set state-policy
|
||||
The
|
||||
.Ar state-policy
|
||||
option sets the default behaviour for states:
|
||||
.Pp
|
||||
.Bl -tag -width group-bound -compact
|
||||
.It Ar if-bound
|
||||
States are bound to interface.
|
||||
.It Ar group-bound
|
||||
States are bound to interface group (i.e. ppp)
|
||||
.It Ar floating
|
||||
States can match packets on any interfaces (the default).
|
||||
.El
|
||||
.Pp
|
||||
For example:
|
||||
.Bd -literal -offset indent
|
||||
set state-policy if-bound
|
||||
.Ed
|
||||
.It Ar set require-order
|
||||
By default
|
||||
.Xr pfctl 8
|
||||
@ -450,6 +482,22 @@ ruleset finishes loading.
|
||||
For example:
|
||||
.Pp
|
||||
.Dl set fingerprints \&"/etc/pf.os.devel\&"
|
||||
.Pp
|
||||
.It Ar set debug
|
||||
Set the debug
|
||||
.Ar level
|
||||
to one of the following:
|
||||
.Pp
|
||||
.Bl -tag -width xxxxxxxxxxxx -compact
|
||||
.It Ar none
|
||||
Don't generate debug messages.
|
||||
.It Ar urgent
|
||||
Generate debug messages only for serious errors.
|
||||
.It Ar misc
|
||||
Generate debug messages for various errors.
|
||||
.It Ar loud
|
||||
Generate debug messages for common conditions.
|
||||
.El
|
||||
.El
|
||||
.Sh TRAFFIC NORMALIZATION
|
||||
Traffic normalization is used to sanitize packet content in such
|
||||
@ -1092,15 +1140,17 @@ are specified, the rule will match packets in both directions.
|
||||
.It Ar log
|
||||
In addition to the action specified, a log message is generated.
|
||||
All packets for that connection are logged, unless the
|
||||
.Ar keep state
|
||||
or
|
||||
.Ar keep state ,
|
||||
.Ar modulate state
|
||||
or
|
||||
.Ar synproxy state
|
||||
options are specified, in which case only the
|
||||
packet that establishes the state is logged.
|
||||
(See
|
||||
.Ar keep state
|
||||
and
|
||||
.Ar keep state ,
|
||||
.Ar modulate state
|
||||
and
|
||||
.Ar synproxy state
|
||||
below).
|
||||
The logged packets are sent to the
|
||||
.Xr pflog 4
|
||||
@ -1114,9 +1164,10 @@ in
|
||||
binary format.
|
||||
.It Ar log-all
|
||||
Used with
|
||||
.Ar keep state
|
||||
or
|
||||
.Ar keep state ,
|
||||
.Ar modulate state
|
||||
or
|
||||
.Ar synproxy state
|
||||
rules to force logging of all packets for a connection.
|
||||
As with
|
||||
.Ar log ,
|
||||
@ -1131,6 +1182,8 @@ is skipped.
|
||||
.It Ar on <interface>
|
||||
This rule applies only to packets coming in on, or going out through, this
|
||||
particular interface.
|
||||
It is also possible to simply give the interface driver name, like ppp or fxp,
|
||||
to make the rule match packets flowing through a group of interfaces.
|
||||
.It Ar <af>
|
||||
This rule applies only to packets of this address family.
|
||||
Supported values are
|
||||
@ -1175,14 +1228,24 @@ Interface names can have modifiers appended:
|
||||
Translates to the network(s) attached to the interface.
|
||||
.It Ar :broadcast
|
||||
Translates to the interface's broadcast address(es).
|
||||
.It Ar :peer
|
||||
Translates to the point to point interface's peer address(es).
|
||||
.It Ar :0
|
||||
Do not include interface aliases.
|
||||
.El
|
||||
.Pp
|
||||
Host names may also have the
|
||||
.Ar :0
|
||||
option appended to restrict the name resolution to the first of each
|
||||
v4 and v6 address found.
|
||||
.Pp
|
||||
Host name resolution and interface to address translation are done at
|
||||
ruleset load-time.
|
||||
When the address of an interface (or host name) changes (under DHCP or PPP,
|
||||
for instance), the ruleset must be reloaded for the change to be reflected
|
||||
in the kernel.
|
||||
Surrounding the interface name in parentheses changes this behaviour.
|
||||
Surrounding the interface name (and optional modifiers) in parentheses
|
||||
changes this behaviour.
|
||||
When the interface name is surrounded by parentheses, the rule is
|
||||
automatically updated whenever the interface changes its address.
|
||||
The ruleset does not need to be reloaded.
|
||||
@ -1205,15 +1268,19 @@ Ports and ranges of ports are specified by using these operators:
|
||||
<= (less than or equal)
|
||||
> (greater than)
|
||||
>= (greater than or equal)
|
||||
>< (range)
|
||||
: (range including boundaries)
|
||||
>< (range excluding boundaries)
|
||||
<> (except range)
|
||||
.Ed
|
||||
.Pp
|
||||
>< and <>
|
||||
are binary operators (they take two arguments), and the range
|
||||
does not include the limits.
|
||||
><, <> and :
|
||||
are binary operators (they take two arguments).
|
||||
For instance:
|
||||
.Bl -tag -width Fl
|
||||
.It Ar port 2000:2004
|
||||
means
|
||||
.Sq all ports >= 2000 and <= 2004 ,
|
||||
hence ports 2000, 2001, 2002, 2003 and 2004.
|
||||
.It Ar port 2000 >< 2004
|
||||
means
|
||||
.Sq all ports > 2000 and < 2004 ,
|
||||
@ -1421,13 +1488,17 @@ A packet is only ever assigned one tag at a time.
|
||||
rules that use the
|
||||
.Ar tag
|
||||
keyword must also use
|
||||
.Ar keep state .
|
||||
.Ar keep state ,
|
||||
.Ar modulate state
|
||||
or
|
||||
.Ar synproxy state .
|
||||
Packet tagging can be done during
|
||||
.Ar nat ,
|
||||
.Ar rdr ,
|
||||
or
|
||||
.Ar binat
|
||||
rules in addition to filter rules.
|
||||
Tags take the same macros as labels (see above).
|
||||
.It Ar tagged <string>
|
||||
Used with filter rules to specify that packets must already
|
||||
be tagged with the given tag in order to match the rule.
|
||||
@ -1533,6 +1604,23 @@ option prevents
|
||||
.Xr pf 4
|
||||
from modifying the source port on TCP and UDP packets.
|
||||
.El
|
||||
.Pp
|
||||
Additionally, the
|
||||
.Ar sticky-address
|
||||
option can be specified to help ensure that multiple connections from the
|
||||
same source are mapped to the same redirection address.
|
||||
This option can be used with the
|
||||
.Ar random
|
||||
and
|
||||
.Ar round-robin
|
||||
pool options.
|
||||
Note that by default these associations are destroyed as soon as there are
|
||||
no longer states which refer to them; in order to make the mappings last
|
||||
beyond the lifetime of the states, increase the global options with
|
||||
.Ar set timeout source-track
|
||||
See
|
||||
.Sx STATEFUL TRACKING OPTIONS
|
||||
for more ways to control the source tracking.
|
||||
.Sh STATEFUL INSPECTION
|
||||
.Xr pf 4
|
||||
is a stateful packet filter, which means it can track the state of
|
||||
@ -1579,6 +1667,37 @@ The initial packet of each connection has the SYN
|
||||
flag set, will be passed and creates state.
|
||||
All further packets of these connections are passed if they match a state.
|
||||
.Pp
|
||||
By default, packets coming in and out of any interface can match a state,
|
||||
but it is also possible to change that behaviour by assigning states to a
|
||||
single interface or a group of interfaces.
|
||||
.Pp
|
||||
The default policy is specified by the
|
||||
.Ar state-policy
|
||||
global option, but this can be adjusted on a per-rule basis by adding one
|
||||
of the
|
||||
.Ar if-bound ,
|
||||
.Ar group-bound
|
||||
or
|
||||
.Ar floating
|
||||
keywords to the
|
||||
.Ar keep state
|
||||
option.
|
||||
For example, if a rule is defined as:
|
||||
.Bd -literal -offset indent
|
||||
pass out on ppp from any to 10.12/16 keep state (group-bound)
|
||||
.Ed
|
||||
.Pp
|
||||
A state created on ppp0 would match packets an all PPP interfaces,
|
||||
but not packets flowing through fxp0 or any other interface.
|
||||
.Pp
|
||||
Keeping rules
|
||||
.Ar floating
|
||||
is the more flexible option when the firewall is in a dynamic routing
|
||||
environment.
|
||||
However, this has some security implications since a state created by one
|
||||
trusted network could allow potentially hostile packets coming in from other
|
||||
interfaces.
|
||||
.Pp
|
||||
Specifying
|
||||
.Ar flags S/SA
|
||||
restricts state creation to the initial SYN
|
||||
@ -1695,7 +1814,7 @@ handshake.
|
||||
The proxy is transparent to both endpoints, they each see a single
|
||||
connection from/to the other endpoint.
|
||||
.Xr pf 4
|
||||
choses random initial sequence numbers for both handshakes.
|
||||
chooses random initial sequence numbers for both handshakes.
|
||||
Once the handshakes are completed, the sequence number modulators
|
||||
(see previous section) are used to translate further packets of the
|
||||
connection.
|
||||
@ -1730,8 +1849,26 @@ support the following options:
|
||||
Limits the number of concurrent states the rule may create.
|
||||
When this limit is reached, further packets matching the rule that would
|
||||
create state are dropped, until existing states time out.
|
||||
.It Ar no-sync
|
||||
Prevent state changes for states created by this rule from appearing on the
|
||||
.Xr pfsync 4
|
||||
interface.
|
||||
.It Ar <timeout> <seconds>
|
||||
Changes the timeout values used for states created by this rule.
|
||||
.Pp
|
||||
When the
|
||||
.Ar source-track
|
||||
keyword is specified, the number of states per source IP is tracked.
|
||||
The following limits can be set:
|
||||
.Pp
|
||||
.Bl -tag -width xxxx -compact
|
||||
.It Ar max-src-nodes
|
||||
Limits the maximum number of source addresses which can simultaneously
|
||||
have state table entries.
|
||||
.It Ar max-src-states
|
||||
Limits the maximum number of simultaneous state entries that a single
|
||||
source address can create with this rule.
|
||||
.El
|
||||
For a list of all valid timeout names, see
|
||||
.Sx OPTIONS
|
||||
above.
|
||||
@ -1740,7 +1877,8 @@ Multiple options can be specified, separated by commas:
|
||||
.Bd -literal
|
||||
pass in proto tcp from any to any \e
|
||||
port www flags S/SA keep state \e
|
||||
(max 100, tcp.established 60, tcp.closing 5)
|
||||
(max 100, source-track rule, max-src-nodes 75, \e
|
||||
max-src-states 3, tcp.established 60, tcp.closing 5)
|
||||
.Ed
|
||||
.El
|
||||
.Sh OPERATING SYSTEM FINGERPRINTING
|
||||
@ -1853,7 +1991,7 @@ to local addresses.
|
||||
One should pass these explicitly.
|
||||
.Sh FRAGMENT HANDLING
|
||||
The size of IP datagrams (packets) can be significantly larger than the
|
||||
the maximum transmission unit (MTU) of the network.
|
||||
maximum transmission unit (MTU) of the network.
|
||||
In cases when it is necessary or more efficient to send such large packets,
|
||||
the large packet will be fragmented into many smaller packets that will each
|
||||
fit onto the wire.
|
||||
@ -2027,7 +2165,7 @@ rule after the
|
||||
rule:
|
||||
.Bd -literal -offset indent
|
||||
anchor spam
|
||||
load anchor spam:manual from /etc/pf-spam.conf
|
||||
load anchor spam:manual from "/etc/pf-spam.conf"
|
||||
.Ed
|
||||
.Pp
|
||||
When
|
||||
@ -2072,8 +2210,11 @@ This example maps incoming requests on port 80 to port 8080, on
|
||||
which a daemon is running (because, for example, it is not run as root,
|
||||
and therefore lacks permission to bind to port 80).
|
||||
.Bd -literal
|
||||
# use a macro for the interface name, so it can be changed easily
|
||||
ext_if = \&"ne3\&"
|
||||
|
||||
# map daemon on 8080 to appear to be on 80
|
||||
rdr on ne3 proto tcp from any to any port 80 -> 127.0.0.1 port 8080
|
||||
rdr on $ext_if proto tcp from any to any port 80 -> 127.0.0.1 port 8080
|
||||
.Ed
|
||||
.Pp
|
||||
If the
|
||||
@ -2081,7 +2222,8 @@ If the
|
||||
modifier is given, packets matching the translation rule are passed without
|
||||
inspecting the filter rules:
|
||||
.Bd -literal
|
||||
rdr pass on ne3 proto tcp from any to any port 80 -> 127.0.0.1 port 8080
|
||||
rdr pass on $ext_if proto tcp from any to any port 80 -> 127.0.0.1 \e
|
||||
port 8080
|
||||
.Ed
|
||||
.Pp
|
||||
In the example below, vlan12 is configured as 192.168.168.1;
|
||||
@ -2096,83 +2238,80 @@ for the nodes on vlan12.
|
||||
nat on ! vlan12 from 192.168.168.0/24 to any -> 204.92.77.111
|
||||
.Ed
|
||||
.Pp
|
||||
In the example below, fxp1 is the outside interface; the machine sits between a
|
||||
fake internal 144.19.74.* network, and a routable external IP of 204.92.77.100.
|
||||
In the example below, the machine sits between a fake internal 144.19.74.*
|
||||
network, and a routable external IP of 204.92.77.100.
|
||||
The
|
||||
.Ar no nat
|
||||
rule excludes protocol AH from being translated.
|
||||
.Bd -literal
|
||||
# NO NAT
|
||||
no nat on fxp1 proto ah from 144.19.74.0/24 to any
|
||||
nat on fxp1 from 144.19.74.0/24 to any -> 204.92.77.100
|
||||
no nat on $ext_if proto ah from 144.19.74.0/24 to any
|
||||
nat on $ext_if from 144.19.74.0/24 to any -> 204.92.77.100
|
||||
.Ed
|
||||
.Pp
|
||||
In the example below, fxp0 is the internal interface.
|
||||
Packets bound
|
||||
for one specific server, as well as those generated by the sysadmins
|
||||
are not proxied; all other connections are.
|
||||
In the example below, packets bound for one specific server, as well as those
|
||||
generated by the sysadmins are not proxied; all other connections are.
|
||||
.Bd -literal
|
||||
# NO RDR
|
||||
no rdr on fxp0 proto { tcp, udp } from any to $server port 80
|
||||
no rdr on fxp0 proto { tcp, udp } from $sysadmins to any port 80
|
||||
rdr on fxp0 proto { tcp, udp } from any to any port 80 -> 127.0.0.1 port 80
|
||||
no rdr on $int_if proto { tcp, udp } from any to $server port 80
|
||||
no rdr on $int_if proto { tcp, udp } from $sysadmins to any port 80
|
||||
rdr on $int_if proto { tcp, udp } from any to any port 80 -> 127.0.0.1 \e
|
||||
port 80
|
||||
.Ed
|
||||
.Pp
|
||||
This longer example uses both a NAT and a redirection.
|
||||
Interface kue0 is the outside interface, and its external address is
|
||||
157.161.48.183.
|
||||
Interface fxp0 is the inside interface, and we are running
|
||||
The external interface has the address 157.161.48.183.
|
||||
On the internal interface, we are running
|
||||
.Xr ftp-proxy 8 ,
|
||||
listening for outbound ftp sessions captured to port 8021.
|
||||
.Bd -literal
|
||||
# NAT
|
||||
# Translate outgoing packets' source addresses (any protocol).
|
||||
# In this case, any address but the gateway's external address is mapped.
|
||||
nat on kue0 inet from ! (kue0) to any -> (kue0)
|
||||
nat on $ext_if inet from ! ($ext_if) to any -> ($ext_if)
|
||||
|
||||
# NAT PROXYING
|
||||
# Map outgoing packets' source port to an assigned proxy port instead of
|
||||
# an arbitrary port.
|
||||
# In this case, proxy outgoing isakmp with port 500 on the gateway.
|
||||
nat on kue0 inet proto udp from any port = isakmp to any -> (kue0) \e
|
||||
nat on $ext_if inet proto udp from any port = isakmp to any -> ($ext_if) \e
|
||||
port 500
|
||||
|
||||
# BINAT
|
||||
# Translate outgoing packets' source address (any protocol).
|
||||
# Translate incoming packets' destination address to an internal machine
|
||||
# (bidirectional).
|
||||
binat on kue0 from 10.1.2.150 to any -> (kue0)
|
||||
binat on $ext_if from 10.1.2.150 to any -> ($ext_if)
|
||||
|
||||
# RDR
|
||||
# Translate incoming packets' destination addresses.
|
||||
# As an example, redirect a TCP and UDP port to an internal machine.
|
||||
rdr on kue0 inet proto tcp from any to (kue0) port 8080 -> 10.1.2.151 \e
|
||||
port 22
|
||||
rdr on kue0 inet proto udp from any to (kue0) port 8080 -> 10.1.2.151 \e
|
||||
port 53
|
||||
rdr on $ext_if inet proto tcp from any to ($ext_if) port 8080 \e
|
||||
-> 10.1.2.151 port 22
|
||||
rdr on $ext_if inet proto udp from any to ($ext_if) port 8080 \e
|
||||
-> 10.1.2.151 port 53
|
||||
|
||||
# RDR
|
||||
# Translate outgoing ftp control connections to send them to localhost
|
||||
# for proxying with ftp-proxy(8) running on port 8021.
|
||||
rdr on fxp0 proto tcp from any to any port 21 -> 127.0.0.1 port 8021
|
||||
rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
|
||||
.Ed
|
||||
.Pp
|
||||
In this example, a NAT gateway is set up to translate internal addresses
|
||||
using a pool of public addresses (192.0.2.16/28) and to redirect
|
||||
incoming web server connections to a group of web servers on the internal
|
||||
network.
|
||||
Interface fxp0 is the external interface.
|
||||
.Bd -literal
|
||||
# NAT LOAD BALANCE
|
||||
# Translate outgoing packets' source addresses using an address pool.
|
||||
# A given source address is always translated to the same pool address by
|
||||
# using the source-hash keyword.
|
||||
nat on fxp0 inet from any to any -> 192.0.2.16/28 source-hash
|
||||
nat on $ext_if inet from any to any -> 192.0.2.16/28 source-hash
|
||||
|
||||
# RDR ROUND ROBIN
|
||||
# Translate incoming web server connections to a group of web servers on
|
||||
# the internal network.
|
||||
rdr on fxp0 proto tcp from any to any port 80 \e
|
||||
rdr on $ext_if proto tcp from any to any port 80 \e
|
||||
-> { 10.1.2.155, 10.1.2.160, 10.1.2.161 } round-robin
|
||||
.Ed
|
||||
.Sh FILTER EXAMPLES
|
||||
@ -2283,8 +2422,11 @@ option = "set" ( [ "timeout" ( timeout | "{" timeout-list "}" ) ] |
|
||||
[ "limit" ( limit-item | "{" limit-list "}" ) ] |
|
||||
[ "loginterface" ( interface-name | "none" ) ] |
|
||||
[ "block-policy" ( "drop" | "return" ) ] |
|
||||
[ "state-policy" ( "if-bound" | "group-bound" |
|
||||
"floating" ) ]
|
||||
[ "require-order" ( "yes" | "no" ) ]
|
||||
[ "fingerprints" filename ] )
|
||||
[ "fingerprints" filename ] |
|
||||
[ "debug" ( "none" | "urgent" | "misc" | "loud" ) ] )
|
||||
|
||||
pf-rule = action [ ( "in" | "out" ) ]
|
||||
[ "log" | "log-all" ] [ "quick" ]
|
||||
@ -2299,7 +2441,7 @@ filteropt = user | group | flags | icmp-type | icmp6-type | tos |
|
||||
"max-mss" number | "random-id" | "reassemble tcp" |
|
||||
fragmentation | "allow-opts" |
|
||||
"label" string | "tag" string | [ ! ] "tagged" string
|
||||
"queue" "(" string | ( string [ [ "," ] string ] ) ")"
|
||||
"queue" ( string | "(" string [ [ "," ] string ] ")" )
|
||||
|
||||
nat-rule = [ "no" ] "nat" [ "pass" ] [ "on" ifspec ] [ af ]
|
||||
[ protospec ] hosts [ "tag" string ]
|
||||
@ -2341,7 +2483,7 @@ anchor-rule = "anchor" string [ ( "in" | "out" ) ] [ "on" ifspec ]
|
||||
trans-anchors = ( "nat-anchor" | "rdr-anchor" | "binat-anchor" ) string
|
||||
[ "on" ifspec ] [ af ] [ "proto" ] [ protospec ] [ hosts ]
|
||||
|
||||
load-anchor = "load" anchorname:rulesetname "from" filename
|
||||
load-anchor = "load anchor" anchorname:rulesetname "from" filename
|
||||
|
||||
queueopts-list = queueopts-list queueopts | queueopts
|
||||
queueopts = [ "bandwidth" bandwidth-spec ] |
|
||||
@ -2350,7 +2492,7 @@ queueopts = [ "bandwidth" bandwidth-spec ] |
|
||||
schedulers = ( cbq-def | priq-def | hfsc-def )
|
||||
bandwidth-spec = "number" ( "b" | "Kb" | "Mb" | "Gb" | "%" )
|
||||
|
||||
action = "pass" | "block" [ "return" ] | "scrub"
|
||||
action = "pass" | "block" [ return ] | "scrub"
|
||||
return = "drop" | "return" | "return-rst" [ "( ttl" number ")" ] |
|
||||
"return-icmp" [ "(" icmpcode ["," icmp6code ] ")" ] |
|
||||
"return-icmp6" [ "(" icmp6code ")" ]
|
||||
@ -2413,7 +2555,10 @@ tos = "tos" ( "lowdelay" | "throughput" | "reliability" |
|
||||
[ "0x" ] number )
|
||||
|
||||
state-opts = state-opt [ [ "," ] state-opts ]
|
||||
state-opt = ( "max" number ) | ( timeout )
|
||||
state-opt = ( "max" number | "no-sync" | timeout |
|
||||
"source-track" [ ( "rule" | "global" ) ] |
|
||||
"max-src-nodes" number | "max-src-states" number |
|
||||
"if-bound" | "group-bound" | "floating" )
|
||||
|
||||
fragmentation = [ "fragment reassemble" | "fragment crop" |
|
||||
"fragment drop-ovl" ]
|
||||
@ -2424,15 +2569,15 @@ timeout = ( "tcp.first" | "tcp.opening" | "tcp.established" |
|
||||
"udp.first" | "udp.single" | "udp.multiple" |
|
||||
"icmp.first" | "icmp.error" |
|
||||
"other.first" | "other.single" | "other.multiple" |
|
||||
"frag" | "interval" |
|
||||
"frag" | "interval" | "src.track" |
|
||||
"adaptive.start" | "adaptive.end" ) number
|
||||
|
||||
limit-list = limit-item [ [ "," ] limit-list ]
|
||||
limit-item = ( "states" | "frags" ) number
|
||||
limit-item = ( "states" | "frags" | "src-nodes" ) number
|
||||
|
||||
pooltype = ( "bitmask" | "random" |
|
||||
"source-hash" [ ( hex-key | string-key ) ] |
|
||||
"round-robin" )
|
||||
"round-robin" ) [ sticky-address ]
|
||||
|
||||
subqueue = string | "{" queue-list "}"
|
||||
queue-list = string [ [ "," ] string ]
|
||||
@ -2470,6 +2615,7 @@ Example rulesets.
|
||||
.Xr ip 4 ,
|
||||
.Xr ip6 4 ,
|
||||
.Xr pf 4 ,
|
||||
.Xr pfsync 4 ,
|
||||
.Xr tcp 4 ,
|
||||
.Xr udp 4 ,
|
||||
.Xr hosts 5 ,
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: pf.os.5,v 1.4 2003/08/28 09:41:23 jmc Exp $
|
||||
.\" $OpenBSD: pf.os.5,v 1.5 2003/10/25 07:55:27 jmc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org>
|
||||
.\"
|
||||
@ -77,7 +77,7 @@ Allow any window size which is a multiple of the maximum transmission unit
|
||||
The
|
||||
.Ar ttl
|
||||
value is the initial time to live in the IP header.
|
||||
The fingerprint code will account for the volatility of the packets's TTL
|
||||
The fingerprint code will account for the volatility of the packet's TTL
|
||||
as it traverses a network.
|
||||
.Pp
|
||||
The
|
||||
|
@ -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.
|
||||
@ -30,19 +30,20 @@
|
||||
.Nm pflog
|
||||
.Nd packet filter logging interface
|
||||
.Sh SYNOPSIS
|
||||
.Sy pseudo-device Nm pflog Em <number>
|
||||
.Cd "pseudo-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
|
||||
|
@ -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.
|
||||
@ -30,19 +30,48 @@
|
||||
.Nm pfsync
|
||||
.Nd packet filter states table logging interface
|
||||
.Sh SYNOPSIS
|
||||
.Sy pseudo-device Nm pfsync
|
||||
.Cd "pseudo-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
|
||||
@ -61,16 +90,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
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pf_print_state.c,v 1.33 2003/07/06 22:01:28 deraadt Exp $ */
|
||||
/* $OpenBSD: pf_print_state.c,v 1.39 2004/02/10 17:48:08 henning Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Daniel Hartmeier
|
||||
@ -50,9 +50,24 @@ void print_name(struct pf_addr *, sa_family_t);
|
||||
void
|
||||
print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose)
|
||||
{
|
||||
switch(addr->type) {
|
||||
switch (addr->type) {
|
||||
case PF_ADDR_DYNIFTL:
|
||||
printf("(%s)", addr->v.ifname);
|
||||
printf("(%s", addr->v.ifname);
|
||||
if (addr->iflags & PFI_AFLAG_NETWORK)
|
||||
printf(":network");
|
||||
if (addr->iflags & PFI_AFLAG_BROADCAST)
|
||||
printf(":broadcast");
|
||||
if (addr->iflags & PFI_AFLAG_PEER)
|
||||
printf(":peer");
|
||||
if (addr->iflags & PFI_AFLAG_NOALIAS)
|
||||
printf(":0");
|
||||
if (verbose) {
|
||||
if (addr->p.dyncnt <= 0)
|
||||
printf(":*");
|
||||
else
|
||||
printf(":%d", addr->p.dyncnt);
|
||||
}
|
||||
printf(")");
|
||||
break;
|
||||
case PF_ADDR_TABLE:
|
||||
if (verbose)
|
||||
@ -85,7 +100,10 @@ print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose)
|
||||
printf("?");
|
||||
return;
|
||||
}
|
||||
if (! PF_AZERO(&addr->v.a.mask, af)) {
|
||||
|
||||
/* mask if not _both_ address and mask are zero */
|
||||
if (!(PF_AZERO(&addr->v.a.addr, AF_INET6) &&
|
||||
PF_AZERO(&addr->v.a.mask, AF_INET6))) {
|
||||
int bits = unmask(&addr->v.a.mask, af);
|
||||
|
||||
if (bits != (af == AF_INET ? 32 : 128))
|
||||
@ -140,8 +158,10 @@ print_host(struct pf_state_host *h, sa_family_t af, int opts)
|
||||
aw.v.a.addr = h->addr;
|
||||
if (af == AF_INET)
|
||||
aw.v.a.mask.addr32[0] = 0xffffffff;
|
||||
else
|
||||
else {
|
||||
memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask));
|
||||
af = AF_INET6;
|
||||
}
|
||||
print_addr(&aw, af, opts & PF_OPT_VERBOSE2);
|
||||
}
|
||||
|
||||
@ -177,6 +197,7 @@ print_state(struct pf_state *s, int opts)
|
||||
src = &s->dst;
|
||||
dst = &s->src;
|
||||
}
|
||||
printf("%s ", s->u.ifname);
|
||||
if ((p = getprotobynumber(s->proto)) != NULL)
|
||||
printf("%s ", p->p_name);
|
||||
else
|
||||
@ -256,8 +277,16 @@ print_state(struct pf_state *s, int opts)
|
||||
printf(", anchor %u", s->anchor.nr);
|
||||
if (s->rule.nr != -1)
|
||||
printf(", rule %u", s->rule.nr);
|
||||
if (s->src_node != NULL)
|
||||
printf(", source-track");
|
||||
if (s->nat_src_node != NULL)
|
||||
printf(", sticky-address");
|
||||
printf("\n");
|
||||
}
|
||||
if (opts & PF_OPT_VERBOSE2) {
|
||||
printf(" id: %016llx creatorid: %08x\n",
|
||||
betoh64(s->id), ntohl(s->creatorid));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: pfctl.8,v 1.102 2003/09/18 09:18:51 jmc Exp $
|
||||
.\" $OpenBSD: pfctl.8,v 1.110 2004/03/20 09:31:42 david Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2001 Kjell Wooding. All rights reserved.
|
||||
.\"
|
||||
@ -33,15 +33,17 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm pfctl
|
||||
.Bk -words
|
||||
.Op Fl AdeghnNqrROvz
|
||||
.Op Fl AdeghNnOqRrvz
|
||||
.Op Fl a Ar anchor Ns Op Ar :ruleset
|
||||
.Op Fl D Ar macro=value
|
||||
.Op Fl f Ar file
|
||||
.Op Fl F Ar modifier
|
||||
.Op Fl f Ar file
|
||||
.Op Fl i Ar interface
|
||||
.Op Fl k Ar host
|
||||
.Op Fl p Ar device
|
||||
.Op Fl s Ar modifier
|
||||
.Op Fl t Ar table
|
||||
.Op Fl T Ar command Op Ar address ...
|
||||
.Op Fl t Ar table
|
||||
.Op Fl x Ar level
|
||||
.Ek
|
||||
.Sh DESCRIPTION
|
||||
@ -93,6 +95,9 @@ The
|
||||
utility provides several commands.
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl A
|
||||
Load only the queue rules present in the rule file.
|
||||
Other rules and options are ignored.
|
||||
.It Fl a Ar anchor Ns Op Ar :ruleset
|
||||
Apply flags
|
||||
.Fl f ,
|
||||
@ -134,11 +139,6 @@ This is similar to C rules for variables.
|
||||
It is possible to create distinct tables with the same name in the global
|
||||
ruleset and in an anchor, but this is often bad design and a warning will be
|
||||
issued in that case.
|
||||
.It Fl A
|
||||
Load only the queue rules present in the rule file.
|
||||
Other rules and options are ignored.
|
||||
.It Fl d
|
||||
Disable the packet filter.
|
||||
.It Fl D Ar macro=value
|
||||
Define
|
||||
.Ar macro
|
||||
@ -148,17 +148,10 @@ on the command line.
|
||||
Overrides the definition of
|
||||
.Ar macro
|
||||
in the ruleset.
|
||||
.It Fl d
|
||||
Disable the packet filter.
|
||||
.It Fl e
|
||||
Enable the packet filter.
|
||||
.It Fl f Ar file
|
||||
Load the rules contained in
|
||||
.Ar file .
|
||||
This
|
||||
.Ar file
|
||||
may contain macros, tables, options, and normalization, queueing,
|
||||
translation, and filtering rules.
|
||||
With the exception of macros and tables, the statements must appear in that
|
||||
order.
|
||||
.It Fl F Ar modifier
|
||||
Flush the filter parameters specified by
|
||||
.Ar modifier
|
||||
@ -173,6 +166,8 @@ Flush the queue rules.
|
||||
Flush the filter rules.
|
||||
.It Fl F Ar state
|
||||
Flush the state table (NAT and filter).
|
||||
.It Fl F Ar Sources
|
||||
Flush the source tracking table.
|
||||
.It Fl F Ar info
|
||||
Flush the filter information (statistics that are not bound to rules).
|
||||
.It Fl F Ar Tables
|
||||
@ -182,8 +177,22 @@ Flush the passive operating system fingerprints.
|
||||
.It Fl F Ar all
|
||||
Flush all of the above.
|
||||
.El
|
||||
.It Fl f Ar file
|
||||
Load the rules contained in
|
||||
.Ar file .
|
||||
This
|
||||
.Ar file
|
||||
may contain macros, tables, options, and normalization, queueing,
|
||||
translation, and filtering rules.
|
||||
With the exception of macros and tables, the statements must appear in that
|
||||
order.
|
||||
.It Fl g
|
||||
Include output helpful for debugging.
|
||||
.It Fl h
|
||||
Help.
|
||||
.It Fl i Ar interface
|
||||
Restrict the operation to the given
|
||||
.Ar interface .
|
||||
.It Fl k Ar host
|
||||
Kill all of the state entries originating from the specified
|
||||
.Ar host .
|
||||
@ -207,29 +216,32 @@ to
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -k host1 -k host2
|
||||
.Ed
|
||||
.It Fl h
|
||||
Help.
|
||||
.It Fl n
|
||||
Do not actually load rules, just parse them.
|
||||
.It Fl N
|
||||
Load only the NAT rules present in the rule file.
|
||||
Other rules and options are ignored.
|
||||
.It Fl q
|
||||
Only print errors and warnings.
|
||||
.It Fl r
|
||||
Perform reverse DNS lookups on states when displaying them.
|
||||
.It Fl R
|
||||
Load only the filter rules present in the rule file.
|
||||
Other rules and options are ignored.
|
||||
.It Fl n
|
||||
Do not actually load rules, just parse them.
|
||||
.It Fl O
|
||||
Load only the options present in the rule file.
|
||||
Other rules and options are ignored.
|
||||
.It Fl p Ar device
|
||||
Use the device file
|
||||
.Ar device
|
||||
instead of the default
|
||||
.Pa /dev/pf .
|
||||
.It Fl q
|
||||
Only print errors and warnings.
|
||||
.It Fl R
|
||||
Load only the filter rules present in the rule file.
|
||||
Other rules and options are ignored.
|
||||
.It Fl r
|
||||
Perform reverse DNS lookups on states when displaying them.
|
||||
.It Fl s Ar modifier
|
||||
Show the filter parameters specified by
|
||||
.Ar modifier
|
||||
(may be abbreviated):
|
||||
.Pp
|
||||
.Bl -tag -width xxxxxxxxxxxx -compact
|
||||
.Bl -tag -width xxxxxxxxxxxxx -compact
|
||||
.It Fl s Ar nat
|
||||
Show the currently loaded NAT rules.
|
||||
.It Fl s Ar queue
|
||||
@ -261,8 +273,13 @@ is specified as well, the named rulesets currently loaded in the specified
|
||||
anchor are shown instead.
|
||||
.It Fl s Ar state
|
||||
Show the contents of the state table.
|
||||
.It Fl s Ar Sources
|
||||
Show the contents of the source tracking table.
|
||||
.It Fl s Ar info
|
||||
Show filter information (statistics and counters).
|
||||
When used together with
|
||||
.Fl v ,
|
||||
source tracking statistics are also shown.
|
||||
.It Fl s Ar labels
|
||||
Show per-rule statistics (label, evaluations, packets, bytes) of
|
||||
filter rules with labels, useful for accounting.
|
||||
@ -274,16 +291,17 @@ Show the current pool memory hard limits.
|
||||
Show the list of tables.
|
||||
.It Fl s Ar osfp
|
||||
Show the list of operating system fingerprints.
|
||||
Can be used in combination with
|
||||
.Fl o Ar file
|
||||
to list the fingerprints in a
|
||||
.Xr pf.os 5
|
||||
file.
|
||||
.It Fl s Ar Interfaces
|
||||
Show the list of interfaces and interface drivers available to PF.
|
||||
When used together with a double
|
||||
.Fl v ,
|
||||
interface statistics are also shown.
|
||||
.Fl i
|
||||
can be used to select an interface or a group of interfaces.
|
||||
.It Fl s Ar all
|
||||
Show all of the above.
|
||||
Show all of the above, except for the lists of interfaces and operating
|
||||
system fingerprints.
|
||||
.El
|
||||
.It Fl t Ar table
|
||||
Specify the name of the table.
|
||||
.It Fl T Ar command Op Ar address ...
|
||||
Specify the
|
||||
.Ar command
|
||||
@ -334,7 +352,7 @@ Comments starting with a "#" are allowed in the text file.
|
||||
With these commands, the
|
||||
.Fl v
|
||||
flag can also be used once or twice, in which case
|
||||
.Nm pfctl
|
||||
.Nm
|
||||
will print the
|
||||
detailed result of the operation for each individual address, prefixed by
|
||||
one of the following letters:
|
||||
@ -359,7 +377,7 @@ The address/network has been cleared (statistics).
|
||||
Each table maintains a set of counters that can be retrieved using the
|
||||
.Fl v
|
||||
flag of
|
||||
.Nm pfctl .
|
||||
.Nm .
|
||||
For example, the following commands define a wide open firewall which will keep
|
||||
track of packets going to or coming from the
|
||||
.Ox
|
||||
@ -367,8 +385,8 @@ ftp server.
|
||||
The following commands configure the firewall and send 10 pings to the ftp
|
||||
server:
|
||||
.Bd -literal -offset indent
|
||||
# printf \&"table <test> { ftp.openbsd.org }\en \e
|
||||
\ \ pass out to <test> keep state\en" \&| pfctl -f-
|
||||
# printf "table <test> { ftp.openbsd.org }\en \e
|
||||
pass out to <test> keep state\en" | pfctl -f-
|
||||
# ping -qc10 ftp.openbsd.org
|
||||
.Ed
|
||||
.Pp
|
||||
@ -381,12 +399,12 @@ The time at which the current accounting started is also shown with the
|
||||
line.
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -t test -vTshow
|
||||
\ \ \ 129.128.5.191
|
||||
\ \ \ \ Cleared: \ \ \ \ Thu Feb 13 18:55:18 2003
|
||||
\ \ \ \ In/Block: \ \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ In/Pass: \ \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ]
|
||||
\ \ \ \ Out/Block: \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ Out/Pass: \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ]
|
||||
129.128.5.191
|
||||
Cleared: Thu Feb 13 18:55:18 2003
|
||||
In/Block: [ Packets: 0 Bytes: 0 ]
|
||||
In/Pass: [ Packets: 10 Bytes: 840 ]
|
||||
Out/Block: [ Packets: 0 Bytes: 0 ]
|
||||
Out/Pass: [ Packets: 10 Bytes: 840 ]
|
||||
.Ed
|
||||
.Pp
|
||||
Similarly, it is possible to view global information about the tables
|
||||
@ -401,19 +419,19 @@ packet statistics for the whole table:
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -vvsTables
|
||||
--a-r- test
|
||||
\ \ \ \ Addresses: \ \ 1
|
||||
\ \ \ \ Cleared: \ \ \ \ Thu Feb 13 18:55:18 2003
|
||||
\ \ \ \ References: \ [ Anchors: 0 \ \ \ \ \ \ \ Rules: 1 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ Evaluations: [ NoMatch: 3496 \ \ \ \ Match: 1 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ In/Block: \ \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ In/Pass: \ \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ]
|
||||
\ \ \ \ In/XPass: \ \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ Out/Block: \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ Out/Pass: \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ]
|
||||
\ \ \ \ Out/XPass: \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
Addresses: 1
|
||||
Cleared: Thu Feb 13 18:55:18 2003
|
||||
References: [ Anchors: 0 Rules: 1 ]
|
||||
Evaluations: [ NoMatch: 3496 Match: 1 ]
|
||||
In/Block: [ Packets: 0 Bytes: 0 ]
|
||||
In/Pass: [ Packets: 10 Bytes: 840 ]
|
||||
In/XPass: [ Packets: 0 Bytes: 0 ]
|
||||
Out/Block: [ Packets: 0 Bytes: 0 ]
|
||||
Out/Pass: [ Packets: 10 Bytes: 840 ]
|
||||
Out/XPass: [ Packets: 0 Bytes: 0 ]
|
||||
.Ed
|
||||
.Pp
|
||||
As we can see here, only one packet - the initial ping request - matched the
|
||||
As we can see here, only one packet \- the initial ping request \- matched the
|
||||
table; but all packets passing as the result of the state are correctly
|
||||
accounted for.
|
||||
Reloading the table(s) or ruleset will not affect packet accounting in any way.
|
||||
@ -421,14 +439,14 @@ The two
|
||||
.Ar XPass
|
||||
counters are incremented instead of the
|
||||
.Ar Pass
|
||||
counters when a \&"stateful\&" packet is passed but doesn't match the table
|
||||
counters when a "stateful" packet is passed but doesn't match the table
|
||||
anymore.
|
||||
This will happen in our example if someone flushes the table while the ping
|
||||
command is running.
|
||||
.Pp
|
||||
When used with a single
|
||||
.Fl v ,
|
||||
.Nm pfctl
|
||||
.Nm
|
||||
will only display the first line containing the table flags and name.
|
||||
The flags are defined as follows:
|
||||
.Pp
|
||||
@ -459,6 +477,8 @@ For tables which are referenced (used) by rules.
|
||||
This flag is set when a table in the main ruleset is hidden by one or more
|
||||
tables of the same name in sub-rulesets (anchors).
|
||||
.El
|
||||
.It Fl t Ar table
|
||||
Specify the name of the table.
|
||||
.It Fl v
|
||||
Produce more verbose output.
|
||||
A second use of
|
||||
|
@ -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
|
||||
@ -60,17 +61,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 *);
|
||||
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);
|
||||
@ -82,6 +85,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;
|
||||
@ -90,6 +95,8 @@ int loadopt;
|
||||
int altqsupport;
|
||||
|
||||
int dev = -1;
|
||||
int first_title = 1;
|
||||
int labels = 0;
|
||||
|
||||
const char *infile;
|
||||
|
||||
@ -98,6 +105,7 @@ static const struct {
|
||||
int index;
|
||||
} pf_limits[] = {
|
||||
{ "states", PF_LIMIT_STATES },
|
||||
{ "src-nodes", PF_LIMIT_SRC_NODES },
|
||||
{ "frags", PF_LIMIT_FRAGS },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
@ -156,12 +164,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[] = {
|
||||
@ -179,12 +189,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);
|
||||
}
|
||||
|
||||
@ -239,7 +251,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;
|
||||
@ -269,19 +281,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);
|
||||
@ -290,7 +296,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;
|
||||
@ -320,24 +326,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);
|
||||
@ -346,32 +342,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];
|
||||
@ -386,6 +400,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));
|
||||
@ -419,7 +436,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];
|
||||
@ -545,8 +563,18 @@ pfctl_print_rule_counters(struct pf_rule *rule, int opts)
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
printf(" [ Evaluations: %-8llu Packets: %-8llu "
|
||||
"Bytes: %-10llu States: %-6u]\n",
|
||||
rule->evaluations, rule->packets,
|
||||
rule->bytes, rule->states);
|
||||
(unsigned long long)rule->evaluations,
|
||||
(unsigned long long)rule->packets,
|
||||
(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
|
||||
@ -554,7 +582,7 @@ 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) {
|
||||
@ -571,6 +599,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;
|
||||
@ -587,11 +617,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;
|
||||
@ -609,11 +653,14 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname,
|
||||
if (pr.rule.label[0]) {
|
||||
printf("%s ", pr.rule.label);
|
||||
printf("%llu %llu %llu\n",
|
||||
pr.rule.evaluations, pr.rule.packets,
|
||||
pr.rule.bytes);
|
||||
(unsigned long long)pr.rule.evaluations,
|
||||
(unsigned long long)pr.rule.packets,
|
||||
(unsigned long long)pr.rule.bytes);
|
||||
}
|
||||
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);
|
||||
}
|
||||
@ -641,11 +688,14 @@ pfctl_show_rules(int dev, int opts, int format, char *anchorname,
|
||||
if (pr.rule.label[0]) {
|
||||
printf("%s ", pr.rule.label);
|
||||
printf("%llu %llu %llu\n",
|
||||
pr.rule.evaluations, pr.rule.packets,
|
||||
pr.rule.bytes);
|
||||
(unsigned long long)pr.rule.evaluations,
|
||||
(unsigned long long)pr.rule.packets,
|
||||
(unsigned long long)pr.rule.bytes);
|
||||
}
|
||||
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);
|
||||
}
|
||||
@ -660,7 +710,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;
|
||||
@ -708,6 +758,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);
|
||||
@ -717,21 +771,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");
|
||||
@ -748,16 +845,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))
|
||||
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);
|
||||
p++;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_show_status(int dev)
|
||||
pfctl_show_status(int dev, int opts)
|
||||
{
|
||||
struct pf_status status;
|
||||
|
||||
@ -765,16 +866,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;
|
||||
@ -792,14 +897,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);
|
||||
@ -837,6 +944,7 @@ int
|
||||
pfctl_add_rule(struct pfctl *pf, struct pf_rule *r)
|
||||
{
|
||||
u_int8_t rs_num;
|
||||
struct pfioc_rule pr;
|
||||
|
||||
switch (r->action) {
|
||||
case PF_SCRUB:
|
||||
@ -874,12 +982,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)
|
||||
@ -912,26 +1027,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 pfr_buffer *t, buf;
|
||||
struct pfioc_altq pa;
|
||||
struct pfctl pf;
|
||||
struct pfr_table trs;
|
||||
int i;
|
||||
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,
|
||||
@ -947,46 +1067,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: "
|
||||
@ -994,57 +1121,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);
|
||||
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
|
||||
@ -1062,7 +1162,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)) {
|
||||
@ -1180,6 +1280,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)
|
||||
{
|
||||
@ -1250,14 +1399,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 {
|
||||
@ -1274,8 +1424,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))
|
||||
@ -1309,8 +1457,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;
|
||||
@ -1339,6 +1487,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");
|
||||
@ -1373,6 +1524,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) {
|
||||
@ -1422,14 +1576,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();
|
||||
@ -1468,11 +1616,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;
|
||||
@ -1503,32 +1654,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;
|
||||
@ -1539,6 +1696,9 @@ main(int argc, char *argv[])
|
||||
pfctl_load_fingerprints(dev, opts);
|
||||
pfctl_show_fingerprints(opts);
|
||||
break;
|
||||
case 'I':
|
||||
pfctl_show_ifaces(ifaceopt, opts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1554,7 +1714,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);
|
||||
@ -1562,11 +1725,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);
|
||||
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);
|
||||
@ -1577,7 +1743,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,
|
||||
@ -1590,7 +1756,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))
|
||||
|
@ -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
|
||||
@ -33,7 +33,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 */
|
||||
@ -74,13 +75,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);
|
||||
|
||||
#ifndef DEFAULT_PRIORITY
|
||||
#define DEFAULT_PRIORITY 1
|
||||
@ -111,5 +116,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_ */
|
||||
|
@ -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
|
||||
@ -21,7 +21,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/limits.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
@ -29,6 +28,7 @@
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -82,8 +82,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)
|
||||
{
|
||||
@ -158,14 +156,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] != NULL) {
|
||||
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 ");
|
||||
@ -261,6 +259,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);
|
||||
@ -410,8 +410,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);
|
||||
@ -485,9 +483,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;
|
||||
@ -495,10 +496,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);
|
||||
}
|
||||
@ -593,9 +594,6 @@ eval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa)
|
||||
}
|
||||
}
|
||||
|
||||
if (pa->qid == 0)
|
||||
pa->qid = ++max_qid;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -665,13 +663,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);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pfctl_osfp.c,v 1.4 2003/08/27 17:42:00 frantzen Exp $ */
|
||||
/* $OpenBSD: pfctl_osfp.c,v 1.8 2004/02/27 10:42:00 henning Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.org>
|
||||
@ -31,6 +31,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "pfctl_parser.h"
|
||||
#include "pfctl.h"
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
@ -308,11 +309,17 @@ pfctl_load_fingerprints(int dev, int opts)
|
||||
void
|
||||
pfctl_show_fingerprints(int opts)
|
||||
{
|
||||
printf("Passive OS Fingerprints:\n");
|
||||
printf("\tClass\tVersion\tSubtype(subversion)\n");
|
||||
printf("\t-----\t-------\t-------------------\n");
|
||||
if (LIST_FIRST(&classes) != NULL) {
|
||||
if (opts & PF_OPT_SHOWALL) {
|
||||
pfctl_print_title("OS FINGERPRINTS:");
|
||||
printf("%u fingerprints loaded\n", fingerprint_count);
|
||||
} else {
|
||||
printf("Class\tVersion\tSubtype(subversion)\n");
|
||||
printf("-----\t-------\t-------------------\n");
|
||||
sort_name_list(opts, &classes);
|
||||
print_name_list(opts, &classes, "\t");
|
||||
print_name_list(opts, &classes, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Lookup a fingerprint */
|
||||
|
@ -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
|
||||
@ -31,6 +32,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
@ -192,6 +194,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 }
|
||||
};
|
||||
|
||||
@ -458,23 +461,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;
|
||||
@ -484,48 +491,54 @@ 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");
|
||||
printf(" %-25s %14llu %16llu\n", "Bytes In",
|
||||
s->bcounters[0][0], s->bcounters[1][0]);
|
||||
(unsigned long long)s->bcounters[0][0],
|
||||
(unsigned long long)s->bcounters[1][0]);
|
||||
printf(" %-25s %14llu %16llu\n", "Bytes Out",
|
||||
s->bcounters[0][1], s->bcounters[1][1]);
|
||||
(unsigned long long)s->bcounters[0][1],
|
||||
(unsigned long long)s->bcounters[1][1]);
|
||||
printf(" Packets In\n");
|
||||
printf(" %-23s %14llu %16llu\n", "Passed",
|
||||
s->pcounters[0][0][PF_PASS],
|
||||
s->pcounters[1][0][PF_PASS]);
|
||||
(unsigned long long)s->pcounters[0][0][PF_PASS],
|
||||
(unsigned long long)s->pcounters[1][0][PF_PASS]);
|
||||
printf(" %-23s %14llu %16llu\n", "Blocked",
|
||||
s->pcounters[0][0][PF_DROP],
|
||||
s->pcounters[1][0][PF_DROP]);
|
||||
(unsigned long long)s->pcounters[0][0][PF_DROP],
|
||||
(unsigned long long)s->pcounters[1][0][PF_DROP]);
|
||||
printf(" Packets Out\n");
|
||||
printf(" %-23s %14llu %16llu\n", "Passed",
|
||||
s->pcounters[0][1][PF_PASS],
|
||||
s->pcounters[1][1][PF_PASS]);
|
||||
(unsigned long long)s->pcounters[0][1][PF_PASS],
|
||||
(unsigned long long)s->pcounters[1][1][PF_PASS]);
|
||||
printf(" %-23s %14llu %16llu\n\n", "Blocked",
|
||||
s->pcounters[0][1][PF_DROP],
|
||||
s->pcounters[1][1][PF_DROP]);
|
||||
(unsigned long long)s->pcounters[0][1][PF_DROP],
|
||||
(unsigned long long)s->pcounters[1][1][PF_DROP]);
|
||||
}
|
||||
printf("%-27s %14s %16s\n", "State Table", "Total", "Rate");
|
||||
printf(" %-25s %14u %14s\n", "current entries", s->states, "");
|
||||
for (i = 0; i < FCNT_MAX; i++) {
|
||||
printf(" %-25s %14llu", pf_fcounters[i],
|
||||
printf(" %-25s %14llu ", pf_fcounters[i],
|
||||
(unsigned long long)s->fcounters[i]);
|
||||
if (runtime > 0)
|
||||
printf("%14.1f/s\n",
|
||||
@ -533,6 +546,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],
|
||||
@ -545,6 +572,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)
|
||||
{
|
||||
@ -582,7 +660,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)
|
||||
@ -701,7 +779,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])
|
||||
@ -712,6 +796,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)
|
||||
@ -879,6 +1003,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");
|
||||
@ -897,7 +1023,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;
|
||||
@ -919,6 +1046,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,
|
||||
@ -930,6 +1061,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;
|
||||
}
|
||||
@ -944,15 +1079,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();
|
||||
|
||||
@ -960,14 +1138,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;
|
||||
@ -977,23 +1169,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) {
|
||||
@ -1018,9 +1231,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);
|
||||
}
|
||||
|
||||
@ -1078,29 +1288,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 (!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");
|
||||
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)) {
|
||||
while ((p = strrchr(ps, ':')) != NULL) {
|
||||
if (!strcmp(p+1, "network"))
|
||||
flags |= PFI_AFLAG_NETWORK;
|
||||
else if (!strcmp(p+1, "broadcast"))
|
||||
flags |= PFI_AFLAG_BROADCAST;
|
||||
else if (!strcmp(p+1, "peer"))
|
||||
flags |= PFI_AFLAG_PEER;
|
||||
else if (!strcmp(p+1, "0"))
|
||||
flags |= PFI_AFLAG_NOALIAS;
|
||||
else {
|
||||
free(ps);
|
||||
return (NULL);
|
||||
}
|
||||
*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);
|
||||
}
|
||||
@ -1114,10 +1334,17 @@ 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) {
|
||||
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");
|
||||
@ -1127,7 +1354,6 @@ host_v4(const char *s, int mask)
|
||||
set_ipmask(h, bits);
|
||||
h->next = NULL;
|
||||
h->tail = h;
|
||||
}
|
||||
|
||||
return (h);
|
||||
}
|
||||
@ -1167,12 +1393,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);
|
||||
|
||||
@ -1180,6 +1414,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");
|
||||
@ -1211,6 +1456,7 @@ host_dns(const char *s, int v4mask, int v6mask)
|
||||
}
|
||||
}
|
||||
freeaddrinfo(res0);
|
||||
free(ps);
|
||||
|
||||
return (h);
|
||||
}
|
||||
@ -1284,3 +1530,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);
|
||||
}
|
||||
|
@ -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
|
||||
@ -45,6 +45,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
|
||||
|
||||
@ -66,19 +67,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;
|
||||
@ -90,6 +85,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 */
|
||||
@ -98,6 +94,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;
|
||||
@ -143,7 +143,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 *);
|
||||
@ -154,15 +154,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 *);
|
||||
@ -217,8 +220,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);
|
||||
|
@ -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>
|
||||
@ -81,25 +81,37 @@ 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);
|
||||
|
||||
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);
|
||||
}
|
||||
@ -155,7 +167,7 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root)
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
return (mnr);
|
||||
}
|
||||
|
||||
void
|
||||
@ -245,12 +257,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
|
||||
@ -277,10 +290,10 @@ print_cbqstats(struct queue_stats cur)
|
||||
{
|
||||
printf(" [ pkts: %10llu bytes: %10llu "
|
||||
"dropped pkts: %6llu bytes: %6llu ]\n",
|
||||
cur.data.cbq_stats.xmit_cnt.packets,
|
||||
cur.data.cbq_stats.xmit_cnt.bytes,
|
||||
cur.data.cbq_stats.drop_cnt.packets,
|
||||
cur.data.cbq_stats.drop_cnt.bytes);
|
||||
(unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
|
||||
(unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
|
||||
(unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
|
||||
(unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
|
||||
printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
|
||||
cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
|
||||
cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
|
||||
@ -298,10 +311,10 @@ print_priqstats(struct queue_stats cur)
|
||||
{
|
||||
printf(" [ pkts: %10llu bytes: %10llu "
|
||||
"dropped pkts: %6llu bytes: %6llu ]\n",
|
||||
cur.data.priq_stats.xmitcnt.packets,
|
||||
cur.data.priq_stats.xmitcnt.bytes,
|
||||
cur.data.priq_stats.dropcnt.packets,
|
||||
cur.data.priq_stats.dropcnt.bytes);
|
||||
(unsigned long long)cur.data.priq_stats.xmitcnt.packets,
|
||||
(unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
|
||||
(unsigned long long)cur.data.priq_stats.dropcnt.packets,
|
||||
(unsigned long long)cur.data.priq_stats.dropcnt.bytes);
|
||||
printf(" [ qlength: %3d/%3d ]\n",
|
||||
cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
|
||||
|
||||
@ -318,10 +331,10 @@ print_hfscstats(struct queue_stats cur)
|
||||
{
|
||||
printf(" [ pkts: %10llu bytes: %10llu "
|
||||
"dropped pkts: %6llu bytes: %6llu ]\n",
|
||||
cur.data.hfsc_stats.xmit_cnt.packets,
|
||||
cur.data.hfsc_stats.xmit_cnt.bytes,
|
||||
cur.data.hfsc_stats.drop_cnt.packets,
|
||||
cur.data.hfsc_stats.drop_cnt.bytes);
|
||||
(unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
|
||||
(unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
|
||||
(unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
|
||||
(unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
|
||||
printf(" [ qlength: %3d/%3d ]\n",
|
||||
cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pfctl_radix.c,v 1.21 2003/09/24 09:12:35 cedric Exp $ */
|
||||
/* $OpenBSD: pfctl_radix.c,v 1.24 2004/02/10 18:29:30 henning Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Cedric Berger
|
||||
@ -259,7 +259,8 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (tbl == NULL || size == NULL || *size < 0 || (*size && addr == NULL)) {
|
||||
if (tbl == NULL || size == NULL || *size < 0 ||
|
||||
(*size && addr == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
@ -281,7 +282,8 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (tbl == NULL || size == NULL || *size < 0 || (*size && addr == NULL)) {
|
||||
if (tbl == NULL || size == NULL || *size < 0 ||
|
||||
(*size && addr == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
@ -454,11 +456,40 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* interface management code */
|
||||
|
||||
int
|
||||
pfi_get_ifaces(const char *filter, struct pfi_if *buf, int *size, int flags)
|
||||
{
|
||||
struct pfioc_iface io;
|
||||
|
||||
if (size == NULL || *size < 0 || (*size && buf == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfiio_flags = flags;
|
||||
if (filter != NULL)
|
||||
if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
|
||||
sizeof(io.pfiio_name)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
io.pfiio_buffer = buf;
|
||||
io.pfiio_esize = sizeof(*buf);
|
||||
io.pfiio_size = *size;
|
||||
if (ioctl(dev, DIOCIGETIFACES, &io))
|
||||
return (-1);
|
||||
*size = io.pfiio_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* buffer management code */
|
||||
|
||||
size_t buf_esize[PFRB_MAX] = { 0,
|
||||
sizeof(struct pfr_table), sizeof(struct pfr_tstats),
|
||||
sizeof(struct pfr_addr), sizeof(struct pfr_astats),
|
||||
sizeof(struct pfi_if), sizeof(struct pfioc_trans_e)
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
@ -61,12 +61,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)) && \
|
||||
@ -165,6 +172,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);
|
||||
@ -348,13 +359,14 @@ print_tstats(struct pfr_tstats *ts, int debug)
|
||||
ts->pfrts_refcnt[PFR_REFCNT_ANCHOR],
|
||||
ts->pfrts_refcnt[PFR_REFCNT_RULE]);
|
||||
printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n",
|
||||
ts->pfrts_nomatch, ts->pfrts_match);
|
||||
(unsigned long long)ts->pfrts_nomatch,
|
||||
(unsigned long long)ts->pfrts_match);
|
||||
for (dir = 0; dir < PFR_DIR_MAX; dir++)
|
||||
for (op = 0; op < PFR_OP_TABLE_MAX; op++)
|
||||
printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
|
||||
stats_text[dir][op],
|
||||
ts->pfrts_packets[dir][op],
|
||||
ts->pfrts_bytes[dir][op]);
|
||||
(unsigned long long)ts->pfrts_packets[dir][op],
|
||||
(unsigned long long)ts->pfrts_bytes[dir][op]);
|
||||
}
|
||||
|
||||
int
|
||||
@ -431,8 +443,8 @@ print_astats(struct pfr_astats *as, int dns)
|
||||
for (op = 0; op < PFR_OP_ADDR_MAX; op++)
|
||||
printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
|
||||
stats_text[dir][op],
|
||||
as->pfras_packets[dir][op],
|
||||
as->pfras_bytes[dir][op]);
|
||||
(unsigned long long)as->pfras_packets[dir][op],
|
||||
(unsigned long long)as->pfras_bytes[dir][op]);
|
||||
}
|
||||
|
||||
void
|
||||
@ -449,12 +461,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;
|
||||
|
||||
@ -522,3 +533,79 @@ 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);
|
||||
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(")");
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: pflogd.8,v 1.22 2003/06/03 13:16:08 jmc Exp $
|
||||
.\" $OpenBSD: pflogd.8,v 1.24 2004/01/16 10:45:49 jmc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2001 Can Erkin Acar. All rights reserved.
|
||||
.\"
|
||||
@ -32,7 +32,7 @@
|
||||
.Nd packet filter logging daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm pflogd
|
||||
.Op Fl D
|
||||
.Op Fl Dx
|
||||
.Op Fl d Ar delay
|
||||
.Op Fl f Ar filename
|
||||
.Op Fl s Ar snaplen
|
||||
@ -57,11 +57,11 @@ hopefully offline in case there are bugs in the packet parsing code of
|
||||
.Pp
|
||||
.Nm
|
||||
closes and then re-opens the log file when it receives
|
||||
.Va SIGHUP ,
|
||||
.Dv SIGHUP ,
|
||||
permitting
|
||||
.Xr newsyslog 8
|
||||
to rotate logfiles automatically.
|
||||
.Va SIGALRM
|
||||
.Dv SIGALRM
|
||||
causes
|
||||
.Nm
|
||||
to flush the current logfile buffers to the disk, thus making the most
|
||||
@ -71,22 +71,32 @@ The buffers are also flushed every
|
||||
seconds.
|
||||
.Pp
|
||||
If the log file contains data after a restart or a
|
||||
.Va SIGHUP ,
|
||||
.Dv SIGHUP ,
|
||||
new logs are appended to the existing file.
|
||||
If the existing log file was created with a different snaplen,
|
||||
.Nm
|
||||
temporarily uses the old snaplen to keep the log file consistent.
|
||||
.Pp
|
||||
.Nm
|
||||
tries to preserve the integrity of the log file against I/O errors.
|
||||
Furthermore, integrity of an existing log file is verified before
|
||||
appending.
|
||||
If there is an invalid log file or an I/O error, logging is suspended until a
|
||||
.Dv SIGHUP
|
||||
or a
|
||||
.Dv SIGALRM
|
||||
is received.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl d Ar delay
|
||||
Time in seconds to delay between automatic flushes of the file.
|
||||
This may be specified with a value between 5 and 3600 seconds.
|
||||
If not specified, the default is 60 seconds.
|
||||
.It Fl D
|
||||
Debugging mode.
|
||||
.Nm
|
||||
does not disassociate from the controlling terminal.
|
||||
.It Fl d Ar delay
|
||||
Time in seconds to delay between automatic flushes of the file.
|
||||
This may be specified with a value between 5 and 3600 seconds.
|
||||
If not specified, the default is 60 seconds.
|
||||
.It Fl f Ar filename
|
||||
Log output filename.
|
||||
Default is
|
||||
@ -98,6 +108,8 @@ bytes of data from each packet rather than the default of 96.
|
||||
The default of 96 is adequate for IP, ICMP, TCP, and UDP headers but may
|
||||
truncate protocol information for other protocols.
|
||||
Other file parsers may desire a higher snaplen.
|
||||
.It Fl x
|
||||
Check the integrity of an existing log file, and return.
|
||||
.It Ar expression
|
||||
Selects which packets will be dumped, using the regular language of
|
||||
.Xr tcpdump 8 .
|
||||
@ -106,13 +118,13 @@ Selects which packets will be dumped, using the regular language of
|
||||
.Bl -tag -width /var/run/pflogd.pid -compact
|
||||
.It Pa /var/run/pflogd.pid
|
||||
Process ID of the currently running
|
||||
.Nm pflogd .
|
||||
.Nm .
|
||||
.It Pa /var/log/pflog
|
||||
Default log file.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
Log specific tcp packets to a different log file with a large snaplen
|
||||
(useful with a log-all rule to dump complete sessions)
|
||||
(useful with a log-all rule to dump complete sessions):
|
||||
.Bd -literal -offset indent
|
||||
# pflogd -s 1600 -f suspicious.log port 80 and host evilhost
|
||||
.Ed
|
||||
@ -123,7 +135,8 @@ Display binary logs:
|
||||
.Ed
|
||||
.Pp
|
||||
Display the logs in real time (this does not interfere with the
|
||||
operation of pflogd):
|
||||
operation of
|
||||
.Nm ) :
|
||||
.Bd -literal -offset indent
|
||||
# tcpdump -n -e -ttt -i pflog0
|
||||
.Ed
|
||||
@ -133,7 +146,7 @@ structure defined in
|
||||
.Aq Ar net/if_pflog.h .
|
||||
Tcpdump can restrict the output
|
||||
to packets logged on a specified interface, a rule number, a reason,
|
||||
a direction, an ip family or an action.
|
||||
a direction, an IP family or an action.
|
||||
.Pp
|
||||
.Bl -tag -width "reason match " -compact
|
||||
.It ip
|
||||
@ -141,9 +154,9 @@ Address family equals IPv4.
|
||||
.It ip6
|
||||
Address family equals IPv6.
|
||||
.It ifname kue0
|
||||
Interface name equals "kue0"
|
||||
Interface name equals "kue0".
|
||||
.It on kue0
|
||||
Interface name equals "kue0"
|
||||
Interface name equals "kue0".
|
||||
.It rulenum 10
|
||||
Rule number equals 10.
|
||||
.It reason match
|
||||
|
@ -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
|
||||
@ -31,6 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
@ -45,21 +46,14 @@
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <util.h>
|
||||
|
||||
#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;
|
||||
|
||||
@ -72,15 +66,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)
|
||||
@ -125,7 +147,7 @@ logmsg(int pri, const char *message, ...)
|
||||
__dead void
|
||||
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);
|
||||
}
|
||||
@ -148,37 +170,60 @@ 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)
|
||||
else {
|
||||
if (pcap_setfilter(hpcap, &bprog) < 0)
|
||||
logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
|
||||
if (filter != NULL)
|
||||
free(filter);
|
||||
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);
|
||||
|
||||
/* lock */
|
||||
if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
|
||||
logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -187,45 +232,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;
|
||||
@ -237,58 +288,224 @@ 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) {
|
||||
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);
|
||||
} else if (scan_dump(fp, st.st_size)) {
|
||||
/* XXX move file and continue? */
|
||||
fclose(fp);
|
||||
return (1);
|
||||
}
|
||||
snaplen = tmpsnap;
|
||||
|
||||
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,
|
||||
"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) {
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
while ((ch = getopt(argc, argv, "Dxd:s:f:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'D':
|
||||
Debug = 1;
|
||||
@ -305,6 +522,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();
|
||||
@ -327,6 +549,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);
|
||||
@ -334,25 +577,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));
|
||||
|
||||
@ -360,38 +607,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)
|
||||
|
47
contrib/pf/pflogd/pflogd.h
Normal file
47
contrib/pf/pflogd/pflogd.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* $OpenBSD: pflogd.h,v 1.2 2004/01/15 20:15:14 canacar Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003 Can Erkin Acar
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/limits.h>
|
||||
#include <pcap.h>
|
||||
|
||||
#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 1 /* filter optimization */
|
||||
#define FLUSH_DELAY 60 /* flush delay */
|
||||
|
||||
#define PFLOGD_LOG_FILE "/var/log/pflog"
|
||||
#define PFLOGD_DEFAULT_IF "pflog0"
|
||||
|
||||
#define PFLOGD_MAXSNAPLEN INT_MAX
|
||||
#define PFLOGD_BUFSIZE 65536 /* buffer size for incoming packets */
|
||||
|
||||
void logmsg(int priority, const char *message, ...);
|
||||
|
||||
/* Privilege separation */
|
||||
int priv_init(void);
|
||||
int priv_set_snaplen(int snaplen);
|
||||
int priv_open_log(void);
|
||||
pcap_t *pcap_open_live_fd(int fd, int snaplen, char *ebuf);
|
||||
|
||||
void set_pcap_filter(void);
|
||||
/* File descriptor send/recv */
|
||||
void send_fd(int, int);
|
||||
int receive_fd(int);
|
||||
|
||||
extern int Debug;
|
305
contrib/pf/pflogd/privsep.c
Normal file
305
contrib/pf/pflogd/privsep.c
Normal file
@ -0,0 +1,305 @@
|
||||
/* $OpenBSD: privsep.c,v 1.8 2004/03/14 19:17:05 otto Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003 Can Erkin Acar
|
||||
* Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* 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/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/bpf.h>
|
||||
|
||||
#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 <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include "pflogd.h"
|
||||
|
||||
enum cmd_types {
|
||||
PRIV_SET_SNAPLEN, /* set the snaplength */
|
||||
PRIV_OPEN_LOG /* open logfile for appending */
|
||||
};
|
||||
|
||||
static int priv_fd = -1;
|
||||
static volatile pid_t child_pid = -1;
|
||||
|
||||
volatile sig_atomic_t gotsig_chld = 0;
|
||||
|
||||
static void sig_pass_to_chld(int);
|
||||
static void sig_chld(int);
|
||||
static int may_read(int, void *, size_t);
|
||||
static void must_read(int, void *, size_t);
|
||||
static void must_write(int, void *, size_t);
|
||||
static int set_snaplen(int snap);
|
||||
|
||||
/* bpf filter expression common to parent and child */
|
||||
extern char *filter;
|
||||
extern char *errbuf;
|
||||
extern char *filename;
|
||||
extern pcap_t *hpcap;
|
||||
|
||||
/* based on syslogd privsep */
|
||||
int
|
||||
priv_init(void)
|
||||
{
|
||||
int i, fd, socks[2], cmd;
|
||||
int snaplen, ret;
|
||||
struct passwd *pw;
|
||||
|
||||
for (i = 1; i < _NSIG; i++)
|
||||
signal(i, SIG_DFL);
|
||||
|
||||
/* Create sockets */
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1)
|
||||
err(1, "socketpair() failed");
|
||||
|
||||
pw = getpwnam("_pflogd");
|
||||
if (pw == NULL)
|
||||
errx(1, "unknown user _pflogd");
|
||||
endpwent();
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid < 0)
|
||||
err(1, "fork() failed");
|
||||
|
||||
if (!child_pid) {
|
||||
gid_t gidset[1];
|
||||
|
||||
/* Child - drop privileges and return */
|
||||
if (chroot(pw->pw_dir) != 0)
|
||||
err(1, "unable to chroot");
|
||||
if (chdir("/") != 0)
|
||||
err(1, "unable to chdir");
|
||||
|
||||
gidset[0] = pw->pw_gid;
|
||||
if (setgroups(1, gidset) == -1)
|
||||
err(1, "setgroups() failed");
|
||||
if (setegid(pw->pw_gid) == -1)
|
||||
err(1, "setegid() failed");
|
||||
if (setgid(pw->pw_gid) == -1)
|
||||
err(1, "setgid() failed");
|
||||
if (seteuid(pw->pw_uid) == -1)
|
||||
err(1, "seteuid() failed");
|
||||
if (setuid(pw->pw_uid) == -1)
|
||||
err(1, "setuid() failed");
|
||||
close(socks[0]);
|
||||
priv_fd = socks[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Father */
|
||||
/* Pass ALRM/TERM/HUP through to child, and accept CHLD */
|
||||
signal(SIGALRM, sig_pass_to_chld);
|
||||
signal(SIGTERM, sig_pass_to_chld);
|
||||
signal(SIGHUP, sig_pass_to_chld);
|
||||
signal(SIGCHLD, sig_chld);
|
||||
|
||||
setproctitle("[priv]");
|
||||
close(socks[1]);
|
||||
|
||||
while (!gotsig_chld) {
|
||||
if (may_read(socks[0], &cmd, sizeof(int)))
|
||||
break;
|
||||
switch (cmd) {
|
||||
case PRIV_SET_SNAPLEN:
|
||||
logmsg(LOG_DEBUG,
|
||||
"[priv]: msg PRIV_SET_SNAPLENGTH received");
|
||||
must_read(socks[0], &snaplen, sizeof(int));
|
||||
|
||||
ret = set_snaplen(snaplen);
|
||||
if (ret) {
|
||||
logmsg(LOG_NOTICE,
|
||||
"[priv]: set_snaplen failed for snaplen %d",
|
||||
snaplen);
|
||||
}
|
||||
|
||||
must_write(socks[0], &ret, sizeof(int));
|
||||
break;
|
||||
|
||||
case PRIV_OPEN_LOG:
|
||||
logmsg(LOG_DEBUG,
|
||||
"[priv]: msg PRIV_OPEN_LOG received");
|
||||
/* create or append logs but do not follow symlinks */
|
||||
fd = open(filename,
|
||||
O_RDWR|O_CREAT|O_APPEND|O_NONBLOCK|O_NOFOLLOW,
|
||||
0600);
|
||||
if (fd < 0)
|
||||
logmsg(LOG_NOTICE,
|
||||
"[priv]: failed to open %s: %s",
|
||||
filename, strerror(errno));
|
||||
send_fd(socks[0], fd);
|
||||
close(fd);
|
||||
break;
|
||||
|
||||
default:
|
||||
logmsg(LOG_ERR, "[priv]: unknown command %d", cmd);
|
||||
_exit(1);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* this is called from parent */
|
||||
static int
|
||||
set_snaplen(int snap)
|
||||
{
|
||||
if (hpcap == NULL)
|
||||
return (1);
|
||||
|
||||
hpcap->snapshot = snap;
|
||||
set_pcap_filter();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* send the snaplength to privileged process
|
||||
*/
|
||||
int
|
||||
priv_set_snaplen(int snaplen)
|
||||
{
|
||||
int cmd, ret;
|
||||
|
||||
if (priv_fd < 0)
|
||||
errx(1, "%s: called from privileged portion", __func__);
|
||||
|
||||
cmd = PRIV_SET_SNAPLEN;
|
||||
|
||||
must_write(priv_fd, &cmd, sizeof(int));
|
||||
must_write(priv_fd, &snaplen, sizeof(int));
|
||||
|
||||
must_read(priv_fd, &ret, sizeof(int));
|
||||
|
||||
/* also set hpcap->snapshot in child */
|
||||
if (ret == 0)
|
||||
hpcap->snapshot = snaplen;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Open log-file */
|
||||
int
|
||||
priv_open_log(void)
|
||||
{
|
||||
int cmd, fd;
|
||||
|
||||
if (priv_fd < 0)
|
||||
errx(1, "%s: called from privileged portion\n", __func__);
|
||||
|
||||
cmd = PRIV_OPEN_LOG;
|
||||
must_write(priv_fd, &cmd, sizeof(int));
|
||||
fd = receive_fd(priv_fd);
|
||||
|
||||
return (fd);
|
||||
}
|
||||
|
||||
/* If priv parent gets a TERM or HUP, pass it through to child instead */
|
||||
static void
|
||||
sig_pass_to_chld(int sig)
|
||||
{
|
||||
int oerrno = errno;
|
||||
|
||||
if (child_pid != -1)
|
||||
kill(child_pid, sig);
|
||||
errno = oerrno;
|
||||
}
|
||||
|
||||
/* if parent gets a SIGCHLD, it will exit */
|
||||
static void
|
||||
sig_chld(int sig)
|
||||
{
|
||||
gotsig_chld = 1;
|
||||
}
|
||||
|
||||
/* Read all data or return 1 for error. */
|
||||
static int
|
||||
may_read(int fd, void *buf, size_t n)
|
||||
{
|
||||
char *s = buf;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = read(fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
return (1);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Read data with the assertion that it all must come through, or
|
||||
* else abort the process. Based on atomicio() from openssh. */
|
||||
static void
|
||||
must_read(int fd, void *buf, size_t n)
|
||||
{
|
||||
char *s = buf;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = read(fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
_exit(0);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Write data with the assertion that it all has to be written, or
|
||||
* else abort the process. Based on atomicio() from openssh. */
|
||||
static void
|
||||
must_write(int fd, void *buf, size_t n)
|
||||
{
|
||||
char *s = buf;
|
||||
ssize_t res, pos = 0;
|
||||
|
||||
while (n > pos) {
|
||||
res = write(fd, s + pos, n - pos);
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == EAGAIN)
|
||||
continue;
|
||||
case 0:
|
||||
_exit(0);
|
||||
default:
|
||||
pos += res;
|
||||
}
|
||||
}
|
||||
}
|
120
contrib/pf/pflogd/privsep_fdpass.c
Normal file
120
contrib/pf/pflogd/privsep_fdpass.c
Normal file
@ -0,0 +1,120 @@
|
||||
/* $OpenBSD: privsep_fdpass.c,v 1.1 2003/10/22 18:51:55 canacar Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2002 Matthieu Herrb
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "pflogd.h"
|
||||
|
||||
void
|
||||
send_fd(int sock, int fd)
|
||||
{
|
||||
struct msghdr msg;
|
||||
char tmp[CMSG_SPACE(sizeof(int))];
|
||||
struct cmsghdr *cmsg;
|
||||
struct iovec vec;
|
||||
int result = 0;
|
||||
ssize_t n;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
if (fd >= 0) {
|
||||
msg.msg_control = (caddr_t)tmp;
|
||||
msg.msg_controllen = CMSG_LEN(sizeof(int));
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
*(int *)CMSG_DATA(cmsg) = fd;
|
||||
} else {
|
||||
result = errno;
|
||||
}
|
||||
|
||||
vec.iov_base = &result;
|
||||
vec.iov_len = sizeof(int);
|
||||
msg.msg_iov = &vec;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
if ((n = sendmsg(sock, &msg, 0)) == -1)
|
||||
warn("%s: sendmsg(%d)", __func__, sock);
|
||||
if (n != sizeof(int))
|
||||
warnx("%s: sendmsg: expected sent 1 got %ld",
|
||||
__func__, (long)n);
|
||||
}
|
||||
|
||||
int
|
||||
receive_fd(int sock)
|
||||
{
|
||||
struct msghdr msg;
|
||||
char tmp[CMSG_SPACE(sizeof(int))];
|
||||
struct cmsghdr *cmsg;
|
||||
struct iovec vec;
|
||||
ssize_t n;
|
||||
int result;
|
||||
int fd;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
vec.iov_base = &result;
|
||||
vec.iov_len = sizeof(int);
|
||||
msg.msg_iov = &vec;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = tmp;
|
||||
msg.msg_controllen = sizeof(tmp);
|
||||
|
||||
if ((n = recvmsg(sock, &msg, 0)) == -1)
|
||||
warn("%s: recvmsg", __func__);
|
||||
if (n != sizeof(int))
|
||||
warnx("%s: recvmsg: expected received 1 got %ld",
|
||||
__func__, (long)n);
|
||||
if (result == 0) {
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (cmsg->cmsg_type != SCM_RIGHTS)
|
||||
warnx("%s: expected type %d got %d", __func__,
|
||||
SCM_RIGHTS, cmsg->cmsg_type);
|
||||
fd = (*(int *)CMSG_DATA(cmsg));
|
||||
return fd;
|
||||
} else {
|
||||
errno = result;
|
||||
return -1;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user