Commit resolved import of OpenBSD 4.1 pf userland from perforce.

Approved by:	re (kensmith)
This commit is contained in:
Max Laier 2007-07-03 12:30:03 +00:00
parent fc515400ab
commit 5ee7cd2107
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=171172
28 changed files with 3717 additions and 3499 deletions

View File

@ -1,29 +1,19 @@
.\" $FreeBSD$ .\" $FreeBSD$
.\" $OpenBSD: authpf.8,v 1.38 2005/01/04 09:57:04 jmc Exp $ .\" $OpenBSD: authpf.8,v 1.43 2007/02/24 17:21:04 beck Exp $
.\" .\"
.\" Copyright (c) 2002 Bob Beck (beck@openbsd.org>. All rights reserved. .\" Copyright (c) 1998-2007 Bob Beck (beck@openbsd.org>. All rights reserved.
.\" .\"
.\" Redistribution and use in source and binary forms, with or without .\" Permission to use, copy, modify, and distribute this software for any
.\" modification, are permitted provided that the following conditions .\" purpose with or without fee is hereby granted, provided that the above
.\" are met: .\" copyright notice and this permission notice appear in all copies.
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\" .\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" 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.
.\" .\"
.Dd March 28, 2006 .Dd March 28, 2006
.Dt AUTHPF 8 .Dt AUTHPF 8
@ -230,8 +220,11 @@ it becomes unresponsive, or if arp or address spoofing is used to
hijack the session. hijack the session.
Note that TCP keepalives are not sufficient for Note that TCP keepalives are not sufficient for
this, since they are not secure. this, since they are not secure.
Also note that Also note that the various SSH tunnelling mechanisms,
such as
.Ar AllowTcpForwarding .Ar AllowTcpForwarding
and
.Ar PermitTunnel ,
should be disabled for should be disabled for
.Nm .Nm
users to prevent them from circumventing restrictions imposed by the users to prevent them from circumventing restrictions imposed by the
@ -429,8 +422,7 @@ TCP connections.
external_if = "xl0" external_if = "xl0"
internal_if = "fxp0" internal_if = "fxp0"
pass in log quick on $internal_if proto tcp from $user_ip to any \e pass in log quick on $internal_if proto tcp from $user_ip to any
keep state
pass in quick on $internal_if from $user_ip to any pass in quick on $internal_if from $user_ip to any
.Ed .Ed
.Pp .Pp
@ -445,16 +437,15 @@ ipsec_gw="10.2.3.4"
# rdr ftp for proxying by ftp-proxy(8) # rdr ftp for proxying by ftp-proxy(8)
rdr on $internal_if proto tcp from $user_ip to any port 21 \e rdr on $internal_if proto tcp from $user_ip to any port 21 \e
-> 127.0.0.1 port 8081 -> 127.0.0.1 port 8021
# allow out ftp, ssh, www and https only, and allow user to negotiate # allow out ftp, ssh, www and https only, and allow user to negotiate
# ipsec with the ipsec server. # ipsec with the ipsec server.
pass in log quick on $internal_if proto tcp from $user_ip to any \e pass in log quick on $internal_if proto tcp from $user_ip to any \e
port { 21, 22, 80, 443 } flags S/SA port { 21, 22, 80, 443 }
pass in quick on $internal_if proto tcp from $user_ip to any \e pass in quick on $internal_if proto tcp from $user_ip to any \e
port { 21, 22, 80, 443 } port { 21, 22, 80, 443 }
pass in quick proto udp from $user_ip to $ipsec_gw port = isakmp \e pass in quick proto udp from $user_ip to $ipsec_gw port = isakmp
keep state
pass in quick proto esp from $user_ip to $ipsec_gw pass in quick proto esp from $user_ip to $ipsec_gw
.Ed .Ed
.Pp .Pp
@ -469,7 +460,7 @@ int_if = "fxp0"
# nat and tag connections... # nat and tag connections...
nat on $ext_if from $user_ip to any tag $user_ip -> $ext_addr 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 in quick on $int_if from $user_ip to any
pass out log quick on $ext_if tagged $user_ip keep state pass out log quick on $ext_if tagged $user_ip
.Ed .Ed
.Pp .Pp
With the above rules added by With the above rules added by
@ -495,7 +486,7 @@ lines will give SMTP and IMAP access to logged in users:
.Bd -literal .Bd -literal
table <authpf_users> persist table <authpf_users> persist
pass in on $ext_if proto tcp from <authpf_users> \e pass in on $ext_if proto tcp from <authpf_users> \e
to port { smtp imap } keep state to port { smtp imap }
.Ed .Ed
.Pp .Pp
It is also possible to use the "authpf_users" It is also possible to use the "authpf_users"
@ -522,6 +513,7 @@ rdr-anchor "authpf/*" from <authpf_users>
.Xr pf 4 , .Xr pf 4 ,
.Xr pf.conf 5 , .Xr pf.conf 5 ,
.Xr fdescfs 5 , .Xr fdescfs 5 ,
.Xr securelevel 7 ,
.Xr ftp-proxy 8 .Xr ftp-proxy 8
.Sh HISTORY .Sh HISTORY
The The

View File

@ -1,28 +1,19 @@
/* $OpenBSD: authpf.c,v 1.89 2005/02/10 04:24:15 joel Exp $ */ /* $OpenBSD: authpf.c,v 1.104 2007/02/24 17:35:08 beck Exp $ */
/* /*
* Copyright (C) 1998 - 2002 Bob Beck (beck@openbsd.org). * Copyright (C) 1998 - 2007 Bob Beck (beck@openbsd.org).
* *
* Redistribution and use in source and binary forms, with or without * Permission to use, copy, modify, and distribute this software for any
* modification, are permitted provided that the following conditions * purpose with or without fee is hereby granted, provided that the above
* are met: * copyright notice and this permission notice appear in all copies.
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
@ -56,15 +47,13 @@ __FBSDID("$FreeBSD$");
#include "pathnames.h" #include "pathnames.h"
extern int symset(const char *, const char *, int);
static int read_config(FILE *); static int read_config(FILE *);
static void print_message(char *); static void print_message(char *);
static int allowed_luser(char *); static int allowed_luser(char *);
static int check_luser(char *, char *); static int check_luser(char *, char *);
static int remove_stale_rulesets(void); static int remove_stale_rulesets(void);
static int change_filter(int, const char *, const char *); static int change_filter(int, const char *, const char *);
static int change_table(int, const char *, const char *); static int change_table(int, const char *);
static void authpf_kill_states(void); static void authpf_kill_states(void);
int dev; /* pf device */ int dev; /* pf device */
@ -73,7 +62,6 @@ char rulesetname[MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 2];
char tablename[PF_TABLE_NAME_SIZE] = "authpf_users"; char tablename[PF_TABLE_NAME_SIZE] = "authpf_users";
FILE *pidfp; FILE *pidfp;
char *infile; /* file name printed by yyerror() in parse.y */
char luser[MAXLOGNAME]; /* username */ char luser[MAXLOGNAME]; /* username */
char ipsrc[256]; /* ip as a string */ char ipsrc[256]; /* ip as a string */
char pidfile[MAXPATHLEN]; /* we save pid in this file. */ char pidfile[MAXPATHLEN]; /* we save pid in this file. */
@ -102,11 +90,16 @@ main(int argc, char *argv[])
struct in6_addr ina; struct in6_addr ina;
struct passwd *pw; struct passwd *pw;
char *cp; char *cp;
gid_t gid;
uid_t uid; uid_t uid;
char *shell; char *shell;
login_cap_t *lc; login_cap_t *lc;
config = fopen(PATH_CONFFILE, "r"); config = fopen(PATH_CONFFILE, "r");
if (config == NULL) {
syslog(LOG_ERR, "can not open %s (%m)", PATH_CONFFILE);
exit(1);
}
if ((cp = getenv("SSH_TTY")) == NULL) { if ((cp = getenv("SSH_TTY")) == NULL) {
syslog(LOG_ERR, "non-interactive session connection for authpf"); syslog(LOG_ERR, "non-interactive session connection for authpf");
@ -143,7 +136,6 @@ main(int argc, char *argv[])
uid = getuid(); uid = getuid();
pw = getpwuid(uid); pw = getpwuid(uid);
endpwent();
if (pw == NULL) { if (pw == NULL) {
syslog(LOG_ERR, "cannot find user for uid %u", uid); syslog(LOG_ERR, "cannot find user for uid %u", uid);
goto die; goto die;
@ -256,6 +248,8 @@ main(int argc, char *argv[])
if (++lockcnt > 10) { if (++lockcnt > 10) {
syslog(LOG_ERR, "cannot kill previous authpf (pid %d)", syslog(LOG_ERR, "cannot kill previous authpf (pid %d)",
otherpid); otherpid);
fclose(pidfp);
pidfp = NULL;
goto dogdeath; goto dogdeath;
} }
sleep(1); sleep(1);
@ -265,12 +259,22 @@ main(int argc, char *argv[])
* it's lock, giving us a chance to get it now * it's lock, giving us a chance to get it now
*/ */
fclose(pidfp); fclose(pidfp);
pidfp = NULL;
} while (1); } while (1);
/* whack the group list */
gid = getegid();
if (setgroups(1, &gid) == -1) {
syslog(LOG_INFO, "setgroups: %s", strerror(errno));
do_death(0);
}
/* revoke privs */ /* revoke privs */
seteuid(getuid()); uid = getuid();
setuid(getuid()); if (setresuid(uid, uid, uid) == -1) {
syslog(LOG_INFO, "setresuid: %s", strerror(errno));
do_death(0);
}
openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON); openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON);
if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) { if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) {
@ -278,8 +282,8 @@ main(int argc, char *argv[])
do_death(0); do_death(0);
} }
if (config == NULL || read_config(config)) { if (read_config(config)) {
syslog(LOG_INFO, "bad or nonexistent %s", PATH_CONFFILE); syslog(LOG_ERR, "invalid config file %s", PATH_CONFFILE);
do_death(0); do_death(0);
} }
@ -298,7 +302,7 @@ main(int argc, char *argv[])
printf("Unable to modify filters\r\n"); printf("Unable to modify filters\r\n");
do_death(0); do_death(0);
} }
if (change_table(1, luser, ipsrc) == -1) { if (change_table(1, ipsrc) == -1) {
printf("Unable to modify table\r\n"); printf("Unable to modify table\r\n");
change_filter(0, luser, ipsrc); change_filter(0, luser, ipsrc);
do_death(0); do_death(0);
@ -309,7 +313,7 @@ main(int argc, char *argv[])
signal(SIGALRM, need_death); signal(SIGALRM, need_death);
signal(SIGPIPE, need_death); signal(SIGPIPE, need_death);
signal(SIGHUP, need_death); signal(SIGHUP, need_death);
signal(SIGSTOP, need_death); signal(SIGQUIT, need_death);
signal(SIGTSTP, need_death); signal(SIGTSTP, need_death);
while (1) { while (1) {
printf("\r\nHello %s. ", luser); printf("\r\nHello %s. ", luser);
@ -559,9 +563,11 @@ check_luser(char *luserdir, char *luser)
while (fputs(tmp, stdout) != EOF && !feof(f)) { while (fputs(tmp, stdout) != EOF && !feof(f)) {
if (fgets(tmp, sizeof(tmp), f) == NULL) { if (fgets(tmp, sizeof(tmp), f) == NULL) {
fflush(stdout); fflush(stdout);
fclose(f);
return (0); return (0);
} }
} }
fclose(f);
} }
fflush(stdout); fflush(stdout);
return (0); return (0);
@ -645,6 +651,7 @@ change_filter(int add, const char *luser, const char *ipsrc)
char *fdpath = NULL, *userstr = NULL, *ipstr = NULL; char *fdpath = NULL, *userstr = NULL, *ipstr = NULL;
char *rsn = NULL, *fn = NULL; char *rsn = NULL, *fn = NULL;
pid_t pid; pid_t pid;
gid_t gid;
int s; int s;
if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) { if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) {
@ -684,8 +691,14 @@ change_filter(int add, const char *luser, const char *ipsrc)
switch (pid = fork()) { switch (pid = fork()) {
case -1: case -1:
err(1, "fork failed"); syslog(LOG_ERR, "fork failed");
goto error;
case 0: case 0:
/* revoke group privs before exec */
gid = getgid();
if (setregid(gid, gid) == -1) {
err(1, "setregid");
}
execvp(PATH_PFCTL, pargv); execvp(PATH_PFCTL, pargv);
warn("exec of %s failed", PATH_PFCTL); warn("exec of %s failed", PATH_PFCTL);
_exit(1); _exit(1);
@ -694,10 +707,8 @@ change_filter(int add, const char *luser, const char *ipsrc)
/* parent */ /* parent */
waitpid(pid, &s, 0); waitpid(pid, &s, 0);
if (s != 0) { if (s != 0) {
if (WIFEXITED(s)) { syslog(LOG_ERR, "pfctl exited abnormally");
syslog(LOG_ERR, "pfctl exited abnormally"); goto error;
goto error;
}
} }
if (add) { if (add) {
@ -718,16 +729,10 @@ change_filter(int add, const char *luser, const char *ipsrc)
syslog(LOG_ERR, "malloc failed"); syslog(LOG_ERR, "malloc failed");
error: error:
free(fdpath); free(fdpath);
fdpath = NULL;
free(rsn); free(rsn);
rsn = NULL;
free(userstr); free(userstr);
userstr = NULL;
free(ipstr); free(ipstr);
ipstr = NULL;
free(fn); free(fn);
fn = NULL;
infile = NULL;
return (-1); return (-1);
} }
@ -735,13 +740,14 @@ change_filter(int add, const char *luser, const char *ipsrc)
* Add/remove this IP from the "authpf_users" table. * Add/remove this IP from the "authpf_users" table.
*/ */
static int static int
change_table(int add, const char *luser, const char *ipsrc) change_table(int add, const char *ipsrc)
{ {
struct pfioc_table io; struct pfioc_table io;
struct pfr_addr addr; struct pfr_addr addr;
bzero(&io, sizeof(io)); bzero(&io, sizeof(io));
strlcpy(io.pfrio_table.pfrt_name, tablename, sizeof(io.pfrio_table)); strlcpy(io.pfrio_table.pfrt_name, tablename,
sizeof(io.pfrio_table.pfrt_name));
io.pfrio_buffer = &addr; io.pfrio_buffer = &addr;
io.pfrio_esize = sizeof(addr); io.pfrio_esize = sizeof(addr);
io.pfrio_size = 1; io.pfrio_size = 1;
@ -834,13 +840,11 @@ do_death(int active)
if (active) { if (active) {
change_filter(0, luser, ipsrc); change_filter(0, luser, ipsrc);
change_table(0, luser, ipsrc); change_table(0, ipsrc);
authpf_kill_states(); authpf_kill_states();
remove_stale_rulesets(); remove_stale_rulesets();
} }
if (pidfp) if (pidfile[0] && (pidfp != NULL))
ftruncate(fileno(pidfp), 0);
if (pidfile[0])
if (unlink(pidfile) == -1) if (unlink(pidfile) == -1)
syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile); syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile);
exit(ret); exit(ret);

View File

@ -1,295 +1,185 @@
.\" $OpenBSD: ftp-proxy.8,v 1.42 2004/11/19 00:47:23 jmc Exp $ .\" $OpenBSD: ftp-proxy.8,v 1.7 2006/12/30 13:01:54 camield Exp $
.\" .\"
.\" Copyright (c) 1996-2001 .\" Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
.\" Obtuse Systems Corporation, All rights reserved.
.\" .\"
.\" Redistribution and use in source and binary forms, with or without .\" Permission to use, copy, modify, and distribute this software for any
.\" modification, are permitted provided that the following conditions .\" purpose with or without fee is hereby granted, provided that the above
.\" are met: .\" copyright notice and this permission notice appear in all copies.
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\" .\"
.\" THIS SOFTWARE IS PROVIDED BY OBTUSE SYSTEMS AND CONTRIBUTORS ``AS IS'' AND .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ARE DISCLAIMED. IN NO EVENT SHALL OBTUSE OR CONTRIBUTORS BE LIABLE .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" 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.
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd August 17, 2001 .Dd November 28, 2004
.Dt FTP-PROXY 8 .Dt FTP-PROXY 8
.Os .Os
.Sh NAME .Sh NAME
.Nm ftp-proxy .Nm ftp-proxy
.Nd Internet File Transfer Protocol proxy server .Nd Internet File Transfer Protocol proxy daemon
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm ftp-proxy .Nm ftp-proxy
.Bk -words .Op Fl 6Adrv
.Op Fl AnrVw
.Op Fl a Ar address .Op Fl a Ar address
.Op Fl D Ar debuglevel .Op Fl b Ar address
.Op Fl g Ar group .Op Fl D Ar level
.Op Fl M Ar maxport .Op Fl m Ar maxsessions
.Op Fl m Ar minport .Op Fl P Ar port
.Op Fl R Ar address[:port] .Op Fl p Ar port
.Op Fl S Ar address .Op Fl q Ar queue
.Op Fl R Ar address
.Op Fl t Ar timeout .Op Fl t Ar timeout
.Op Fl u Ar user
.Ek
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
is a proxy for the Internet File Transfer Protocol. is a proxy for the Internet File Transfer Protocol.
The proxy uses FTP control connections should be redirected into the proxy using the
.Xr pf 4 .Xr pf 4
and expects to have the FTP control connection as described in .Ar rdr
.Xr services 5 command, after which the proxy connects to the server on behalf of
redirected to it via a the client.
.Pp
The proxy allows data connections to pass, rewriting and redirecting
them so that the right addresses are used.
All connections from the client to the server have their source
address rewritten so they appear to come from the proxy.
Consequently, all connections from the server to the proxy have
their destination address rewritten, so they are redirected to the
client.
The proxy uses the
.Xr pf 4 .Xr pf 4
.Em rdr .Ar anchor
command. facility for this.
An example of how to do that is further down in this document. .Pp
Assuming the FTP control connection is from $client to $server, the
proxy connected to the server using the $proxy source address, and
$port is negotiated, then
.Nm ftp-proxy
adds the following rules to the various anchors.
(These example rules use inet, but the proxy also supports inet6.)
.Pp
In case of active mode (PORT or EPRT):
.Bd -literal -offset 2n
rdr from $server to $proxy port $port -> $client
pass quick inet proto tcp \e
from $server to $client port $port
.Ed
.Pp
In case of passive mode (PASV or EPSV):
.Bd -literal -offset 2n
nat from $client to $server port $port -> $proxy
pass in quick inet proto tcp \e
from $client to $server port $port
pass out quick inet proto tcp \e
from $proxy to $server port $port
.Ed
.Pp .Pp
The options are as follows: The options are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl 6
IPv6 mode.
The proxy will expect and use IPv6 addresses for all communication.
Only the extended FTP modes EPSV and EPRT are allowed with IPv6.
The proxy is in IPv4 mode by default.
.It Fl A .It Fl A
Permit only anonymous FTP connections. Only permit anonymous FTP connections.
The proxy will allow connections to log in to other sites as the user Either user "ftp" or user "anonymous" is allowed.
.Qq ftp
or
.Qq anonymous
only.
Any attempt to log in as another user will be blocked by the proxy.
.It Fl a Ar address .It Fl a Ar address
Specify the local IP address to use in The proxy will use this as the source address for the control
.Xr bind 2 connection to a server.
as the source for connections made by .It Fl b Ar address
.Nm ftp-proxy Address where the proxy will listen for redirected control connections.
when connecting to destination FTP servers. The default is 127.0.0.1, or ::1 in IPv6 mode.
This may be necessary if the interface address of .It Fl D Ar level
your default route is not reachable from the destinations Debug level, ranging from 0 to 7.
.Nm Higher is more verbose.
is attempting connections to, or this address is different from the one The default is 5.
connections are being NATed to. (These levels correspond to the
In the usual case this means that .Xr syslog 3
.Ar address levels.)
should be a publicly visible IP address assigned to one of .It Fl d
the interfaces on the machine running Do not daemonize.
.Nm The process will stay in the foreground, logging to standard error.
and should be the same address to which you are translating traffic .It Fl m Ar maxsessions
if you are using the Maximum number of concurrent FTP sessions.
.Fl n When the proxy reaches this limit, new connections are denied.
option. The default is 100 sessions.
.It Fl D Ar debuglevel The limit can be lowered to a minimum of 1, or raised to a maximum of 500.
Specify a debug level, where the proxy emits verbose debug output .It Fl P Ar port
into Fixed server port.
.Xr syslogd 8 Only used in combination with
at level .Fl R .
.Dv LOG_DEBUG . The default is port 21.
Meaningful values of debuglevel are 0-3, where 0 is no debug output and .It Fl p Ar port
3 is lots of debug output, the default being 0. Port where the proxy will listen for redirected connections.
.It Fl g Ar group The default is port 8021.
Specify the named group to drop group privileges to, after doing .It Fl q Ar queue
.Xr pf 4 Create rules with queue
lookups which require root. .Ar queue
By default, appended, so that data connections can be queued.
.Nm .It Fl R Ar address
uses the default group of the user it drops privilege to. Fixed server address, also known as reverse mode.
.It Fl M Ar maxport The proxy will always connect to the same server, regardless of
Specify the upper end of the port range the proxy will use for the where the client wanted to connect to (before it was redirected).
data connections it establishes. Use this option to proxy for a server behind NAT, or to forward all
The default is connections to another proxy.
.Dv IPPORT_HILASTAUTO
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
mode.
In this mode, the proxy will not attempt to proxy passive mode
.Pq PASV or EPSV
data connections.
In order for this to work, the machine running the proxy will need to
be forwarding packets and doing network address translation to allow
the outbound passive connections from the client to reach the server.
See
.Xr pf.conf 5
for more details on NAT.
The proxy only ignores passive mode data connections when using this flag;
it will still proxy PORT and EPRT mode data connections.
Without this flag,
.Nm
does not require any IP forwarding or NAT beyond the
.Em rdr
necessary to capture the FTP control connection.
.It Fl R Ar address:[port]
Reverse proxy mode for FTP servers running behind a NAT gateway.
In this mode, no redirection is needed.
The proxy is run from
.Xr inetd 8
on the port that external clients connect to (usually 21).
Control connections and passive data connections are forwarded
to the server.
.It Fl r .It Fl r
Use reverse host Rewrite sourceport to 20 in active mode to suit ancient clients that insist
.Pq reverse DNS on this RFC property.
lookups for logging and libwrap use.
By default,
the proxy does not look up hostnames for libwrap or logging purposes.
.It Fl S Ar address
Source address to use for data connections made by the proxy.
Useful when there are multiple addresses (aliases) available
to the proxy.
Clients may expect data connections to have the same source
address as the control connections, and reject or drop other
connections.
.It Fl t Ar timeout .It Fl t Ar timeout
Specifies a timeout, in seconds. Number of seconds that the control connection can be idle, before the
The proxy will exit and close open connections if it sees no data proxy will disconnect.
for the duration of the timeout. The maximum is 86400 seconds, which is also the default.
The default is 0, which means the proxy will not time out. Do not set this too low, because the control connection is usually
.It Fl u Ar user idle when large data transfers are taking place.
Specify the named user to drop privilege to, after doing .It Fl v
.Xr pf 4 Set the 'log' flag on pf rules committed by
lookups which require root privilege. .Nm .
By default, Use twice to set the 'log-all' flag.
.Nm The pf rules do not log by default.
drops privilege to the user
.Em proxy .
.Pp
Running as root means that the source of data connections the proxy makes
for PORT and EPRT will be the RFC mandated port 20.
When running as a non-root user, the source of the data connections from
.Nm
will be chosen randomly from the range
.Ar minport
to
.Ar maxport
as described above.
.It Fl V
Be verbose.
With this option the proxy logs the control commands
sent by clients and the replies sent by the servers to
.Xr syslogd 8 .
.It Fl w
Use the tcp wrapper access control library
.Xr hosts_access 3 ,
allowing connections to be allowed or denied based on the tcp wrapper's
.Xr hosts.allow 5
and
.Xr hosts.deny 5
files.
The proxy does libwrap operations after determining the destination
of the captured control connection, so that tcp wrapper rules may
be written based on the destination as well as the source of FTP connections.
.El .El
.Pp .Sh CONFIGURATION
.Nm ftp-proxy To make use of the proxy,
is run from
.Xr inetd 8
and requires that FTP connections are redirected to it using a
.Em rdr
rule.
A typical way to do this would be to use a
.Xr pf.conf 5 .Xr pf.conf 5
rule such as needs the following rules.
All anchors are mandatory.
Adjust the rules as needed.
.Pp
In the NAT section:
.Bd -literal -offset 2n .Bd -literal -offset 2n
int_if = \&"xl0\&" nat-anchor "ftp-proxy/*"
rdr pass on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021 rdr-anchor "ftp-proxy/*"
rdr pass on $int_if proto tcp from $lan to any port 21 -> \e
127.0.0.1 port 8021
.Ed .Ed
.Pp .Pp
.Xr inetd 8 In the rule section:
must then be configured to run
.Nm
on the port from above using
.Bd -literal -offset 2n .Bd -literal -offset 2n
ftp-proxy stream tcp nowait root /usr/libexec/ftp-proxy ftp-proxy anchor "ftp-proxy/*"
pass out proto tcp from $proxy to any port 21
.Ed .Ed
.Pp
in
.Xr inetd.conf 5 .
.Pp
.Nm
accepts the redirected control connections and forwards them
to the server.
The proxy replaces the address and port number that the client
sends through the control connection to the server with its own
address and proxy port, where it listens for the data connection.
When the server opens the data connection back to this port, the
proxy forwards it to the client.
The
.Xr pf.conf 5
rules need to let pass connections to these proxy ports
(see options
.Fl u , m ,
and
.Fl M
above) in on the external interface.
The following example allows only ports 49152 to 65535 to pass in
statefully:
.Bd -literal -offset indent
block in on $ext_if proto tcp all
pass in on $ext_if inet proto tcp from any to $ext_if \e
port > 49151 keep state
.Ed
.Pp
Alternatively, rules can make use of the fact that by default,
.Nm
runs as user
.Qq proxy
to allow the backchannel connections, as in the following example:
.Bd -literal -offset indent
block in on $ext_if proto tcp all
pass in on $ext_if inet proto tcp from any to $ext_if \e
user proxy keep state
.Ed
.Pp
These examples do not cover the connections from the proxy to the
foreign FTP server.
If one does not pass outgoing connections by default additional rules
are needed.
.Sh SEE ALSO .Sh SEE ALSO
.Xr ftp 1 , .Xr ftp 1 ,
.Xr pf 4 , .Xr pf 4 ,
.Xr hosts.allow 5 ,
.Xr hosts.deny 5 ,
.Xr inetd.conf 5 ,
.Xr pf.conf 5 ,
.Xr inetd 8 ,
.Xr pfctl 8 ,
.Xr syslogd 8
.Sh BUGS
Extended Passive mode
.Pq EPSV
is not supported by the proxy and will not work unless the proxy is run
in network address translation mode.
When not in network address translation mode, the proxy returns an error
to the client, hopefully forcing the client to revert to passive mode
.Pq PASV
which is supported.
EPSV will work in network address translation mode, assuming a
.Xr pf.conf 5 .Xr pf.conf 5
setup which allows the EPSV connections through to their destinations. .Sh CAVEATS
.Xr pf 4
does not allow the ruleset to be modified if the system is running at a
.Xr securelevel 7
higher than 1.
At that level
.Nm ftp-proxy
cannot add rules to the anchors and FTP data connections may get blocked.
.Pp .Pp
IPv6 is not yet supported. Negotiated data connection ports below 1024 are not allowed.
.Pp
The negotiated IP address for active modes is ignored for security
reasons.
This makes third party file transfers impossible.
.Pp
.Nm ftp-proxy
chroots to "/var/empty" and changes to user "proxy" to drop privileges.

File diff suppressed because it is too large Load Diff

View File

@ -1,259 +0,0 @@
/* $OpenBSD: getline.c,v 1.16 2004/09/16 04:50:51 deraadt Exp $ */
/*
* Copyright (c) 1985, 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*
* @(#)ftpcmd.y 5.24 (Berkeley) 2/25/91
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/telnet.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sysexits.h>
#include <syslog.h>
#include <unistd.h>
#include "util.h"
int refill_buffer(struct csiob *iobp);
/*
* Refill the io buffer if we KNOW that data is available
*
* Returns 1 if any new data was obtained, 0 otherwise.
*/
int
refill_buffer(struct csiob *iobp)
{
int rqlen, rlen;
if (!(iobp->data_available))
return(0);
if (iobp->got_eof)
return(0);
/*
* The buffer has been entirely consumed if next_byte == io_buffer_len.
* Otherwise, there is some still-to-be-used data in io_buffer.
* Shuffle it to the start of the buffer.
* Note that next_byte will never exceed io_buffer_len.
* Also, note that we MUST use bcopy because the two regions could
* overlap (memcpy isn't defined to work properly with overlapping
* regions).
*/
if (iobp->next_byte < iobp->io_buffer_len) {
int dst_ix = 0;
int src_ix = iobp->next_byte;
int amount = iobp->io_buffer_len - iobp->next_byte;
bcopy(&iobp->io_buffer[src_ix], &iobp->io_buffer[dst_ix],
amount);
iobp->io_buffer_len = amount;
} else if (iobp->next_byte == iobp->io_buffer_len)
iobp->io_buffer_len = 0;
else {
syslog(LOG_ERR, "next_byte(%d) > io_buffer_len(%d)",
iobp->next_byte, iobp->io_buffer_len);
exit(EX_OSERR);
}
iobp->next_byte = 0;
/* don't do tiny reads, grow first if we need to */
rqlen = iobp->io_buffer_size - iobp->io_buffer_len;
if (rqlen <= 128) {
unsigned char *tmp;
iobp->io_buffer_size += 128;
tmp = realloc(iobp->io_buffer, iobp->io_buffer_size);
if (tmp == NULL) {
syslog(LOG_INFO, "Insufficient memory");
exit(EX_UNAVAILABLE);
}
iobp->io_buffer = tmp;
rqlen = iobp->io_buffer_size - iobp->io_buffer_len;
}
/*
* Always leave an unused byte at the end of the buffer
* because the debug output uses that byte from time to time
* to ensure that something that is being printed is \0 terminated.
*/
rqlen -= 1;
doread:
rlen = read(iobp->fd, &iobp->io_buffer[iobp->io_buffer_len], rqlen);
iobp->data_available = 0;
switch (rlen) {
case -1:
if (errno == EAGAIN || errno == EINTR)
goto doread;
if (errno != ECONNRESET) {
syslog(LOG_INFO, "read() failed on socket from %s (%m)",
iobp->who);
exit(EX_DATAERR);
}
/* fall through to EOF case */
case 0:
iobp->got_eof = 1;
return(0);
break;
default:
iobp->io_buffer_len += rlen;
break;
}
return(1);
}
/*
* telnet_getline - a hacked up version of fgets to ignore TELNET escape codes.
*
* This code is derived from the getline routine found in the UC Berkeley
* ftpd code.
*
*/
int
telnet_getline(struct csiob *iobp, struct csiob *telnet_passthrough)
{
unsigned char ch;
int ix;
unsigned char tbuf[100];
iobp->line_buffer[0] = '\0';
/*
* If the buffer is empty then refill it right away.
*/
if (iobp->next_byte == iobp->io_buffer_len)
if (!refill_buffer(iobp))
return(0);
/*
* Is there a telnet command in the buffer?
*/
ch = iobp->io_buffer[iobp->next_byte];
if (ch == IAC) {
/*
* Yes - buffer must have at least three bytes in it
*/
if (iobp->io_buffer_len - iobp->next_byte < 3) {
if (!refill_buffer(iobp))
return(0);
if (iobp->io_buffer_len - iobp->next_byte < 3)
return(0);
}
iobp->next_byte++;
ch = iobp->io_buffer[iobp->next_byte++];
switch (ch) {
case WILL:
case WONT:
case DO:
case DONT:
tbuf[0] = IAC;
tbuf[1] = ch;
tbuf[2] = iobp->io_buffer[iobp->next_byte++];
(void)send(telnet_passthrough->fd, tbuf, 3,
telnet_passthrough->send_oob_flags);
break;
case IAC:
break;
default:
break;
}
return(1);
} else {
int clen;
/*
* Is there a newline in the buffer?
*/
for (ix = iobp->next_byte; ix < iobp->io_buffer_len;
ix += 1) {
if (iobp->io_buffer[ix] == '\n')
break;
if (iobp->io_buffer[ix] == '\0') {
syslog(LOG_INFO,
"got NUL byte from %s - bye!",
iobp->who);
exit(EX_DATAERR);
}
}
if (ix == iobp->io_buffer_len) {
if (!refill_buffer(iobp))
return(0);
/*
* Empty line returned
* will try again soon!
*/
return(1);
}
/*
* Expand the line buffer if it isn't big enough. We
* use a fudge factor of 5 rather than trying to
* figure out exactly how to account for the '\0 \r\n' and
* such. The correct fudge factor is 0, 1 or 2 but
* anything higher also works. We also grow it by a
* bunch to avoid having to do this often. Yes this is
* nasty.
*/
if (ix - iobp->next_byte > iobp->line_buffer_size - 5) {
unsigned char *tmp;
iobp->line_buffer_size = 256 + ix - iobp->next_byte;
tmp = realloc(iobp->line_buffer,
iobp->line_buffer_size);
if (tmp == NULL) {
syslog(LOG_INFO, "Insufficient memory");
exit(EX_UNAVAILABLE);
}
iobp->line_buffer = tmp;
}
/* +1 is for the newline */
clen = (ix+1) - iobp->next_byte;
memcpy(iobp->line_buffer, &iobp->io_buffer[iobp->next_byte],
clen);
iobp->next_byte += clen;
iobp->line_buffer[clen] = '\0';
return(1);
}
}

View File

@ -1,306 +0,0 @@
/* $OpenBSD: util.c,v 1.19 2004/07/06 19:49:11 dhartmei Exp $ */
/*
* Copyright (c) 1996-2001
* Obtuse Systems Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Obtuse Systems nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE OBTUSE SYSTEMS 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 OBTUSE
* SYSTEMS CORPORATION 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/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <net/if.h>
#include <net/pfvar.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sysexits.h>
#include <syslog.h>
#include <unistd.h>
#include "util.h"
extern int ReverseMode;
int Debug_Level;
int Use_Rdns;
in_addr_t Bind_Addr = INADDR_NONE;
void debuglog(int debug_level, const char *fmt, ...);
void
debuglog(int debug_level, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (Debug_Level >= debug_level)
vsyslog(LOG_DEBUG, fmt, ap);
va_end(ap);
}
int
get_proxy_env(int connected_fd, struct sockaddr_in *real_server_sa_ptr,
struct sockaddr_in *client_sa_ptr, struct sockaddr_in *proxy_sa_ptr)
{
struct pfioc_natlook natlook;
socklen_t slen;
int fd;
slen = sizeof(*proxy_sa_ptr);
if (getsockname(connected_fd, (struct sockaddr *)proxy_sa_ptr,
&slen) != 0) {
syslog(LOG_ERR, "getsockname() failed (%m)");
return(-1);
}
slen = sizeof(*client_sa_ptr);
if (getpeername(connected_fd, (struct sockaddr *)client_sa_ptr,
&slen) != 0) {
syslog(LOG_ERR, "getpeername() failed (%m)");
return(-1);
}
if (ReverseMode)
return(0);
/*
* Build up the pf natlook structure.
* Just for IPv4 right now
*/
memset((void *)&natlook, 0, sizeof(natlook));
natlook.af = AF_INET;
natlook.saddr.addr32[0] = client_sa_ptr->sin_addr.s_addr;
natlook.daddr.addr32[0] = proxy_sa_ptr->sin_addr.s_addr;
natlook.proto = IPPROTO_TCP;
natlook.sport = client_sa_ptr->sin_port;
natlook.dport = proxy_sa_ptr->sin_port;
natlook.direction = PF_OUT;
/*
* Open the pf device and lookup the mapping pair to find
* the original address we were supposed to connect to.
*/
fd = open("/dev/pf", O_RDWR);
if (fd == -1) {
syslog(LOG_ERR, "cannot open /dev/pf (%m)");
exit(EX_UNAVAILABLE);
}
if (ioctl(fd, DIOCNATLOOK, &natlook) == -1) {
syslog(LOG_INFO,
"pf nat lookup failed %s:%hu (%m)",
inet_ntoa(client_sa_ptr->sin_addr),
ntohs(client_sa_ptr->sin_port));
close(fd);
return(-1);
}
close(fd);
/*
* Now jam the original address and port back into the into
* destination sockaddr_in for the proxy to deal with.
*/
memset((void *)real_server_sa_ptr, 0, sizeof(struct sockaddr_in));
real_server_sa_ptr->sin_port = natlook.rdport;
real_server_sa_ptr->sin_addr.s_addr = natlook.rdaddr.addr32[0];
real_server_sa_ptr->sin_len = sizeof(struct sockaddr_in);
real_server_sa_ptr->sin_family = AF_INET;
return(0);
}
/*
* Transfer one unit of data across a pair of sockets
*
* A unit of data is as much as we get with a single read(2) call.
*/
int
xfer_data(const char *what_read,int from_fd, int to_fd, struct in_addr from,
struct in_addr to)
{
int rlen, offset, xerrno, mark, flags = 0;
char tbuf[4096];
/*
* Are we at the OOB mark?
*/
if (ioctl(from_fd, SIOCATMARK, &mark) < 0) {
xerrno = errno;
syslog(LOG_ERR, "cannot ioctl(SIOCATMARK) socket from %s (%m)",
what_read);
errno = xerrno;
return(-1);
}
if (mark)
flags = MSG_OOB; /* Yes - at the OOB mark */
snarf:
rlen = recv(from_fd, tbuf, sizeof(tbuf), flags);
if (rlen == -1 && flags == MSG_OOB && errno == EINVAL) {
/* OOB didn't work */
flags = 0;
rlen = recv(from_fd, tbuf, sizeof(tbuf), flags);
}
if (rlen == 0) {
debuglog(3, "EOF on read socket");
return(0);
} else if (rlen == -1) {
if (errno == EAGAIN || errno == EINTR)
goto snarf;
xerrno = errno;
syslog(LOG_ERR, "xfer_data (%s): failed (%m) with flags 0%o",
what_read, flags);
errno = xerrno;
return(-1);
} else {
offset = 0;
debuglog(3, "got %d bytes from socket", rlen);
while (offset < rlen) {
int wlen;
fling:
wlen = send(to_fd, &tbuf[offset], rlen - offset,
flags);
if (wlen == 0) {
debuglog(3, "zero-length write");
goto fling;
} else if (wlen == -1) {
if (errno == EAGAIN || errno == EINTR)
goto fling;
xerrno = errno;
syslog(LOG_INFO, "write failed (%m)");
errno = xerrno;
return(-1);
} else {
debuglog(3, "wrote %d bytes to socket",wlen);
offset += wlen;
}
}
return(offset);
}
}
/*
* get_backchannel_socket gets us a socket bound somewhere in a
* particular range of ports
*/
int
get_backchannel_socket(int type, int min_port, int max_port, int start_port,
int direction, struct sockaddr_in *sap)
{
int count;
/*
* Make sure that direction is 'defined' and that min_port is not
* greater than max_port.
*/
if (direction != -1)
direction = 1;
/* by default we go up by one port until we find one */
if (min_port > max_port) {
errno = EINVAL;
return(-1);
}
count = 1 + max_port - min_port;
/*
* Pick a port we can bind to from within the range we want.
* If the caller specifies -1 as the starting port number then
* we pick one somewhere in the range to try.
* This is an optimization intended to speedup port selection and
* has NOTHING to do with security.
*/
if (start_port == -1)
start_port = (arc4random() % count) + min_port;
if (start_port < min_port || start_port > max_port) {
errno = EINVAL;
return(-1);
}
while (count-- > 0) {
struct sockaddr_in sa;
int one, fd;
fd = socket(AF_INET, type, 0);
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
* port in question was a listen port recently.
*/
one = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one,
sizeof(one)) == -1)
return(-1);
sa.sin_port = htons(start_port);
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == 0) {
if (sap != NULL)
*sap = sa;
return(fd);
}
if (errno != EADDRINUSE)
return(-1);
/* if it's in use, try the next port */
close(fd);
start_port += direction;
if (start_port < min_port)
start_port = max_port;
else if (start_port > max_port)
start_port = min_port;
}
errno = EAGAIN;
return(-1);
}

View File

@ -1,68 +0,0 @@
/* $OpenBSD: util.h,v 1.5 2005/02/24 15:49:08 dhartmei Exp $ */
/*
* Copyright (c) 1996-2001
* Obtuse Systems Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the Obtuse Systems nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 OBTUSE SYSTEMS CORPORATION 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.
*/
struct proxy_channel {
int pc_to_fd, pc_from_fd;
int pc_alive;
int pc_nextbyte;
int pc_flags;
int pc_length;
int pc_size;
struct sockaddr_in pc_from_sa, pc_to_sa;
int (*pc_filter)( void ** databuf, int datalen);
char *pc_buffer;
};
struct csiob {
int fd;
int line_buffer_size, io_buffer_size, io_buffer_len, next_byte;
unsigned char *io_buffer, *line_buffer;
struct sockaddr_in sa, real_sa;
const char *who;
char alive, got_eof, data_available;
int send_oob_flags;
};
extern int telnet_getline(struct csiob *iobp,
struct csiob *telnet_passthrough);
extern int get_proxy_env(int fd, struct sockaddr_in *server_sa_ptr,
struct sockaddr_in *client_sa_ptr, struct sockaddr_in *proxy_sa_ptr);
extern int get_backchannel_socket(int type, int min_port, int max_port,
int start_port, int direction, struct sockaddr_in *sap);
extern int xfer_data(const char *what_read, int from_fd, int to_fd,
struct in_addr from, struct in_addr to);
extern char *ProgName;

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: pf.4,v 1.54 2004/12/22 17:17:55 dhartmei Exp $ .\" $OpenBSD: pf.4,v 1.58 2007/02/09 11:39:06 henning Exp $
.\" .\"
.\" Copyright (C) 2001, Kjell Wooding. All rights reserved. .\" Copyright (C) 2001, Kjell Wooding. All rights reserved.
.\" .\"
@ -186,6 +186,11 @@ using the
obtained through a preceding obtained through a preceding
.Dv DIOCGETRULES .Dv DIOCGETRULES
call. call.
If
.Va action
is set to
.Dv PF_GET_CLR_CNTR ,
the per-rule statistics on the requested rule are cleared.
.It Dv DIOCGETADDRS Fa "struct pfioc_pooladdr *pp" .It Dv DIOCGETADDRS Fa "struct pfioc_pooladdr *pp"
Get a Get a
.Va ticket .Va ticket
@ -348,6 +353,7 @@ struct pf_status {
u_int32_t debug; u_int32_t debug;
u_int32_t hostid; u_int32_t hostid;
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
u_int8_t pf_chksum[MD5_DIGEST_LENGTH];
}; };
.Ed .Ed
.It Dv DIOCCLRSTATUS .It Dv DIOCCLRSTATUS
@ -391,19 +397,14 @@ struct pfioc_states {
.Pp .Pp
If If
.Va ps_len .Va ps_len
is zero, all states will be gathered into is non-zero on entry, as many states as possible that can fit into this
.Va pf_states size will be copied into the supplied buffer
and .Va ps_states .
On exit,
.Va ps_len .Va ps_len
will be set to the size they take in memory (i.e., is always set to the total size required to hold all state table entries
(i.e., it is set to
.Li sizeof(struct pf_state) * nr ) . .Li sizeof(struct pf_state) * nr ) .
If
.Va ps_len
is non-zero, as many states that can fit into
.Va ps_len
as possible will be gathered, and
.Va ps_len
will be updated to the size those rules take in memory.
.It Dv DIOCCHANGERULE Fa "struct pfioc_rule *pcr" .It Dv DIOCCHANGERULE Fa "struct pfioc_rule *pcr"
Add or remove the Add or remove the
.Va rule .Va rule
@ -485,7 +486,8 @@ struct pfioc_limit {
unsigned limit; unsigned limit;
}; };
enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS }; enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS,
PF_LIMIT_TABLES, PF_LIMIT_TABLE_ENTRIES, PF_LIMIT_MAX };
.Ed .Ed
.It Dv DIOCGETLIMIT Fa "struct pfioc_limit *pl" .It Dv DIOCGETLIMIT Fa "struct pfioc_limit *pl"
Get the hard Get the hard
@ -523,10 +525,15 @@ struct pfioc_table {
.It Dv DIOCRADDTABLES Fa "struct pfioc_table *io" .It Dv DIOCRADDTABLES Fa "struct pfioc_table *io"
Create one or more tables. Create one or more tables.
On entry, On entry,
.Va pfrio_buffer[pfrio_size] .Va pfrio_buffer
contains a table of must point to an array of
.Vt pfr_table .Vt struct pfr_table
structures. containing at least
.Vt pfrio_size
elements.
.Vt pfrio_esize
must be the size of
.Vt struct pfr_table .
On exit, On exit,
.Va pfrio_nadd .Va pfrio_nadd
contains the number of tables effectively created. contains the number of tables effectively created.
@ -541,12 +548,17 @@ struct pfr_table {
.It Dv DIOCRDELTABLES Fa "struct pfioc_table *io" .It Dv DIOCRDELTABLES Fa "struct pfioc_table *io"
Delete one or more tables. Delete one or more tables.
On entry, On entry,
.Va pfrio_buffer[pfrio_size] .Va pfrio_buffer
contains a table of must point to an array of
.Vt pfr_table .Vt struct pfr_table
structures. containing at least
.Vt pfrio_size
elements.
.Vt pfrio_esize
must be the size of
.Vt struct pfr_table .
On exit, On exit,
.Va pfrio_nadd .Va pfrio_ndel
contains the number of tables effectively deleted. contains the number of tables effectively deleted.
.It Dv DIOCRGETTABLES Fa "struct pfioc_table *io" .It Dv DIOCRGETTABLES Fa "struct pfioc_table *io"
Get the list of all tables. Get the list of all tables.
@ -585,10 +597,15 @@ struct pfr_tstats {
.It Dv DIOCRCLRTSTATS Fa "struct pfioc_table *io" .It Dv DIOCRCLRTSTATS Fa "struct pfioc_table *io"
Clear the statistics of one or more tables. Clear the statistics of one or more tables.
On entry, On entry,
.Va pfrio_buffer[pfrio_size] .Va pfrio_buffer
contains a table of must point to an array of
.Vt pfr_table .Vt struct pfr_table
structures. containing at least
.Vt pfrio_size
elements.
.Vt pfrio_esize
must be the size of
.Vt struct pfr_table .
On exit, On exit,
.Va pfrio_nzero .Va pfrio_nzero
contains the number of tables effectively cleared. contains the number of tables effectively cleared.
@ -605,10 +622,15 @@ Add one or more addresses to a table.
On entry, On entry,
.Va pfrio_table .Va pfrio_table
contains the table ID and contains the table ID and
.Va pfrio_buffer[pfrio_size] .Va pfrio_buffer
contains the list of must point to an array of
.Vt pfr_addr .Vt struct pfr_addr
structures to add. containing at least
.Vt pfrio_size
elements to add to the table.
.Vt pfrio_esize
must be the size of
.Vt struct pfr_addr .
On exit, On exit,
.Va pfrio_nadd .Va pfrio_nadd
contains the number of addresses effectively added. contains the number of addresses effectively added.
@ -631,10 +653,15 @@ Delete one or more addresses from a table.
On entry, On entry,
.Va pfrio_table .Va pfrio_table
contains the table ID and contains the table ID and
.Va pfrio_buffer[pfrio_size] .Va pfrio_buffer
contains the list of must point to an array of
.Vt pfr_addr .Vt struct pfr_addr
structures to delete. containing at least
.Vt pfrio_size
elements to delete from the table.
.Vt pfrio_esize
must be the size of
.Vt struct pfr_addr .
On exit, On exit,
.Va pfrio_ndel .Va pfrio_ndel
contains the number of addresses effectively deleted. contains the number of addresses effectively deleted.
@ -645,10 +672,15 @@ This is the most complicated command, which uses all the structure members.
On entry, On entry,
.Va pfrio_table .Va pfrio_table
contains the table ID and contains the table ID and
.Va pfrio_buffer[pfrio_size] .Va pfrio_buffer
contains the new list of must point to an array of
.Vt pfr_addr .Vt struct pfr_addr
structures. containing at least
.Vt pfrio_size
elements which become the new contents of the table.
.Vt pfrio_esize
must be the size of
.Vt struct pfr_addr .
Additionally, if Additionally, if
.Va pfrio_size2 .Va pfrio_size2
is non-zero, is non-zero,
@ -703,10 +735,15 @@ Clear the statistics of one or more addresses.
On entry, On entry,
.Va pfrio_table .Va pfrio_table
contains the table ID and contains the table ID and
.Va pfrio_buffer[pfrio_size] .Va pfrio_buffer
contains a table of must point to an array of
.Vt pfr_addr .Vt struct pfr_addr
structures to clear. containing at least
.Vt pfrio_size
elements to be cleared from the table.
.Vt pfrio_esize
must be the size of
.Vt struct pfr_addr .
On exit, On exit,
.Va pfrio_nzero .Va pfrio_nzero
contains the number of addresses effectively cleared. contains the number of addresses effectively cleared.
@ -715,13 +752,18 @@ Test if the given addresses match a table.
On entry, On entry,
.Va pfrio_table .Va pfrio_table
contains the table ID and contains the table ID and
.Va pfrio_buffer[pfrio_size] .Va pfrio_buffer
contains a table of must point to an array of
.Vt pfr_addr .Vt struct pfr_addr
structures to test. containing at least
.Vt pfrio_size
elements, each of which will be tested for a match in the table.
.Vt pfrio_esize
must be the size of
.Vt struct pfr_addr .
On exit, the kernel updates the On exit, the kernel updates the
.Vt pfr_addr .Vt pfr_addr
table by setting the array by setting the
.Va pfra_fback .Va pfra_fback
member appropriately. member appropriately.
.It Dv DIOCRSETTFLAGS Fa "struct pfioc_table *io" .It Dv DIOCRSETTFLAGS Fa "struct pfioc_table *io"
@ -731,14 +773,19 @@ or
.Dv PFR_TFLAG_PERSIST .Dv PFR_TFLAG_PERSIST
flags of a table. flags of a table.
On entry, On entry,
.Va pfrio_buffer[pfrio_size] .Va pfrio_buffer
contains a table of must point to an array of
.Vt pfr_table .Vt struct pfr_table
structures, and containing at least
.Vt pfrio_size
elements.
.Va pfrio_esize
must be the size of
.Vt struct pfr_table .
.Va pfrio_setflag .Va pfrio_setflag
contains the flags to add, while must contain the flags to add, while
.Va pfrio_clrflag .Va pfrio_clrflag
contains the flags to remove. must contain the flags to remove.
On exit, On exit,
.Va pfrio_nchange .Va pfrio_nchange
and and
@ -753,7 +800,7 @@ On entry,
.Va pfrio_table .Va pfrio_table
contains the table ID and contains the table ID and
.Va pfrio_buffer[pfrio_size] .Va pfrio_buffer[pfrio_size]
contains the list of contains an array of
.Vt pfr_addr .Vt pfr_addr
structures to put in the table. structures to put in the table.
A valid ticket must also be supplied to A valid ticket must also be supplied to
@ -955,10 +1002,6 @@ struct pfioc_iface {
int pfiio_nzero; int pfiio_nzero;
int pfiio_flags; 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 .Ed
.Pp .Pp
If not empty, If not empty,
@ -968,61 +1011,45 @@ can be used to restrict the search to a specific interface or driver.
is the user-supplied buffer for returning the data. is the user-supplied buffer for returning the data.
On entry, On entry,
.Va pfiio_size .Va pfiio_size
represents the number of contains the number of
.Va pfi_if .Vt pfi_kif
entries that can fit into the buffer. entries that can fit into the buffer.
The kernel will replace this value by the real number of entries it wants The kernel will replace this value by the real number of entries it wants
to return. to return.
.Va pfiio_esize .Va pfiio_esize
should be set to should be set to
.Li sizeof(struct pfi_if) . .Li sizeof(struct pfi_kif) .
.Va pfiio_flags .Pp
should be set to
.Dv PFI_FLAG_GROUP ,
.Dv 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 The data is returned in the
.Vt pfi_if .Vt pfi_kif
structure described below: structure described below:
.Bd -literal .Bd -literal
struct pfi_if { struct pfi_kif {
char pfif_name[IFNAMSIZ]; RB_ENTRY(pfi_kif) pfik_tree;
u_int64_t pfif_packets[2][2][2]; char pfik_name[IFNAMSIZ];
u_int64_t pfif_bytes[2][2][2]; u_int64_t pfik_packets[2][2][2];
u_int64_t pfif_addcnt; u_int64_t pfik_bytes[2][2][2];
u_int64_t pfif_delcnt; u_int32_t pfik_tzero;
long pfif_tzero; int pfik_flags;
int pfif_states; struct pf_state_tree_lan_ext pfik_lan_ext;
int pfif_rules; struct pf_state_tree_ext_gwy pfik_ext_gwy;
int pfif_flags; TAILQ_ENTRY(pfi_kif) pfik_w_states;
void *pfik_ah_cookie;
struct ifnet *pfik_ifp;
struct ifg_group *pfik_group;
int pfik_states;
int pfik_rules;
TAILQ_HEAD(, pfi_dynaddr) pfik_dynaddrs;
}; };
#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 */
.Ed .Ed
.It Dv DIOCICLRISTATS Fa "struct pfioc_iface *io"
Clear the statistics counters of one or more interfaces.
.Va pfiio_name
and
.Va pfiio_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.
.It Dv DIOCSETIFFLAG Fa "struct pfioc_iface *io" .It Dv DIOCSETIFFLAG Fa "struct pfioc_iface *io"
Set the user setable flags (described below) of the pf internal interface Set the user setable flags (described above) of the
description. .Nm
internal interface description.
The filtering process is the same as for The filtering process is the same as for
.Dv DIOCIGETIFACES . .Dv DIOCIGETIFACES .
.Bd -literal .Bd -literal
#define PFI_IFLAG_SKIP 0x0100 /* skip interface */ #define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */
#define PFI_IFLAG_SETABLE_MASK 0x0100 /* mask */
.Ed .Ed
.It Dv DIOCCLRIFFLAG Fa "struct pfioc_iface *io" .It Dv DIOCCLRIFFLAG Fa "struct pfioc_iface *io"
Works as Works as

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: pf.os.5,v 1.6 2004/03/31 11:13:03 dhartmei Exp $ .\" $OpenBSD: pf.os.5,v 1.7 2005/11/16 20:07:18 stevesk Exp $
.\" .\"
.\" Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org> .\" Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org>
.\" .\"
@ -207,37 +207,15 @@ The
output of output of
.Bd -literal .Bd -literal
# tcpdump -s128 -c1 -nv 'tcp[13] == 2' # tcpdump -s128 -c1 -nv 'tcp[13] == 2'
03:13:48.118526 10.0.0.1.3377 > 10.0.0.0.2: S [tcp sum ok] \e 03:13:48.118526 10.0.0.1.3377 > 10.0.0.2.80: S [tcp sum ok] \e
534596083:534596083(0) win 57344 <mss 1460> (DF) [tos 0x10] \e 534596083:534596083(0) win 57344 <mss 1460> (DF) [tos 0x10] \e
(ttl 64, id 11315) (ttl 64, id 11315, len 44)
.Ed .Ed
.Pp .Pp
almost translates into the following fingerprint almost translates into the following fingerprint
.Bd -literal .Bd -literal
57344:64:1:44:M1460: exampleOS:1.0::exampleOS 1.0 57344:64:1:44:M1460: exampleOS:1.0::exampleOS 1.0
.Ed .Ed
.Pp
.Xr tcpdump 1
does not explicitly give the packet length.
But it can usually be derived by adding the size of the IPv4 header to
the size of the TCP header to the size of the TCP options.
The size of both headers is typically twenty each and the usual
sizes of the TCP options are:
.Pp
.Bl -tag -width timestamp -offset indent -compact
.It mss
four bytes.
.It nop
1 byte.
.It sackOK
two bytes.
.It timestamp
ten bytes.
.It wscale
three bytes.
.El
.Pp
In the above example, the packet size comes out to 44 bytes.
.Sh SEE ALSO .Sh SEE ALSO
.Xr tcpdump 1 , .Xr tcpdump 1 ,
.Xr pf 4 , .Xr pf 4 ,

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: pflog.4,v 1.7 2004/03/21 19:47:59 miod Exp $ .\" $OpenBSD: pflog.4,v 1.9 2006/10/25 12:51:31 jmc Exp $
.\" .\"
.\" Copyright (c) 2001 Tobias Weingartner .\" Copyright (c) 2001 Tobias Weingartner
.\" All rights reserved. .\" All rights reserved.
@ -47,6 +47,14 @@ on the
interface, or stored to disk using interface, or stored to disk using
.Xr pflogd 8 . .Xr pflogd 8 .
.Pp .Pp
The pflog0 interface is created automatically at boot if both
.Xr pf 4
and
.Xr pflogd 8
are enabled;
further instances can be created using
.Xr ifconfig 8 .
.Pp
Each packet retrieved on this interface has a header associated Each packet retrieved on this interface has a header associated
with it of length with it of length
.Dv PFLOG_HDRLEN . .Dv PFLOG_HDRLEN .
@ -65,14 +73,22 @@ struct pfloghdr {
char ruleset[PF_RULESET_NAME_SIZE]; char ruleset[PF_RULESET_NAME_SIZE];
u_int32_t rulenr; u_int32_t rulenr;
u_int32_t subrulenr; u_int32_t subrulenr;
uid_t uid;
pid_t pid;
uid_t rule_uid;
pid_t rule_pid;
u_int8_t dir; u_int8_t dir;
u_int8_t pad[3]; u_int8_t pad[3];
}; };
.Ed .Ed
.Sh EXAMPLES .Sh EXAMPLES
Create a
.Nm
interface
and monitor all packets logged on it:
.Bd -literal -offset indent .Bd -literal -offset indent
# ifconfig pflog0 up # ifconfig pflog1 up
# tcpdump -n -e -ttt -i pflog0 # tcpdump -n -e -ttt -i pflog1
.Ed .Ed
.Sh SEE ALSO .Sh SEE ALSO
.Xr tcpdump 1 .Xr tcpdump 1

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: pfsync.4,v 1.22 2005/02/24 15:53:17 jmc Exp $ .\" $OpenBSD: pfsync.4,v 1.24 2006/10/23 07:05:49 jmc Exp $
.\" .\"
.\" Copyright (c) 2002 Michael Shalayeff .\" Copyright (c) 2002 Michael Shalayeff
.\" Copyright (c) 2003-2004 Ryan McBride .\" Copyright (c) 2003-2004 Ryan McBride
@ -209,7 +209,7 @@ The following should be added to the top of
.Pa /etc/pf.conf : .Pa /etc/pf.conf :
.Bd -literal -offset indent .Bd -literal -offset indent
pass quick on { sis2 } proto pfsync pass quick on { sis2 } proto pfsync
pass quick on { sis0 sis1 } proto carp keep state pass on { sis0 sis1 } proto carp
.Ed .Ed
.Pp .Pp
If it is preferable that one firewall handle the traffic, If it is preferable that one firewall handle the traffic,
@ -248,6 +248,9 @@ yet.
.Xr pf.conf 5 , .Xr pf.conf 5 ,
.Xr protocols 5 , .Xr protocols 5 ,
.Xr rc.conf 5 .Xr rc.conf 5
.Xr ifconfig 8 ,
.Xr ifstated 8 ,
.Xr tcpdump 8
.Sh HISTORY .Sh HISTORY
The The
.Nm .Nm

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pf_print_state.c,v 1.40 2004/12/10 22:13:26 henning Exp $ */ /* $OpenBSD: pf_print_state.c,v 1.44 2007/03/01 17:20:53 deraadt Exp $ */
/* /*
* Copyright (c) 2001 Daniel Hartmeier * Copyright (c) 2001 Daniel Hartmeier
@ -100,6 +100,9 @@ print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose)
case PF_ADDR_NOROUTE: case PF_ADDR_NOROUTE:
printf("no-route"); printf("no-route");
return; return;
case PF_ADDR_URPFFAILED:
printf("urpf-failed");
return;
case PF_ADDR_RTLABEL: case PF_ADDR_RTLABEL:
printf("route \"%s\"", addr->v.rtlabelname); printf("route \"%s\"", addr->v.rtlabelname);
return; return;
@ -278,8 +281,15 @@ print_state(struct pf_state *s, int opts)
min = s->expire % 60; min = s->expire % 60;
s->expire /= 60; s->expire /= 60;
printf(", expires in %.2u:%.2u:%.2u", s->expire, min, sec); printf(", expires in %.2u:%.2u:%.2u", s->expire, min, sec);
printf(", %u:%u pkts, %u:%u bytes", printf(", %llu:%llu pkts, %llu:%llu bytes",
#ifdef __FreeBSD__
(unsigned long long)s->packets[0],
(unsigned long long)s->packets[1],
(unsigned long long)s->bytes[0],
(unsigned long long)s->bytes[1]);
#else
s->packets[0], s->packets[1], s->bytes[0], s->bytes[1]); s->packets[0], s->packets[1], s->bytes[0], s->bytes[1]);
#endif
if (s->anchor.nr != -1) if (s->anchor.nr != -1)
printf(", anchor %u", s->anchor.nr); printf(", anchor %u", s->anchor.nr);
if (s->rule.nr != -1) if (s->rule.nr != -1)
@ -291,13 +301,13 @@ print_state(struct pf_state *s, int opts)
printf("\n"); printf("\n");
} }
if (opts & PF_OPT_VERBOSE2) { if (opts & PF_OPT_VERBOSE2) {
printf(" id: %016llx creatorid: %08x%s\n",
#ifdef __FreeBSD__ #ifdef __FreeBSD__
printf(" id: %016llx creatorid: %08x\n", (unsigned long long)be64toh(s->id), ntohl(s->creatorid),
(long long)be64toh(s->id), ntohl(s->creatorid));
#else #else
printf(" id: %016llx creatorid: %08x\n", betoh64(s->id), ntohl(s->creatorid),
betoh64(s->id), ntohl(s->creatorid));
#endif #endif
((s->sync_flags & PFSTATE_NOSYNC) ? " (no-sync)" : ""));
} }
} }

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: pfctl.8,v 1.118 2005/01/05 23:41:45 jmc Exp $ .\" $OpenBSD: pfctl.8,v 1.128 2007/01/30 21:01:56 jmc Exp $
.\" .\"
.\" Copyright (c) 2001 Kjell Wooding. All rights reserved. .\" Copyright (c) 2001 Kjell Wooding. All rights reserved.
.\" .\"
@ -35,23 +35,23 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm pfctl .Nm pfctl
.Bk -words .Bk -words
.Op Fl AdeghmNnOoqRrvz .Op Fl AdeghmNnOqRrvz
.Op Fl a Ar anchor .Op Fl a Ar anchor
.Xo .Oo Fl D Ar macro Ns =
.Oo Fl D .Ar value Oc
.Ar macro Ns = Ns Ar value Oc
.Xc
.Op Fl F Ar modifier .Op Fl F Ar modifier
.Op Fl f Ar file .Op Fl f Ar file
.Op Fl i Ar interface .Op Fl i Ar interface
.Op Fl k Ar host .Op Fl K Ar host | network
.Op Fl k Ar host | network
.Op Fl o Op Ar level
.Op Fl p Ar device .Op Fl p Ar device
.Op Fl s Ar modifier .Op Fl s Ar modifier
.Oo Xo .Oo
.Fl t Ar table .Fl t Ar table
.Fl T Ar command .Fl T Ar command
.Op Ar address ... Oc .Op Ar address ...
.Xc .Oc
.Op Fl x Ar level .Op Fl x Ar level
.Ek .Ek
.Sh DESCRIPTION .Sh DESCRIPTION
@ -140,8 +140,10 @@ rules from the main ruleset is described in
For example, the following will show all filter rules (see the For example, the following will show all filter rules (see the
.Fl s .Fl s
flag below) inside the anchor flag below) inside the anchor
.Li authpf/smith(1234) , .Dq authpf/smith(1234) ,
which would have been created for user smith by which would have been created for user
.Dq smith
by
.Xr authpf 8 , .Xr authpf 8 ,
PID 1234: PID 1234:
.Bd -literal -offset indent .Bd -literal -offset indent
@ -163,6 +165,27 @@ This is similar to C rules for variable scope.
It is possible to create distinct tables with the same name in the global 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 ruleset and in an anchor, but this is often bad design and a warning will be
issued in that case. issued in that case.
.Pp
By default, recursive inline printing of anchors applies only to unnamed
anchors specified inline in the ruleset.
If the anchor name is terminated with a
.Sq *
character, the
.Fl s
flag will recursively print all anchors in a brace delimited block.
For example the following will print the
.Dq authpf
ruleset recursively:
.Bd -literal -offset indent
# pfctl -a 'authpf/*' -sr
.Ed
.Pp
To print the main ruleset recursively, specify only
.Sq *
as the anchor name:
.Bd -literal -offset indent
# pfctl -a '*' -sr
.Ed
.It Fl D Ar macro Ns = Ns Ar value .It Fl D Ar macro Ns = Ns Ar value
Define Define
.Ar macro .Ar macro
@ -217,29 +240,49 @@ Help.
.It Fl i Ar interface .It Fl i Ar interface
Restrict the operation to the given Restrict the operation to the given
.Ar interface . .Ar interface .
.It Fl k Ar host .It Fl K Ar host | network
Kill all of the source tracking entries originating from the specified
.Ar host
or
.Ar network .
A second
.Fl K Ar host
or
.Fl K Ar network
option may be specified, which will kill all the source tracking
entries from the first host/network to the second.
.It Fl k Ar host | network
Kill all of the state entries originating from the specified Kill all of the state entries originating from the specified
.Ar host . .Ar host
or
.Ar network .
A second A second
.Fl k Ar host .Fl k Ar host
or
.Fl k Ar network
option may be specified, which will kill all the state entries option may be specified, which will kill all the state entries
from the first from the first host/network to the second.
.Ar host
to the second
.Ar host .
For example, to kill all of the state entries originating from For example, to kill all of the state entries originating from
.Li host : .Dq host :
.Bd -literal -offset indent .Pp
# pfctl -k host .Dl # pfctl -k host
.Ed
.Pp .Pp
To kill all of the state entries from To kill all of the state entries from
.Li host1 .Dq host1
to to
.Li host2 : .Dq host2 :
.Bd -literal -offset indent .Pp
# pfctl -k host1 -k host2 .Dl # pfctl -k host1 -k host2
.Ed .Pp
To kill all states originating from 192.168.1.0/24 to 172.16.0.0/16:
.Pp
.Dl # pfctl -k 192.168.1.0/24 -k 172.16.0.0/16
.Pp
A network prefix length of 0 can be used as a wildcard.
To kill all states with the target
.Dq host2 :
.Pp
.Dl # pfctl -k 0.0.0.0/0 -k host2
.It Fl m .It Fl m
Merge in explicitly given options without resetting those Merge in explicitly given options without resetting those
which are omitted. which are omitted.
@ -255,11 +298,22 @@ Do not actually load rules, just parse them.
.It Fl O .It Fl O
Load only the options present in the rule file. Load only the options present in the rule file.
Other rules and options are ignored. Other rules and options are ignored.
.It Fl o .It Fl o Op Ar level
Enable the ruleset optimizer. Control the ruleset optimizer.
The ruleset optimizer attempts to improve rulesets by removing rule The ruleset optimizer attempts to improve rulesets by removing rule
duplication and making better use of rule ordering. duplication and making better use of rule ordering.
Specifically, it does four things: .Pp
.Bl -tag -width xxxxxxxxxxxx -compact
.It Fl o Cm none
Disable the ruleset optimizer.
.It Fl o Cm basic
Enable basic ruleset optimizations.
.It Fl o Cm profile
Enable basic ruleset optimizations with profiling.
.El
.Pp
.Cm basic
optimization does does four things:
.Pp .Pp
.Bl -enum -compact .Bl -enum -compact
.It .It
@ -272,10 +326,10 @@ combine multiple rules into a table when advantageous
re-order the rules to improve evaluation performance re-order the rules to improve evaluation performance
.El .El
.Pp .Pp
A second If
.Fl o .Cm profile
may be specified to use the currently loaded ruleset as a feedback profile is specified, the currently loaded ruleset will be examined as a feedback
to tailor the optimization of the profile to tailor the optimization of the
.Ar quick .Ar quick
rules to the actual network behavior. rules to the actual network behavior.
.Pp .Pp
@ -288,6 +342,14 @@ the ruleset optimizer should not be used or a
.Ar label .Ar label
field should be added to all of the accounting rules to act as optimization field should be added to all of the accounting rules to act as optimization
barriers. barriers.
.Pp
To retain compatibility with previous behaviour, a single
.Fl o
without any options will enable
.Cm basic
optimizations, and a second
.Fl o
will enable profiling.
.It Fl p Ar device .It Fl p Ar device
Use the device file Use the device file
.Ar device .Ar device
@ -352,7 +414,8 @@ When used together with
.Fl v , .Fl v ,
source tracking statistics are also shown. source tracking statistics are also shown.
.It Fl s Cm labels .It Fl s Cm labels
Show per-rule statistics (label, evaluations, packets, bytes) of Show per-rule statistics (label, evaluations, packets total, bytes total,
packets in, bytes in, packets out, bytes out) of
filter rules with labels, useful for accounting. filter rules with labels, useful for accounting.
.It Fl s Cm timeouts .It Fl s Cm timeouts
Show the current global timeouts. Show the current global timeouts.
@ -364,8 +427,11 @@ Show the list of tables.
Show the list of operating system fingerprints. Show the list of operating system fingerprints.
.It Fl s Cm Interfaces .It Fl s Cm Interfaces
Show the list of interfaces and interface drivers available to PF. Show the list of interfaces and interface drivers available to PF.
When used together with a double When used together with
.Fl v , .Fl v ,
it additionally lists which interfaces have skip rules activated.
When used together with
.Fl vv ,
interface statistics are also shown. interface statistics are also shown.
.Fl i .Fl i
can be used to select an interface or a group of interfaces. can be used to select an interface or a group of interfaces.
@ -389,6 +455,13 @@ Add one or more addresses in a table.
Automatically create a nonexisting table. Automatically create a nonexisting table.
.It Fl T Cm delete .It Fl T Cm delete
Delete one or more addresses from a table. Delete one or more addresses from a table.
.It Fl T Cm expire Ar number
Delete addresses which had their statistics cleared more than
.Ar number
seconds ago.
For entries which have never had their statistics cleared,
.Ar number
refers to the time they were added to the table.
.It Fl T Cm replace .It Fl T Cm replace
Replace the addresses of the table. Replace the addresses of the table.
Automatically create a nonexisting table. Automatically create a nonexisting table.
@ -465,7 +538,7 @@ The following commands configure the firewall and send 10 pings to the FTP
server: server:
.Bd -literal -offset indent .Bd -literal -offset indent
# printf "table <test> { ftp.openbsd.org }\en \e # printf "table <test> { ftp.openbsd.org }\en \e
pass out to <test> keep state\en" | pfctl -f- pass out to <test>\en" | pfctl -f-
# ping -qc10 ftp.openbsd.org # ping -qc10 ftp.openbsd.org
.Ed .Ed
.Pp .Pp

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pfctl.h,v 1.37 2005/01/05 18:23:10 mcbride Exp $ */ /* $OpenBSD: pfctl.h,v 1.40 2007/02/09 11:25:27 henning Exp $ */
/* /*
* Copyright (c) 2001 Daniel Hartmeier * Copyright (c) 2001 Daniel Hartmeier
@ -34,6 +34,8 @@
#ifndef _PFCTL_H_ #ifndef _PFCTL_H_
#define _PFCTL_H_ #define _PFCTL_H_
enum pfctl_show { PFCTL_SHOW_RULES, PFCTL_SHOW_LABELS, PFCTL_SHOW_NOTHING };
enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS, enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS,
PFRB_IFACES, PFRB_TRANS, PFRB_MAX }; PFRB_IFACES, PFRB_TRANS, PFRB_MAX };
struct pfr_buffer { struct pfr_buffer {
@ -74,7 +76,7 @@ int pfr_buf_grow(struct pfr_buffer *, int);
int pfr_buf_load(struct pfr_buffer *, char *, int, int pfr_buf_load(struct pfr_buffer *, char *, int,
int (*)(struct pfr_buffer *, char *, int)); int (*)(struct pfr_buffer *, char *, int));
char *pfr_strerror(int); char *pfr_strerror(int);
int pfi_get_ifaces(const char *, struct pfi_if *, int *, int); int pfi_get_ifaces(const char *, struct pfi_kif *, int *);
int pfi_clr_istats(const char *, int *, int); int pfi_clr_istats(const char *, int *, int);
void pfctl_print_title(char *); void pfctl_print_title(char *);
@ -111,7 +113,6 @@ extern int loadopt;
int check_commit_altq(int, int); int check_commit_altq(int, int);
void pfaltq_store(struct pf_altq *); void pfaltq_store(struct pf_altq *);
void pfaltq_free(struct pf_altq *);
struct pf_altq *pfaltq_lookup(const char *); struct pf_altq *pfaltq_lookup(const char *);
char *rate2str(double); char *rate2str(double);

View File

@ -1,5 +1,4 @@
/* $OpenBSD: pfctl_altq.c,v 1.86 2005/02/28 14:04:51 henning Exp $ */ /* $OpenBSD: pfctl_altq.c,v 1.91 2006/11/28 00:08:50 henning Exp $ */
/* add: $OpenBSD: pfctl_altq.c,v 1.91 2006/11/28 00:08:50 henning Exp $ */
/* /*
* Copyright (c) 2002 * Copyright (c) 2002
@ -101,21 +100,6 @@ pfaltq_store(struct pf_altq *a)
TAILQ_INSERT_TAIL(&altqs, altq, entries); TAILQ_INSERT_TAIL(&altqs, altq, entries);
} }
void
pfaltq_free(struct pf_altq *a)
{
struct pf_altq *altq;
TAILQ_FOREACH(altq, &altqs, entries) {
if (strncmp(a->ifname, altq->ifname, IFNAMSIZ) == 0 &&
strncmp(a->qname, altq->qname, PF_QNAME_SIZE) == 0) {
TAILQ_REMOVE(&altqs, altq, entries);
free(altq);
return;
}
}
}
struct pf_altq * struct pf_altq *
pfaltq_lookup(const char *ifname) pfaltq_lookup(const char *ifname)
{ {
@ -165,7 +149,7 @@ print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw,
struct node_queue_opt *qopts) struct node_queue_opt *qopts)
{ {
if (a->qname[0] != 0) { if (a->qname[0] != 0) {
print_queue(a, level, bw, 0, qopts); print_queue(a, level, bw, 1, qopts);
return; return;
} }
@ -250,8 +234,8 @@ eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
#else #else
if ((rate = getifspeed(pa->ifname)) == 0) { if ((rate = getifspeed(pa->ifname)) == 0) {
#endif #endif
fprintf(stderr, "cannot determine interface bandwidth " fprintf(stderr, "interface %s does not know its bandwidth, "
"for %s, specify an absolute bandwidth\n", "please specify an absolute bandwidth\n",
pa->ifname); pa->ifname);
errors++; errors++;
} else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0) } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0)
@ -502,10 +486,7 @@ cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa)
maxidle = ptime * maxidle; maxidle = ptime * maxidle;
else else
maxidle = ptime * maxidle_s; maxidle = ptime * maxidle_s;
if (minburst) offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom);
offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom);
else
offtime = cptime;
minidle = -((double)opts->maxpktsize * (double)nsPerByte); minidle = -((double)opts->maxpktsize * (double)nsPerByte);
/* scale parameters */ /* scale parameters */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pfctl_optimize.c,v 1.5 2005/01/03 15:18:10 frantzen Exp $ */ /* $OpenBSD: pfctl_optimize.c,v 1.13 2006/10/31 14:17:45 mcbride Exp $ */
/* /*
* Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org> * Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org>
@ -112,6 +112,10 @@ struct pf_rule_field {
PF_RULE_FIELD(prob, BARRIER), PF_RULE_FIELD(prob, BARRIER),
PF_RULE_FIELD(max_states, BARRIER), PF_RULE_FIELD(max_states, BARRIER),
PF_RULE_FIELD(max_src_nodes, BARRIER), PF_RULE_FIELD(max_src_nodes, BARRIER),
PF_RULE_FIELD(max_src_states, BARRIER),
PF_RULE_FIELD(max_src_conn, BARRIER),
PF_RULE_FIELD(max_src_conn_rate, BARRIER),
PF_RULE_FIELD(anchor, BARRIER), /* for now */
/* /*
* These fields must be the same between all rules in the same superblock. * These fields must be the same between all rules in the same superblock.
@ -123,10 +127,18 @@ struct pf_rule_field {
PF_RULE_FIELD(tagname, BREAK), PF_RULE_FIELD(tagname, BREAK),
PF_RULE_FIELD(keep_state, BREAK), PF_RULE_FIELD(keep_state, BREAK),
PF_RULE_FIELD(qname, BREAK), PF_RULE_FIELD(qname, BREAK),
PF_RULE_FIELD(pqname, BREAK),
PF_RULE_FIELD(rt, BREAK), PF_RULE_FIELD(rt, BREAK),
PF_RULE_FIELD(allow_opts, BREAK), PF_RULE_FIELD(allow_opts, BREAK),
PF_RULE_FIELD(rule_flag, BREAK), PF_RULE_FIELD(rule_flag, BREAK),
PF_RULE_FIELD(action, BREAK), PF_RULE_FIELD(action, BREAK),
PF_RULE_FIELD(log, BREAK),
PF_RULE_FIELD(quick, BREAK),
PF_RULE_FIELD(return_ttl, BREAK),
PF_RULE_FIELD(overload_tblname, BREAK),
PF_RULE_FIELD(flush, BREAK),
PF_RULE_FIELD(rpool, BREAK),
PF_RULE_FIELD(logif, BREAK),
/* /*
* Any fields not listed in this structure act as BREAK fields * Any fields not listed in this structure act as BREAK fields
@ -140,7 +152,7 @@ struct pf_rule_field {
*/ */
PF_RULE_FIELD(af, NOMERGE), PF_RULE_FIELD(af, NOMERGE),
PF_RULE_FIELD(ifnot, NOMERGE), PF_RULE_FIELD(ifnot, NOMERGE),
PF_RULE_FIELD(ifname, NOMERGE), PF_RULE_FIELD(ifname, NOMERGE), /* hack for IF groups */
PF_RULE_FIELD(match_tag_not, NOMERGE), PF_RULE_FIELD(match_tag_not, NOMERGE),
PF_RULE_FIELD(match_tagname, NOMERGE), PF_RULE_FIELD(match_tagname, NOMERGE),
PF_RULE_FIELD(os_fingerprint, NOMERGE), PF_RULE_FIELD(os_fingerprint, NOMERGE),
@ -173,7 +185,6 @@ struct pf_rule_field {
PF_RULE_FIELD(packets, DC), PF_RULE_FIELD(packets, DC),
PF_RULE_FIELD(bytes, DC), PF_RULE_FIELD(bytes, DC),
PF_RULE_FIELD(kif, DC), PF_RULE_FIELD(kif, DC),
PF_RULE_FIELD(anchor, DC),
PF_RULE_FIELD(states, DC), PF_RULE_FIELD(states, DC),
PF_RULE_FIELD(src_nodes, DC), PF_RULE_FIELD(src_nodes, DC),
PF_RULE_FIELD(nr, DC), PF_RULE_FIELD(nr, DC),
@ -182,6 +193,9 @@ struct pf_rule_field {
PF_RULE_FIELD(pqid, DC), PF_RULE_FIELD(pqid, DC),
PF_RULE_FIELD(anchor_relative, DC), PF_RULE_FIELD(anchor_relative, DC),
PF_RULE_FIELD(anchor_wildcard, DC), PF_RULE_FIELD(anchor_wildcard, DC),
PF_RULE_FIELD(tag, DC),
PF_RULE_FIELD(match_tag, DC),
PF_RULE_FIELD(overload_tbl, DC),
/* These fields should never be set in a PASS/BLOCK rule */ /* These fields should never be set in a PASS/BLOCK rule */
PF_RULE_FIELD(natpass, NEVER), PF_RULE_FIELD(natpass, NEVER),
@ -201,6 +215,7 @@ void comparable_rule(struct pf_rule *, const struct pf_rule *, int);
int construct_superblocks(struct pfctl *, struct pf_opt_queue *, int construct_superblocks(struct pfctl *, struct pf_opt_queue *,
struct superblocks *); struct superblocks *);
void exclude_supersets(struct pf_rule *, struct pf_rule *); void exclude_supersets(struct pf_rule *, struct pf_rule *);
int interface_group(const char *);
int load_feedback_profile(struct pfctl *, struct superblocks *); int load_feedback_profile(struct pfctl *, struct superblocks *);
int optimize_superblock(struct pfctl *, struct superblock *); int optimize_superblock(struct pfctl *, struct superblock *);
int pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *); int pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *);
@ -243,25 +258,52 @@ int table_identifier;
int int
pfctl_optimize_rules(struct pfctl *pf) pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset *rs)
{ {
struct superblocks superblocks; struct superblocks superblocks;
struct pf_opt_queue opt_queue;
struct superblock *block; struct superblock *block;
struct pf_opt_rule *por; struct pf_opt_rule *por;
int nr; struct pf_rule *r;
struct pf_rulequeue *old_rules;
DEBUG("optimizing ruleset"); DEBUG("optimizing ruleset");
memset(&table_buffer, 0, sizeof(table_buffer)); memset(&table_buffer, 0, sizeof(table_buffer));
skip_init(); skip_init();
TAILQ_INIT(&opt_queue);
if (TAILQ_FIRST(&pf->opt_queue)) old_rules = rs->rules[PF_RULESET_FILTER].active.ptr;
nr = TAILQ_FIRST(&pf->opt_queue)->por_rule.nr; rs->rules[PF_RULESET_FILTER].active.ptr =
rs->rules[PF_RULESET_FILTER].inactive.ptr;
rs->rules[PF_RULESET_FILTER].inactive.ptr = old_rules;
/*
* XXX expanding the pf_opt_rule format throughout pfctl might allow
* us to avoid all this copying.
*/
while ((r = TAILQ_FIRST(rs->rules[PF_RULESET_FILTER].inactive.ptr))
!= NULL) {
TAILQ_REMOVE(rs->rules[PF_RULESET_FILTER].inactive.ptr, r,
entries);
if ((por = calloc(1, sizeof(*por))) == NULL)
err(1, "calloc");
memcpy(&por->por_rule, r, sizeof(*r));
if (TAILQ_FIRST(&r->rpool.list) != NULL) {
TAILQ_INIT(&por->por_rule.rpool.list);
pfctl_move_pool(&r->rpool, &por->por_rule.rpool);
} else
bzero(&por->por_rule.rpool,
sizeof(por->por_rule.rpool));
TAILQ_INSERT_TAIL(&opt_queue, por, por_entry);
}
TAILQ_INIT(&superblocks); TAILQ_INIT(&superblocks);
if (construct_superblocks(pf, &pf->opt_queue, &superblocks)) if (construct_superblocks(pf, &opt_queue, &superblocks))
goto error; goto error;
if (pf->opts & PF_OPT_OPTIMIZE_PROFILE) { if (pf->optimize & PF_OPTIMIZE_PROFILE) {
if (load_feedback_profile(pf, &superblocks)) if (load_feedback_profile(pf, &superblocks))
goto error; goto error;
} }
@ -271,24 +313,21 @@ pfctl_optimize_rules(struct pfctl *pf)
goto error; goto error;
} }
rs->anchor->refcnt = 0;
/*
* Optimizations are done so we turn off the optimization flag and
* put the rules right back into the regular codepath.
*/
pf->opts &= ~PF_OPT_OPTIMIZE;
while ((block = TAILQ_FIRST(&superblocks))) { while ((block = TAILQ_FIRST(&superblocks))) {
TAILQ_REMOVE(&superblocks, block, sb_entry); TAILQ_REMOVE(&superblocks, block, sb_entry);
while ((por = TAILQ_FIRST(&block->sb_rules))) { while ((por = TAILQ_FIRST(&block->sb_rules))) {
TAILQ_REMOVE(&block->sb_rules, por, por_entry); TAILQ_REMOVE(&block->sb_rules, por, por_entry);
por->por_rule.nr = nr++; por->por_rule.nr = rs->anchor->refcnt++;
if (pfctl_add_rule(pf, &por->por_rule, if ((r = calloc(1, sizeof(*r))) == NULL)
por->por_anchor)) { err(1, "calloc");
free(por); memcpy(r, &por->por_rule, sizeof(*r));
goto error; TAILQ_INIT(&r->rpool.list);
} pfctl_move_pool(&por->por_rule.rpool, &r->rpool);
TAILQ_INSERT_TAIL(
rs->rules[PF_RULESET_FILTER].active.ptr,
r, entries);
free(por); free(por);
} }
free(block); free(block);
@ -297,8 +336,8 @@ pfctl_optimize_rules(struct pfctl *pf)
return (0); return (0);
error: error:
while ((por = TAILQ_FIRST(&pf->opt_queue))) { while ((por = TAILQ_FIRST(&opt_queue))) {
TAILQ_REMOVE(&pf->opt_queue, por, por_entry); TAILQ_REMOVE(&opt_queue, por, por_entry);
if (por->por_src_tbl) { if (por->por_src_tbl) {
pfr_buf_clear(por->por_src_tbl->pt_buf); pfr_buf_clear(por->por_src_tbl->pt_buf);
free(por->por_src_tbl->pt_buf); free(por->por_src_tbl->pt_buf);
@ -367,7 +406,8 @@ optimize_superblock(struct pfctl *pf, struct superblock *block)
printf("--- Superblock ---\n"); printf("--- Superblock ---\n");
TAILQ_FOREACH(por, &block->sb_rules, por_entry) { TAILQ_FOREACH(por, &block->sb_rules, por_entry) {
printf(" "); printf(" ");
print_rule(&por->por_rule, por->por_anchor, 1); print_rule(&por->por_rule, por->por_rule.anchor ?
por->por_rule.anchor->name : "", 1);
} }
#endif /* OPT_DEBUG */ #endif /* OPT_DEBUG */
@ -376,7 +416,7 @@ optimize_superblock(struct pfctl *pf, struct superblock *block)
return (1); return (1);
if (combine_rules(pf, block)) if (combine_rules(pf, block))
return (1); return (1);
if ((pf->opts & PF_OPT_OPTIMIZE_PROFILE) && if ((pf->optimize & PF_OPTIMIZE_PROFILE) &&
TAILQ_FIRST(&block->sb_rules)->por_rule.quick && TAILQ_FIRST(&block->sb_rules)->por_rule.quick &&
block->sb_profiled_block) { block->sb_profiled_block) {
if (block_feedback(pf, block)) if (block_feedback(pf, block))
@ -783,14 +823,16 @@ block_feedback(struct pfctl *pf, struct superblock *block)
*/ */
TAILQ_FOREACH(por1, &block->sb_profiled_block->sb_rules, por_entry) { TAILQ_FOREACH(por1, &block->sb_profiled_block->sb_rules, por_entry) {
comparable_rule(&a, &por1->por_rule, DC); comparable_rule(&a, &por1->por_rule, DC);
total_count += por1->por_rule.packets; total_count += por1->por_rule.packets[0] +
por1->por_rule.packets[1];
TAILQ_FOREACH(por2, &block->sb_rules, por_entry) { TAILQ_FOREACH(por2, &block->sb_rules, por_entry) {
if (por2->por_profile_count) if (por2->por_profile_count)
continue; continue;
comparable_rule(&b, &por2->por_rule, DC); comparable_rule(&b, &por2->por_rule, DC);
if (memcmp(&a, &b, sizeof(a)) == 0) { if (memcmp(&a, &b, sizeof(a)) == 0) {
por2->por_profile_count = por2->por_profile_count =
por1->por_rule.packets; por1->por_rule.packets[0] +
por1->por_rule.packets[1];
break; break;
} }
} }
@ -858,6 +900,7 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
DEBUG("Loading %d active rules for a feedback profile", mnr); DEBUG("Loading %d active rules for a feedback profile", mnr);
for (nr = 0; nr < mnr; ++nr) { for (nr = 0; nr < mnr; ++nr) {
struct pf_ruleset *rs;
if ((por = calloc(1, sizeof(*por))) == NULL) { if ((por = calloc(1, sizeof(*por))) == NULL) {
warn("calloc"); warn("calloc");
return (1); return (1);
@ -868,8 +911,8 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
return (1); return (1);
} }
memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule)); memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule));
strlcpy(por->por_anchor, pr.anchor_call, rs = pf_find_or_create_ruleset(pr.anchor_call);
sizeof(por->por_anchor)); por->por_rule.anchor = rs->anchor;
if (TAILQ_EMPTY(&por->por_rule.rpool.list)) if (TAILQ_EMPTY(&por->por_rule.rpool.list))
memset(&por->por_rule.rpool, 0, memset(&por->por_rule.rpool, 0,
sizeof(por->por_rule.rpool)); sizeof(por->por_rule.rpool));
@ -1052,6 +1095,7 @@ skip_cmp_dst_addr(struct pf_rule *a, struct pf_rule *b)
return (1); return (1);
return (0); return (0);
case PF_ADDR_NOROUTE: case PF_ADDR_NOROUTE:
case PF_ADDR_URPFFAILED:
return (0); return (0);
case PF_ADDR_TABLE: case PF_ADDR_TABLE:
return (strcmp(a->dst.addr.v.tblname, b->dst.addr.v.tblname)); return (strcmp(a->dst.addr.v.tblname, b->dst.addr.v.tblname));
@ -1123,6 +1167,7 @@ skip_cmp_src_addr(struct pf_rule *a, struct pf_rule *b)
return (1); return (1);
return (0); return (0);
case PF_ADDR_NOROUTE: case PF_ADDR_NOROUTE:
case PF_ADDR_URPFFAILED:
return (0); return (0);
case PF_ADDR_TABLE: case PF_ADDR_TABLE:
return (strcmp(a->src.addr.v.tblname, b->src.addr.v.tblname)); return (strcmp(a->src.addr.v.tblname, b->src.addr.v.tblname));
@ -1274,8 +1319,8 @@ pf_opt_create_table(struct pfctl *pf, struct pf_opt_tbl *tbl)
tablenum++; tablenum++;
if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, pf->anchor, if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1,
tbl->pt_buf, pf->tticket)) { pf->anchor->name, tbl->pt_buf, pf->anchor->ruleset.tticket)) {
warn("failed to create table %s", tbl->pt_name); warn("failed to create table %s", tbl->pt_name);
return (1); return (1);
} }
@ -1374,15 +1419,34 @@ superblock_inclusive(struct superblock *block, struct pf_opt_rule *por)
} }
} }
/* 'anchor' heads and per-rule src-track are also hard breaks */ /* per-rule src-track is also a hard break */
if (por->por_anchor[0] != '\0' || if (por->por_rule.rule_flag & PFRULE_RULESRCTRACK)
(por->por_rule.rule_flag & PFRULE_RULESRCTRACK))
return (0); return (0);
/*
* Have to handle interface groups seperately. Consider the following
* rules:
* block on EXTIFS to any port 22
* pass on em0 to any port 22
* (where EXTIFS is an arbitrary interface group)
* The optimizer may decide to re-order the pass rule in front of the
* block rule. But what if EXTIFS includes em0??? Such a reordering
* would change the meaning of the ruleset.
* We can't just lookup the EXTIFS group and check if em0 is a member
* because the user is allowed to add interfaces to a group during
* runtime.
* Ergo interface groups become a defacto superblock break :-(
*/
if (interface_group(por->por_rule.ifname) ||
interface_group(TAILQ_FIRST(&block->sb_rules)->por_rule.ifname)) {
if (strcasecmp(por->por_rule.ifname,
TAILQ_FIRST(&block->sb_rules)->por_rule.ifname) != 0)
return (0);
}
comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE); comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE);
comparable_rule(&b, &por->por_rule, NOMERGE); comparable_rule(&b, &por->por_rule, NOMERGE);
if (strcmp(TAILQ_FIRST(&block->sb_rules)->por_anchor, if (memcmp(&a, &b, sizeof(a)) == 0)
por->por_anchor) == 0 && memcmp(&a, &b, sizeof(a)) == 0)
return (1); return (1);
#ifdef OPT_DEBUG #ifdef OPT_DEBUG
@ -1425,6 +1489,24 @@ superblock_inclusive(struct superblock *block, struct pf_opt_rule *por)
} }
/*
* Figure out if an interface name is an actual interface or actually a
* group of interfaces.
*/
int
interface_group(const char *ifname)
{
if (ifname == NULL || !ifname[0])
return (0);
/* Real interfaces must end in a number, interface groups do not */
if (isdigit(ifname[strlen(ifname) - 1]))
return (0);
else
return (1);
}
/* /*
* Make a rule that can directly compared by memcmp() * Make a rule that can directly compared by memcmp()
*/ */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pfctl_parser.c,v 1.211 2004/12/07 10:33:41 dhartmei Exp $ */ /* $OpenBSD: pfctl_parser.c,v 1.234 2006/10/31 23:46:24 mcbride Exp $ */
/* /*
* Copyright (c) 2001 Daniel Hartmeier * Copyright (c) 2001 Daniel Hartmeier
@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include <errno.h> #include <errno.h>
#include <err.h> #include <err.h>
#include <ifaddrs.h> #include <ifaddrs.h>
#include <unistd.h>
#include "pfctl_parser.h" #include "pfctl_parser.h"
#include "pfctl.h" #include "pfctl.h"
@ -70,6 +71,7 @@ void print_fromto(struct pf_rule_addr *, pf_osfp_t,
struct pf_rule_addr *, u_int8_t, u_int8_t, int); struct pf_rule_addr *, u_int8_t, u_int8_t, int);
int ifa_skip_if(const char *filter, struct node_host *p); int ifa_skip_if(const char *filter, struct node_host *p);
struct node_host *ifa_grouplookup(const char *, int);
struct node_host *host_if(const char *, int); struct node_host *host_if(const char *, int);
struct node_host *host_v4(const char *, int); struct node_host *host_v4(const char *, int);
struct node_host *host_v6(const char *, int); struct node_host *host_v6(const char *, int);
@ -483,9 +485,11 @@ const char *pf_scounters[FCNT_MAX+1] = FCNT_NAMES;
void void
print_status(struct pf_status *s, int opts) print_status(struct pf_status *s, int opts)
{ {
char statline[80], *running; char statline[80], *running;
time_t runtime; time_t runtime;
int i; int i;
char buf[PF_MD5_DIGEST_LENGTH * 2 + 1];
static const char hex[] = "0123456789abcdef";
runtime = time(NULL) - s->since; runtime = time(NULL) - s->since;
running = s->running ? "Enabled" : "Disabled"; running = s->running ? "Enabled" : "Disabled";
@ -519,7 +523,18 @@ print_status(struct pf_status *s, int opts)
printf("%15s\n\n", "Debug: Loud"); printf("%15s\n\n", "Debug: Loud");
break; break;
} }
printf("Hostid: 0x%08x\n\n", ntohl(s->hostid));
if (opts & PF_OPT_VERBOSE) {
printf("Hostid: 0x%08x\n", ntohl(s->hostid));
for (i = 0; i < PF_MD5_DIGEST_LENGTH; i++) {
buf[i + i] = hex[s->pf_chksum[i] >> 4];
buf[i + i + 1] = hex[s->pf_chksum[i] & 0x0f];
}
buf[i + i] = '\0';
printf("Checksum: 0x%s\n\n", buf);
}
if (s->ifname[0] != 0) { if (s->ifname[0] != 0) {
printf("Interface Stats for %-16s %5s %16s\n", printf("Interface Stats for %-16s %5s %16s\n",
s->ifname, "IPv4", "IPv6"); s->ifname, "IPv4", "IPv6");
@ -631,7 +646,14 @@ print_src_node(struct pf_src_node *sn, int opts)
printf(", expires in %.2u:%.2u:%.2u", printf(", expires in %.2u:%.2u:%.2u",
sn->expire, min, sec); sn->expire, min, sec);
} }
printf(", %u pkts, %u bytes", sn->packets, sn->bytes); printf(", %llu pkts, %llu bytes",
#ifdef __FreeBSD__
(unsigned long long)(sn->packets[0] + sn->packets[1]),
(unsigned long long)(sn->bytes[0] + sn->bytes[1]));
#else
sn->packets[0] + sn->packets[1],
sn->bytes[0] + sn->bytes[1]);
#endif
switch (sn->ruletype) { switch (sn->ruletype) {
case PF_NAT: case PF_NAT:
if (sn->rule.nr != -1) if (sn->rule.nr != -1)
@ -664,10 +686,13 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
printf("@%d ", r->nr); printf("@%d ", r->nr);
if (r->action > PF_NORDR) if (r->action > PF_NORDR)
printf("action(%d)", r->action); printf("action(%d)", r->action);
else if (anchor_call[0]) else if (anchor_call[0]) {
printf("%s \"%s\"", anchortypes[r->action], if (anchor_call[0] == '_') {
anchor_call); printf("%s", anchortypes[r->action]);
else { } else
printf("%s \"%s\"", anchortypes[r->action],
anchor_call);
} else {
printf("%s", actiontypes[r->action]); printf("%s", actiontypes[r->action]);
if (r->natpass) if (r->natpass)
printf(" pass"); printf(" pass");
@ -722,10 +747,22 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
printf(" in"); printf(" in");
else if (r->direction == PF_OUT) else if (r->direction == PF_OUT)
printf(" out"); printf(" out");
if (r->log == 1) if (r->log) {
printf(" log"); printf(" log");
else if (r->log == 2) if (r->log & ~PF_LOG || r->logif) {
printf(" log-all"); int count = 0;
printf(" (");
if (r->log & PF_LOG_ALL)
printf("%sall", count++ ? ", " : "");
if (r->log & PF_LOG_SOCKET_LOOKUP)
printf("%suser", count++ ? ", " : "");
if (r->logif)
printf("%sto pflog%u", count++ ? ", " : "",
r->logif);
printf(")");
}
}
if (r->quick) if (r->quick)
printf(" quick"); printf(" quick");
if (r->ifname[0]) { if (r->ifname[0]) {
@ -775,7 +812,11 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
print_flags(r->flags); print_flags(r->flags);
printf("/"); printf("/");
print_flags(r->flagset); print_flags(r->flagset);
} } else if (r->action == PF_PASS &&
(!r->proto || r->proto == IPPROTO_TCP) &&
!(r->rule_flag & PFRULE_FRAGMENT) &&
!anchor_call[0] && r->keep_state)
printf(" flags any");
if (r->type) { if (r->type) {
const struct icmptypeent *it; const struct icmptypeent *it;
@ -800,7 +841,9 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
} }
if (r->tos) if (r->tos)
printf(" tos 0x%2.2x", r->tos); printf(" tos 0x%2.2x", r->tos);
if (r->keep_state == PF_STATE_NORMAL) if (!r->keep_state && r->action == PF_PASS && !anchor_call[0])
printf(" no state");
else if (r->keep_state == PF_STATE_NORMAL)
printf(" keep state"); printf(" keep state");
else if (r->keep_state == PF_STATE_MODULATE) else if (r->keep_state == PF_STATE_MODULATE)
printf(" modulate state"); printf(" modulate state");
@ -828,7 +871,7 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
opts = 1; opts = 1;
if (r->rule_flag & PFRULE_SRCTRACK) if (r->rule_flag & PFRULE_SRCTRACK)
opts = 1; opts = 1;
if (r->rule_flag & (PFRULE_IFBOUND | PFRULE_GRBOUND)) if (r->rule_flag & PFRULE_IFBOUND)
opts = 1; opts = 1;
for (i = 0; !opts && i < PFTM_MAX; ++i) for (i = 0; !opts && i < PFTM_MAX; ++i)
if (r->timeout[i]) if (r->timeout[i])
@ -896,12 +939,6 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
printf("if-bound"); printf("if-bound");
opts = 0; opts = 0;
} }
if (r->rule_flag & PFRULE_GRBOUND) {
if (!opts)
printf(", ");
printf("group-bound");
opts = 0;
}
for (i = 0; i < PFTM_MAX; ++i) for (i = 0; i < PFTM_MAX; ++i)
if (r->timeout[i]) { if (r->timeout[i]) {
int j; int j;
@ -909,12 +946,13 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
if (!opts) if (!opts)
printf(", "); printf(", ");
opts = 0; opts = 0;
for (j = 0; j < sizeof(pf_timeouts) / for (j = 0; pf_timeouts[j].name != NULL;
sizeof(pf_timeouts[0]); ++j) ++j)
if (pf_timeouts[j].timeout == i) if (pf_timeouts[j].timeout == i)
break; break;
printf("%s %u", j == PFTM_MAX ? "inv.timeout" : printf("%s %u", pf_timeouts[j].name == NULL ?
pf_timeouts[j].name, r->timeout[i]); "inv.timeout" : pf_timeouts[j].name,
r->timeout[i]);
} }
printf(")"); printf(")");
} }
@ -954,13 +992,14 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
printf(" !"); printf(" !");
printf(" tagged %s", r->match_tagname); printf(" tagged %s", r->match_tagname);
} }
if (r->rtableid != -1)
printf(" rtable %u", r->rtableid);
if (!anchor_call[0] && (r->action == PF_NAT || if (!anchor_call[0] && (r->action == PF_NAT ||
r->action == PF_BINAT || r->action == PF_RDR)) { r->action == PF_BINAT || r->action == PF_RDR)) {
printf(" -> "); printf(" -> ");
print_pool(&r->rpool, r->rpool.proxy_port[0], print_pool(&r->rpool, r->rpool.proxy_port[0],
r->rpool.proxy_port[1], r->af, r->action); r->rpool.proxy_port[1], r->af, r->action);
} }
printf("\n");
} }
void void
@ -1153,13 +1192,31 @@ ifa_load(void)
} }
struct node_host * struct node_host *
ifa_exists(const char *ifa_name, int group_ok) ifa_exists(const char *ifa_name)
{ {
struct node_host *n; struct node_host *n;
struct ifgroupreq ifgr;
int s;
if (iftab == NULL) if (iftab == NULL)
ifa_load(); ifa_load();
/* check wether this is a group */
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
err(1, "socket");
bzero(&ifgr, sizeof(ifgr));
strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == 0) {
/* fake a node_host */
if ((n = calloc(1, sizeof(*n))) == NULL)
err(1, "calloc");
if ((n->ifname = strdup(ifa_name)) == NULL)
err(1, "strdup");
close(s);
return (n);
}
close(s);
for (n = iftab; n; n = n->next) { for (n = iftab; n; n = n->next) {
if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
return (n); return (n);
@ -1168,6 +1225,47 @@ ifa_exists(const char *ifa_name, int group_ok)
return (NULL); return (NULL);
} }
struct node_host *
ifa_grouplookup(const char *ifa_name, int flags)
{
struct ifg_req *ifg;
struct ifgroupreq ifgr;
int s, len;
struct node_host *n, *h = NULL;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
err(1, "socket");
bzero(&ifgr, sizeof(ifgr));
strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
close(s);
return (NULL);
}
len = ifgr.ifgr_len;
if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
err(1, "calloc");
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
err(1, "SIOCGIFGMEMB");
for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
ifg++) {
len -= sizeof(struct ifg_req);
if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL)
continue;
if (h == NULL)
h = n;
else {
h->tail->next = n;
h->tail = n->tail;
}
}
free(ifgr.ifgr_groups);
close(s);
return (h);
}
struct node_host * struct node_host *
ifa_lookup(const char *ifa_name, int flags) ifa_lookup(const char *ifa_name, int flags)
{ {
@ -1175,6 +1273,9 @@ ifa_lookup(const char *ifa_name, int flags)
int got4 = 0, got6 = 0; int got4 = 0, got6 = 0;
const char *last_if = NULL; const char *last_if = NULL;
if ((h = ifa_grouplookup(ifa_name, flags)) != NULL)
return (h);
if (!strncmp(ifa_name, "self", IFNAMSIZ)) if (!strncmp(ifa_name, "self", IFNAMSIZ))
ifa_name = NULL; ifa_name = NULL;
@ -1352,7 +1453,7 @@ host_if(const char *s, int mask)
free(ps); free(ps);
return (NULL); return (NULL);
} }
if (ifa_exists(ps, 1) || !strncmp(ps, "self", IFNAMSIZ)) { if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) {
/* interface with this name exists */ /* interface with this name exists */
h = ifa_lookup(ps, flags); h = ifa_lookup(ps, flags);
for (n = h; n != NULL && mask > -1; n = n->next) for (n = h; n != NULL && mask > -1; n = n->next)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pfctl_parser.h,v 1.80 2005/02/07 18:18:14 david Exp $ */ /* $OpenBSD: pfctl_parser.h,v 1.86 2006/10/31 23:46:25 mcbride Exp $ */
/* /*
* Copyright (c) 2001 Daniel Hartmeier * Copyright (c) 2001 Daniel Hartmeier
@ -48,14 +48,17 @@
#define PF_OPT_DEBUG 0x0200 #define PF_OPT_DEBUG 0x0200
#define PF_OPT_SHOWALL 0x0400 #define PF_OPT_SHOWALL 0x0400
#define PF_OPT_OPTIMIZE 0x0800 #define PF_OPT_OPTIMIZE 0x0800
#define PF_OPT_OPTIMIZE_PROFILE 0x1000
#define PF_OPT_MERGE 0x2000 #define PF_OPT_MERGE 0x2000
#define PF_OPT_RECURSE 0x4000
#define PF_TH_ALL 0xFF #define PF_TH_ALL 0xFF
#define PF_NAT_PROXY_PORT_LOW 50001 #define PF_NAT_PROXY_PORT_LOW 50001
#define PF_NAT_PROXY_PORT_HIGH 65535 #define PF_NAT_PROXY_PORT_HIGH 65535
#define PF_OPTIMIZE_BASIC 0x0001
#define PF_OPTIMIZE_PROFILE 0x0002
#define FCNT_NAMES { \ #define FCNT_NAMES { \
"searches", \ "searches", \
"inserts", \ "inserts", \
@ -64,24 +67,25 @@
} }
struct pfr_buffer; /* forward definition */ struct pfr_buffer; /* forward definition */
struct pf_opt_rule;
TAILQ_HEAD(pf_opt_queue, pf_opt_rule);
struct pfctl { struct pfctl {
int dev; int dev;
int opts; int opts;
int optimize;
int loadopt; int loadopt;
u_int32_t tticket; /* table ticket */ int asd; /* anchor stack depth */
int bn; /* brace number */
int brace;
int tdirty; /* kernel dirty */ int tdirty; /* kernel dirty */
u_int32_t rule_nr; #define PFCTL_ANCHOR_STACK_DEPTH 64
struct pf_anchor *astack[PFCTL_ANCHOR_STACK_DEPTH];
struct pfioc_pooladdr paddr; struct pfioc_pooladdr paddr;
struct pfioc_altq *paltq; struct pfioc_altq *paltq;
struct pfioc_queue *pqueue; struct pfioc_queue *pqueue;
struct pfr_buffer *trans; struct pfr_buffer *trans;
const char *anchor; struct pf_anchor *anchor, *alast;
const char *ruleset; const char *ruleset;
struct pf_opt_queue opt_queue;
/* 'set foo' options */ /* 'set foo' options */
u_int32_t timeout[PFTM_MAX]; u_int32_t timeout[PFTM_MAX];
@ -118,10 +122,6 @@ struct node_host {
struct node_host *next; struct node_host *next;
struct node_host *tail; 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 { struct node_os {
char *os; char *os;
@ -205,19 +205,20 @@ struct pf_opt_rule {
struct pf_rule por_rule; struct pf_rule por_rule;
struct pf_opt_tbl *por_src_tbl; struct pf_opt_tbl *por_src_tbl;
struct pf_opt_tbl *por_dst_tbl; struct pf_opt_tbl *por_dst_tbl;
char por_anchor[MAXPATHLEN];
u_int64_t por_profile_count; u_int64_t por_profile_count;
TAILQ_ENTRY(pf_opt_rule) por_entry; TAILQ_ENTRY(pf_opt_rule) por_entry;
TAILQ_ENTRY(pf_opt_rule) por_skip_entry[PF_SKIP_COUNT]; TAILQ_ENTRY(pf_opt_rule) por_skip_entry[PF_SKIP_COUNT];
}; };
TAILQ_HEAD(pf_opt_queue, pf_opt_rule);
int pfctl_rules(int, char *, int, char *, struct pfr_buffer *); int pfctl_rules(int, char *, FILE *, int, int, char *, struct pfr_buffer *);
int pfctl_optimize_rules(struct pfctl *); int pfctl_optimize_ruleset(struct pfctl *, struct pf_ruleset *);
int pfctl_add_rule(struct pfctl *, struct pf_rule *, const char *); int pfctl_add_rule(struct pfctl *, struct pf_rule *, const char *);
int pfctl_add_altq(struct pfctl *, struct pf_altq *); int pfctl_add_altq(struct pfctl *, struct pf_altq *);
int pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t); int pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t);
void pfctl_move_pool(struct pf_pool *, struct pf_pool *);
void pfctl_clear_pool(struct pf_pool *); void pfctl_clear_pool(struct pf_pool *);
int pfctl_set_timeout(struct pfctl *, const char *, int, int); int pfctl_set_timeout(struct pfctl *, const char *, int, int);
@ -230,7 +231,7 @@ int pfctl_set_interface_flags(struct pfctl *, char *, int, int);
int parse_rules(FILE *, struct pfctl *); int parse_rules(FILE *, struct pfctl *);
int parse_flags(char *); int parse_flags(char *);
int pfctl_load_anchors(int, int, struct pfr_buffer *); int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *);
void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int); 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_src_node(struct pf_src_node *, int);
@ -292,7 +293,7 @@ void set_ipmask(struct node_host *, u_int8_t);
int check_netmask(struct node_host *, sa_family_t); int check_netmask(struct node_host *, sa_family_t);
int unmask(struct pf_addr *, sa_family_t); int unmask(struct pf_addr *, sa_family_t);
void ifa_load(void); void ifa_load(void);
struct node_host *ifa_exists(const char *, int); struct node_host *ifa_exists(const char *);
struct node_host *ifa_lookup(const char *, int); struct node_host *ifa_lookup(const char *, int);
struct node_host *host(const char *); struct node_host *host(const char *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pfctl_table.c,v 1.62 2004/12/22 17:17:55 dhartmei Exp $ */ /* $OpenBSD: pfctl_table.c,v 1.66 2007/03/01 17:20:54 deraadt Exp $ */
/* /*
* Copyright (c) 2002 Cedric Berger * Copyright (c) 2002 Cedric Berger
@ -64,8 +64,7 @@ static void print_addrx(struct pfr_addr *, struct pfr_addr *, int);
static void print_astats(struct pfr_astats *, int); static void print_astats(struct pfr_astats *, int);
static void radix_perror(void); static void radix_perror(void);
static void xprintf(int, const char *, ...); static void xprintf(int, const char *, ...);
static void print_iface(struct pfi_if *, int); static void print_iface(struct pfi_kif *, int);
static void oprintf(int, int, const char *, int *, int);
static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = { static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = {
{ "In/Block:", "In/Pass:", "In/XPass:" }, { "In/Block:", "In/Pass:", "In/XPass:" },
@ -178,7 +177,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
break; break;
} }
if (opts & PF_OPT_SHOWALL && b.pfrb_size > 0) if ((opts & PF_OPT_SHOWALL) && b.pfrb_size > 0)
pfctl_print_title("TABLES:"); pfctl_print_title("TABLES:");
PFRB_FOREACH(p, &b) PFRB_FOREACH(p, &b)
@ -257,6 +256,42 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
print_addrx(a, NULL, print_addrx(a, NULL,
opts & PF_OPT_USEDNS); opts & PF_OPT_USEDNS);
} else if (!strcmp(command, "expire")) {
const char *errstr;
u_int lifetime;
b.pfrb_type = PFRB_ASTATS;
b2.pfrb_type = PFRB_ADDRS;
if (argc != 1 || file != NULL)
usage();
lifetime = strtonum(*argv, 0, UINT_MAX, &errstr);
if (errstr)
errx(1, "expiry time: %s", errstr);
for (;;) {
pfr_buf_grow(&b, b.pfrb_size);
b.pfrb_size = b.pfrb_msize;
RVTEST(pfr_get_astats(&table, b.pfrb_caddr,
&b.pfrb_size, flags));
if (b.pfrb_size <= b.pfrb_msize)
break;
}
PFRB_FOREACH(p, &b)
if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero >
lifetime)
if (pfr_buf_add(&b2,
&((struct pfr_astats *)p)->pfras_a))
err(1, "duplicate buffer");
if (opts & PF_OPT_VERBOSE)
flags |= PFR_FLAG_FEEDBACK;
RVTEST(pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size,
&ndel, flags));
xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size);
if (opts & PF_OPT_VERBOSE)
PFRB_FOREACH(a, &b2)
if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
print_addrx(a, NULL,
opts & PF_OPT_USEDNS);
} else if (!strcmp(command, "show")) { } else if (!strcmp(command, "show")) {
b.pfrb_type = (opts & PF_OPT_VERBOSE) ? b.pfrb_type = (opts & PF_OPT_VERBOSE) ?
PFRB_ASTATS : PFRB_ADDRS; PFRB_ASTATS : PFRB_ADDRS;
@ -294,7 +329,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size, RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size,
&nmatch, flags)); &nmatch, flags));
xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size); xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size);
if (opts & PF_OPT_VERBOSE && !(opts & PF_OPT_VERBOSE2)) if ((opts & PF_OPT_VERBOSE) && !(opts & PF_OPT_VERBOSE2))
PFRB_FOREACH(a, &b) PFRB_FOREACH(a, &b)
if (a->pfra_fback == PFR_FB_MATCH) if (a->pfra_fback == PFR_FB_MATCH)
print_addrx(a, NULL, print_addrx(a, NULL,
@ -542,17 +577,15 @@ int
pfctl_show_ifaces(const char *filter, int opts) pfctl_show_ifaces(const char *filter, int opts)
{ {
struct pfr_buffer b; struct pfr_buffer b;
struct pfi_if *p; struct pfi_kif *p;
int i = 0, f = PFI_FLAG_GROUP|PFI_FLAG_INSTANCE; int i = 0;
if (filter != NULL && *filter && !isdigit(filter[strlen(filter)-1]))
f &= ~PFI_FLAG_INSTANCE;
bzero(&b, sizeof(b)); bzero(&b, sizeof(b));
b.pfrb_type = PFRB_IFACES; b.pfrb_type = PFRB_IFACES;
for (;;) { for (;;) {
pfr_buf_grow(&b, b.pfrb_size); pfr_buf_grow(&b, b.pfrb_size);
b.pfrb_size = b.pfrb_msize; b.pfrb_size = b.pfrb_msize;
if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size, f)) { if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) {
radix_perror(); radix_perror();
return (1); return (1);
} }
@ -568,50 +601,30 @@ pfctl_show_ifaces(const char *filter, int opts)
} }
void void
print_iface(struct pfi_if *p, int opts) print_iface(struct pfi_kif *p, int opts)
{ {
time_t tzero = p->pfif_tzero; time_t tzero = p->pfik_tzero;
int flags = (opts & PF_OPT_VERBOSE) ? p->pfif_flags : 0;
int first = 1;
int i, af, dir, act; int i, af, dir, act;
printf("%s", p->pfif_name); printf("%s", p->pfik_name);
oprintf(flags, PFI_IFLAG_INSTANCE, "instance", &first, 0); if (opts & PF_OPT_VERBOSE) {
oprintf(flags, PFI_IFLAG_GROUP, "group", &first, 0); if (p->pfik_flags & PFI_IFLAG_SKIP)
oprintf(flags, PFI_IFLAG_CLONABLE, "clonable", &first, 0); printf(" (skip)");
oprintf(flags, PFI_IFLAG_DYNAMIC, "dynamic", &first, 0); }
oprintf(flags, PFI_IFLAG_ATTACHED, "attached", &first, 0);
oprintf(flags, PFI_IFLAG_SKIP, "skipped", &first, 1);
#ifdef __FreeBSD__
first = 1;
oprintf(flags, PFI_IFLAG_PLACEHOLDER, "placeholder", &first, 1);
#endif
printf("\n"); printf("\n");
if (!(opts & PF_OPT_VERBOSE2)) if (!(opts & PF_OPT_VERBOSE2))
return; return;
printf("\tCleared: %s", ctime(&tzero)); printf("\tCleared: %s", ctime(&tzero));
printf("\tReferences: [ States: %-18d Rules: %-18d ]\n", printf("\tReferences: [ States: %-18d Rules: %-18d ]\n",
p->pfif_states, p->pfif_rules); p->pfik_states, p->pfik_rules);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
af = (i>>2) & 1; af = (i>>2) & 1;
dir = (i>>1) &1; dir = (i>>1) &1;
act = i & 1; act = i & 1;
printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
istats_text[af][dir][act], istats_text[af][dir][act],
(unsigned long long)p->pfif_packets[af][dir][act], (unsigned long long)p->pfik_packets[af][dir][act],
(unsigned long long)p->pfif_bytes[af][dir][act]); (unsigned long long)p->pfik_bytes[af][dir][act]);
} }
} }
void
oprintf(int flags, int flag, const char *s, int *first, int last)
{
if (flags & flag) {
printf(*first ? "\t(%s" : ", %s", s);
*first = 0;
}
if (last && !*first)
printf(")");
}

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: pflogd.8,v 1.25 2005/01/02 18:15:02 jmc Exp $ .\" $OpenBSD: pflogd.8,v 1.32 2006/12/08 10:26:38 joel Exp $
.\" .\"
.\" Copyright (c) 2001 Can Erkin Acar. All rights reserved. .\" Copyright (c) 2001 Can Erkin Acar. All rights reserved.
.\" .\"
@ -37,14 +37,17 @@
.Op Fl Dx .Op Fl Dx
.Op Fl d Ar delay .Op Fl d Ar delay
.Op Fl f Ar filename .Op Fl f Ar filename
.Op Fl i Ar interface
.Op Fl s Ar snaplen .Op Fl s Ar snaplen
.Op Ar expression .Op Ar expression
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
is a background daemon which reads packets logged by is a background daemon which reads packets logged by
.Xr pf 4 .Xr pf 4
to the packet logging interface to a
.Pa pflog0 .Xr pflog 4
interface, normally
.Pa pflog0 ,
and writes the packets to a logfile (normally and writes the packets to a logfile (normally
.Pa /var/log/pflog ) .Pa /var/log/pflog )
in in
@ -83,7 +86,9 @@ temporarily uses the old snaplen to keep the log file consistent.
tries to preserve the integrity of the log file against I/O errors. tries to preserve the integrity of the log file against I/O errors.
Furthermore, integrity of an existing log file is verified before Furthermore, integrity of an existing log file is verified before
appending. appending.
If there is an invalid log file or an I/O error, logging is suspended until a If there is an invalid log file or an I/O error, the log file is moved
out of the way and a new one is created.
If a new file cannot be created, logging is suspended until a
.Dv SIGHUP .Dv SIGHUP
or a or a
.Dv SIGALRM .Dv SIGALRM
@ -103,11 +108,19 @@ If not specified, the default is 60 seconds.
Log output filename. Log output filename.
Default is Default is
.Pa /var/log/pflog . .Pa /var/log/pflog .
.It Fl i Ar interface
Specifies the
.Xr pflog 4
interface to use.
By default,
.Nm
will use
.Ar pflog0 .
.It Fl s Ar snaplen .It Fl s Ar snaplen
Analyze at most the first Analyze at most the first
.Ar snaplen .Ar snaplen
bytes of data from each packet rather than the default of 96. bytes of data from each packet rather than the default of 116.
The default of 96 is adequate for IP, ICMP, TCP, and UDP headers but may The default of 116 is adequate for IP, ICMP, TCP, and UDP headers but may
truncate protocol information for other protocols. truncate protocol information for other protocols.
Other file parsers may desire a higher snaplen. Other file parsers may desire a higher snaplen.
.It Fl x .It Fl x
@ -131,6 +144,13 @@ Log specific tcp packets to a different log file with a large snaplen
# pflogd -s 1600 -f suspicious.log port 80 and host evilhost # pflogd -s 1600 -f suspicious.log port 80 and host evilhost
.Ed .Ed
.Pp .Pp
Log from another
.Xr pflog 4
interface, excluding specific packets:
.Bd -literal -offset indent
# pflogd -i pflog3 -f network3.log "not (tcp and port 23)"
.Ed
.Pp
Display binary logs: Display binary logs:
.Bd -literal -offset indent .Bd -literal -offset indent
# tcpdump -n -e -ttt -r /var/log/pflog # tcpdump -n -e -ttt -r /var/log/pflog
@ -150,7 +170,7 @@ Tcpdump can restrict the output
to packets logged on a specified interface, a rule number, a reason, 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 .Pp
.Bl -tag -width "reason match " -compact .Bl -tag -width "ruleset authpf " -compact
.It ip .It ip
Address family equals IPv4. Address family equals IPv4.
.It ip6 .It ip6
@ -159,12 +179,16 @@ Address family equals IPv6.
Interface name equals "kue0". Interface name equals "kue0".
.It on kue0 .It on kue0
Interface name equals "kue0". Interface name equals "kue0".
.It ruleset authpf
Ruleset name equals "authpf".
.It rulenum 10 .It rulenum 10
Rule number equals 10. Rule number equals 10.
.It reason match .It reason match
Reason equals match. Reason equals match.
Also accepts "bad-offset", "fragment", "bad-timestamp", "short", Also accepts "bad-offset", "fragment", "bad-timestamp", "short",
"normalize" and "memory". "normalize", "memory", "congestion", "ip-option", "proto-cksum",
"state-mismatch", "state-insert", "state-limit", "src-limit",
and "synproxy".
.It action pass .It action pass
Action equals pass. Action equals pass.
Also accepts "block". Also accepts "block".
@ -192,4 +216,6 @@ The
command appeared in command appeared in
.Ox 3.0 . .Ox 3.0 .
.Sh AUTHORS .Sh AUTHORS
Can Erkin Acar .Nm
was written by
.An Can Erkin Acar Aq canacar@openbsd.org .

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pflogd.c,v 1.33 2005/02/09 12:09:30 henning Exp $ */ /* $OpenBSD: pflogd.c,v 1.37 2006/10/26 13:34:47 jmc Exp $ */
/* /*
* Copyright (c) 2001 Theo de Raadt * Copyright (c) 2001 Theo de Raadt
@ -81,7 +81,7 @@ int flush_buffer(FILE *);
int init_pcap(void); int init_pcap(void);
void logmsg(int, const char *, ...); void logmsg(int, const char *, ...);
void purge_buffer(void); void purge_buffer(void);
int reset_dump(void); int reset_dump(int);
int scan_dump(FILE *, off_t); int scan_dump(FILE *, off_t);
int set_snaplen(int); int set_snaplen(int);
void set_suspended(int); void set_suspended(int);
@ -90,6 +90,8 @@ void sig_close(int);
void sig_hup(int); void sig_hup(int);
void usage(void); void usage(void);
static int try_reset_dump(int);
/* buffer must always be greater than snaplen */ /* buffer must always be greater than snaplen */
static int bufpkt = 0; /* number of packets in buffer */ static int bufpkt = 0; /* number of packets in buffer */
static int buflen = 0; /* allocated size of buffer */ static int buflen = 0; /* allocated size of buffer */
@ -108,8 +110,9 @@ set_suspended(int s)
return; return;
suspended = s; suspended = s;
setproctitle("[%s] -s %d -f %s", setproctitle("[%s] -s %d -i %s -f %s",
suspended ? "suspended" : "running", cur_snaplen, filename); suspended ? "suspended" : "running",
cur_snaplen, interface, filename);
} }
char * char *
@ -159,8 +162,9 @@ __dead void
#endif #endif
usage(void) usage(void)
{ {
fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename] "); fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename]");
fprintf(stderr, "[-s snaplen] [expression]\n"); fprintf(stderr, " [-i interface] [-s snaplen]\n");
fprintf(stderr, " [expression]\n");
exit(1); exit(1);
} }
@ -240,7 +244,25 @@ set_snaplen(int snap)
} }
int int
reset_dump(void) reset_dump(int nomove)
{
int ret;
for (;;) {
ret = try_reset_dump(nomove);
if (ret <= 0)
break;
}
return (ret);
}
/*
* tries to (re)open log file, nomove flag is used with -x switch
* returns 0: success, 1: retry (log moved), -1: error
*/
int
try_reset_dump(int nomove)
{ {
struct pcap_file_header hdr; struct pcap_file_header hdr;
struct stat st; struct stat st;
@ -262,26 +284,26 @@ reset_dump(void)
*/ */
fd = priv_open_log(); fd = priv_open_log();
if (fd < 0) if (fd < 0)
return (1); return (-1);
fp = fdopen(fd, "a+"); fp = fdopen(fd, "a+");
if (fp == NULL) { if (fp == NULL) {
close(fd);
logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno)); logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
return (1); close(fd);
return (-1);
} }
if (fstat(fileno(fp), &st) == -1) { if (fstat(fileno(fp), &st) == -1) {
fclose(fp);
logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno)); logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
return (1); fclose(fp);
return (-1);
} }
/* set FILE unbuffered, we do our own buffering */ /* set FILE unbuffered, we do our own buffering */
if (setvbuf(fp, NULL, _IONBF, 0)) { if (setvbuf(fp, NULL, _IONBF, 0)) {
fclose(fp);
logmsg(LOG_ERR, "Failed to set output buffers"); logmsg(LOG_ERR, "Failed to set output buffers");
return (1); fclose(fp);
return (-1);
} }
#define TCPDUMP_MAGIC 0xa1b2c3d4 #define TCPDUMP_MAGIC 0xa1b2c3d4
@ -289,11 +311,9 @@ reset_dump(void)
if (st.st_size == 0) { if (st.st_size == 0) {
if (snaplen != cur_snaplen) { if (snaplen != cur_snaplen) {
logmsg(LOG_NOTICE, "Using snaplen %d", snaplen); logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
if (set_snaplen(snaplen)) { if (set_snaplen(snaplen))
fclose(fp);
logmsg(LOG_WARNING, logmsg(LOG_WARNING,
"Failed, using old settings"); "Failed, using old settings");
}
} }
hdr.magic = TCPDUMP_MAGIC; hdr.magic = TCPDUMP_MAGIC;
hdr.version_major = PCAP_VERSION_MAJOR; hdr.version_major = PCAP_VERSION_MAJOR;
@ -305,11 +325,15 @@ reset_dump(void)
if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) { if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
fclose(fp); fclose(fp);
return (1); return (-1);
} }
} else if (scan_dump(fp, st.st_size)) { } else if (scan_dump(fp, st.st_size)) {
/* XXX move file and continue? */
fclose(fp); fclose(fp);
if (nomove || priv_move_log()) {
logmsg(LOG_ERR,
"Invalid/incompatible log file, move it away");
return (-1);
}
return (1); return (1);
} }
@ -352,7 +376,6 @@ scan_dump(FILE *fp, off_t size)
hdr.version_minor != PCAP_VERSION_MINOR || hdr.version_minor != PCAP_VERSION_MINOR ||
hdr.linktype != hpcap->linktype || hdr.linktype != hpcap->linktype ||
hdr.snaplen > PFLOGD_MAXSNAPLEN) { hdr.snaplen > PFLOGD_MAXSNAPLEN) {
logmsg(LOG_ERR, "Invalid/incompatible log file, move it away");
return (1); return (1);
} }
@ -563,7 +586,7 @@ main(int argc, char **argv)
closefrom(STDERR_FILENO + 1); closefrom(STDERR_FILENO + 1);
#endif #endif
while ((ch = getopt(argc, argv, "Dxd:s:f:")) != -1) { while ((ch = getopt(argc, argv, "Dxd:f:i:s:")) != -1) {
switch (ch) { switch (ch) {
case 'D': case 'D':
Debug = 1; Debug = 1;
@ -576,6 +599,9 @@ main(int argc, char **argv)
case 'f': case 'f':
filename = optarg; filename = optarg;
break; break;
case 'i':
interface = optarg;
break;
case 's': case 's':
snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN, snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN,
&errstr); &errstr);
@ -648,7 +674,7 @@ main(int argc, char **argv)
bufpkt = 0; bufpkt = 0;
} }
if (reset_dump()) { if (reset_dump(Xflag) < 0) {
if (Xflag) if (Xflag)
return (1); return (1);
@ -674,7 +700,7 @@ main(int argc, char **argv)
if (gotsig_close) if (gotsig_close)
break; break;
if (gotsig_hup) { if (gotsig_hup) {
if (reset_dump()) { if (reset_dump(0)) {
logmsg(LOG_ERR, logmsg(LOG_ERR,
"Logging suspended: open error"); "Logging suspended: open error");
set_suspended(1); set_suspended(1);
@ -685,6 +711,8 @@ main(int argc, char **argv)
if (gotsig_alrm) { if (gotsig_alrm) {
if (dpcap) if (dpcap)
flush_buffer(dpcap); flush_buffer(dpcap);
else
gotsig_hup = 1;
gotsig_alrm = 0; gotsig_alrm = 0;
alarm(delay); alarm(delay);
} }

View File

@ -1,122 +0,0 @@
/* $FreeBSD$ */
/* $OpenBSD: pidfile.c,v 1.5 2002/05/26 09:29:02 deraadt Exp $ */
/* $NetBSD: pidfile.c,v 1.4 2001/02/19 22:43:42 cgd Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$OpenBSD: pidfile.c,v 1.5 2002/05/26 09:29:02 deraadt Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <errno.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef __FreeBSD__
#include "pidfile.h"
#else
#include <util.h>
#endif
static char *pidfile_path;
static pid_t pidfile_pid;
static void pidfile_cleanup(void);
extern char *__progname;
int
pidfile(const char *basename)
{
FILE *f;
int save_errno;
pid_t pid;
if (basename == NULL)
basename = __progname;
if (pidfile_path != NULL) {
free(pidfile_path);
pidfile_path = NULL;
}
/* _PATH_VARRUN includes trailing / */
(void) asprintf(&pidfile_path, "%s%s.pid", _PATH_VARRUN, basename);
if (pidfile_path == NULL)
return (-1);
if ((f = fopen(pidfile_path, "w")) == NULL) {
save_errno = errno;
free(pidfile_path);
pidfile_path = NULL;
errno = save_errno;
return (-1);
}
pid = getpid();
if (fprintf(f, "%ld\n", (long)pid) <= 0 || fclose(f) != 0) {
save_errno = errno;
(void) unlink(pidfile_path);
free(pidfile_path);
pidfile_path = NULL;
errno = save_errno;
return (-1);
}
pidfile_pid = pid;
if (atexit(pidfile_cleanup) < 0) {
save_errno = errno;
(void) unlink(pidfile_path);
free(pidfile_path);
pidfile_path = NULL;
pidfile_pid = 0;
errno = save_errno;
return (-1);
}
return (0);
}
static void
pidfile_cleanup(void)
{
if (pidfile_path != NULL && pidfile_pid == getpid())
(void) unlink(pidfile_path);
}

View File

@ -1 +0,0 @@
int pidfile(const char *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: privsep.c,v 1.13 2004/12/22 09:21:02 otto Exp $ */ /* $OpenBSD: privsep.c,v 1.16 2006/10/25 20:55:04 moritz Exp $ */
/* /*
* Copyright (c) 2003 Can Erkin Acar * Copyright (c) 2003 Can Erkin Acar
@ -20,7 +20,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -30,19 +30,28 @@ __FBSDID("$FreeBSD$");
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#ifndef __FreeBSD__
#include <pcap.h>
#include <pcap-int.h>
#endif
#include <pwd.h> #include <pwd.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef __FreeBSD__
/* XXX: pcap pollutes namespace with strlcpy if not present previously */
#include <pcap.h> #include <pcap.h>
#include <pcap-int.h> #include <pcap-int.h>
#endif
#include <syslog.h> #include <syslog.h>
#include <unistd.h> #include <unistd.h>
#include "pflogd.h" #include "pflogd.h"
enum cmd_types { enum cmd_types {
PRIV_SET_SNAPLEN, /* set the snaplength */ PRIV_SET_SNAPLEN, /* set the snaplength */
PRIV_MOVE_LOG, /* move logfile away */
PRIV_OPEN_LOG /* open logfile for appending */ PRIV_OPEN_LOG /* open logfile for appending */
}; };
@ -57,10 +66,8 @@ static int may_read(int, void *, size_t);
static void must_read(int, void *, size_t); static void must_read(int, void *, size_t);
static void must_write(int, void *, size_t); static void must_write(int, void *, size_t);
static int set_snaplen(int snap); static int set_snaplen(int snap);
static int move_log(const char *name);
/* bpf filter expression common to parent and child */
extern char *filter;
extern char *errbuf;
extern char *filename; extern char *filename;
extern pcap_t *hpcap; extern pcap_t *hpcap;
@ -102,16 +109,12 @@ priv_init(void)
err(1, "unable to chdir"); err(1, "unable to chdir");
gidset[0] = pw->pw_gid; gidset[0] = pw->pw_gid;
if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
err(1, "setresgid() failed");
if (setgroups(1, gidset) == -1) if (setgroups(1, gidset) == -1)
err(1, "setgroups() failed"); err(1, "setgroups() failed");
if (setegid(pw->pw_gid) == -1) if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
err(1, "setegid() failed"); err(1, "setresuid() 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]); close(socks[0]);
priv_fd = socks[1]; priv_fd = socks[1];
return 0; return 0;
@ -165,6 +168,13 @@ priv_init(void)
close(fd); close(fd);
break; break;
case PRIV_MOVE_LOG:
logmsg(LOG_DEBUG,
"[priv]: msg PRIV_MOVE_LOG received");
ret = move_log(filename);
must_write(socks[0], &ret, sizeof(int));
break;
default: default:
logmsg(LOG_ERR, "[priv]: unknown command %d", cmd); logmsg(LOG_ERR, "[priv]: unknown command %d", cmd);
_exit(1); _exit(1);
@ -188,6 +198,47 @@ set_snaplen(int snap)
return 0; return 0;
} }
static int
move_log(const char *name)
{
char ren[PATH_MAX];
int len;
for (;;) {
int fd;
len = snprintf(ren, sizeof(ren), "%s.bad.%08x",
name, arc4random());
if (len >= sizeof(ren)) {
logmsg(LOG_ERR, "[priv] new name too long");
return (1);
}
/* lock destinanion */
fd = open(ren, O_CREAT|O_EXCL, 0);
if (fd >= 0) {
close(fd);
break;
}
/* if file exists, try another name */
if (errno != EEXIST && errno != EINTR) {
logmsg(LOG_ERR, "[priv] failed to create new name: %s",
strerror(errno));
return (1);
}
}
if (rename(name, ren)) {
logmsg(LOG_ERR, "[priv] failed to rename %s to %s: %s",
name, ren, strerror(errno));
return (1);
}
logmsg(LOG_NOTICE,
"[priv]: log file %s moved to %s", name, ren);
return (0);
}
/* /*
* send the snaplength to privileged process * send the snaplength to privileged process
@ -229,6 +280,21 @@ priv_open_log(void)
return (fd); return (fd);
} }
/* Move-away and reopen log-file */
int
priv_move_log(void)
{
int cmd, ret;
if (priv_fd < 0)
errx(1, "%s: called from privileged portion\n", __func__);
cmd = PRIV_MOVE_LOG;
must_write(priv_fd, &cmd, sizeof(int));
must_read(priv_fd, &ret, sizeof(int));
return (ret);
}
/* If priv parent gets a TERM or HUP, pass it through to child instead */ /* If priv parent gets a TERM or HUP, pass it through to child instead */
static void static void

View File

@ -1,4 +1,5 @@
/* $OpenBSD: filter.c,v 1.1 2005/12/28 19:07:07 jcs Exp $ */ /* $OpenBSD: filter.c,v 1.1 2005/12/28 19:07:07 jcs Exp $ */
/* $FreeBSD$ */
/* /*
* Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl> * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
@ -297,9 +298,15 @@ prepare_rule(u_int32_t id, int rs_num, struct sockaddr *src,
pfr.rule.quick = 1; pfr.rule.quick = 1;
pfr.rule.log = rule_log; pfr.rule.log = rule_log;
pfr.rule.keep_state = 1; pfr.rule.keep_state = 1;
#ifdef __FreeBSD__
pfr.rule.flags = (proto == IPPROTO_TCP ? TH_SYN : 0);
pfr.rule.flagset = (proto == IPPROTO_TCP ?
(TH_SYN|TH_ACK|TH_FIN|TH_RST) : 0);
#else
pfr.rule.flags = (proto == IPPROTO_TCP ? TH_SYN : NULL); pfr.rule.flags = (proto == IPPROTO_TCP ? TH_SYN : NULL);
pfr.rule.flagset = (proto == IPPROTO_TCP ? pfr.rule.flagset = (proto == IPPROTO_TCP ?
(TH_SYN|TH_ACK|TH_FIN|TH_RST) : NULL); (TH_SYN|TH_ACK|TH_FIN|TH_RST) : NULL);
#endif
pfr.rule.max_states = 1; pfr.rule.max_states = 1;
if (qname != NULL) if (qname != NULL)
strlcpy(pfr.rule.qname, qname, sizeof pfr.rule.qname); strlcpy(pfr.rule.qname, qname, sizeof pfr.rule.qname);