diff options
author | cvs2svn <cvs2svn@FreeBSD.org> | 2004-08-22 16:53:40 +0000 |
---|---|---|
committer | cvs2svn <cvs2svn@FreeBSD.org> | 2004-08-22 16:53:40 +0000 |
commit | 5897943788391c9a9b3a61efa832fe803621d5c6 (patch) | |
tree | 958169248788d69649041f20ea06ea88c8d21d54 | |
parent | 8a7574f3ced06b8564a828b8f9ffc0b905f9b7b5 (diff) |
This commit was manufactured by cvs2svn to create tagvendor/pf/3.5.001
'pf-vendor-pf_openbsd_3_5_001'.
Notes
Notes:
svn path=/vendor/pf/dist/; revision=134173
svn path=/vendor/pf/3.5.001/; revision=134174; tag=vendor/pf/3.5.001
-rw-r--r-- | contrib/pf/authpf/authpf.8 | 495 | ||||
-rw-r--r-- | contrib/pf/authpf/authpf.c | 911 | ||||
-rw-r--r-- | contrib/pf/authpf/pathnames.h | 37 | ||||
-rw-r--r-- | contrib/pf/ftp-proxy/ftp-proxy.8 | 274 | ||||
-rw-r--r-- | contrib/pf/ftp-proxy/ftp-proxy.c | 1329 | ||||
-rw-r--r-- | contrib/pf/ftp-proxy/getline.c | 259 | ||||
-rw-r--r-- | contrib/pf/ftp-proxy/util.c | 301 | ||||
-rw-r--r-- | contrib/pf/ftp-proxy/util.h | 68 | ||||
-rw-r--r-- | contrib/pf/man/pf.4 | 837 | ||||
-rw-r--r-- | contrib/pf/man/pf.conf.5 | 2632 | ||||
-rw-r--r-- | contrib/pf/man/pf.os.5 | 242 | ||||
-rw-r--r-- | contrib/pf/man/pflog.4 | 89 | ||||
-rw-r--r-- | contrib/pf/man/pfsync.4 | 226 | ||||
-rw-r--r-- | contrib/pf/pflogd/pflogd.8 | 192 | ||||
-rw-r--r-- | contrib/pf/pflogd/pflogd.c | 643 | ||||
-rw-r--r-- | contrib/pf/pflogd/pflogd.h | 47 | ||||
-rw-r--r-- | contrib/pf/pflogd/pidfile.c | 121 | ||||
-rw-r--r-- | contrib/pf/pflogd/pidfile.h | 1 | ||||
-rw-r--r-- | contrib/pf/pflogd/privsep.c | 305 | ||||
-rw-r--r-- | contrib/pf/pflogd/privsep_fdpass.c | 120 |
20 files changed, 0 insertions, 9129 deletions
diff --git a/contrib/pf/authpf/authpf.8 b/contrib/pf/authpf/authpf.8 deleted file mode 100644 index b6977da2fce9..000000000000 --- a/contrib/pf/authpf/authpf.8 +++ /dev/null @@ -1,495 +0,0 @@ -.\" $OpenBSD: authpf.8,v 1.31 2003/12/10 04:10:37 beck Exp $ -.\" -.\" Copyright (c) 2002 Bob Beck (beck@openbsd.org>. All rights reserved. -.\" -.\" 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. 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 -.\" 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 AUTHOR 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. -.\" -.Dd January 10, 2002 -.Dt AUTHPF 8 -.Os -.Sh NAME -.Nm authpf -.Nd authenticating gateway user shell -.Sh SYNOPSIS -.Nm authpf -.Sh DESCRIPTION -.Nm -is a user shell for authenticating gateways. -It is used to change -.Xr pf 4 -rules when a user authenticates and starts a session with -.Xr sshd 8 -and to undo these changes when the user's session exits. -It is designed for changing filter and translation rules for an individual -source IP address as long as a user maintains an active -.Xr ssh 1 -session. -Typical use would be for a gateway that authenticates users before -allowing them Internet use, or a gateway that allows different users into -different places. -.Nm -logs the successful start and end of a session to -.Xr syslogd 8 . -This, combined with properly set up filter rules and secure switches, -can be used to ensure users are held accountable for their network traffic. -.Pp -.Nm -can add filter and translation rules using the syntax described in -.Xr pf.conf 5 . -.Nm -requires that the -.Xr pf 4 -system be enabled before use. -.Pp -.Nm -is meant to be used with users who can connect via -.Xr ssh 1 -only. -On startup, -.Nm -retrieves the client's connecting IP address via the -.Ev SSH_CLIENT -environment variable and, after performing additional access checks, -reads a template file to determine what filter and translation rules -(if any) to add. -On session exit the same rules that were added at startup are removed. -.Pp -Each -.Nm -process stores its rules in a separate ruleset inside a -.Xr pf 4 -.Pa anchor -shared by all -.Nm -processes. -By default, the -.Pa anchor -name "authpf" is used, and the ruleset names equal the username and PID of the -.Nm -processes as "username(pid)". -The following rules need to be added to the main ruleset -.Pa /etc/pf.conf -in order to cause evaluation of any -.Nm -rules: -.Bd -literal -offset indent -nat-anchor authpf -rdr-anchor authpf -binat-anchor authpf -anchor authpf -.Ed -.Sh FILTER AND TRANSLATION RULES -Filter and translation rules for -.Nm -use the same format described in -.Xr pf.conf 5 . -The only difference is that these rules may (and probably should) use -the macro -.Em user_ip , -which is assigned the connecting IP address whenever -.Nm -is run. -Additionally, the macro -.Em user_id -is assigned the user name. -.Pp -Filter and nat rules will first be searched for in -.Pa /etc/authpf/users/$USER/ -and then in -.Pa /etc/authpf/ . -Per-user rules from the -.Pa /etc/authpf/users/$USER/ -directory are intended to be used when non-default rules -are needed on an individual user basis. -It is important to ensure that a user can not write or change -these configuration files. -.Pp -Filter and translation rules are loaded from the file -.Pa /etc/authpf/users/$USER/authpf.rules . -If this file does not exist the file -.Pa /etc/authpf/authpf.rules -is used. -The -.Pa authpf.rules -file must exist in one of the above locations for -.Nm -to run. -.Pp -Translation rules are also loaded from this file. -The use of translation rules in an -.Pa authpf.rules -file is optional. -.Sh CONFIGURATION -Options are controlled by the -.Pa /etc/authpf/authpf.conf -file. -If the file is empty, defaults are used for all -configuration options. -The file consists of pairs of the form -.Li name=value , -one per line. -Currently, the allowed values are as follows: -.Bl -tag -width Ds -.It anchor=name -Use the specified -.Pa anchor -name instead of "authpf". -.El -.Sh USER MESSAGES -On successful invocation, -.Nm -displays a message telling the user he or she has been authenticated. -It will additionally display the contents of the file -.Pa /etc/authpf/authpf.message -if the file exists and is readable. -.Pp -There exist two methods for providing additional granularity to the control -offered by -.Nm -- it is possible to set the gateway to explicitly allow users who have -authenticated to -.Xr ssh 1 -and deny access to only a few troublesome individuals. -This is done by creating a file with the banned user's login name as the -filename in -.Pa /etc/authpf/banned/ . -The contents of this file will be displayed to a banned user, thus providing -a method for informing the user that they have been banned, and where they can -go and how to get there if they want to have their service restored. -This is the default behaviour. -.Pp -It is also possible to configure -.Nm -to only allow specific users access. -This is done by listing their login names, one per line, in -.Pa /etc/authpf/authpf.allow . -If "*" is found on a line, then all usernames match. -If -.Nm -is unable to verify the user's permission to use the gateway, it will -print a brief message and die. -It should be noted that a ban takes precedence over an allow. -.Pp -On failure, messages will be logged to -.Xr syslogd 8 -for the system administrator. -The user does not see these, but will be told the system is unavailable due to -technical difficulties. -The contents of the file -.Pa /etc/authpf/authpf.problem -will also be displayed if the file exists and is readable. -.Sh CONFIGURATION ISSUES -.Nm -maintains the changed filter rules as long as the user maintains an -active session. -It is important to remember however, that the existence -of this session means the user is authenticated. -Because of this, it is important to configure -.Xr sshd 8 -to ensure the security of the session, and to ensure that the network -through which users connect is secure. -.Xr sshd 8 -should be configured to use the -.Ar ClientAliveInterval -and -.Ar ClientAliveCountMax -parameters to ensure that a ssh session is terminated quickly if -it becomes unresponsive, or if arp or address spoofing is used to -hijack the session. -Note that TCP keepalives are not sufficient for -this, since they are not secure. -.Pp -.Nm -will remove statetable entries that were created during a user's -session. -This ensures that there will be no unauthenticated traffic -allowed to pass after the controlling -.Xr ssh 1 -session has been closed. -.Pp -.Nm -is designed for gateway machines which typically do not have regular -(non-administrative) users using the machine. -An administrator must remember that -.Nm -can be used to modify the filter rules through the environment in -which it is run, and as such could be used to modify the filter rules -(based on the contents of the configuration files) by regular -users. -In the case where a machine has regular users using it, as well -as users with -.Nm -as their shell, the regular users should be prevented from running -.Nm -by using the -.Pa /etc/authpf/authpf.allow -or -.Pa /etc/authpf/banned/ -facilities. -.Pp -.Nm -modifies the packet filter and address translation rules, and because -of this it needs to be configured carefully. -.Nm -will not run and will exit silently if the -.Pa /etc/authpf/authpf.conf -file does not exist. -After considering the effect -.Nm -may have on the main packet filter rules, the system administrator may -enable -.Nm -by creating an appropriate -.Pa /etc/authpf/authpf.conf -file. -.Sh EXAMPLES -.Sy Control Files -\- To illustrate the user-specific access control -mechanisms, let us consider a typical user named bob. -Normally, as long as bob can authenticate himself, the -.Nm -program will load the appropriate rules. -Enter the -.Pa /etc/authpf/banned/ -directory. -If bob has somehow fallen from grace in the eyes of the -powers-that-be, they can prohibit him from using the gateway by creating -the file -.Pa /etc/authpf/banned/bob -containing a message about why he has been banned from using the network. -Once bob has done suitable penance, his access may be restored by moving or -removing the file -.Pa /etc/authpf/banned/bob . -.Pp -Now consider a workgroup containing alice, bob, carol and dave. -They have a -wireless network which they would like to protect from unauthorized use. -To accomplish this, they create the file -.Pa /etc/authpf/authpf.allow -which lists their login ids, one per line. -At this point, even if eve could authenticate to -.Xr sshd 8 , -she would not be allowed to use the gateway. -Adding and removing users from -the work group is a simple matter of maintaining a list of allowed userids. -If bob once again manages to annoy the powers-that-be, they can ban him from -using the gateway by creating the familiar -.Pa /etc/authpf/banned/bob -file. -Though bob is listed in the allow file, he is prevented from using -this gateway due to the existence of a ban file. -.Pp -.Sy Distributed Authentication -\- It is often desirable to interface with a -distributed password system rather than forcing the sysadmins to keep a large -number of local password files in sync. -The -.Xr login.conf 5 -mechanism in -.Ox -can be used to fork the right shell. -To make that happen, -.Xr login.conf 5 -should have entries that look something like this: -.Bd -literal -offset indent -shell-default:shell=/bin/csh - -default:\e - ... - :shell=/usr/sbin/authpf - -daemon:\e - ... - :shell=/bin/csh:\e - :tc=default: - -staff:\e - ... - :shell=/bin/csh:\e - :tc=default: -.Ed -.Pp -Using a default password file, all users will get -.Nm -as their shell except for root who will get -.Pa /bin/csh . -.Pp -.Sy SSH Configuration -\- As stated earlier, -.Xr sshd 8 -must be properly configured to detect and defeat network attacks. -To that end, the following options should be added to -.Xr sshd_config 5 : -.Bd -literal -offset indent -Protocol 2 -ClientAliveInterval 15 -ClientAliveCountMax 3 -.Ed -.Pp -This ensures that unresponsive or spoofed sessions are terminated within a -minute, since a hijacker should not be able to spoof ssh keepalive messages. -.Pp -.Sy Banners -\- Once authenticated, the user is shown the contents of -.Pa /etc/authpf/authpf.message . -This message may be a screen-full of the appropriate use policy, the contents -of -.Pa /etc/motd -or something as simple as the following: -.Bd -literal -offset indent -This means you will be held accountable by the powers that be -for traffic originating from your machine, so please play nice. -.Ed -.Pp -To tell the user where to go when the system is broken, -.Pa /etc/authpf/authpf.problem -could contain something like this: -.Bd -literal -offset indent -Sorry, there appears to be some system problem. To report this -problem so we can fix it, please phone 1-900-314-1597 or send -an email to remove@bulkmailerz.net. -.Ed -.Pp -.Sy Packet Filter Rules -\- In areas where this gateway is used to protect a -wireless network (a hub with several hundred ports), the default rule set as -well as the per-user rules should probably allow very few things beyond -encrypted protocols like -.Xr ssh 1 , -.Xr ssl 8 , -or -.Xr ipsec 4 . -On a securely switched network, with plug-in jacks for visitors who are -given authentication accounts, you might want to allow out everything. -In this context, a secure switch is one that tries to prevent address table -overflow attacks. -.Pp -Example -.Pa /etc/pf.conf : -.Bd -literal -# by default we allow internal clients to talk to us using -# ssh and use us as a dns server. -internal_if="fxp1" -gateway_addr="10.0.1.1" -nat-anchor authpf -rdr-anchor authpf -binat-anchor authpf -block in on $internal_if from any to any -pass in quick on $internal_if proto tcp from any to $gateway_addr \e - port = ssh -pass in quick on $internal_if proto udp from any to $gateway_addr \e - port = domain -anchor authpf -.Ed -.Pp -.Sy For a switched, wired net -\- This example -.Pa /etc/authpf/authpf.rules -makes no real restrictions; it turns the IP address on and off, logging -TCP connections. -.Bd -literal -external_if = "xl0" -internal_if = "fxp0" - -pass in log quick on $internal_if proto tcp from $user_ip to any \e - keep state -pass in quick on $internal_if from $user_ip to any -.Ed -.Pp -.Sy For a wireless or shared net -\- This example -.Pa /etc/authpf/authpf.rules -could be used for an insecure network (such as a public wireless network) where -we might need to be a bit more restrictive. -.Bd -literal -internal_if="fxp1" -ipsec_gw="10.2.3.4" - -# rdr ftp for proxying by ftp-proxy(8) -rdr on $internal_if proto tcp from $user_ip to any port 21 \e - -> 127.0.0.1 port 8081 - -# allow out ftp, ssh, www and https only, and allow user to negotiate -# ipsec with the ipsec server. -pass in log quick on $internal_if proto tcp from $user_ip to any \e - port { 21, 22, 80, 443 } flags S/SA -pass in quick on $internal_if proto tcp from $user_ip to any \e - port { 21, 22, 80, 443 } -pass in quick proto udp from $user_ip to $ipsec_gw port = isakmp \e - keep state -pass in quick proto esp from $user_ip to $ipsec_gw -.Ed -.Pp -.Sy Dealing with NAT -\- The following -.Pa /etc/authpf/authpf.rules -shows how to deal with NAT, using tags: -.Bd -literal -ext_if = "fxp1" -ext_addr = 129.128.11.10 -int_if = "fxp0" -# nat and tag connections... -nat on $ext_if from $user_ip to any tag $user_ip -> $ext_addr -pass in quick on $int_if from $user_ip to any -pass out log quick on $ext_if tagged $user_ip keep state -.Ed -.Pp -With the above rules added by -.Nm , -outbound connections corresponding to each users NAT'ed connections -will be logged as in the example below, where the user may be identified -from the ruleset name. -.Bd -literal -# tcpdump -n -e -ttt -i pflog0 -Oct 31 19:42:30.296553 rule 0.bbeck(20267).1/0(match): pass out on fxp1: \e -129.128.11.10.60539 > 198.137.240.92.22: S 2131494121:2131494121(0) win \e -16384 <mss 1460,nop,nop,sackOK> (DF) -.Ed -.Sh FILES -.Bl -tag -width "/etc/authpf/authpf.conf" -compact -.It Pa /etc/authpf/authpf.conf -.It Pa /etc/authpf/authpf.allow -.It Pa /etc/authpf/authpf.rules -.It Pa /etc/authpf/authpf.message -.It Pa /etc/authpf/authpf.problem -.El -.Sh SEE ALSO -.Xr pf 4 , -.Xr pf.conf 5 , -.Xr ftp-proxy 8 -.Sh HISTORY -The -.Nm -program first appeared in -.Ox 3.1 . -.Sh BUGS -Configuration issues are tricky. -The authenticating -.Xr ssh 1 -connection may be secured, but if the network is not secured the user may -expose insecure protocols to attackers on the same network, or enable other -attackers on the network to pretend to be the user by spoofing their IP -address. -.Pp -.Nm -is not designed to prevent users from denying service to other users. diff --git a/contrib/pf/authpf/authpf.c b/contrib/pf/authpf/authpf.c deleted file mode 100644 index 515cf8edea2b..000000000000 --- a/contrib/pf/authpf/authpf.c +++ /dev/null @@ -1,911 +0,0 @@ -/* $OpenBSD: authpf.c,v 1.75 2004/01/29 01:55:10 deraadt Exp $ */ - -/* - * Copyright (C) 1998 - 2002 Bob Beck (beck@openbsd.org). - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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/file.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/time.h> - -#include <net/if.h> -#include <net/pfvar.h> -#include <arpa/inet.h> - -#include <err.h> -#include <errno.h> -#include <pwd.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> - -#include <pfctl_parser.h> -#include <pfctl.h> - -#include "pathnames.h" - -extern int symset(const char *, const char *, int); - -static int read_config(FILE *); -static void print_message(char *); -static int allowed_luser(char *); -static int check_luser(char *, char *); -static int remove_stale_rulesets(void); -static int change_filter(int, const char *, const char *); -static void authpf_kill_states(void); - -int dev; /* pf device */ -char anchorname[PF_ANCHOR_NAME_SIZE] = "authpf"; -char rulesetname[PF_RULESET_NAME_SIZE]; - -FILE *pidfp; -char *infile; /* file name printed by yyerror() in parse.y */ -char luser[MAXLOGNAME]; /* username */ -char ipsrc[256]; /* ip as a string */ -char pidfile[MAXPATHLEN]; /* we save pid in this file. */ - -struct timeval Tstart, Tend; /* start and end times of session */ - -volatile sig_atomic_t want_death; -static void need_death(int signo); -static __dead void do_death(int); - -/* - * User shell for authenticating gateways. Sole purpose is to allow - * a user to ssh to a gateway, and have the gateway modify packet - * filters to allow access, then remove access when the user finishes - * up. Meant to be used only from ssh(1) connections. - */ -int -main(int argc, char *argv[]) -{ - int lockcnt = 0, n, pidfd; - FILE *config; - struct in_addr ina; - struct passwd *pw; - char *cp; - uid_t uid; - - config = fopen(PATH_CONFFILE, "r"); - - if ((cp = getenv("SSH_TTY")) == NULL) { - syslog(LOG_ERR, "non-interactive session connection for authpf"); - exit(1); - } - - if ((cp = getenv("SSH_CLIENT")) == NULL) { - syslog(LOG_ERR, "cannot determine connection source"); - exit(1); - } - - if (strlcpy(ipsrc, cp, sizeof(ipsrc)) >= sizeof(ipsrc)) { - syslog(LOG_ERR, "SSH_CLIENT variable too long"); - exit(1); - } - cp = strchr(ipsrc, ' '); - if (!cp) { - syslog(LOG_ERR, "corrupt SSH_CLIENT variable %s", ipsrc); - exit(1); - } - *cp = '\0'; - if (inet_pton(AF_INET, ipsrc, &ina) != 1) { - syslog(LOG_ERR, - "cannot determine IP from SSH_CLIENT %s", ipsrc); - exit(1); - } - /* open the pf device */ - dev = open(PATH_DEVFILE, O_RDWR); - if (dev == -1) { - syslog(LOG_ERR, "cannot open packet filter device (%m)"); - goto die; - } - - uid = getuid(); - pw = getpwuid(uid); - if (pw == NULL) { - syslog(LOG_ERR, "cannot find user for uid %u", uid); - goto die; - } - if (strcmp(pw->pw_shell, PATH_AUTHPF_SHELL)) { - syslog(LOG_ERR, "wrong shell for user %s, uid %u", - pw->pw_name, pw->pw_uid); - goto die; - } - - /* - * Paranoia, but this data _does_ come from outside authpf, and - * truncation would be bad. - */ - if (strlcpy(luser, pw->pw_name, sizeof(luser)) >= sizeof(luser)) { - syslog(LOG_ERR, "username too long: %s", pw->pw_name); - goto die; - } - - if ((n = snprintf(rulesetname, sizeof(rulesetname), "%s(%ld)", - luser, (long)getpid())) < 0 || n >= sizeof(rulesetname)) { - syslog(LOG_INFO, "%s(%ld) too large, ruleset name will be %ld", - luser, (long)getpid(), (long)getpid()); - if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld", - (long)getpid())) < 0 || n >= sizeof(rulesetname)) { - syslog(LOG_ERR, "pid too large for ruleset name"); - goto die; - } - } - - - /* Make our entry in /var/authpf as /var/authpf/ipaddr */ - n = snprintf(pidfile, sizeof(pidfile), "%s/%s", PATH_PIDFILE, ipsrc); - if (n < 0 || (u_int)n >= sizeof(pidfile)) { - syslog(LOG_ERR, "path to pidfile too long"); - goto die; - } - - /* - * If someone else is already using this ip, then this person - * wants to switch users - so kill the old process and exit - * as well. - * - * Note, we could print a message and tell them to log out, but the - * usual case of this is that someone has left themselves logged in, - * with the authenticated connection iconized and someone else walks - * up to use and automatically logs in before using. If this just - * gets rid of the old one silently, the new user never knows they - * could have used someone else's old authentication. If we - * tell them to log out before switching users it is an invitation - * for abuse. - */ - - do { - int save_errno, otherpid = -1; - char otherluser[MAXLOGNAME]; - - if ((pidfd = open(pidfile, O_RDWR|O_CREAT, 0644)) == -1 || - (pidfp = fdopen(pidfd, "r+")) == NULL) { - if (pidfd != -1) - close(pidfd); - syslog(LOG_ERR, "cannot open or create %s: %s", pidfile, - strerror(errno)); - goto die; - } - - if (flock(fileno(pidfp), LOCK_EX|LOCK_NB) == 0) - break; - save_errno = errno; - - /* Mark our pid, and username to our file. */ - - rewind(pidfp); - /* 31 == MAXLOGNAME - 1 */ - if (fscanf(pidfp, "%d\n%31s\n", &otherpid, otherluser) != 2) - otherpid = -1; - syslog(LOG_DEBUG, "tried to lock %s, in use by pid %d: %s", - pidfile, otherpid, strerror(save_errno)); - - if (otherpid > 0) { - syslog(LOG_INFO, - "killing prior auth (pid %d) of %s by user %s", - otherpid, ipsrc, otherluser); - if (kill((pid_t) otherpid, SIGTERM) == -1) { - syslog(LOG_INFO, - "could not kill process %d: (%m)", - otherpid); - } - } - - /* - * we try to kill the previous process and acquire the lock - * for 10 seconds, trying once a second. if we can't after - * 10 attempts we log an error and give up - */ - if (++lockcnt > 10) { - syslog(LOG_ERR, "cannot kill previous authpf (pid %d)", - otherpid); - goto dogdeath; - } - sleep(1); - - /* re-open, and try again. The previous authpf process - * we killed above should unlink the file and release - * it's lock, giving us a chance to get it now - */ - fclose(pidfp); - } while (1); - - /* revoke privs */ - seteuid(getuid()); - setuid(getuid()); - - openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON); - - if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) { - syslog(LOG_INFO, "user %s prohibited", luser); - do_death(0); - } - - if (config == NULL || read_config(config)) { - syslog(LOG_INFO, "bad or nonexistent %s", PATH_CONFFILE); - do_death(0); - } - - if (remove_stale_rulesets()) { - syslog(LOG_INFO, "error removing stale rulesets"); - do_death(0); - } - - /* We appear to be making headway, so actually mark our pid */ - rewind(pidfp); - fprintf(pidfp, "%ld\n%s\n", (long)getpid(), luser); - fflush(pidfp); - (void) ftruncate(fileno(pidfp), ftell(pidfp)); - - if (change_filter(1, luser, ipsrc) == -1) { - printf("Unable to modify filters\r\n"); - do_death(0); - } - - signal(SIGTERM, need_death); - signal(SIGINT, need_death); - signal(SIGALRM, need_death); - signal(SIGPIPE, need_death); - signal(SIGHUP, need_death); - signal(SIGSTOP, need_death); - signal(SIGTSTP, need_death); - while (1) { - printf("\r\nHello %s, ", luser); - printf("You are authenticated from host \"%s\"\r\n", ipsrc); - setproctitle("%s@%s", luser, ipsrc); - print_message(PATH_MESSAGE); - while (1) { - sleep(10); - if (want_death) - do_death(1); - } - } - - /* NOTREACHED */ -dogdeath: - printf("\r\n\r\nSorry, this service is currently unavailable due to "); - printf("technical difficulties\r\n\r\n"); - print_message(PATH_PROBLEM); - printf("\r\nYour authentication process (pid %ld) was unable to run\n", - (long)getpid()); - sleep(180); /* them lusers read reaaaaal slow */ -die: - do_death(0); -} - -/* - * reads config file in PATH_CONFFILE to set optional behaviours up - */ -static int -read_config(FILE *f) -{ - char buf[1024]; - int i = 0; - - do { - char **ap; - char *pair[4], *cp, *tp; - int len; - - if (fgets(buf, sizeof(buf), f) == NULL) { - fclose(f); - return (0); - } - i++; - len = strlen(buf); - if (buf[len - 1] != '\n' && !feof(f)) { - syslog(LOG_ERR, "line %d too long in %s", i, - PATH_CONFFILE); - return (1); - } - buf[len - 1] = '\0'; - - for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) - ; /* nothing */ - - if (!*cp || *cp == '#' || *cp == '\n') - continue; - - for (ap = pair; ap < &pair[3] && - (*ap = strsep(&cp, "=")) != NULL; ) { - if (**ap != '\0') - ap++; - } - if (ap != &pair[2]) - goto parse_error; - - tp = pair[1] + strlen(pair[1]); - while ((*tp == ' ' || *tp == '\t') && tp >= pair[1]) - *tp-- = '\0'; - - if (strcasecmp(pair[0], "anchor") == 0) { - if (!pair[1][0] || strlcpy(anchorname, pair[1], - sizeof(anchorname)) >= sizeof(anchorname)) - goto parse_error; - } - } while (!feof(f) && !ferror(f)); - fclose(f); - return (0); - -parse_error: - fclose(f); - syslog(LOG_ERR, "parse error, line %d of %s", i, PATH_CONFFILE); - return (1); -} - - -/* - * splatter a file to stdout - max line length of 1024, - * used for spitting message files at users to tell them - * they've been bad or we're unavailable. - */ -static void -print_message(char *filename) -{ - char buf[1024]; - FILE *f; - - if ((f = fopen(filename, "r")) == NULL) - return; /* fail silently, we don't care if it isn't there */ - - do { - if (fgets(buf, sizeof(buf), f) == NULL) { - fflush(stdout); - fclose(f); - return; - } - } while (fputs(buf, stdout) != EOF && !feof(f)); - fflush(stdout); - fclose(f); -} - -/* - * allowed_luser checks to see if user "luser" is allowed to - * use this gateway by virtue of being listed in an allowed - * users file, namely /etc/authpf/authpf.allow . - * - * If /etc/authpf/authpf.allow does not exist, then we assume that - * all users who are allowed in by sshd(8) are permitted to - * use this gateway. If /etc/authpf/authpf.allow does exist, then a - * user must be listed if the connection is to continue, else - * the session terminates in the same manner as being banned. - */ -static int -allowed_luser(char *luser) -{ - char *buf, *lbuf; - int matched; - size_t len; - FILE *f; - - if ((f = fopen(PATH_ALLOWFILE, "r")) == NULL) { - if (errno == ENOENT) { - /* - * allowfile doesn't exist, thus this gateway - * isn't restricted to certain users... - */ - return (1); - } - - /* - * luser may in fact be allowed, but we can't open - * the file even though it's there. probably a config - * problem. - */ - syslog(LOG_ERR, "cannot open allowed users file %s (%s)", - PATH_ALLOWFILE, strerror(errno)); - return (0); - } else { - /* - * /etc/authpf/authpf.allow exists, thus we do a linear - * search to see if they are allowed. - * also, if username "*" exists, then this is a - * "public" gateway, such as it is, so let - * everyone use it. - */ - lbuf = NULL; - while ((buf = fgetln(f, &len))) { - if (buf[len - 1] == '\n') - buf[len - 1] = '\0'; - else { - if ((lbuf = (char *)malloc(len + 1)) == NULL) - err(1, NULL); - memcpy(lbuf, buf, len); - lbuf[len] = '\0'; - buf = lbuf; - } - - matched = strcmp(luser, buf) == 0 || strcmp("*", buf) == 0; - - if (lbuf != NULL) { - free(lbuf); - lbuf = NULL; - } - - if (matched) - return (1); /* matched an allowed username */ - } - syslog(LOG_INFO, "denied access to %s: not listed in %s", - luser, PATH_ALLOWFILE); - - /* reuse buf */ - buf = "\n\nSorry, you are not allowed to use this facility!\n"; - fputs(buf, stdout); - } - fflush(stdout); - return (0); -} - -/* - * check_luser checks to see if user "luser" has been banned - * from using us by virtue of having an file of the same name - * in the "luserdir" directory. - * - * If the user has been banned, we copy the contents of the file - * to the user's screen. (useful for telling the user what to - * do to get un-banned, or just to tell them they aren't - * going to be un-banned.) - */ -static int -check_luser(char *luserdir, char *luser) -{ - FILE *f; - int n; - char tmp[MAXPATHLEN]; - - n = snprintf(tmp, sizeof(tmp), "%s/%s", luserdir, luser); - if (n < 0 || (u_int)n >= sizeof(tmp)) { - syslog(LOG_ERR, "provided banned directory line too long (%s)", - luserdir); - return (0); - } - if ((f = fopen(tmp, "r")) == NULL) { - if (errno == ENOENT) { - /* - * file or dir doesn't exist, so therefore - * this luser isn't banned.. all is well - */ - return (1); - } else { - /* - * luser may in fact be banned, but we can't open the - * file even though it's there. probably a config - * problem. - */ - syslog(LOG_ERR, "cannot open banned file %s (%s)", - tmp, strerror(errno)); - return (0); - } - } else { - /* - * luser is banned - spit the file at them to - * tell what they can do and where they can go. - */ - syslog(LOG_INFO, "denied access to %s: %s exists", - luser, tmp); - - /* reuse tmp */ - strlcpy(tmp, "\n\n-**- Sorry, you have been banned! -**-\n\n", - sizeof(tmp)); - while (fputs(tmp, stdout) != EOF && !feof(f)) { - if (fgets(tmp, sizeof(tmp), f) == NULL) { - fflush(stdout); - return (0); - } - } - } - fflush(stdout); - return (0); -} - -/* - * Search for rulesets left by other authpf processes (either because they - * died ungracefully or were terminated) and remove them. - */ -static int -remove_stale_rulesets(void) -{ - struct pfioc_ruleset prs; - const int action[PF_RULESET_MAX] = { PF_SCRUB, - PF_PASS, PF_NAT, PF_BINAT, PF_RDR }; - u_int32_t nr, mnr; - - memset(&prs, 0, sizeof(prs)); - strlcpy(prs.anchor, anchorname, sizeof(prs.anchor)); - if (ioctl(dev, DIOCGETRULESETS, &prs)) { - if (errno == EINVAL) - return (0); - else - return (1); - } - - mnr = prs.nr; - nr = 0; - while (nr < mnr) { - char *s, *t; - pid_t pid; - - prs.nr = nr; - if (ioctl(dev, DIOCGETRULESET, &prs)) - return (1); - errno = 0; - if ((t = strchr(prs.name, '(')) == NULL) - t = prs.name; - else - t++; - pid = strtoul(t, &s, 10); - if (!prs.name[0] || errno || - (*s && (t == prs.name || *s != ')'))) - return (1); - if (kill(pid, 0) && errno != EPERM) { - int i; - - for (i = 0; i < PF_RULESET_MAX; ++i) { - struct pfioc_rule pr; - - memset(&pr, 0, sizeof(pr)); - memcpy(pr.anchor, prs.anchor, sizeof(pr.anchor)); - memcpy(pr.ruleset, prs.name, sizeof(pr.ruleset)); - pr.rule.action = action[i]; - if ((ioctl(dev, DIOCBEGINRULES, &pr) || - ioctl(dev, DIOCCOMMITRULES, &pr)) && - errno != EINVAL) - return (1); - } - mnr--; - } else - nr++; - } - return (0); -} - -/* - * Add/remove filter entries for user "luser" from ip "ipsrc" - */ -static int -change_filter(int add, const char *luser, const char *ipsrc) -{ - char fn[MAXPATHLEN]; - FILE *f = NULL; - struct pfctl pf; - struct pfr_buffer t; - int i; - - if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) { - syslog(LOG_ERR, "invalid luser/ipsrc"); - goto error; - } - - if (add) { - if ((i = snprintf(fn, sizeof(fn), "%s/%s/authpf.rules", - PATH_USER_DIR, luser)) < 0 || i >= sizeof(fn)) { - syslog(LOG_ERR, "user rule path too long"); - goto error; - } - if ((f = fopen(fn, "r")) == NULL && errno != ENOENT) { - syslog(LOG_ERR, "cannot open %s (%m)", fn); - goto error; - } - if (f == NULL) { - if (strlcpy(fn, PATH_PFRULES, sizeof(fn)) >= - sizeof(fn)) { - syslog(LOG_ERR, "rule path too long"); - goto error; - } - if ((f = fopen(fn, "r")) == NULL) { - syslog(LOG_ERR, "cannot open %s (%m)", fn); - goto error; - } - } - } - - if (pfctl_load_fingerprints(dev, 0)) { - syslog(LOG_ERR, "unable to load kernel's OS fingerprints"); - goto error; - } - bzero(&t, sizeof(t)); - t.pfrb_type = PFRB_TRANS; - memset(&pf, 0, sizeof(pf)); - for (i = 0; i < PF_RULESET_MAX; ++i) { - if (pfctl_add_trans(&t, i, anchorname, rulesetname)) { - syslog(LOG_ERR, "pfctl_add_trans %m"); - goto error; - } - } - if (pfctl_trans(dev, &t, DIOCXBEGIN, 0)) { - syslog(LOG_ERR, "DIOCXBEGIN (%s) %m", add?"add":"remove"); - goto error; - } - - if (add) { - if (symset("user_ip", ipsrc, 0) || - symset("user_id", luser, 0)) { - syslog(LOG_ERR, "symset"); - goto error; - } - - pf.dev = dev; - pf.trans = &t; - pf.anchor = anchorname; - pf.ruleset = rulesetname; - - infile = fn; - if (parse_rules(f, &pf) < 0) { - syslog(LOG_ERR, "syntax error in rule file: " - "authpf rules not loaded"); - goto error; - } - - infile = NULL; - fclose(f); - f = NULL; - } - - if (pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) { - syslog(LOG_ERR, "DIOCXCOMMIT (%s) %m", add?"add":"remove"); - goto error; - } - - if (add) { - gettimeofday(&Tstart, NULL); - syslog(LOG_INFO, "allowing %s, user %s", ipsrc, luser); - } else { - gettimeofday(&Tend, NULL); - syslog(LOG_INFO, "removed %s, user %s - duration %ld seconds", - ipsrc, luser, Tend.tv_sec - Tstart.tv_sec); - } - return (0); - -error: - if (f != NULL) - fclose(f); - if (pfctl_trans(dev, &t, DIOCXROLLBACK, 0)) - syslog(LOG_ERR, "DIOCXROLLBACK (%s) %m", add?"add":"remove"); - - infile = NULL; - return (-1); -} - -/* - * This is to kill off states that would otherwise be left behind stateful - * rules. This means we don't need to allow in more traffic than we really - * want to, since we don't have to worry about any luser sessions lasting - * longer than their ssh session. This function is based on - * pfctl_kill_states from pfctl. - */ -static void -authpf_kill_states(void) -{ - struct pfioc_state_kill psk; - struct in_addr target; - - memset(&psk, 0, sizeof(psk)); - psk.psk_af = AF_INET; - - inet_pton(AF_INET, ipsrc, &target); - - /* Kill all states from ipsrc */ - psk.psk_src.addr.v.a.addr.v4 = target; - memset(&psk.psk_src.addr.v.a.mask, 0xff, - sizeof(psk.psk_src.addr.v.a.mask)); - if (ioctl(dev, DIOCKILLSTATES, &psk)) - syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)"); - - /* Kill all states to ipsrc */ - psk.psk_af = AF_INET; - memset(&psk.psk_src, 0, sizeof(psk.psk_src)); - psk.psk_dst.addr.v.a.addr.v4 = target; - memset(&psk.psk_dst.addr.v.a.mask, 0xff, - sizeof(psk.psk_dst.addr.v.a.mask)); - if (ioctl(dev, DIOCKILLSTATES, &psk)) - syslog(LOG_ERR, "DIOCKILLSTATES failed (%m)"); -} - -/* signal handler that makes us go away properly */ -static void -need_death(int signo) -{ - want_death = 1; -} - -/* - * function that removes our stuff when we go away. - */ -static __dead void -do_death(int active) -{ - int ret = 0; - - if (active) { - change_filter(0, luser, ipsrc); - authpf_kill_states(); - remove_stale_rulesets(); - } - if (pidfp) - ftruncate(fileno(pidfp), 0); - if (pidfile[0]) - if (unlink(pidfile) == -1) - syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile); - exit(ret); -} - -/* - * callbacks for parse_rules(void) - */ - -int -pfctl_add_rule(struct pfctl *pf, struct pf_rule *r) -{ - u_int8_t rs_num; - struct pfioc_rule pr; - - switch (r->action) { - case PF_PASS: - case PF_DROP: - rs_num = PF_RULESET_FILTER; - break; - case PF_SCRUB: - rs_num = PF_RULESET_SCRUB; - break; - case PF_NAT: - case PF_NONAT: - rs_num = PF_RULESET_NAT; - break; - case PF_RDR: - case PF_NORDR: - rs_num = PF_RULESET_RDR; - break; - case PF_BINAT: - case PF_NOBINAT: - rs_num = PF_RULESET_BINAT; - break; - default: - syslog(LOG_ERR, "invalid rule action %d", r->action); - return (1); - } - - bzero(&pr, sizeof(pr)); - strlcpy(pr.anchor, pf->anchor, sizeof(pr.anchor)); - strlcpy(pr.ruleset, pf->ruleset, sizeof(pr.ruleset)); - if (pfctl_add_pool(pf, &r->rpool, r->af)) - return (1); - pr.ticket = pfctl_get_ticket(pf->trans, rs_num, pf->anchor, - pf->ruleset); - pr.pool_ticket = pf->paddr.ticket; - memcpy(&pr.rule, r, sizeof(pr.rule)); - if (ioctl(pf->dev, DIOCADDRULE, &pr)) { - syslog(LOG_ERR, "DIOCADDRULE %m"); - return (1); - } - pfctl_clear_pool(&r->rpool); - return (0); -} - -int -pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af) -{ - struct pf_pooladdr *pa; - - if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) { - syslog(LOG_ERR, "DIOCBEGINADDRS %m"); - return (1); - } - pf->paddr.af = af; - TAILQ_FOREACH(pa, &p->list, entries) { - memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); - if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) { - syslog(LOG_ERR, "DIOCADDADDR %m"); - return (1); - } - } - return (0); -} - -void -pfctl_clear_pool(struct pf_pool *pool) -{ - struct pf_pooladdr *pa; - - while ((pa = TAILQ_FIRST(&pool->list)) != NULL) { - TAILQ_REMOVE(&pool->list, pa, entries); - free(pa); - } -} - -int -pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) -{ - fprintf(stderr, "altq rules not supported in authpf\n"); - return (1); -} - -int -pfctl_set_optimization(struct pfctl *pf, const char *opt) -{ - fprintf(stderr, "set optimization not supported in authpf\n"); - return (1); -} - -int -pfctl_set_logif(struct pfctl *pf, char *ifname) -{ - fprintf(stderr, "set loginterface not supported in authpf\n"); - return (1); -} - -int -pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid) -{ - fprintf(stderr, "set hostid not supported in authpf\n"); - return (1); -} - -int -pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) -{ - fprintf(stderr, "set timeout not supported in authpf\n"); - return (1); -} - -int -pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit) -{ - fprintf(stderr, "set limit not supported in authpf\n"); - return (1); -} - -int -pfctl_set_debug(struct pfctl *pf, char *d) -{ - fprintf(stderr, "set debug not supported in authpf\n"); - return (1); -} - -int -pfctl_define_table(char *name, int flags, int addrs, const char *anchor, - const char *ruleset, struct pfr_buffer *ab, u_int32_t ticket) -{ - fprintf(stderr, "table definitions not yet supported in authpf\n"); - return (1); -} - -int -pfctl_rules(int dev, char *filename, int opts, char *anchorname, - char *rulesetname, struct pfr_buffer *t) -{ - /* never called, no anchors inside anchors, but we need the stub */ - fprintf(stderr, "load anchor not supported from authpf\n"); - return (1); -} - -void -pfctl_print_title(char *title) -{ -} diff --git a/contrib/pf/authpf/pathnames.h b/contrib/pf/authpf/pathnames.h deleted file mode 100644 index 97d1d7426b04..000000000000 --- a/contrib/pf/authpf/pathnames.h +++ /dev/null @@ -1,37 +0,0 @@ -/* $OpenBSD: pathnames.h,v 1.6 2003/06/03 20:38:59 beck Exp $ */ - -/* - * Copyright (C) 2002 Chris Kuethe (ckuethe@ualberta.ca) - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - */ - -#define PATH_CONFFILE "/etc/authpf/authpf.conf" -#define PATH_ALLOWFILE "/etc/authpf/authpf.allow" -#define PATH_PFRULES "/etc/authpf/authpf.rules" -#define PATH_PROBLEM "/etc/authpf/authpf.problem" -#define PATH_MESSAGE "/etc/authpf/authpf.message" -#define PATH_USER_DIR "/etc/authpf/users" -#define PATH_BAN_DIR "/etc/authpf/banned" -#define PATH_DEVFILE "/dev/pf" -#define PATH_PIDFILE "/var/authpf" -#define PATH_AUTHPF_SHELL "/usr/sbin/authpf" diff --git a/contrib/pf/ftp-proxy/ftp-proxy.8 b/contrib/pf/ftp-proxy/ftp-proxy.8 deleted file mode 100644 index e68bdde495cc..000000000000 --- a/contrib/pf/ftp-proxy/ftp-proxy.8 +++ /dev/null @@ -1,274 +0,0 @@ -.\" $OpenBSD: ftp-proxy.8,v 1.40 2004/03/16 08:50:07 jmc Exp $ -.\" -.\" Copyright (c) 1996-2001 -.\" Obtuse Systems Corporation, All rights reserved. -.\" -.\" 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 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 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. -.\" -.Dd August 17, 2001 -.Dt FTP-PROXY 8 -.Os -.Sh NAME -.Nm ftp-proxy -.Nd Internet File Transfer Protocol proxy server -.Sh SYNOPSIS -.Nm ftp-proxy -.Op Fl AnrVw -.Op Fl a Ar address -.Op Fl D Ar debuglevel -.Op Fl g Ar group -.Op Fl M Ar maxport -.Op Fl m Ar minport -.Op Fl t Ar timeout -.Op Fl u Ar user -.Sh DESCRIPTION -.Nm -is a proxy for the Internet File Transfer Protocol. -The proxy uses -.Xr pf 4 -and expects to have the FTP control connection as described in -.Xr services 5 -redirected to it via a -.Xr pf 4 -.Em rdr -command. -An example of how to do that is further down in this document. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl A -Permit only anonymous FTP connections. -The proxy will allow connections to log in to other sites as the user -.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 -Specify the local IP address to use in -.Xr bind 2 -as the source for connections made by -.Nm ftp-proxy -when connecting to destination FTP servers. -This may be necessary if the interface address of -your default route is not reachable from the destinations -.Nm -is attempting connections to, or this address is different from the one -connections are being NATed to. -In the usual case this means that -.Ar address -should be a publicly visible IP address assigned to one of -the interfaces on the machine running -.Nm -and should be the same address to which you are translating traffic -if you are using the -.Fl n -option. -.It Fl D Ar debuglevel -Specify a debug level, where the proxy emits verbose debug output -into -.Xr syslogd 8 -at level -.Dv LOG_DEBUG . -Meaningful values of debuglevel are 0-3, where 0 is no debug output and -3 is lots of debug output, the default being 0. -.It Fl g Ar group -Specify the named group to drop group privileges to, after doing -.Xr pf 4 -lookups which require root. -By default, -.Nm -uses the default group of the user it drops privilege to. -.It Fl M Ar maxport -Specify the upper end of the port range the proxy will use for the -data connections it establishes. -The default is -.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 -Use reverse host -.Pq reverse DNS -lookups for logging and libwrap use. -By default, -the proxy does not look up hostnames for libwrap or logging purposes. -.It Fl t Ar timeout -Specifies a timeout, in seconds. -The proxy will exit and close open connections if it sees no data -for the duration of the timeout. -The default is 0, which means the proxy will not time out. -.It Fl u Ar user -Specify the named user to drop privilege to, after doing -.Xr pf 4 -lookups which require root privilege. -By default, -.Nm -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 -.Pp -.Nm ftp-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 -rule such as -.Bd -literal -offset 2n -int_if = \&"xl0\&" -rdr pass on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021 -.Ed -.Pp -.Xr inetd 8 -must then be configured to run -.Nm -on the port from above using -.Bd -literal -offset 2n -127.0.0.1:8021 stream tcp nowait root /usr/libexec/ftp-proxy ftp-proxy -.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 -.Xr ftp 1 , -.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 -setup which allows the EPSV connections through to their destinations. -.Pp -IPv6 is not yet supported. diff --git a/contrib/pf/ftp-proxy/ftp-proxy.c b/contrib/pf/ftp-proxy/ftp-proxy.c deleted file mode 100644 index 18bc0a619a20..000000000000 --- a/contrib/pf/ftp-proxy/ftp-proxy.c +++ /dev/null @@ -1,1329 +0,0 @@ -/* $OpenBSD: ftp-proxy.c,v 1.35 2004/03/14 21:51:44 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 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. - * - */ - -/* - * ftp proxy, Originally based on juniper_ftp_proxy from the Obtuse - * Systems juniper firewall, written by Dan Boulet <danny@obtuse.com> - * and Bob Beck <beck@obtuse.com> - * - * This version basically passes everything through unchanged except - * for the PORT and the * "227 Entering Passive Mode" reply. - * - * A PORT command is handled by noting the IP address and port number - * specified and then configuring a listen port on some very high port - * number and telling the server about it using a PORT message. - * We then watch for an in-bound connection on the port from the server - * and connect to the client's port when it happens. - * - * A "227 Entering Passive Mode" reply is handled by noting the IP address - * and port number specified and then configuring a listen port on some - * very high port number and telling the client about it using a - * "227 Entering Passive Mode" reply. - * We then watch for an in-bound connection on the port from the client - * and connect to the server's port when it happens. - * - * supports tcp wrapper lookups/access control with the -w flag using - * the real destination address - the tcp wrapper stuff is done after - * the real destination address is retrieved from pf - * - */ - -/* - * TODO: - * Plenty, this is very basic, with the idea to get it in clean first. - * - * - IPv6 and EPASV support - * - Content filter support - * - filename filter support - * - per-user rules perhaps. - */ - -#include <sys/param.h> -#include <sys/time.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <netinet/in.h> - -#include <arpa/inet.h> - -#include <ctype.h> -#include <errno.h> -#include <grp.h> -#include <netdb.h> -#include <pwd.h> -#include <signal.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sysexits.h> -#include <syslog.h> -#include <unistd.h> - -#include "util.h" - -#ifdef LIBWRAP -#include <tcpd.h> -int allow_severity = LOG_INFO; -int deny_severity = LOG_NOTICE; -#endif /* LIBWRAP */ - -int min_port = IPPORT_HIFIRSTAUTO; -int max_port = IPPORT_HILASTAUTO; - -#define STARTBUFSIZE 1024 /* Must be at least 3 */ - -/* - * Variables used to support PORT mode connections. - * - * This gets a bit complicated. - * - * If PORT mode is on then client_listen_sa describes the socket that - * the real client is listening on and server_listen_sa describes the - * socket that we are listening on (waiting for the real server to connect - * with us). - * - * If PASV mode is on then client_listen_sa describes the socket that - * we are listening on (waiting for the real client to connect to us on) - * and server_listen_sa describes the socket that the real server is - * listening on. - * - * If the socket we are listening on gets a connection then we connect - * to the other side's socket. Similarly, if a connected socket is - * shutdown then we shutdown the other side's socket. - */ - -double xfer_start_time; - -struct sockaddr_in real_server_sa; -struct sockaddr_in client_listen_sa; -struct sockaddr_in server_listen_sa; - -int client_listen_socket = -1; /* Only used in PASV mode */ -int client_data_socket = -1; /* Connected socket to real client */ -int server_listen_socket = -1; /* Only used in PORT mode */ -int server_data_socket = -1; /* Connected socket to real server */ -int client_data_bytes, server_data_bytes; - -int AnonFtpOnly; -int Verbose; -int NatMode; - -char ClientName[NI_MAXHOST]; -char RealServerName[NI_MAXHOST]; -char OurName[NI_MAXHOST]; - -char *User = "proxy"; -char *Group; - -extern int Debug_Level; -extern int Use_Rdns; -extern in_addr_t Bind_Addr; -extern char *__progname; - -typedef enum { - UNKNOWN_MODE, - PORT_MODE, - PASV_MODE, - EPRT_MODE, - EPSV_MODE -} connection_mode_t; - -connection_mode_t connection_mode; - -extern void debuglog(int debug_level, const char *fmt, ...); -double wallclock_time(void); -void show_xfer_stats(void); -void log_control_command (char *cmd, int client); -int new_dataconn(int server); -void do_client_cmd(struct csiob *client, struct csiob *server); -void do_server_reply(struct csiob *server, struct csiob *client); -static void -usage(void) -{ - syslog(LOG_NOTICE, - "usage: %s [-AnrVw] [-a address] [-D debuglevel [-g group]" - " [-M maxport] [-m minport] [-t timeout] [-u user]", __progname); - exit(EX_USAGE); -} - -static void -close_client_data(void) -{ - if (client_data_socket >= 0) { - shutdown(client_data_socket, 2); - close(client_data_socket); - client_data_socket = -1; - } -} - -static void -close_server_data(void) -{ - if (server_data_socket >= 0) { - shutdown(server_data_socket, 2); - close(server_data_socket); - server_data_socket = -1; - } -} - -static void -drop_privs(void) -{ - struct passwd *pw; - struct group *gr; - uid_t uid = 0; - gid_t gid = 0; - - if (User != NULL) { - pw = getpwnam(User); - if (pw == NULL) { - syslog(LOG_ERR, "cannot find user %s", User); - exit(EX_USAGE); - } - uid = pw->pw_uid; - gid = pw->pw_gid; - } - - if (Group != NULL) { - gr = getgrnam(Group); - if (gr == NULL) { - syslog(LOG_ERR, "cannot find group %s", Group); - exit(EX_USAGE); - } - gid = gr->gr_gid; - } - - if (gid != 0 && (setegid(gid) == -1 || setgid(gid) == -1)) { - syslog(LOG_ERR, "cannot drop group privs (%m)"); - exit(EX_CONFIG); - } - - if (uid != 0 && (seteuid(uid) == -1 || setuid(uid) == -1)) { - syslog(LOG_ERR, "cannot drop root privs (%m)"); - exit(EX_CONFIG); - } -} - -#ifdef LIBWRAP -/* - * Check a connection against the tcpwrapper, log if we're going to - * reject it, returns: 0 -> reject, 1 -> accept. We add in hostnames - * if we are set to do reverse DNS, otherwise no. - */ -static int -check_host(struct sockaddr_in *client_sin, struct sockaddr_in *server_sin) -{ - char cname[NI_MAXHOST]; - char sname[NI_MAXHOST]; - struct request_info request; - int i; - - request_init(&request, RQ_DAEMON, __progname, RQ_CLIENT_SIN, - client_sin, RQ_SERVER_SIN, server_sin, RQ_CLIENT_ADDR, - inet_ntoa(client_sin->sin_addr), 0); - - if (Use_Rdns) { - /* - * We already looked these up, but we have to do it again - * for tcp wrapper, to ensure that we get the DNS name, since - * the tcp wrapper cares about these things, and we don't - * want to pass in a printed address as a name. - */ - i = getnameinfo((struct sockaddr *) &client_sin->sin_addr, - sizeof(&client_sin->sin_addr), cname, sizeof(cname), - NULL, 0, NI_NAMEREQD); - - if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) - strlcpy(cname, STRING_UNKNOWN, sizeof(cname)); - - i = getnameinfo((struct sockaddr *)&server_sin->sin_addr, - sizeof(&server_sin->sin_addr), sname, sizeof(sname), - NULL, 0, NI_NAMEREQD); - - if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) - strlcpy(sname, STRING_UNKNOWN, sizeof(sname)); - } else { - /* - * ensure the TCP wrapper doesn't start doing - * reverse DNS lookups if we aren't supposed to. - */ - strlcpy(cname, STRING_UNKNOWN, sizeof(cname)); - strlcpy(sname, STRING_UNKNOWN, sizeof(sname)); - } - - request_set(&request, RQ_SERVER_ADDR, inet_ntoa(server_sin->sin_addr), - 0); - request_set(&request, RQ_CLIENT_NAME, cname, RQ_SERVER_NAME, sname, 0); - - if (!hosts_access(&request)) { - syslog(LOG_NOTICE, "tcpwrappers rejected: %s -> %s", - ClientName, RealServerName); - return(0); - } - return(1); -} -#endif /* LIBWRAP */ - -double -wallclock_time(void) -{ - struct timeval tv; - - gettimeofday(&tv, NULL); - return(tv.tv_sec + tv.tv_usec / 1e6); -} - -/* - * Show the stats for this data transfer - */ -void -show_xfer_stats(void) -{ - char tbuf[1000]; - double delta; - size_t len; - int i; - - if (!Verbose) - return; - - delta = wallclock_time() - xfer_start_time; - - if (delta < 0.001) - delta = 0.001; - - if (client_data_bytes == 0 && server_data_bytes == 0) { - syslog(LOG_INFO, - "data transfer complete (no bytes transferred)"); - return; - } - - len = sizeof(tbuf); - - if (delta >= 60) { - int idelta; - - idelta = delta + 0.5; - if (idelta >= 60*60) { - i = snprintf(tbuf, len, - "data transfer complete (%dh %dm %ds", - idelta / (60*60), (idelta % (60*60)) / 60, - idelta % 60); - if (i >= len) - goto logit; - len -= i; - } else { - i = snprintf(tbuf, len, - "data transfer complete (%dm %ds", idelta / 60, - idelta % 60); - if (i >= len) - goto logit; - len -= i; - } - } else { - i = snprintf(tbuf, len, "data transfer complete (%.1fs", - delta); - if (i >= len) - goto logit; - len -= i; - } - - if (client_data_bytes > 0) { - i = snprintf(&tbuf[strlen(tbuf)], len, - ", %d bytes to server) (%.1fKB/s", client_data_bytes, - (client_data_bytes / delta) / (double)1024); - if (i >= len) - goto logit; - len -= i; - } - if (server_data_bytes > 0) { - i = snprintf(&tbuf[strlen(tbuf)], len, - ", %d bytes to client) (%.1fKB/s", server_data_bytes, - (server_data_bytes / delta) / (double)1024); - if (i >= len) - goto logit; - len -= i; - } - strlcat(tbuf, ")", sizeof(tbuf)); - logit: - syslog(LOG_INFO, "%s", tbuf); -} - -void -log_control_command (char *cmd, int client) -{ - /* log an ftp control command or reply */ - char *logstring; - int level = LOG_DEBUG; - - if (!Verbose) - return; - - /* don't log passwords */ - if (strncasecmp(cmd, "pass ", 5) == 0) - logstring = "PASS XXXX"; - else - logstring = cmd; - if (client) { - /* log interesting stuff at LOG_INFO, rest at LOG_DEBUG */ - if ((strncasecmp(cmd, "user ", 5) == 0) || - (strncasecmp(cmd, "retr ", 5) == 0) || - (strncasecmp(cmd, "cwd ", 4) == 0) || - (strncasecmp(cmd, "stor " ,5) == 0)) - level = LOG_INFO; - } - syslog(level, "%s %s", client ? "client:" : " server:", - logstring); -} - -/* - * set ourselves up for a new data connection. Direction is toward client if - * "server" is 0, towards server otherwise. - */ -int -new_dataconn(int server) -{ - /* - * Close existing data conn. - */ - - if (client_listen_socket != -1) { - close(client_listen_socket); - client_listen_socket = -1; - } - close_client_data(); - - if (server_listen_socket != -1) { - close(server_listen_socket); - server_listen_socket = -1; - } - close_server_data(); - - if (server) { - bzero(&server_listen_sa, sizeof(server_listen_sa)); - server_listen_socket = get_backchannel_socket(SOCK_STREAM, - min_port, max_port, -1, 1, &server_listen_sa); - - if (server_listen_socket == -1) { - syslog(LOG_INFO, "server socket bind() failed (%m)"); - exit(EX_OSERR); - } - if (listen(server_listen_socket, 5) != 0) { - syslog(LOG_INFO, "server socket listen() failed (%m)"); - exit(EX_OSERR); - } - } else { - bzero(&client_listen_sa, sizeof(client_listen_sa)); - client_listen_socket = get_backchannel_socket(SOCK_STREAM, - min_port, max_port, -1, 1, &client_listen_sa); - - if (client_listen_socket == -1) { - syslog(LOG_NOTICE, - "cannot get client listen socket (%m)"); - exit(EX_OSERR); - } - if (listen(client_listen_socket, 5) != 0) { - syslog(LOG_NOTICE, - "cannot listen on client socket (%m)"); - exit(EX_OSERR); - } - } - return(0); -} - -static void -connect_pasv_backchannel(void) -{ - struct sockaddr_in listen_sa; - socklen_t salen; - - /* - * We are about to accept a connection from the client. - * This is a PASV data connection. - */ - debuglog(2, "client listen socket ready"); - - close_server_data(); - close_client_data(); - - salen = sizeof(listen_sa); - client_data_socket = accept(client_listen_socket, - (struct sockaddr *)&listen_sa, &salen); - - if (client_data_socket < 0) { - syslog(LOG_NOTICE, "accept() failed (%m)"); - exit(EX_OSERR); - } - close(client_listen_socket); - client_listen_socket = -1; - memset(&listen_sa, 0, sizeof(listen_sa)); - - server_data_socket = get_backchannel_socket(SOCK_STREAM, min_port, - max_port, -1, 1, &listen_sa); - if (server_data_socket < 0) { - syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)"); - exit(EX_OSERR); - } - if (connect(server_data_socket, (struct sockaddr *) &server_listen_sa, - sizeof(server_listen_sa)) != 0) { - syslog(LOG_NOTICE, "connect() failed (%m)"); - exit(EX_NOHOST); - } - client_data_bytes = 0; - server_data_bytes = 0; - xfer_start_time = wallclock_time(); -} - -static void -connect_port_backchannel(void) -{ - struct sockaddr_in listen_sa; - socklen_t salen; - - /* - * We are about to accept a connection from the server. - * This is a PORT or EPRT data connection. - */ - debuglog(2, "server listen socket ready"); - - close_server_data(); - close_client_data(); - - salen = sizeof(listen_sa); - server_data_socket = accept(server_listen_socket, - (struct sockaddr *)&listen_sa, &salen); - if (server_data_socket < 0) { - syslog(LOG_NOTICE, "accept() failed (%m)"); - exit(EX_OSERR); - } - close(server_listen_socket); - server_listen_socket = -1; - - if (getuid() != 0) { - /* - * We're not running as root, so we get a backchannel - * socket bound in our designated range, instead of - * getting one bound to port 20 - This is deliberately - * not RFC compliant. - */ - bzero(&listen_sa.sin_addr, sizeof(struct in_addr)); - client_data_socket = get_backchannel_socket(SOCK_STREAM, - min_port, max_port, -1, 1, &listen_sa); - if (client_data_socket < 0) { - syslog(LOG_NOTICE, "get_backchannel_socket() failed (%m)"); - exit(EX_OSERR); - } - - } else { - - /* - * We're root, get our backchannel socket bound to port - * 20 here, so we're fully RFC compliant. - */ - client_data_socket = socket(AF_INET, SOCK_STREAM, 0); - - salen = 1; - listen_sa.sin_family = AF_INET; - bzero(&listen_sa.sin_addr, sizeof(struct in_addr)); - listen_sa.sin_port = htons(20); - - if (setsockopt(client_data_socket, SOL_SOCKET, SO_REUSEADDR, - &salen, sizeof(salen)) == -1) { - syslog(LOG_NOTICE, "setsockopt() failed (%m)"); - exit(EX_OSERR); - } - - if (bind(client_data_socket, (struct sockaddr *)&listen_sa, - sizeof(listen_sa)) == - 1) { - syslog(LOG_NOTICE, "data channel bind() failed (%m)"); - exit(EX_OSERR); - } - } - - if (connect(client_data_socket, (struct sockaddr *) &client_listen_sa, - sizeof(client_listen_sa)) != 0) { - syslog(LOG_INFO, "cannot connect data channel (%m)"); - exit(EX_NOHOST); - } - - client_data_bytes = 0; - server_data_bytes = 0; - xfer_start_time = wallclock_time(); -} - -void -do_client_cmd(struct csiob *client, struct csiob *server) -{ - int i, j, rv; - char tbuf[100]; - char *sendbuf = NULL; - - log_control_command((char *)client->line_buffer, 1); - - /* client->line_buffer is an ftp control command. - * There is no reason for these to be very long. - * In the interest of limiting buffer overrun attempts, - * we catch them here. - */ - if (strlen((char *)client->line_buffer) > 512) { - syslog(LOG_NOTICE, "excessively long control command"); - exit(EX_DATAERR); - } - - /* - * Check the client user provided if needed - */ - if (AnonFtpOnly && strncasecmp((char *)client->line_buffer, "user ", - strlen("user ")) == 0) { - char *cp; - - cp = (char *) client->line_buffer + strlen("user "); - if ((strcasecmp(cp, "ftp\r\n") != 0) && - (strcasecmp(cp, "anonymous\r\n") != 0)) { - /* - * this isn't anonymous - give the client an - * error before they send a password - */ - snprintf(tbuf, sizeof(tbuf), - "500 Only anonymous FTP is allowed\r\n"); - j = 0; - i = strlen(tbuf); - do { - rv = send(client->fd, tbuf + j, i - j, 0); - if (rv == -1 && errno != EAGAIN && - errno != EINTR) - break; - else if (rv != -1) - j += rv; - } while (j >= 0 && j < i); - sendbuf = NULL; - } else - sendbuf = (char *)client->line_buffer; - } else if ((strncasecmp((char *)client->line_buffer, "eprt ", - strlen("eprt ")) == 0)) { - - /* Watch out for EPRT commands */ - char *line = NULL, *q, *p, *result[3], delim; - struct addrinfo hints, *res = NULL; - unsigned long proto; - - j = 0; - line = strdup((char *)client->line_buffer+strlen("eprt ")); - if (line == NULL) { - syslog(LOG_ERR, "insufficient memory"); - exit(EX_UNAVAILABLE); - } - p = line; - delim = p[0]; - p++; - - memset(result,0, sizeof(result)); - for (i = 0; i < 3; i++) { - q = strchr(p, delim); - if (!q || *q != delim) - goto parsefail; - *q++ = '\0'; - result[i] = p; - p = q; - } - - proto = strtoul(result[0], &p, 10); - if (!*result[0] || *p) - goto protounsupp; - - memset(&hints, 0, sizeof(hints)); - if (proto != 1) /* 1 == AF_INET - all we support for now */ - goto protounsupp; - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_NUMERICHOST; /*no DNS*/ - if (getaddrinfo(result[1], result[2], &hints, &res)) - goto parsefail; - if (res->ai_next) - goto parsefail; - if (sizeof(client_listen_sa) < res->ai_addrlen) - goto parsefail; - memcpy(&client_listen_sa, res->ai_addr, res->ai_addrlen); - - debuglog(1, "client wants us to use %s:%u", - inet_ntoa(client_listen_sa.sin_addr), - htons(client_listen_sa.sin_port)); - - /* - * Configure our own listen socket and tell the server about it - */ - new_dataconn(1); - connection_mode = EPRT_MODE; - - debuglog(1, "we want server to use %s:%u", - inet_ntoa(server->sa.sin_addr), - ntohs(server_listen_sa.sin_port)); - - snprintf(tbuf, sizeof(tbuf), "EPRT |%d|%s|%u|\r\n", 1, - inet_ntoa(server->sa.sin_addr), - ntohs(server_listen_sa.sin_port)); - debuglog(1, "to server (modified): %s", tbuf); - sendbuf = tbuf; - goto out; -parsefail: - snprintf(tbuf, sizeof(tbuf), - "500 Invalid argument; rejected\r\n"); - sendbuf = NULL; - goto out; -protounsupp: - /* we only support AF_INET for now */ - if (proto == 2) - snprintf(tbuf, sizeof(tbuf), - "522 Protocol not supported, use (1)\r\n"); - else - snprintf(tbuf, sizeof(tbuf), - "501 Protocol not supported\r\n"); - sendbuf = NULL; -out: - if (line) - free(line); - if (res) - freeaddrinfo(res); - if (sendbuf == NULL) { - debuglog(1, "to client (modified): %s", tbuf); - i = strlen(tbuf); - do { - rv = send(client->fd, tbuf + j, i - j, 0); - if (rv == -1 && errno != EAGAIN && - errno != EINTR) - break; - else if (rv != -1) - j += rv; - } while (j >= 0 && j < i); - } - } else if (!NatMode && (strncasecmp((char *)client->line_buffer, - "epsv", strlen("epsv")) == 0)) { - - /* - * If we aren't in NAT mode, deal with EPSV. - * EPSV is a problem - Unlike PASV, the reply from the - * server contains *only* a port, we can't modify the reply - * to the client and get the client to connect to us without - * resorting to using a dynamic rdr rule we have to add in - * for the reply to this connection, and take away afterwards. - * so this will wait until we have the right solution for rule - * additions/deletions in pf. - * - * in the meantime we just tell the client we don't do it, - * and most clients should fall back to using PASV. - */ - - snprintf(tbuf, sizeof(tbuf), - "500 EPSV command not understood\r\n"); - debuglog(1, "to client (modified): %s", tbuf); - j = 0; - i = strlen(tbuf); - do { - rv = send(client->fd, tbuf + j, i - j, 0); - if (rv == -1 && errno != EAGAIN && errno != EINTR) - break; - else if (rv != -1) - j += rv; - } while (j >= 0 && j < i); - sendbuf = NULL; - } else if (strncasecmp((char *)client->line_buffer, "port ", - strlen("port ")) == 0) { - unsigned int values[6]; - char *tailptr; - - debuglog(1, "Got a PORT command"); - - tailptr = (char *)&client->line_buffer[strlen("port ")]; - values[0] = 0; - - i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0], - &values[1], &values[2], &values[3], &values[4], - &values[5]); - if (i != 6) { - syslog(LOG_INFO, "malformed PORT command (%s)", - client->line_buffer); - exit(EX_DATAERR); - } - - for (i = 0; i<6; i++) { - if (values[i] > 255) { - syslog(LOG_INFO, - "malformed PORT command (%s)", - client->line_buffer); - exit(EX_DATAERR); - } - } - - client_listen_sa.sin_family = AF_INET; - client_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) | - (values[1] << 16) | (values[2] << 8) | - (values[3] << 0)); - - client_listen_sa.sin_port = htons((values[4] << 8) | - values[5]); - debuglog(1, "client wants us to use %u.%u.%u.%u:%u", - values[0], values[1], values[2], values[3], - (values[4] << 8) | values[5]); - - /* - * Configure our own listen socket and tell the server about it - */ - new_dataconn(1); - connection_mode = PORT_MODE; - - debuglog(1, "we want server to use %s:%u", - inet_ntoa(server->sa.sin_addr), - ntohs(server_listen_sa.sin_port)); - - snprintf(tbuf, sizeof(tbuf), "PORT %u,%u,%u,%u,%u,%u\r\n", - ((u_char *)&server->sa.sin_addr.s_addr)[0], - ((u_char *)&server->sa.sin_addr.s_addr)[1], - ((u_char *)&server->sa.sin_addr.s_addr)[2], - ((u_char *)&server->sa.sin_addr.s_addr)[3], - ((u_char *)&server_listen_sa.sin_port)[0], - ((u_char *)&server_listen_sa.sin_port)[1]); - - debuglog(1, "to server (modified): %s", tbuf); - - sendbuf = tbuf; - } else - sendbuf = (char *)client->line_buffer; - - /* - *send our (possibly modified) control command in sendbuf - * on it's way to the server - */ - if (sendbuf != NULL) { - j = 0; - i = strlen(sendbuf); - do { - rv = send(server->fd, sendbuf + j, i - j, 0); - if (rv == -1 && errno != EAGAIN && errno != EINTR) - break; - else if (rv != -1) - j += rv; - } while (j >= 0 && j < i); - } -} - -void -do_server_reply(struct csiob *server, struct csiob *client) -{ - int code, i, j, rv; - struct in_addr *iap; - static int continuing = 0; - char tbuf[100], *sendbuf, *p; - - log_control_command((char *)server->line_buffer, 0); - - if (strlen((char *)server->line_buffer) > 512) { - /* - * someone's playing games. Have a cow in the syslogs and - * exit - we don't pass this on for fear of hurting - * our other end, which might be poorly implemented. - */ - syslog(LOG_NOTICE, "long FTP control reply"); - exit(EX_DATAERR); - } - - /* - * Watch out for "227 Entering Passive Mode ..." replies - */ - code = strtol((char *)server->line_buffer, &p, 10); - if (isspace(server->line_buffer[0])) - code = 0; - if (!*(server->line_buffer) || (*p != ' ' && *p != '-')) { - if (continuing) - goto sendit; - syslog(LOG_INFO, "malformed control reply"); - exit(EX_DATAERR); - } - if (code <= 0 || code > 999) { - if (continuing) - goto sendit; - syslog(LOG_INFO, "invalid server reply code %d", code); - exit(EX_DATAERR); - } - if (*p == '-') - continuing = 1; - else - continuing = 0; - if (code == 227 && !NatMode) { - unsigned int values[6]; - char *tailptr; - - debuglog(1, "Got a PASV reply"); - debuglog(1, "{%s}", (char *)server->line_buffer); - - tailptr = (char *)strchr((char *)server->line_buffer, '('); - if (tailptr == NULL) { - tailptr = strrchr((char *)server->line_buffer, ' '); - if (tailptr == NULL) { - syslog(LOG_NOTICE, "malformed 227 reply"); - exit(EX_DATAERR); - } - } - tailptr++; /* skip past space or ( */ - - values[0] = 0; - - i = sscanf(tailptr, "%u,%u,%u,%u,%u,%u", &values[0], - &values[1], &values[2], &values[3], &values[4], - &values[5]); - if (i != 6) { - syslog(LOG_INFO, "malformed PASV reply (%s)", - client->line_buffer); - exit(EX_DATAERR); - } - for (i = 0; i<6; i++) - if (values[i] > 255) { - syslog(LOG_INFO, "malformed PASV reply(%s)", - client->line_buffer); - exit(EX_DATAERR); - } - - server_listen_sa.sin_family = AF_INET; - server_listen_sa.sin_addr.s_addr = htonl((values[0] << 24) | - (values[1] << 16) | (values[2] << 8) | (values[3] << 0)); - server_listen_sa.sin_port = htons((values[4] << 8) | - values[5]); - - debuglog(1, "server wants us to use %s:%u", - inet_ntoa(server_listen_sa.sin_addr), (values[4] << 8) | - values[5]); - - new_dataconn(0); - connection_mode = PASV_MODE; - iap = &(server->sa.sin_addr); - - debuglog(1, "we want client to use %s:%u", inet_ntoa(*iap), - htons(client_listen_sa.sin_port)); - - snprintf(tbuf, sizeof(tbuf), - "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n", - ((u_char *)iap)[0], ((u_char *)iap)[1], - ((u_char *)iap)[2], ((u_char *)iap)[3], - ((u_char *)&client_listen_sa.sin_port)[0], - ((u_char *)&client_listen_sa.sin_port)[1]); - debuglog(1, "to client (modified): %s", tbuf); - sendbuf = tbuf; - } else { - sendit: - sendbuf = (char *)server->line_buffer; - } - - /* - * send our (possibly modified) control command in sendbuf - * on it's way to the client - */ - j = 0; - i = strlen(sendbuf); - do { - rv = send(client->fd, sendbuf + j, i - j, 0); - if (rv == -1 && errno != EAGAIN && errno != EINTR) - break; - else if (rv != -1) - j += rv; - } while (j >= 0 && j < i); - -} - -int -main(int argc, char *argv[]) -{ - struct csiob client_iob, server_iob; - struct sigaction new_sa, old_sa; - int sval, ch, flags, i; - socklen_t salen; - int one = 1; - long timeout_seconds = 0; - struct timeval tv; -#ifdef LIBWRAP - int use_tcpwrapper = 0; -#endif /* LIBWRAP */ - - while ((ch = getopt(argc, argv, "a:D:g:m:M:t:u:AnVwr")) != -1) { - char *p; - switch (ch) { - case 'a': - if (!*optarg) - usage(); - if ((Bind_Addr = inet_addr(optarg)) == INADDR_NONE) { - syslog(LOG_NOTICE, - "%s: invalid address", optarg); - usage(); - } - break; - case 'A': - AnonFtpOnly = 1; /* restrict to anon usernames only */ - break; - case 'D': - Debug_Level = strtol(optarg, &p, 10); - if (!*optarg || *p) - usage(); - break; - case 'g': - Group = optarg; - break; - case 'm': - min_port = strtol(optarg, &p, 10); - if (!*optarg || *p) - usage(); - if (min_port < 0 || min_port > USHRT_MAX) - usage(); - break; - case 'M': - max_port = strtol(optarg, &p, 10); - if (!*optarg || *p) - usage(); - if (max_port < 0 || max_port > USHRT_MAX) - usage(); - break; - case 'n': - NatMode = 1; /* pass all passives, we're using NAT */ - break; - case 'r': - Use_Rdns = 1; /* look up hostnames */ - break; - case 't': - timeout_seconds = strtol(optarg, &p, 10); - if (!*optarg || *p) - usage(); - break; - case 'u': - User = optarg; - break; - case 'V': - Verbose = 1; - break; -#ifdef LIBWRAP - case 'w': - use_tcpwrapper = 1; /* do the libwrap thing */ - break; -#endif /* LIBWRAP */ - default: - usage(); - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if (max_port < min_port) - usage(); - - openlog(__progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); - - setlinebuf(stdout); - setlinebuf(stderr); - - memset(&client_iob, 0, sizeof(client_iob)); - memset(&server_iob, 0, sizeof(server_iob)); - - if (get_proxy_env(0, &real_server_sa, &client_iob.sa) == -1) - exit(EX_PROTOCOL); - - /* - * We may now drop root privs, as we have done our ioctl for - * pf. If we do drop root, we can't make backchannel connections - * for PORT and EPRT come from port 20, which is not strictly - * RFC compliant. This shouldn't cause problems for all but - * the stupidest ftp clients and the stupidest packet filters. - */ - drop_privs(); - - /* - * We check_host after get_proxy_env so that checks are done - * against the original destination endpoint, not the endpoint - * of our side of the rdr. This allows the use of tcpwrapper - * rules to restrict destinations as well as sources of connections - * for ftp. - */ - if (Use_Rdns) - flags = 0; - else - flags = NI_NUMERICHOST | NI_NUMERICSERV; - - i = getnameinfo((struct sockaddr *)&client_iob.sa, - sizeof(client_iob.sa), ClientName, sizeof(ClientName), NULL, 0, - flags); - - if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) { - debuglog(2, "name resolution failure (client)"); - exit(EX_OSERR); - } - - i = getnameinfo((struct sockaddr *)&real_server_sa, - sizeof(real_server_sa), RealServerName, sizeof(RealServerName), - NULL, 0, flags); - - if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) { - debuglog(2, "name resolution failure (server)"); - exit(EX_OSERR); - } - -#ifdef LIBWRAP - if (use_tcpwrapper && !check_host(&client_iob.sa, &real_server_sa)) - exit(EX_NOPERM); -#endif - - client_iob.fd = 0; - - syslog(LOG_INFO, "accepted connection from %s:%u to %s:%u", ClientName, - ntohs(client_iob.sa.sin_port), RealServerName, - ntohs(real_server_sa.sin_port)); - - server_iob.fd = get_backchannel_socket(SOCK_STREAM, min_port, max_port, - -1, 1, &server_iob.sa); - - if (connect(server_iob.fd, (struct sockaddr *)&real_server_sa, - sizeof(real_server_sa)) != 0) { - syslog(LOG_INFO, "cannot connect to %s:%u (%m)", RealServerName, - ntohs(real_server_sa.sin_port)); - exit(EX_NOHOST); - } - - /* - * Now that we are connected to the real server, get the name - * of our end of the server socket so we know our IP address - * from the real server's perspective. - */ - salen = sizeof(server_iob.sa); - getsockname(server_iob.fd, (struct sockaddr *)&server_iob.sa, &salen); - - i = getnameinfo((struct sockaddr *)&server_iob.sa, - sizeof(server_iob.sa), OurName, sizeof(OurName), NULL, 0, flags); - - if (i != 0 && i != EAI_NONAME && i != EAI_AGAIN) { - debuglog(2, "name resolution failure (local)"); - exit(EX_OSERR); - } - - debuglog(1, "local socket is %s:%u", OurName, - ntohs(server_iob.sa.sin_port)); - - /* ignore SIGPIPE */ - bzero(&new_sa, sizeof(new_sa)); - new_sa.sa_handler = SIG_IGN; - (void)sigemptyset(&new_sa.sa_mask); - new_sa.sa_flags = SA_RESTART; - if (sigaction(SIGPIPE, &new_sa, &old_sa) != 0) { - syslog(LOG_ERR, "sigaction() failed (%m)"); - exit(EX_OSERR); - } - - if (setsockopt(client_iob.fd, SOL_SOCKET, SO_OOBINLINE, (char *)&one, - sizeof(one)) == -1) { - syslog(LOG_NOTICE, "cannot set SO_OOBINLINE (%m)"); - exit(EX_OSERR); - } - - client_iob.line_buffer_size = STARTBUFSIZE; - client_iob.line_buffer = malloc(client_iob.line_buffer_size); - client_iob.io_buffer_size = STARTBUFSIZE; - client_iob.io_buffer = malloc(client_iob.io_buffer_size); - client_iob.next_byte = 0; - client_iob.io_buffer_len = 0; - client_iob.alive = 1; - client_iob.who = "client"; - client_iob.send_oob_flags = 0; - client_iob.real_sa = client_iob.sa; - - server_iob.line_buffer_size = STARTBUFSIZE; - server_iob.line_buffer = malloc(server_iob.line_buffer_size); - server_iob.io_buffer_size = STARTBUFSIZE; - server_iob.io_buffer = malloc(server_iob.io_buffer_size); - server_iob.next_byte = 0; - server_iob.io_buffer_len = 0; - server_iob.alive = 1; - server_iob.who = "server"; - server_iob.send_oob_flags = MSG_OOB; - server_iob.real_sa = real_server_sa; - - if (client_iob.line_buffer == NULL || client_iob.io_buffer == NULL || - server_iob.line_buffer == NULL || server_iob.io_buffer == NULL) { - syslog (LOG_NOTICE, "insufficient memory"); - exit(EX_UNAVAILABLE); - } - - while (client_iob.alive || server_iob.alive) { - int maxfd = 0; - fd_set *fdsp; - - if (client_iob.fd > maxfd) - maxfd = client_iob.fd; - if (client_listen_socket > maxfd) - maxfd = client_listen_socket; - if (client_data_socket > maxfd) - maxfd = client_data_socket; - if (server_iob.fd > maxfd) - maxfd = server_iob.fd; - if (server_listen_socket > maxfd) - maxfd = server_listen_socket; - if (server_data_socket > maxfd) - maxfd = server_data_socket; - - debuglog(3, "client is %s; server is %s", - client_iob.alive ? "alive" : "dead", - server_iob.alive ? "alive" : "dead"); - - fdsp = (fd_set *)calloc(howmany(maxfd + 1, NFDBITS), - sizeof(fd_mask)); - if (fdsp == NULL) { - syslog(LOG_NOTICE, "insufficient memory"); - exit(EX_UNAVAILABLE); - } - - if (client_iob.alive && telnet_getline(&client_iob, - &server_iob)) { - debuglog(3, "client line buffer is \"%s\"", - (char *)client_iob.line_buffer); - if (client_iob.line_buffer[0] != '\0') - do_client_cmd(&client_iob, &server_iob); - } else if (server_iob.alive && telnet_getline(&server_iob, - &client_iob)) { - debuglog(3, "server line buffer is \"%s\"", - (char *)server_iob.line_buffer); - if (server_iob.line_buffer[0] != '\0') - do_server_reply(&server_iob, &client_iob); - } else { - if (client_iob.alive) { - FD_SET(client_iob.fd, fdsp); - if (client_listen_socket >= 0) - FD_SET(client_listen_socket, fdsp); - if (client_data_socket >= 0) - FD_SET(client_data_socket, fdsp); - } - if (server_iob.alive) { - FD_SET(server_iob.fd, fdsp); - if (server_listen_socket >= 0) - FD_SET(server_listen_socket, fdsp); - if (server_data_socket >= 0) - FD_SET(server_data_socket, fdsp); - } - tv.tv_sec = timeout_seconds; - tv.tv_usec = 0; - - doselect: - sval = select(maxfd + 1, fdsp, NULL, NULL, - (tv.tv_sec == 0) ? NULL : &tv); - if (sval == 0) { - /* - * This proxy has timed out. Expire it - * quietly with an obituary in the syslogs - * for any passing mourners. - */ - syslog(LOG_INFO, - "timeout: no data for %ld seconds", - timeout_seconds); - exit(EX_OK); - } - if (sval == -1) { - if (errno == EINTR || errno == EAGAIN) - goto doselect; - syslog(LOG_NOTICE, - "select() failed (%m)"); - exit(EX_OSERR); - } - if (client_data_socket >= 0 && - FD_ISSET(client_data_socket, fdsp)) { - int rval; - - debuglog(3, "transfer: client to server"); - rval = xfer_data("client to server", - client_data_socket, - server_data_socket, - client_iob.sa.sin_addr, - real_server_sa.sin_addr); - if (rval <= 0) { - close_client_data(); - close_server_data(); - show_xfer_stats(); - } else - client_data_bytes += rval; - } - if (server_data_socket >= 0 && - FD_ISSET(server_data_socket, fdsp)) { - int rval; - - debuglog(3, "transfer: server to client"); - rval = xfer_data("server to client", - server_data_socket, - client_data_socket, - real_server_sa.sin_addr, - client_iob.sa.sin_addr); - if (rval <= 0) { - close_client_data(); - close_server_data(); - show_xfer_stats(); - } else - server_data_bytes += rval; - } - if (server_listen_socket >= 0 && - FD_ISSET(server_listen_socket, fdsp)) { - connect_port_backchannel(); - } - if (client_listen_socket >= 0 && - FD_ISSET(client_listen_socket, fdsp)) { - connect_pasv_backchannel(); - } - if (client_iob.alive && - FD_ISSET(client_iob.fd, fdsp)) { - client_iob.data_available = 1; - } - if (server_iob.alive && - FD_ISSET(server_iob.fd, fdsp)) { - server_iob.data_available = 1; - } - } - free(fdsp); - if (client_iob.got_eof) { - shutdown(server_iob.fd, 1); - shutdown(client_iob.fd, 0); - client_iob.got_eof = 0; - client_iob.alive = 0; - } - if (server_iob.got_eof) { - shutdown(client_iob.fd, 1); - shutdown(server_iob.fd, 0); - server_iob.got_eof = 0; - server_iob.alive = 0; - } - } - - if (Verbose) - syslog(LOG_INFO, "session ended"); - - exit(EX_OK); -} diff --git a/contrib/pf/ftp-proxy/getline.c b/contrib/pf/ftp-proxy/getline.c deleted file mode 100644 index 2be388340029..000000000000 --- a/contrib/pf/ftp-proxy/getline.c +++ /dev/null @@ -1,259 +0,0 @@ -/* $OpenBSD: getline.c,v 1.15 2003/06/28 01:04:57 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) { - 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; - 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) { - 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); - } -} diff --git a/contrib/pf/ftp-proxy/util.c b/contrib/pf/ftp-proxy/util.c deleted file mode 100644 index 17a88cae6431..000000000000 --- a/contrib/pf/ftp-proxy/util.c +++ /dev/null @@ -1,301 +0,0 @@ -/* $OpenBSD: util.c,v 1.18 2004/01/22 16:10:30 beck 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" - -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 pfioc_natlook natlook; - socklen_t slen; - int fd; - - slen = sizeof(*real_server_sa_ptr); - if (getsockname(connected_fd, (struct sockaddr *)real_server_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); - } - - /* - * 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] = real_server_sa_ptr->sin_addr.s_addr; - natlook.proto = IPPROTO_TCP; - natlook.sport = client_sa_ptr->sin_port; - natlook.dport = real_server_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); -} diff --git a/contrib/pf/ftp-proxy/util.h b/contrib/pf/ftp-proxy/util.h deleted file mode 100644 index 597cd18d33bb..000000000000 --- a/contrib/pf/ftp-proxy/util.h +++ /dev/null @@ -1,68 +0,0 @@ -/* $OpenBSD: util.h,v 1.3 2002/05/23 10:22:14 deraadt 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; - 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); - -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; - - diff --git a/contrib/pf/man/pf.4 b/contrib/pf/man/pf.4 deleted file mode 100644 index df0ff6c0fb83..000000000000 --- a/contrib/pf/man/pf.4 +++ /dev/null @@ -1,837 +0,0 @@ -.\" $OpenBSD: pf.4,v 1.48 2004/03/27 17:15:30 henning Exp $ -.\" -.\" Copyright (C) 2001, Kjell Wooding. 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 project 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 PROJECT 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 PROJECT 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. -.\" -.Dd June 24, 2001 -.Dt PF 4 -.Os -.Sh NAME -.Nm pf -.Nd packet filter -.Sh SYNOPSIS -.Cd "pseudo-device pf" -.Sh DESCRIPTION -Packet filtering takes place in the kernel. -A pseudo-device, -.Pa /dev/pf , -allows userland processes to control the -behavior of the packet filter through an -.Xr ioctl 2 -interface. -There are commands to enable and disable the filter, load rulesets, -add and remove individual rules or state table entries, -and retrieve statistics. -The most commonly used functions are covered by -.Xr pfctl 8 . -.Pp -Manipulations like loading a ruleset that involve more than a single -ioctl call require a so-called ticket, which prevents the occurrence of -multiple concurrent manipulations. -.Pp -Fields of ioctl parameter structures that refer to packet data (like -addresses and ports) are generally expected in network byte-order. -.Sh FILES -.Bl -tag -width /dev/pf -compact -.It Pa /dev/pf -packet filtering device. -.El -.Sh IOCTL INTERFACE -pf supports the following -.Xr ioctl 2 -commands: -.Bl -tag -width xxxxxx -.It Dv DIOCSTART -Starts the packet filter. -.It Dv DIOCSTOP -Stops the packet filter. -.It Dv DIOCSTARTALTQ -Starts the ALTQ bandwidth control system. -.It Dv DIOCSTOPALTQ -Stops the ALTQ bandwidth control system. -.It Dv DIOCBEGINADDRS Fa "struct pfioc_pooladdr" -.Bd -literal -struct pfioc_pooladdr { - u_int32_t action; - u_int32_t ticket; - u_int32_t nr; - u_int32_t r_num; - u_int8_t r_action; - u_int8_t r_last; - u_int8_t af; - char anchor[PF_ANCHOR_NAME_SIZE]; - char ruleset[PF_RULESET_NAME_SIZE]; - struct pf_pooladdr addr; -}; -.Ed -.Pp -Clears the buffer address pool -and returns a -.Va ticket -for subsequent DIOCADDADDR, DIOCADDRULE and DIOCCHANGERULE calls. -.It Dv DIOCADDADDR Fa "struct pfioc_pooladdr" -.Pp -Adds pool address -.Va addr -to the buffer address pool to be used in the following -DIOCADDRULE or DIOCCHANGERULE call. -All other members of the structure are ignored. -.It Dv DIOCADDRULE Fa "struct pfioc_rule" -.Bd -literal -struct pfioc_rule { - u_int32_t action; - u_int32_t ticket; - u_int32_t pool_ticket; - u_int32_t nr; - char anchor[PF_ANCHOR_NAME_SIZE]; - char ruleset[PF_RULESET_NAME_SIZE]; - struct pf_rule rule; -}; -.Ed -.Pp -Adds -.Va rule -at the end of the inactive ruleset. -Requires -.Va ticket -obtained through preceding DIOCXBEGIN call, and -.Va pool_ticket -obtained through DIOCBEGINADDRS call. -DIOCADDADDR must also be called if any pool addresses are required. -The optional -.Va anchor -and -.Va ruleset -names indicate the anchor and ruleset in which to append the rule. -.Va nr -and -.Va action -are ignored. -.It Dv DIOCADDALTQ Fa "struct pfioc_altq" -Adds -.Bd -literal -struct pfioc_altq { - u_int32_t action; - u_int32_t ticket; - u_int32_t nr; - struct pf_altq altq; -}; -.Ed -.It Dv DIOCGETRULES Fa "struct pfioc_rule" -Returns -.Va ticket -for subsequent DIOCGETRULE calls and -.Va nr -of rules in the active ruleset. -.It Dv DIOCGETRULE Fa "struct pfioc_rule" -Returns -.Va rule -number -.Va nr -using -.Va ticket -obtained through a preceding DIOCGETRULES call. -.It Dv DIOCGETADDRS Fa "struct pfioc_pooladdr" -Returns -.Va ticket -for subsequent DIOCGETADDR calls and -.Va nr -of pool addresses in the rule specified with -.Va r_action , -.Va r_num , -.Va anchor -and -.Va ruleset . -.It Dv DIOCGETADDR Fa "struct pfioc_pooladdr" -Returns pool address -.Va addr -number -.Va nr -from the rule specified with -.Va r_action , -.Va r_num , -.Va anchor -and -.Va ruleset -using -.Va ticket -obtained through a preceding DIOCGETADDRS call. -.It Dv DIOCGETALTQS Fa "struct pfioc_altq" -Returns -.Va ticket -for subsequent DIOCGETALTQ calls and -.Va nr -of queues in the active list. -.It Dv DIOCGETALTQ Fa "struct pfioc_altq" -Returns -.Va altq -number -.Va nr -using -.Va ticket -obtained through a preceding DIOCGETALTQS call. -.It Dv DIOCGETQSTATS Fa "struct pfioc_qstats" -Returns statistics on a queue. -.Bd -literal -struct pfioc_qstats { - u_int32_t ticket; - u_int32_t nr; - void *buf; - int nbytes; - u_int8_t scheduler; -}; -.Ed -.Pp -A pointer to a buffer of statistics -.Va buf -of length -.Va nbytes -for the queue specified by -.Va nr . -.It Dv DIOCADDSTATE Fa "struct pfioc_state" -Adds a state entry. -.It Dv DIOCGETSTATE Fa "struct pfioc_state" -.Bd -literal -struct pfioc_state { - u_int32_t nr; - struct pf_state state; -}; -.Ed -.Pp -Extracts the entry with the specified number from the state table. -.It Dv DIOCKILLSTATES Fa "struct pfioc_state_kill" -Removes matching entries from the state table. -Returns the number of killed states in psk_af. -.Bd -literal -struct pfioc_state_kill { - int psk_af; - int psk_proto; - struct pf_rule_addr psk_src; - struct pf_rule_addr psk_dst; - char psk_ifname[IFNAMSIZ]; -}; -.Ed -.It Dv DIOCCLRSTATES Fa "struct pfioc_state_kill" -Clears all states. -It works like -.Dv DIOCKILLSTATES , -but ignores the psk_af, psk_proto, psk_src and psk_dst fields of the -.Fa pfioc_state_kill -structure. -.It Dv DIOCSETSTATUSIF Fa "struct pfioc_if" -.Bd -literal -struct pfioc_if { - char ifname[IFNAMSIZ]; -}; -.Ed -.Pp -Specifies the interface for which statistics are accumulated. -.It Dv DIOCGETSTATUS Fa "struct pf_status" -.Bd -literal -struct pf_status { - u_int64_t counters[PFRES_MAX]; - u_int64_t fcounters[FCNT_MAX]; - u_int64_t scounters[SCNT_MAX]; - u_int64_t pcounters[2][2][3]; - u_int64_t bcounters[2][2]; - u_int64_t stateid; - u_int32_t running; - u_int32_t states; - u_int32_t src_nodes; - u_int32_t since; - u_int32_t debug; - u_int32_t hostid; - char ifname[IFNAMSIZ]; -}; -.Ed -.Pp -Gets the internal packet filter statistics. -.It Dv DIOCCLRSTATUS -Clears the internal packet filter statistics. -.It Dv DIOCNATLOOK Fa "struct pfioc_natlook" -Looks up a state table entry by source and destination addresses and ports. -.Bd -literal -struct pfioc_natlook { - struct pf_addr saddr; - struct pf_addr daddr; - struct pf_addr rsaddr; - struct pf_addr rdaddr; - u_int16_t sport; - u_int16_t dport; - u_int16_t rsport; - u_int16_t rdport; - sa_family_t af; - u_int8_t proto; - u_int8_t direction; -}; -.Ed -.It Dv DIOCSETDEBUG Fa "u_int32_t" -Sets the debug level. -.Bd -literal -enum { PF_DEBUG_NONE=0, PF_DEBUG_URGENT=1, PF_DEBUG_MISC=2 }; -.Ed -.It Dv DIOCGETSTATES Fa "struct pfioc_states" -.Bd -literal -struct pfioc_states { - int ps_len; - union { - caddr_t psu_buf; - struct pf_state *psu_states; - } ps_u; -#define ps_buf ps_u.psu_buf -#define ps_states ps_u.psu_states -}; -.Ed -.It Dv DIOCCHANGERULE Fa "struct pfioc_rule" -Adds or removes the -.Va rule -in the ruleset specified by -.Va rule.action . -.Bd -literal -enum { PF_CHANGE_ADD_HEAD=1, PF_CHANGE_ADD_TAIL=2, - PF_CHANGE_ADD_BEFORE=3, PF_CHANGE_ADD_AFTER=4, - PF_CHANGE_REMOVE=5, PF_CHANGE_GET_TICKET=6 }; -.Ed -.Pp -The type of operation to be performed is indicated by -.Va action . -.Pp -.Va ticket -must be set to the value obtained with PF_CHANGE_GET_TICKET -for all actions except PF_CHANGE_GET_TICKET. -.Va pool_ticket -must be set to the value obtained with the DIOCBEGINADDRS call -for all actions except PF_CHANGE_REMOVE and PF_CHANGE_GET_TICKET. -.Pp -.Va anchor -and -.Va ruleset -indicate which anchor and ruleset the operation applies to. -.Va nr -indicates the rule number against which PF_CHANGE_ADD_BEFORE, -PF_CHANGE_ADD_AFTER or PF_CHANGE_REMOVE actions are applied. -.It Dv DIOCCHANGEADDR Fa "struct pfioc_pooladdr" -Adds or removes a pool address -.Va addr -from a rule specified with -.Va r_action , -.Va r_num , -.Va anchor -and -.Va ruleset . -.It Dv DIOCSETTIMEOUT Fa "struct pfioc_tm" -.Bd -literal -struct pfioc_tm { - int timeout; - int seconds; -}; -.Ed -.It Dv DIOCGETTIMEOUT Fa "struct pfioc_tm" -.It Dv DIOCCLRRULECTRS -Clear per-rule statistics. -.It Dv DIOCSETLIMIT Fa "struct pfioc_limit" -Sets hard limits on the memory pools used by the packet filter. -.Bd -literal -struct pfioc_limit { - int index; - unsigned limit; -}; -.Ed -.It Dv DIOCGETLIMIT Fa "struct pfioc_limit" -.It Dv DIOCRCLRTABLES Fa "struct pfioc_table" -Clear all tables. -All the IOCTLs that manipulate radix tables -use the same structure described below. -For -.Dv DIOCRCLRTABLES, pfrio_ndel contains on exit the number -of tables deleted. -.Bd -literal -struct pfioc_table { - struct pfr_table pfrio_table; - void *pfrio_buffer; - int pfrio_esize; - int pfrio_size; - int pfrio_size2; - int pfrio_nadd; - int pfrio_ndel; - int pfrio_nchange; - int pfrio_flags; - int pfrio_ticket; -}; -#define pfrio_exists pfrio_nadd -#define pfrio_nzero pfrio_nadd -#define pfrio_nmatch pfrio_nadd -#define pfrio_naddr pfrio_size2 -#define pfrio_setflag pfrio_size2 -#define pfrio_clrflag pfrio_nadd -.Ed -.It Dv DIOCRADDTABLES Fa "struct pfioc_table" -Creates one or more tables. -On entry, pfrio_buffer[pfrio_size] contains a table of pfr_table structures. -On exit, pfrio_nadd contains the number of tables effectively created. -.Bd -literal -struct pfr_table { - char pfrt_anchor[PF_ANCHOR_NAME_SIZE]; - char pfrt_ruleset[PF_RULESET_NAME_SIZE]; - char pfrt_name[PF_TABLE_NAME_SIZE]; - u_int32_t pfrt_flags; - u_int8_t pfrt_fback; -}; -.Ed -.It Dv DIOCRDELTABLES Fa "struct pfioc_table" -Deletes one or more tables. -On entry, pfrio_buffer[pfrio_size] contains a table of pfr_table structures. -On exit, pfrio_nadd contains the number of tables effectively deleted. -.It Dv DIOCRGETTABLES Fa "struct pfioc_table" -Get the list of all tables. -On entry, pfrio_buffer[pfrio_size] contains a valid writeable buffer for -pfr_table structures. -On exit, pfrio_size contains the number of tables written into the buffer. -If the buffer is too small, the kernel does not store anything but just -returns the required buffer size, without error. -.It Dv DIOCRGETTSTATS Fa "struct pfioc_table" -Like -.Dv DIOCRGETTABLES , -but returns an array of pfr_tstats structures. -.Bd -literal -struct pfr_tstats { - struct pfr_table pfrts_t; - u_int64_t pfrts_packets - [PFR_DIR_MAX][PFR_OP_TABLE_MAX]; - u_int64_t pfrts_bytes - [PFR_DIR_MAX][PFR_OP_TABLE_MAX]; - u_int64_t pfrts_match; - u_int64_t pfrts_nomatch; - long pfrts_tzero; - int pfrts_cnt; - int pfrts_refcnt[PFR_REFCNT_MAX]; -}; -#define pfrts_name pfrts_t.pfrt_name -#define pfrts_flags pfrts_t.pfrt_flags -.Ed -.It Dv DIOCRCLRTSTATS Fa "struct pfioc_table" -Clears the statistics of one or more tables. -On entry, pfrio_buffer[pfrio_size] contains a table of pfr_table structures. -On exit, pfrio_nzero contains the number of tables effectively cleared. -.It Dv DIOCRCLRADDRS Fa "struct pfioc_table" -Clear all addresses in a table. -On entry, pfrio_table contains the table to clear. -On exit, pfrio_ndel contains the number of addresses removed. -.It Dv DIOCRADDADDRS Fa "struct pfioc_table" -Add one or more addresses to a table. -On entry, pfrio_table contains the table id and pfrio_buffer[pfrio_size] -contains the list of pfr_addr structures to add. -On exit, pfrio_nadd contains the number of addresses effectively added. -.Bd -literal -struct pfr_addr { - union { - struct in_addr _pfra_ip4addr; - struct in6_addr _pfra_ip6addr; - } pfra_u; - u_int8_t pfra_af; - u_int8_t pfra_net; - u_int8_t pfra_not; - u_int8_t pfra_fback; -}; -#define pfra_ip4addr pfra_u._pfra_ip4addr -#define pfra_ip6addr pfra_u._pfra_ip6addr -.Ed -.It Dv DIOCRDELADDRS Fa "struct pfioc_table" -Delete one or more addresses from a table. -On entry, pfrio_table contains the table id and pfrio_buffer[pfrio_size] -contains the list of pfr_addr structures to delete. -On exit, pfrio_ndel contains the number of addresses effectively deleted. -.It Dv DIOCRSETADDRS Fa "struct pfioc_table" -Replace the content of a table by a new address list. -This is the most complicated command, which uses all the structure members. -On entry, pfrio_table contains the table id and pfrio_buffer[pfrio_size] -contains the new list of pfr_addr structures. -In addition to that, if size2 is nonzero, pfrio_buffer[pfrio_size..pfrio_size2] -must be a writeable buffer, into which the kernel can copy the addresses that -have been deleted during the replace operation. -On exit, pfrio_ndel, pfrio_nadd and pfrio_nchange contain the number of -addresses deleted, added and changed by the kernel. -If pfrio_size2 was set on -entry, pfrio_size2 will point to the size of the buffer used, exactly like -.Dv DIOCRGETADDRS . -.It Dv DIOCRGETADDRS Fa "struct pfioc_table" -Get all the addresses of a table. -On entry, pfrio_table contains the table id and pfrio_buffer[pfrio_size] -contains a valid writeable buffer for pfr_addr structures. -On exit, pfrio_size contains the number of addresses written into the buffer. -If the buffer was too small, the kernel does not store anything but just -return the required buffer size, without returning an error. -.It Dv DIOCRGETASTATS Fa "struct pfioc_table" -Like -.Dv DIOCRGETADDRS , -but returns an array of pfr_astats structures. -.Bd -literal -struct pfr_astats { - struct pfr_addr pfras_a; - u_int64_t pfras_packets - [PFR_DIR_MAX][PFR_OP_ADDR_MAX]; - u_int64_t pfras_bytes - [PFR_DIR_MAX][PFR_OP_ADDR_MAX]; - long pfras_tzero; -}; -.Ed -.It Dv DIOCRCLRASTATS Fa "struct pfioc_table" -Clears the statistics of one or more addresses. -On entry, pfrio_table contains the table id and pfrio_buffer[pfrio_size] -contains a table of pfr_addr structures to clear. -On exit, pfrio_nzero contains the number of addresses effectively cleared. -.It Dv DIOCRTSTADDRS Fa "struct pfioc_table" -Test if the given addresses match a table. -On entry, pfrio_table contains the table id and pfrio_buffer[pfrio_size] -contains a table of pfr_addr structures to test. -On exit, the kernel updates the pfr_addr table by setting the pfra_fback -member appropriately. -.It Dv DIOCRSETTFLAGS Fa "struct pfioc_table" -Change the -.Va const -or -.Va persist -flag of a table. -On entry, pfrio_buffer[pfrio_size] contains a table of pfr_table structures, -and pfrio_setflag contains the flags to add, while pfrio_clrflag contains the -flags to remove. -On exit, pfrio_nchange and pfrio_ndel contain the number of tables altered -or deleted by the kernel. -Yes, tables can be deleted if one removes the -.Va persist -flag of an unreferenced table. -.It Dv DIOCRINADEFINE Fa "struct pfioc_table" -Defines a table in the inactive set. -On entry, pfrio_table contains the table id and pfrio_buffer[pfrio_size] -contains the list of pfr_addr structures to put in the table. -A valid ticket must also be supplied to pfrio_ticket. -On exit, pfrio_nadd contains 0 if the table was already defined in the -inactive list, or 1 if a new table has been created. -pfrio_naddr contains the number of addresses effectively put in the table. -.It Dv DIOCXBEGIN Fa "struct pfioc_trans" -.Bd -literal -#define PF_RULESET_ALTQ (PF_RULESET_MAX) -#define PF_RULESET_TABLE (PF_RULESET_MAX+1) -struct pfioc_trans { - int size; /* number of elements */ - int esize; /* size of each element in bytes */ - struct pfioc_trans_e { - int rs_num; - char anchor[PF_ANCHOR_NAME_SIZE]; - char ruleset[PF_RULESET_NAME_SIZE]; - u_int32_t ticket; - } *array; -}; -.Ed -.Pp -Clears all the inactive rulesets specified in the -.Fa "struct pfioc_trans_e" -array. -For each ruleset, a ticket is returned for subsequent "add rule" IOCTLs, -as well as for the -.Dv DIOCXCOMMIT -and -.Dv DIOCXROLLBACK -calls. -.It Dv DIOCXCOMMIT Fa "struct pfioc_trans" -Atomically switch a vector of inactive rulesets to the active rulesets. -Implemented as a standard 2-phase commit, which will either fail for all -rulesets or completely succeed. -All tickets need to be valid. -Returns -.Dv EBUSY -if a concurrent process is trying to update some of the same rulesets -concurrently. -.It Dv DIOCXROLLBACK Fa "struct pfioc_trans" -Clean up the kernel by undoing all changes that have taken place on the -inactive rulesets since the last -.Dv DIOCXBEGIN . -.Dv DIOCXROLLBACK -will silently ignore rulesets for which the ticket is invalid. -.It Dv DIOCFPFLUSH -Flush the passive OS fingerprint table. -.It Dv DIOCFPADD Fa "struct pf_osfp_ioctl" -.Bd -literal -struct pf_osfp_ioctl { - struct pf_osfp_entry { - SLIST_ENTRY(pf_osfp_entry) fp_entry; - pf_osfp_t fp_os; - char fp_class_nm[PF_OSFP_LEN]; - char fp_version_nm[PF_OSFP_LEN]; - char fp_subtype_nm[PF_OSFP_LEN]; - } fp_os; - u_int16_t fp_mss; - u_int16_t fp_wsize; - u_int16_t fp_psize; - u_int8_t fp_ttl; - u_int8_t fp_wscale; - u_int8_t fp_flags; - int fp_getnum; -}; -.Ed -.Pp -Add a passive OS fingerprint to the table. -Set -.Va fp_os.fp_os -to the packed fingerprint, -.Va fp_os.fp_class_nm -to the name of the class (Linux, Windows, etc), -.Va fp_os.fp_version_nm -to the name of the version (NT, 95, 98), and -.Va fp_os.fp_subtype_nm -to the name of the subtype or patchlevel. -The members -.Va fp_mss , -.Va fp_wsize , -.Va fp_psize , -.Va fp_ttl , -and -.Va fp_wscale -are set to the TCP MSS, the TCP window size, the IP length and the IP TTL of -the TCP SYN packet respectively. -The -.Va fp_flags -member is filled according to the net/pfvar.h include file PF_OSFP_* defines. -The -.Va fp_getnum -is not used with this ioctl. -.Pp -The structure's slack space must be zeroed for correct operation; memset -the whole structure to zero before filling and sending to the kernel. -.It Dv DIOCFPGET Fa "struct pf_osfp_ioctl" -.Bd -literal -struct pf_osfp_ioctl { - struct pf_osfp_entry { - SLIST_ENTRY(pf_osfp_entry) fp_entry; - pf_osfp_t fp_os; - char fp_class_nm[PF_OSFP_LEN]; - char fp_version_nm[PF_OSFP_LEN]; - char fp_subtype_nm[PF_OSFP_LEN]; - } fp_os; - u_int16_t fp_mss; - u_int16_t fp_wsize; - u_int16_t fp_psize; - u_int8_t fp_ttl; - u_int8_t fp_wscale; - u_int8_t fp_flags; - int fp_getnum; -}; -.Ed -.Pp -Get the passive OS fingerprint number -.Va fp_getnum -from the kernel's fingerprint list. -The rest of the structure members will come back filled. -Get the whole list by repeatedly incrementing the -.Va fp_getnum -number until the ioctl returns EBUSY. -.It Dv DIOCGETSRCNODES Fa "struct pfioc_src_nodes" -.Bd -literal -struct pfioc_src_nodes { - int psn_len; - union { - caddr_t psu_buf; - struct pf_src_node *psu_src_nodes; - } psn_u; -#define psn_buf psn_u.psu_buf -#define psn_src_nodes psn_u.psu_src_nodes -}; -.Ed -.Pp -Get the list of source nodes kept by the -.Ar sticky-address -and -.Ar source-track -options. -The ioctl must be called once with -.Va psn_len -set to 0. -If the ioctl returns without error, -.Va psn_len -will be set to the size of the buffer required to hold all the -.Va pf_src_node -structures held in the table. -A buffer of this size should then be allocated, and a pointer to this buffer -placed in -.Va psn_buf . -The ioctl must then be called again to fill this buffer with the actual -source node data. -After the ioctl call -.Va psn_len -will be set to the length of the buffer actually used. -.It Dv DIOCCLRSRCNODES Fa "struct pfioc_table" -Clear the tree of source tracking nodes. -.It Dv DIOCIGETIFACES Fa "struct pfioc_iface" -Gets the list of interfaces and interface drivers known to -.Nm . -All the IOCTLs that manipulate interfaces -use the same structure described below: -.Bd -literal -struct pfioc_iface { - char pfiio_name[IFNAMSIZ]; - void *pfiio_buffer; - int pfiio_esize; - int pfiio_size; - int pfiio_nzero; - int pfiio_flags; -}; - -#define PFI_FLAG_GROUP 0x0001 /* gets groups of interfaces */ -#define PFI_FLAG_INSTANCE 0x0002 /* gets single interfaces */ -#define PFI_FLAG_ALLMASK 0x0003 -.Ed -.Pp -If not empty, -.Va pfiio_name -can be used to restrict the search to a specific interface or driver. -.Va pfiio_buffer[pfiio_size] -is the user-supplied buffer for returning the data. -On entry, -.Va pfiio_size -represents the number of -.Va pfi_if -entries that can fit into the buffer. -The kernel will replace this value by the real number of entries it wants -to return. -.Va pfiio_esize -should be set to sizeof(struct pfi_if). -.Va pfiio_flags -should be set to -.Dv PFI_FLAG_GROUP , PFI_FLAG_INSTANCE , -or both to tell the kernel to return a group of interfaces -(drivers, like "fxp"), real interface instances (like "fxp1") or both. -The data is returned in the -.Va pfi_if -structure described below: -.Bd -literal -struct pfi_if { - char pfif_name[IFNAMSIZ]; - u_int64_t pfif_packets[2][2][2]; - u_int64_t pfif_bytes[2][2][2]; - u_int64_t pfif_addcnt; - u_int64_t pfif_delcnt; - long pfif_tzero; - int pfif_states; - int pfif_rules; - int pfif_flags; -}; - -#define PFI_IFLAG_GROUP 0x0001 /* group of interfaces */ -#define PFI_IFLAG_INSTANCE 0x0002 /* single instance */ -#define PFI_IFLAG_CLONABLE 0x0010 /* clonable group */ -#define PFI_IFLAG_DYNAMIC 0x0020 /* dynamic group */ -#define PFI_IFLAG_ATTACHED 0x0040 /* interface attached */ -#define PFI_IFLAG_REFERENCED 0x0080 /* referenced by rules */ -.Ed -.It Dv DIOCICLRISTATS Fa "struct pfioc_iface" -Clear the statistics counters of one or more interfaces. -.Va pfiio_name -and -.Va pfrio_flags -can be used to select which interfaces need to be cleared. -The filtering process is the same as for -.Dv DIOCIGETIFACES . -.Va pfiio_nzero -will be set by the kernel to the number of interfaces and drivers -that have been cleared. -.El -.Sh EXAMPLES -The following example demonstrates how to use the DIOCNATLOOK command -to find the internal host/port of a NATed connection. -.Bd -literal -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <sys/fcntl.h> -#include <net/if.h> -#include <netinet/in.h> -#include <net/pfvar.h> -#include <err.h> -#include <stdio.h> -#include <stdlib.h> - -u_int32_t -read_address(const char *s) -{ - int a, b, c, d; - - sscanf(s, "%i.%i.%i.%i", &a, &b, &c, &d); - return htonl(a << 24 | b << 16 | c << 8 | d); -} - -void -print_address(u_int32_t a) -{ - a = ntohl(a); - printf("%d.%d.%d.%d", a >> 24 & 255, a >> 16 & 255, - a >> 8 & 255, a & 255); -} - -int -main(int argc, char *argv[]) -{ - struct pfioc_natlook nl; - int dev; - - if (argc != 5) { - printf("%s <gwy addr> <gwy port> <ext addr> <ext port>\\n", - argv[0]); - return 1; - } - - dev = open("/dev/pf", O_RDWR); - if (dev == -1) - err(1, "open(\\"/dev/pf\\") failed"); - - memset(&nl, 0, sizeof(struct pfioc_natlook)); - nl.saddr.v4.s_addr = read_address(argv[1]); - nl.sport = htons(atoi(argv[2])); - nl.daddr.v4.s_addr = read_address(argv[3]); - nl.dport = htons(atoi(argv[4])); - nl.af = AF_INET; - nl.proto = IPPROTO_TCP; - nl.direction = PF_IN; - - if (ioctl(dev, DIOCNATLOOK, &nl)) - err(1, "DIOCNATLOOK"); - - printf("internal host "); - print_address(nl.rsaddr.v4.s_addr); - printf(":%u\\n", ntohs(nl.rsport)); - return 0; -} -.Ed -.Sh SEE ALSO -.Xr ioctl 2 , -.Xr bridge 4 , -.Xr pflog 4 , -.Xr pfsync 4 , -.Xr pfctl 8 -.Sh HISTORY -The -.Nm -packet filtering mechanism first appeared in -.Ox 3.0 . diff --git a/contrib/pf/man/pf.conf.5 b/contrib/pf/man/pf.conf.5 deleted file mode 100644 index b5db41295518..000000000000 --- a/contrib/pf/man/pf.conf.5 +++ /dev/null @@ -1,2632 +0,0 @@ -.\" $OpenBSD: pf.conf.5,v 1.292 2004/02/24 05:44:48 mcbride Exp $ -.\" -.\" Copyright (c) 2002, Daniel Hartmeier -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" -.\" - Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" - Redistributions in binary form must reproduce the above -.\" copyright notice, this list of conditions and the following -.\" disclaimer in the documentation and/or other materials provided -.\" with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -.\" POSSIBILITY OF SUCH DAMAGE. -.\" -.Dd November 19, 2002 -.Dt PF.CONF 5 -.Os -.Sh NAME -.Nm pf.conf -.Nd packet filter configuration file -.Sh DESCRIPTION -The -.Xr pf 4 -packet filter modifies, drops or passes packets according to rules or -definitions specified in -.Nm pf.conf . -.Sh STATEMENT ORDER -There are seven types of statements in -.Nm pf.conf : -.Bl -tag -width xxxx -.It Cm Macros -User-defined variables may be defined and used later, simplifying -the configuration file. -Macros must be defined before they are referenced in -.Nm pf.conf . -.It Cm Tables -Tables provide a mechanism for increasing the performance and flexibility of -rules with large numbers of source or destination addresses. -.It Cm Options -Options tune the behaviour of the packet filtering engine. -.It Cm Traffic Normalization Li (e.g. Em scrub ) -Traffic normalization protects internal machines against inconsistencies -in Internet protocols and implementations. -.It Cm Queueing -Queueing provides rule-based bandwidth control. -.It Cm Translation Li (Various forms of NAT) -Translation rules specify how addresses are to be mapped or redirected to -other addresses. -.It Cm Packet Filtering -Stateful and stateless packet filtering provides rule-based blocking or -passing of packets. -.El -.Pp -With the exception of -.Cm macros -and -.Cm tables , -the types of statements should be grouped and appear in -.Nm pf.conf -in the order shown above, as this matches the operation of the underlying -packet filtering engine. -By default -.Xr pfctl 8 -enforces this order (see -.Ar set require-order -below). -.Sh MACROS -Much like -.Xr cpp 1 -or -.Xr m4 1 , -macros can be defined that will later be expanded in context. -Macro names must start with a letter, and may contain letters, digits -and underscores. -Macro names may not be reserved words (for example -.Ar pass , -.Ar in , -.Ar out ) . -Macros are not expanded inside quotes. -.Pp -For example, -.Bd -literal -offset indent -ext_if = \&"kue0\&" -all_ifs = \&"{\&" $ext_if lo0 \&"}\&" -pass out on $ext_if from any to any keep state -pass in on $ext_if proto tcp from any to any port 25 keep state -.Ed -.Sh TABLES -Tables are named structures which can hold a collection of addresses and -networks. -Lookups against tables in -.Xr pf 4 -are relatively fast, making a single rule with tables much more efficient, -in terms of -processor usage and memory consumption, than a large number of rules which -differ only in IP address (either created explicitly or automatically by rule -expansion). -.Pp -Tables can be used as the source or destination of filter rules, -.Ar scrub -rules -or -translation rules such as -.Ar nat -or -.Ar rdr -(see below for details on the various rule types). -Tables can also be used for the redirect address of -.Ar nat -and -.Ar rdr -rules and in the routing options of filter rules, but only for -.Ar round-robin -pools. -.Pp -Tables can be defined with any of the following -.Xr pfctl 8 -mechanisms. -As with macros, reserved words may not be used as table names. -.Bl -tag -width "manually" -.It Ar manually -Persistent tables can be manually created with the -.Ar add -or -.Ar replace -option of -.Xr pfctl 8 , -before or after the ruleset has been loaded. -.It Pa pf.conf -Table definitions can be placed directly in this file, and loaded at the -same time as other rules are loaded, atomically. -Table definitions inside -.Nm pf.conf -use the -.Ar table -statement, and are especially useful to define non-persistent tables. -The contents of a pre-existing table defined without a list of addresses -to initialize it is not altered when -.Nm pf.conf -is loaded. -A table initialized with the empty list, -.Li { } , -will be cleared on load. -.El -.Pp -Tables may be defined with the following two attributes: -.Bl -tag -width persist -.It Ar persist -The -.Ar persist -flag forces the kernel to keep the table even when no rules refer to it. -If the flag is not set, the kernel will automatically remove the table -when the last rule referring to it is flushed. -.It Ar const -The -.Ar const -flag prevents the user from altering the contents of the table once it -has been created. -Without that flag, -.Xr pfctl 8 -can be used to add or remove addresses from the table at any time, even -when running with -.Xr securelevel 7 -= 2. -.El -.Pp -For example, -.Bd -literal -offset indent -table <private> const { 10/8, 172.16/12, 192.168/16 } -table <badhosts> persist -block on fxp0 from { <private>, <badhosts> } to any -.Ed -.Pp -creates a table called private, to hold RFC 1918 private network -blocks, and a table called badhosts, which is initially empty. -A filter rule is set up to block all traffic coming from addresses listed in -either table. -The private table cannot have its contents changed and the badhosts table -will exist even when no active filter rules reference it. -Addresses may later be added to the badhosts table, so that traffic from -these hosts can be blocked by using -.Bd -literal -offset indent -# pfctl -t badhosts -Tadd 204.92.77.111 -.Ed -.Pp -A table can also be initialized with an address list specified in one or more -external files, using the following syntax: -.Bd -literal -offset indent -table <spam> persist file \&"/etc/spammers\&" file \&"/etc/openrelays\&" -block on fxp0 from <spam> to any -.Ed -.Pp -The files -.Pa /etc/spammers -and -.Pa /etc/openrelays -list IP addresses, one per line. -Any lines beginning with a # are treated as comments and ignored. -In addition to being specified by IP address, hosts may also be -specified by their hostname. -When the resolver is called to add a hostname to a table, -.Em all -resulting IPv4 and IPv6 addresses are placed into the table. -IP addresses can also be entered in a table by specifying a valid interface -name or the -.Em self -keyword, in which case all addresses assigned to the interface(s) will be -added to the table. -.Sh OPTIONS -.Xr pf 4 -may be tuned for various situations using the -.Ar set -command. -.Bl -tag -width xxxx -.It Ar set timeout -.Pp -.Bl -tag -width interval -compact -.It Ar interval -Interval between purging expired states and fragments. -.It Ar frag -Seconds before an unassembled fragment is expired. -.It Ar src.track -Length of time to retain a source tracking entry after the last state -expires. -.El -.Pp -When a packet matches a stateful connection, the seconds to live for the -connection will be updated to that of the -.Ar proto.modifier -which corresponds to the connection state. -Each packet which matches this state will reset the TTL. -Tuning these values may improve the performance of the -firewall at the risk of dropping valid idle connections. -.Pp -.Bl -tag -width xxxx -compact -.It Ar tcp.first -The state after the first packet. -.It Ar tcp.opening -The state before the destination host ever sends a packet. -.It Ar tcp.established -The fully established state. -.It Ar tcp.closing -The state after the first FIN has been sent. -.It Ar tcp.finwait -The state after both FINs have been exchanged and the connection is closed. -Some hosts (notably web servers on Solaris) send TCP packets even after closing -the connection. -Increasing -.Ar tcp.finwait -(and possibly -.Ar tcp.closing ) -can prevent blocking of such packets. -.It Ar tcp.closed -The state after one endpoint sends an RST. -.El -.Pp -ICMP and UDP are handled in a fashion similar to TCP, but with a much more -limited set of states: -.Pp -.Bl -tag -width xxxx -compact -.It Ar udp.first -The state after the first packet. -.It Ar udp.single -The state if the source host sends more than one packet but the destination -host has never sent one back. -.It Ar udp.multiple -The state if both hosts have sent packets. -.It Ar icmp.first -The state after the first packet. -.It Ar icmp.error -The state after an ICMP error came back in response to an ICMP packet. -.El -.Pp -Other protocols are handled similarly to UDP: -.Pp -.Bl -tag -width xxxx -compact -.It Ar other.first -.It Ar other.single -.It Ar other.multiple -.El -.Pp -Timeout values can be reduced adaptively as the number of state table -entries grows. -.Pp -.Bl -tag -width xxxx -compact -.It Ar adaptive.start -When the number of state entries exceeds this value, adaptive scaling -begins. -All timeout values are scaled linearly with factor -(adaptive.end - number of states) / (adaptive.end - adaptive.start). -.It Ar adaptive.end -When reaching this number of state entries, all timeout values become -zero, effectively purging all state entries immediately. -This value is used to define the scale factor, it should not actually -be reached (set a lower state limit, see below). -.El -.Pp -These values can be defined both globally and for each rule. -When used on a per-rule basis, the values relate to the number of -states created by the rule, otherwise to the total number of -states. -.Pp -For example: -.Bd -literal -offset indent -set timeout tcp.first 120 -set timeout tcp.established 86400 -set timeout { adaptive.start 6000, adaptive.end 12000 } -set limit states 10000 -.Ed -.Pp -With 9000 state table entries, the timeout values are scaled to 50% -(tcp.first 60, tcp.established 43200). -.Pp -.It Ar set loginterface -Enable collection of packet and byte count statistics for the given interface. -These statistics can be viewed using -.Bd -literal -offset indent -# pfctl -s info -.Ed -.Pp -In this example -.Xr pf 4 -collects statistics on the interface named dc0: -.Bd -literal -offset indent -set loginterface dc0 -.Ed -.Pp -One can disable the loginterface using: -.Bd -literal -offset indent -set loginterface none -.Ed -.Pp -.It Ar set limit -Sets hard limits on the memory pools used by the packet filter. -See -.Xr pool 9 -for an explanation of memory pools. -.Pp -For example, -.Bd -literal -offset indent -set limit states 20000 -.Ed -.Pp -sets the maximum number of entries in the memory pool used by state table -entries (generated by -.Ar keep state -rules) to 20000. -Using -.Bd -literal -offset indent -set limit frags 20000 -.Ed -.Pp -sets the maximum number of entries in the memory pool used for fragment -reassembly (generated by -.Ar scrub -rules) to 20000. -Finally, -.Bd -literal -offset indent -set limit src-nodes 2000 -.Ed -.Pp -sets the maximum number of entries in the memory pool used for tracking -source IP addresses (generated by the -.Ar sticky-address -and -.Ar source-track -options) to 2000. -.Pp -These can be combined: -.Bd -literal -offset indent -set limit { states 20000, frags 20000, src-nodes 2000 } -.Ed -.Pp -.It Ar set optimization -Optimize the engine for one of the following network environments: -.Pp -.Bl -tag -width xxxx -compact -.It Ar normal -A normal network environment. -Suitable for almost all networks. -.It Ar high-latency -A high-latency environment (such as a satellite connection). -.It Ar satellite -Alias for -.Ar high-latency . -.It Ar aggressive -Aggressively expire connections. -This can greatly reduce the memory usage of the firewall at the cost of -dropping idle connections early. -.It Ar conservative -Extremely conservative settings. -Avoid dropping legitimate connections at the -expense of greater memory utilization (possibly much greater on a busy -network) and slightly increased processor utilization. -.El -.Pp -For example: -.Bd -literal -offset indent -set optimization aggressive -.Ed -.Pp -.It Ar set block-policy -The -.Ar block-policy -option sets the default behaviour for the packet -.Ar block -action: -.Pp -.Bl -tag -width xxxxxxxx -compact -.It Ar drop -Packet is silently dropped. -.It Ar return -A TCP RST is returned for blocked TCP packets, -an ICMP UNREACHABLE is returned for blocked UDP packets, -and all other packets are silently dropped. -.El -.Pp -For example: -.Bd -literal -offset indent -set block-policy return -.Ed -.It Ar set state-policy -The -.Ar state-policy -option sets the default behaviour for states: -.Pp -.Bl -tag -width group-bound -compact -.It Ar if-bound -States are bound to interface. -.It Ar group-bound -States are bound to interface group (i.e. ppp) -.It Ar floating -States can match packets on any interfaces (the default). -.El -.Pp -For example: -.Bd -literal -offset indent -set state-policy if-bound -.Ed -.It Ar set require-order -By default -.Xr pfctl 8 -enforces an ordering of the statement types in the ruleset to: -.Em options , -.Em normalization , -.Em queueing , -.Em translation , -.Em filtering . -Setting this option to -.Ar no -disables this enforcement. -There may be non-trivial and non-obvious implications to an out of -order ruleset. -Consider carefully before disabling the order enforcement. -.It Ar set fingerprints -Load fingerprints of known operating systems from the given filename. -By default fingerprints of known operating systems are automatically -loaded from -.Xr pf.os 5 -in -.Pa /etc -but can be overridden via this option. -Setting this option may leave a small period of time where the fingerprints -referenced by the currently active ruleset are inconsistent until the new -ruleset finishes loading. -.Pp -For example: -.Pp -.Dl set fingerprints \&"/etc/pf.os.devel\&" -.Pp -.It Ar set debug -Set the debug -.Ar level -to one of the following: -.Pp -.Bl -tag -width xxxxxxxxxxxx -compact -.It Ar none -Don't generate debug messages. -.It Ar urgent -Generate debug messages only for serious errors. -.It Ar misc -Generate debug messages for various errors. -.It Ar loud -Generate debug messages for common conditions. -.El -.El -.Sh TRAFFIC NORMALIZATION -Traffic normalization is used to sanitize packet content in such -a way that there are no ambiguities in packet interpretation on -the receiving side. -The normalizer does IP fragment reassembly to prevent attacks -that confuse intrusion detection systems by sending overlapping -IP fragments. -Packet normalization is invoked with the -.Ar scrub -directive. -.Pp -.Ar scrub -has the following options: -.Bl -tag -width xxxx -.It Ar no-df -Clears the -.Ar dont-fragment -bit from a matching IP packet. -Some operating systems are known to generate fragmented packets with the -.Ar dont-fragment -bit set. -This is particularly true with NFS. -.Ar Scrub -will drop such fragmented -.Ar dont-fragment -packets unless -.Ar no-df -is specified. -.Pp -Unfortunately some operating systems also generate their -.Ar dont-fragment -packets with a zero IP identification field. -Clearing the -.Ar dont-fragment -bit on packets with a zero IP ID may cause deleterious results if an -upstream router later fragments the packet. -Using the -.Ar random-id -modifier (see below) is recommended in combination with the -.Ar no-df -modifier to ensure unique IP identifiers. -.It Ar min-ttl <number> -Enforces a minimum TTL for matching IP packets. -.It Ar max-mss <number> -Enforces a maximum MSS for matching TCP packets. -.It Ar random-id -Replaces the IP identification field with random values to compensate -for predictable values generated by many hosts. -This option only applies to outgoing packets that are not fragmented -after the optional fragment reassembly. -.It Ar fragment reassemble -Using -.Ar scrub -rules, fragments can be reassembled by normalization. -In this case, fragments are buffered until they form a complete -packet, and only the completed packet is passed on to the filter. -The advantage is that filter rules have to deal only with complete -packets, and can ignore fragments. -The drawback of caching fragments is the additional memory cost. -But the full reassembly method is the only method that currently works -with NAT. -This is the default behavior of a -.Ar scrub -rule if no fragmentation modifier is supplied. -.It Ar fragment crop -The default fragment reassembly method is expensive, hence the option -to crop is provided. -In this case, -.Xr pf 4 -will track the fragments and cache a small range descriptor. -Duplicate fragments are dropped and overlaps are cropped. -Thus data will only occur once on the wire with ambiguities resolving to -the first occurrence. -Unlike the -.Ar fragment reassemble -modifier, fragments are not buffered, they are passed as soon as they -are received. -The -.Ar fragment crop -reassembly mechanism does not yet work with NAT. -.Pp -.It Ar fragment drop-ovl -This option is similar to the -.Ar fragment crop -modifier except that all overlapping or duplicate fragments will be -dropped, and all further corresponding fragments will be -dropped as well. -.It Ar reassemble tcp -Statefully normalizes TCP connections. -.Ar scrub reassemble tcp -rules may not have the direction (in/out) specified. -.Ar reassemble tcp -performs the following normalizations: -.Pp -.Bl -tag -width timeout -compact -.It ttl -Neither side of the connection is allowed to reduce their IP TTL. -An attacker may send a packet such that it reaches the firewall, affects -the firewall state, and expires before reaching the destination host. -.Ar reassemble tcp -will raise the TTL of all packets back up to the highest value seen on -the connection. -.It timeout modulation -Modern TCP stacks will send a timestamp on every TCP packet and echo -the other endpoint's timestamp back to them. -Many operating systems will merely start the timestamp at zero when -first booted, and increment it several times a second. -The uptime of the host can be deduced by reading the timestamp and multiplying -by a constant. -Also observing several different timestamps can be used to count hosts -behind a NAT device. -And spoofing TCP packets into a connection requires knowing or guessing -valid timestamps. -Timestamps merely need to be monotonically increasing and not derived off a -guessable base time. -.Ar reassemble tcp -will cause -.Ar scrub -to modulate the TCP timestamps with a random number. -.El -.El -.Pp -For example, -.Bd -literal -offset indent -scrub in on $ext_if all fragment reassemble -.Ed -.Sh QUEUEING -Packets can be assigned to queues for the purpose of bandwidth -control. -At least two declarations are required to configure queues, and later -any packet filtering rule can reference the defined queues by name. -During the filtering component of -.Nm pf.conf , -the last referenced -.Ar queue -name is where any packets from -.Ar pass -rules will be queued, while for -.Ar block -rules it specifies where any resulting ICMP or TCP RST -packets should be queued. -The -.Ar scheduler -defines the algorithm used to decide which packets get delayed, dropped, or -sent out immediately. -There are three -.Ar schedulers -currently supported. -.Bl -tag -width xxxx -.It Ar cbq -Class Based Queueing. -.Ar Queues -attached to an interface build a tree, thus each -.Ar queue -can have further child -.Ar queues . -Each queue can have a -.Ar priority -and a -.Ar bandwidth -assigned. -.Ar Priority -mainly controls the time packets take to get sent out, while -.Ar bandwidth -has primarily effects on throughput. -.It Ar priq -Priority Queueing. -.Ar Queues -are flat attached to the interface, thus, -.Ar queues -cannot have further child -.Ar queues . -Each -.Ar queue -has a unique -.Ar priority -assigned, ranging from 0 to 15. -Packets in the -.Ar queue -with the highest -.Ar priority -are processed first. -.It Ar hfsc -Hierarchical Fair Service Curve. -.Ar Queues -attached to an interface build a tree, thus each -.Ar queue -can have further child -.Ar queues . -Each queue can have a -.Ar priority -and a -.Ar bandwidth -assigned. -.Ar Priority -mainly controls the time packets take to get sent out, while -.Ar bandwidth -has primarily effects on throughput. -.El -.Pp -The interfaces on which queueing should be activated are declared using -the -.Ar altq on -declaration. -.Ar altq on -has the following keywords: -.Bl -tag -width xxxx -.It Ar <interface> -Queueing is enabled on the named interface. -.It Ar <scheduler> -Specifies which queueing scheduler to use. -Currently supported values -are -.Ar cbq -for Class Based Queueing, -.Ar priq -for Priority Queueing and -.Ar hfsc -for the Hierarchical Fair Service Curve scheduler. -.It Ar bandwidth <bw> -The maximum bitrate for all queues on an -interface may be specified using the -.Ar bandwidth -keyword. -The value can be specified as an absolute value or as a -percentage of the interface bandwidth. -When using an absolute value, the suffixes -.Ar b , -.Ar Kb , -.Ar Mb , -and -.Ar Gb -are used to represent bits, kilobits, megabits, and -gigabits per second, respectively. -The value must not exceed the interface bandwidth. -If -.Ar bandwidth -is not specified, the interface bandwidth is used. -.It Ar qlimit <limit> -The maximum number of packets held in the queue. -The default is 50. -.It Ar tbrsize <size> -Adjusts the size, in bytes, of the token bucket regulator. -If not specified, heuristics based on the -interface bandwidth are used to determine the size. -.It Ar queue <list> -Defines a list of subqueues to create on an interface. -.El -.Pp -In the following example, the interface dc0 -should queue up to 5 Mbit/s in four second-level queues using -Class Based Queueing. -Those four queues will be shown in a later example. -.Bd -literal -offset indent -altq on dc0 cbq bandwidth 5Mb queue { std, http, mail, ssh } -.Ed -.Pp -Once interfaces are activated for queueing using the -.Ar altq -directive, a sequence of -.Ar queue -directives may be defined. -The name associated with a -.Ar queue -must match a queue defined in the -.Ar altq -directive (e.g. mail), or, except for the -.Ar priq -.Ar scheduler , -in a parent -.Ar queue -declaration. -The following keywords can be used: -.Bl -tag -width xxxx -.It Ar on <interface> -Specifies the interface the queue operates on. -If not given, it operates on all matching interfaces. -.It Ar bandwidth <bw> -Specifies the maximum bitrate to be processed by the queue. -This value must not exceed the value of the parent -.Ar queue -and can be specified as an absolute value or a percentage of the parent -queue's bandwidth. -The -.Ar priq -scheduler does not support bandwidth specification. -.It Ar priority <level> -Between queues a priority level can be set. -For -.Ar cbq -and -.Ar hfsc , -the range is 0 to 7 and for -.Ar priq , -the range is 0 to 15. -The default for all is 1. -.Ar Priq -queues with a higher priority are always served first. -.Ar Cbq -and -.Ar Hfsc -queues with a higher priority are preferred in the case of overload. -.It Ar qlimit <limit> -The maximum number of packets held in the queue. -The default is 50. -.El -.Pp -The -.Ar scheduler -can get additional parameters with -.Ar <scheduler> Ns Li (\& Ar <parameters> No ) . -Parameters are as follows: -.Bl -tag -width Fl -.It Ar default -Packets not matched by another queue are assigned to this one. -Exactly one default queue is required. -.It Ar red -Enable RED (Random Early Detection) on this queue. -RED drops packets with a probability proportional to the average -queue length. -.It Ar rio -Enables RIO on this queue. -RIO is RED with IN/OUT, thus running -RED two times more than RIO would achieve the same effect. -RIO is currently not supported in the GENERIC kernel. -.It Ar ecn -Enables ECN (Explicit Congestion Notification) on this queue. -ECN implies RED. -.El -.Pp -The -.Ar cbq -.Ar scheduler -supports an additional option: -.Bl -tag -width Fl -.It Ar borrow -The queue can borrow bandwidth from the parent. -.El -.Pp -The -.Ar hfsc -.Ar scheduler -supports some additional options: -.Bl -tag -width Fl -.It Ar realtime <sc> -The minimum required bandwidth for the queue. -.It Ar upperlimit <sc> -The maximum allowed bandwidth for the queue. -.It Ar linkshare <sc> -The bandwidth share of a backlogged queue. -.El -.Pp -<sc> is an acronym for -.Ar service curve . -.Pp -The format for service curve specifications is -.Ar ( m1 , d , m2 ) . -.Ar m2 -controls the bandwidth assigned to the queue. -.Ar m1 -and -.Ar d -are optional and can be used to control the initial bandwidth assignment. -For the first -.Ar d -milliseconds the queue gets the bandwidth given as -.Ar m1 , -afterwards the value given in -.Ar m2 . -.Pp -Furthermore, with -.Ar cbq -and -.Ar hfsc , -child queues can be specified as in an -.Ar altq -declaration, thus building a tree of queues using a part of -their parent's bandwidth. -.Pp -Packets can be assigned to queues based on filter rules by using the -.Ar queue -keyword. -Normally only one -.Ar queue -is specified; when a second one is specified it will instead be used for -packets which have a -.Em TOS -of -.Em lowdelay -and for TCP ACKs with no data payload. -.Pp -To continue the previous example, the examples below would specify the -four referenced -queues, plus a few child queues. -Interactive -.Xr ssh 1 -sessions get priority over bulk transfers like -.Xr scp 1 -and -.Xr sftp 1 . -The queues may then be referenced by filtering rules (see -.Sx PACKET FILTERING -below). -.Bd -literal -queue std bandwidth 10% cbq(default) -queue http bandwidth 60% priority 2 cbq(borrow red) \e - { employees, developers } -queue developers bandwidth 75% cbq(borrow) -queue employees bandwidth 15% -queue mail bandwidth 10% priority 0 cbq(borrow ecn) -queue ssh bandwidth 20% cbq(borrow) { ssh_interactive, ssh_bulk } -queue ssh_interactive priority 7 -queue ssh_bulk priority 0 - -block return out on dc0 inet all queue std -pass out on dc0 inet proto tcp from $developerhosts to any port 80 \e - keep state queue developers -pass out on dc0 inet proto tcp from $employeehosts to any port 80 \e - keep state queue employees -pass out on dc0 inet proto tcp from any to any port 22 \e - keep state queue(ssh_bulk, ssh_interactive) -pass out on dc0 inet proto tcp from any to any port 25 \e - keep state queue mail -.Ed -.Sh TRANSLATION -Translation rules modify either the source or destination address of the -packets associated with a stateful connection. -A stateful connection is automatically created to track packets matching -such a rule as long as they are not blocked by the filtering section of -.Nm pf.conf . -The translation engine modifies the specified address and/or port in the -packet, recalculates IP, TCP and UDP checksums as necessary, and passes it to -the packet filter for evaluation. -.Pp -Since translation occurs before filtering the filter -engine will see packets as they look after any -addresses and ports have been translated. Filter rules -will therefore have to filter based on the translated -address and port number. -Packets that match a translation rule are only automatically passed if -the -.Ar pass -modifier is given, otherwise they are -still subject to -.Ar block -and -.Ar pass -rules. -.Pp -The state entry created permits -.Xr pf 4 -to keep track of the original address for traffic associated with that state -and correctly direct return traffic for that connection. -.Pp -Various types of translation are possible with pf: -.Bl -tag -width xxxx -.It Ar binat -A -.Ar binat -rule specifies a bidirectional mapping between an external IP netblock -and an internal IP netblock. -.It Ar nat -A -.Ar nat -rule specifies that IP addresses are to be changed as the packet -traverses the given interface. -This technique allows one or more IP addresses -on the translating host to support network traffic for a larger range of -machines on an "inside" network. -Although in theory any IP address can be used on the inside, it is strongly -recommended that one of the address ranges defined by RFC 1918 be used. -These netblocks are: -.Bd -literal -10.0.0.0 - 10.255.255.255 (all of net 10, i.e., 10/8) -172.16.0.0 - 172.31.255.255 (i.e., 172.16/12) -192.168.0.0 - 192.168.255.255 (i.e., 192.168/16) -.Ed -.It Pa rdr -The packet is redirected to another destination and possibly a -different port. -.Ar rdr -rules can optionally specify port ranges instead of single ports. -rdr ... port 2000:2999 -> ... port 4000 -redirects ports 2000 to 2999 (inclusive) to port 4000. -rdr ... port 2000:2999 -> ... port 4000:* -redirects port 2000 to 4000, 2001 to 4001, ..., 2999 to 4999. -.El -.Pp -In addition to modifying the address, some translation rules may modify -source or destination ports for -.Xr tcp 4 -or -.Xr udp 4 -connections; implicitly in the case of -.Ar nat -rules and explicitly in the case of -.Ar rdr -rules. -Port numbers are never translated with a -.Ar binat -rule. -.Pp -For each packet processed by the translator, the translation rules are -evaluated in sequential order, from first to last. -The first matching rule decides what action is taken. -.Pp -The -.Ar no -option prefixed to a translation rule causes packets to remain untranslated, -much in the same way as -.Ar drop quick -works in the packet filter (see below). -If no rule matches the packet it is passed to the filter engine unmodified. -.Pp -Translation rules apply only to packets that pass through -the specified interface, and if no interface is specified, -translation is applied to packets on all interfaces. -For instance, redirecting port 80 on an external interface to an internal -web server will only work for connections originating from the outside. -Connections to the address of the external interface from local hosts will -not be redirected, since such packets do not actually pass through the -external interface. -Redirections cannot reflect packets back through the interface they arrive -on, they can only be redirected to hosts connected to different interfaces -or to the firewall itself. -.Pp -Note that redirecting external incoming connections to the loopback -address, as in -.Bd -literal -offset indent -rdr on ne3 inet proto tcp to port 8025 -> 127.0.0.1 port 25 -.Ed -.Pp -will effectively allow an external host to connect to daemons -bound solely to the loopback address, circumventing the traditional -blocking of such connections on a real interface. -Unless this effect is desired, any of the local non-loopback addresses -should be used as redirection target instead, which allows external -connections only to daemons bound to this address or not bound to -any address. -.Pp -See -.Sx TRANSLATION EXAMPLES -below. -.Sh PACKET FILTERING -.Xr pf 4 -has the ability to -.Ar block -and -.Ar pass -packets based on attributes of their layer 3 (see -.Xr ip 4 -and -.Xr ip6 4 ) -and layer 4 (see -.Xr icmp 4 , -.Xr icmp6 4 , -.Xr tcp 4 , -.Xr udp 4 ) -headers. -In addition, packets may also be -assigned to queues for the purpose of bandwidth control. -.Pp -For each packet processed by the packet filter, the filter rules are -evaluated in sequential order, from first to last. -The last matching rule decides what action is taken. -.Pp -The following actions can be used in the filter: -.Bl -tag -width xxxx -.It Ar block -The packet is blocked. -There are a number of ways in which a -.Ar block -rule can behave when blocking a packet. -The default behaviour is to -.Ar drop -packets silently, however this can be overridden or made -explicit either globally, by setting the -.Ar block-policy -option, or on a per-rule basis with one of the following options: -.Pp -.Bl -tag -width xxxx -compact -.It Ar drop -The packet is silently dropped. -.It Ar return-rst -This applies only to -.Xr tcp 4 -packets, and issues a TCP RST which closes the -connection. -.It Ar return-icmp -.It Ar return-icmp6 -This causes ICMP messages to be returned for packets which match the rule. -By default this is an ICMP UNREACHABLE message, however this -can be overridden by specifying a message as a code or number. -.It Ar return -This causes a TCP RST to be returned for -.Xr tcp 4 -packets and an ICMP UNREACHABLE for UDP and other packets. -.El -.Pp -Options returning packets have no effect if -.Xr pf 4 -operates on a -.Xr bridge 4 . -.It Ar pass -The packet is passed. -.El -.Pp -If no rule matches the packet, the default action is -.Ar pass . -.Pp -To block everything by default and only pass packets -that match explicit rules, one uses -.Bd -literal -offset indent -block all -.Ed -.Pp -as the first filter rule. -.Pp -See -.Sx FILTER EXAMPLES -below. -.Sh PARAMETERS -The rule parameters specify the packets to which a rule applies. -A packet always comes in on, or goes out through, one interface. -Most parameters are optional. -If a parameter is specified, the rule only applies to packets with -matching attributes. -Certain parameters can be expressed as lists, in which case -.Xr pfctl 8 -generates all needed rule combinations. -.Bl -tag -width xxxx -.It Ar in No or Ar out -This rule applies to incoming or outgoing packets. -If neither -.Ar in -nor -.Ar out -are specified, the rule will match packets in both directions. -.It Ar log -In addition to the action specified, a log message is generated. -All packets for that connection are logged, unless the -.Ar keep state , -.Ar modulate state -or -.Ar synproxy state -options are specified, in which case only the -packet that establishes the state is logged. -(See -.Ar keep state , -.Ar modulate state -and -.Ar synproxy state -below). -The logged packets are sent to the -.Xr pflog 4 -interface. -This interface is monitored by the -.Xr pflogd 8 -logging daemon, which dumps the logged packets to the file -.Pa /var/log/pflog -in -.Xr pcap 3 -binary format. -.It Ar log-all -Used with -.Ar keep state , -.Ar modulate state -or -.Ar synproxy state -rules to force logging of all packets for a connection. -As with -.Ar log , -packets are logged to -.Xr pflog 4 . -.It Ar quick -If a packet matches a rule which has the -.Ar quick -option set, this rule -is considered the last matching rule, and evaluation of subsequent rules -is skipped. -.It Ar on <interface> -This rule applies only to packets coming in on, or going out through, this -particular interface. -It is also possible to simply give the interface driver name, like ppp or fxp, -to make the rule match packets flowing through a group of interfaces. -.It Ar <af> -This rule applies only to packets of this address family. -Supported values are -.Ar inet -and -.Ar inet6 . -.It Ar proto <protocol> -This rule applies only to packets of this protocol. -Common protocols are -.Xr icmp 4 , -.Xr icmp6 4 , -.Xr tcp 4 , -and -.Xr udp 4 . -For a list of all the protocol name to number mappings used by -.Xr pfctl 8 , -see the file -.Em /etc/protocols . -.It Xo -.Ar from <source> port <source> os <source> -.Ar to <dest> port <dest> -.Xc -This rule applies only to packets with the specified source and destination -addresses and ports. -.Pp -Addresses can be specified in CIDR notation (matching netblocks), as -symbolic host names or interface names, or as any of the following keywords: -.Pp -.Bl -tag -width xxxxxxxxxxxx -compact -.It Ar any -Any address. -.It Ar no-route -Any address which is not currently routable. -.It Ar <table> -Any address that matches the given table. -.El -.Pp -Interface names can have modifiers appended: -.Pp -.Bl -tag -width xxxxxxxxxxxx -compact -.It Ar :network -Translates to the network(s) attached to the interface. -.It Ar :broadcast -Translates to the interface's broadcast address(es). -.It Ar :peer -Translates to the point to point interface's peer address(es). -.It Ar :0 -Do not include interface aliases. -.El -.Pp -Host names may also have the -.Ar :0 -option appended to restrict the name resolution to the first of each -v4 and v6 address found. -.Pp -Host name resolution and interface to address translation are done at -ruleset load-time. -When the address of an interface (or host name) changes (under DHCP or PPP, -for instance), the ruleset must be reloaded for the change to be reflected -in the kernel. -Surrounding the interface name (and optional modifiers) in parentheses -changes this behaviour. -When the interface name is surrounded by parentheses, the rule is -automatically updated whenever the interface changes its address. -The ruleset does not need to be reloaded. -This is especially useful with -.Ar nat . -.Pp -Ports can be specified either by number or by name. -For example, port 80 can be specified as -.Em www . -For a list of all port name to number mappings used by -.Xr pfctl 8 , -see the file -.Pa /etc/services . -.Pp -Ports and ranges of ports are specified by using these operators: -.Bd -literal -offset indent -= (equal) -!= (unequal) -< (less than) -<= (less than or equal) -> (greater than) ->= (greater than or equal) -: (range including boundaries) ->< (range excluding boundaries) -<> (except range) -.Ed -.Pp -><, <> and : -are binary operators (they take two arguments). -For instance: -.Bl -tag -width Fl -.It Ar port 2000:2004 -means -.Sq all ports >= 2000 and <= 2004 , -hence ports 2000, 2001, 2002, 2003 and 2004. -.It Ar port 2000 >< 2004 -means -.Sq all ports > 2000 and < 2004 , -hence ports 2001, 2002 and 2003. -.It Ar port 2000 <> 2004 -means -.Sq all ports < 2000 or > 2004 , -hence ports 1-1999 and 2005-65535. -.El -.Pp -The operating system of the source host can be specified in the case of TCP -rules with the -.Ar OS -modifier. -See the -.Sx OPERATING SYSTEM FINGERPRINTING -section for more information. -.Pp -The host, port and OS specifications are optional, as in the following examples: -.Bd -literal -offset indent -pass in all -pass in from any to any -pass in proto tcp from any port <= 1024 to any -pass in proto tcp from any to any port 25 -pass in proto tcp from 10.0.0.0/8 port > 1024 \e - to ! 10.1.2.3 port != ssh -pass in proto tcp from any os "OpenBSD" flags S/SA -.Ed -.It Ar all -This is equivalent to "from any to any". -.It Ar group <group> -Similar to -.Ar user , -this rule only applies to packets of sockets owned by the specified group. -.It Ar user <user> -This rule only applies to packets of sockets owned by the specified user. -For outgoing connections initiated from the firewall, this is the user -that opened the connection. -For incoming connections to the firewall itself, this is the user that -listens on the destination port. -For forwarded connections, where the firewall is not a connection endpoint, -the user and group are -.Em unknown . -.Pp -All packets, both outgoing and incoming, of one connection are associated -with the same user and group. -Only TCP and UDP packets can be associated with users; for other protocols -these parameters are ignored. -.Pp -User and group refer to the effective (as opposed to the real) IDs, in -case the socket is created by a setuid/setgid process. -User and group IDs are stored when a socket is created; -when a process creates a listening socket as root (for instance, by -binding to a privileged port) and subsequently changes to another -user ID (to drop privileges), the credentials will remain root. -.Pp -User and group IDs can be specified as either numbers or names. -The syntax is similar to the one for ports. -The value -.Em unknown -matches packets of forwarded connections. -.Em unknown -can only be used with the operators -.Cm = -and -.Cm != . -Other constructs like -.Cm user >= unknown -are invalid. -Forwarded packets with unknown user and group ID match only rules -that explicitly compare against -.Em unknown -with the operators -.Cm = -or -.Cm != . -For instance -.Cm user >= 0 -does not match forwarded packets. -The following example allows only selected users to open outgoing -connections: -.Bd -literal -offset indent -block out proto { tcp, udp } all -pass out proto { tcp, udp } all \e - user { < 1000, dhartmei } keep state -.Ed -.It Ar flags <a>/<b> | /<b> -This rule only applies to TCP packets that have the flags -.Ar <a> -set out of set -.Ar <b> . -Flags not specified in -.Ar <b> -are ignored. -The flags are: (F)IN, (S)YN, (R)ST, (P)USH, (A)CK, (U)RG, (E)CE, and C(W)R. -.Bl -tag -width Fl -.It Ar flags S/S -Flag SYN is set. -The other flags are ignored. -.It Ar flags S/SA -Out of SYN and ACK, exactly SYN may be set. -SYN, SYN+PSH and SYN+RST match, but SYN+ACK, ACK and ACK+RST do not. -This is more restrictive than the previous example. -.It Ar flags /SFRA -If the first set is not specified, it defaults to none. -All of SYN, FIN, RST and ACK must be unset. -.El -.It Ar icmp-type <type> code <code> -.It Ar icmp6-type <type> code <code> -This rule only applies to ICMP or ICMPv6 packets with the specified type -and code. -This parameter is only valid for rules that cover protocols ICMP or -ICMP6. -The protocol and the ICMP type indicator (icmp-type or icmp6-type) -must match. -.It Ar allow-opts -By default, packets which contain IP options are blocked. -When -.Ar allow-opts -is specified for a -.Ar pass -rule, packets that pass the filter based on that rule (last matching) -do so even if they contain IP options. -For packets that match state, the rule that initially created the -state is used. -The implicit -.Ar pass -rule that is used when a packet does not match any rules does not -allow IP options. -.It Ar label <string> -Adds a label (name) to the rule, which can be used to identify the rule. -For instance, -pfctl -s labels -shows per-rule statistics for rules that have labels. -.Pp -The following macros can be used in labels: -.Pp -.Bl -tag -width $srcaddr -compact -offset indent -.It Ar $if -The interface. -.It Ar $srcaddr -The source IP address. -.It Ar $dstaddr -The destination IP address. -.It Ar $srcport -The source port specification. -.It Ar $dstport -The destination port specification. -.It Ar $proto -The protocol name. -.It Ar $nr -The rule number. -.El -.Pp -For example: -.Bd -literal -offset indent -ips = \&"{ 1.2.3.4, 1.2.3.5 }\&" -pass in proto tcp from any to $ips \e - port > 1023 label \&"$dstaddr:$dstport\&" -.Ed -.Pp -expands to -.Bd -literal -offset indent -pass in inet proto tcp from any to 1.2.3.4 \e - port > 1023 label \&"1.2.3.4:>1023\&" -pass in inet proto tcp from any to 1.2.3.5 \e - port > 1023 label \&"1.2.3.5:>1023\&" -.Ed -.Pp -The macro expansion for the -.Ar label -directive occurs only at configuration file parse time, not during runtime. -.It Ar queue <queue> | ( <queue> , <queue> ) -Packets matching this rule will be assigned to the specified queue. -If two queues are given, packets which have a -.Em tos -of -.Em lowdelay -and TCP ACKs with no data payload will be assigned to the second one. -See -.Sx QUEUEING -for setup details. -.Pp -For example: -.Bd -literal -offset indent -pass in proto tcp to port 25 queue mail -pass in proto tcp to port 22 queue(ssh_bulk, ssh_prio) -.Ed -.It Ar tag <string> -Packets matching this rule will be tagged with the -specified string. -The tag acts as an internal marker that can be used to -identify these packets later on. -This can be used, for example, to provide trust between -interfaces and to determine if packets have been -processed by translation rules. -Tags are -.Qq sticky , -meaning that the packet will be tagged even if the rule -is not the last matching rule. -Further matching rules can replace the tag with a -new one but will not remove a previously applied tag. -A packet is only ever assigned one tag at a time. -.Ar pass -rules that use the -.Ar tag -keyword must also use -.Ar keep state , -.Ar modulate state -or -.Ar synproxy state . -Packet tagging can be done during -.Ar nat , -.Ar rdr , -or -.Ar binat -rules in addition to filter rules. -Tags take the same macros as labels (see above). -.It Ar tagged <string> -Used with filter rules to specify that packets must already -be tagged with the given tag in order to match the rule. -Inverse tag matching can also be done -by specifying the -.Cm !\& -operator before the -.Ar tagged -keyword. -.El -.Sh ROUTING -If a packet matches a rule with a route option set, the packet filter will -route the packet according to the type of route option. -When such a rule creates state, the route option is also applied to all -packets matching the same connection. -.Bl -tag -width xxxx -.It Ar fastroute -The -.Ar fastroute -option does a normal route lookup to find the next hop for the packet. -.It Ar route-to -The -.Ar route-to -option routes the packet to the specified interface with an optional address -for the next hop. -When a -.Ar route-to -rule creates state, only packets that pass in the same direction as the -filter rule specifies will be routed in this way. -Packets passing in the opposite direction (replies) are not affected -and are routed normally. -.It Ar reply-to -The -.Ar reply-to -option is similar to -.Ar route-to , -but routes packets that pass in the opposite direction (replies) to the -specified interface. -Opposite direction is only defined in the context of a state entry, and -.Ar route-to -is useful only in rules that create state. -It can be used on systems with multiple external connections to -route all outgoing packets of a connection through the interface -the incoming connection arrived through (symmetric routing enforcement). -.It Ar dup-to -The -.Ar dup-to -option creates a duplicate of the packet and routes it like -.Ar route-to . -The original packet gets routed as it normally would. -.El -.Sh POOL OPTIONS -For -.Ar nat -and -.Ar rdr -rules, (as well as for the -.Ar route-to , -.Ar reply-to -and -.Ar dup-to -rule options) for which there is a single redirection address which has a -subnet mask smaller than 32 for IPv4 or 128 for IPv6 (more than one IP -address), a variety of different methods for assigning this address can be -used: -.Bl -tag -width xxxx -.It Ar bitmask -The -.Ar bitmask -option applies the network portion of the redirection address to the address -to be modified (source with -.Ar nat , -destination with -.Ar rdr ) . -.It Ar random -The -.Ar random -option selects an address at random within the defined block of addresses. -.It Ar source-hash -The -.Ar source-hash -option uses a hash of the source address to determine the redirection address, -ensuring that the redirection address is always the same for a given source. -An optional key can be specified after this keyword either in hex or as a -string; by default -.Xr pfctl 8 -randomly generates a key for source-hash every time the -ruleset is reloaded. -.It Ar round-robin -The -.Ar round-robin -option loops through the redirection address(es). -.Pp -When more than one redirection address is specified, -.Ar round-robin -is the only permitted pool type. -.It Ar static-port -With -.Ar nat -rules, the -.Ar static-port -option prevents -.Xr pf 4 -from modifying the source port on TCP and UDP packets. -.El -.Pp -Additionally, the -.Ar sticky-address -option can be specified to help ensure that multiple connections from the -same source are mapped to the same redirection address. -This option can be used with the -.Ar random -and -.Ar round-robin -pool options. -Note that by default these associations are destroyed as soon as there are -no longer states which refer to them; in order to make the mappings last -beyond the lifetime of the states, increase the global options with -.Ar set timeout source-track -See -.Sx STATEFUL TRACKING OPTIONS -for more ways to control the source tracking. -.Sh STATEFUL INSPECTION -.Xr pf 4 -is a stateful packet filter, which means it can track the state of -a connection. -Instead of passing all traffic to port 25, for instance, it is possible -to pass only the initial packet, and then begin to keep state. -Subsequent traffic will flow because the filter is aware of the connection. -.Pp -If a packet matches a -.Ar pass ... keep state -rule, the filter creates a state for this connection and automatically -lets pass all subsequent packets of that connection. -.Pp -Before any rules are evaluated, the filter checks whether the packet -matches any state. -If it does, the packet is passed without evaluation of any rules. -.Pp -States are removed after the connection is closed or has timed out. -.Pp -This has several advantages. -Comparing a packet to a state involves checking its sequence numbers. -If the sequence numbers are outside the narrow windows of expected -values, the packet is dropped. -This prevents spoofing attacks, such as when an attacker sends packets with -a fake source address/port but does not know the connection's sequence -numbers. -.Pp -Also, looking up states is usually faster than evaluating rules. -If there are 50 rules, all of them are evaluated sequentially in O(n). -Even with 50000 states, only 16 comparisons are needed to match a -state, since states are stored in a binary search tree that allows -searches in O(log2 n). -.Pp -For instance: -.Bd -literal -offset indent -block all -pass out proto tcp from any to any flags S/SA keep state -pass in proto tcp from any to any port 25 flags S/SA keep state -.Ed -.Pp -This ruleset blocks everything by default. -Only outgoing connections and incoming connections to port 25 are allowed. -The initial packet of each connection has the SYN -flag set, will be passed and creates state. -All further packets of these connections are passed if they match a state. -.Pp -By default, packets coming in and out of any interface can match a state, -but it is also possible to change that behaviour by assigning states to a -single interface or a group of interfaces. -.Pp -The default policy is specified by the -.Ar state-policy -global option, but this can be adjusted on a per-rule basis by adding one -of the -.Ar if-bound , -.Ar group-bound -or -.Ar floating -keywords to the -.Ar keep state -option. -For example, if a rule is defined as: -.Bd -literal -offset indent -pass out on ppp from any to 10.12/16 keep state (group-bound) -.Ed -.Pp -A state created on ppp0 would match packets an all PPP interfaces, -but not packets flowing through fxp0 or any other interface. -.Pp -Keeping rules -.Ar floating -is the more flexible option when the firewall is in a dynamic routing -environment. -However, this has some security implications since a state created by one -trusted network could allow potentially hostile packets coming in from other -interfaces. -.Pp -Specifying -.Ar flags S/SA -restricts state creation to the initial SYN -packet of the TCP handshake. -One can also be less restrictive, and allow state creation from -intermediate -.Pq non-SYN -packets. -This will cause -.Xr pf 4 -to synchronize to existing connections, for instance -if one flushes the state table. -.Pp -For UDP, which is stateless by nature, -.Ar keep state -will create state as well. -UDP packets are matched to states using only host addresses and ports. -.Pp -ICMP messages fall into two categories: ICMP error messages, which always -refer to a TCP or UDP packet, are matched against the referred to connection. -If one keeps state on a TCP connection, and an ICMP source quench message -referring to this TCP connection arrives, it will be matched to the right -state and get passed. -.Pp -For ICMP queries, -.Ar keep state -creates an ICMP state, and -.Xr pf 4 -knows how to match ICMP replies to states. -For example, -.Bd -literal -offset indent -pass out inet proto icmp all icmp-type echoreq keep state -.Ed -.Pp -allows echo requests (such as those created by -.Xr ping 8 ) -out, creates state, and matches incoming echo replies correctly to states. -.Pp -Note: -.Ar nat , binat No and Ar rdr -rules implicitly create state for connections. -.Sh STATE MODULATION -Much of the security derived from TCP is attributable to how well the -initial sequence numbers (ISNs) are chosen. -Some popular stack implementations choose -.Em very -poor ISNs and thus are normally susceptible to ISN prediction exploits. -By applying a -.Ar modulate state -rule to a TCP connection, -.Xr pf 4 -will create a high quality random sequence number for each connection -endpoint. -.Pp -The -.Ar modulate state -directive implicitly keeps state on the rule and is -only applicable to TCP connections. -.Pp -For instance: -.Bd -literal -offset indent -block all -pass out proto tcp from any to any modulate state -pass in proto tcp from any to any port 25 flags S/SA modulate state -.Ed -.Pp -There are two caveats associated with state modulation: -A -.Ar modulate state -rule can not be applied to a pre-existing but unmodulated connection. -Such an application would desynchronize TCP's strict -sequencing between the two endpoints. -Instead, -.Xr pf 4 -will treat the -.Ar modulate state -modifier as a -.Ar keep state -modifier and the pre-existing connection will be inferred without -the protection conferred by modulation. -.Pp -The other caveat affects currently modulated states when the state table -is lost (firewall reboot, flushing the state table, etc...). -.Xr pf 4 -will not be able to infer a connection again after the state table flushes -the connection's modulator. -When the state is lost, the connection may be left dangling until the -respective endpoints time out the connection. -It is possible on a fast local network for the endpoints to start an ACK -storm while trying to resynchronize after the loss of the modulator. -Using a -.Ar flags S/SA -modifier on -.Ar modulate state -rules between fast networks is suggested to prevent ACK storms. -.Sh SYN PROXY -By default, -.Xr pf 4 -passes packets that are part of a -.Xr tcp 4 -handshake between the endpoints. -The -.Ar synproxy state -option can be used to cause -.Xr pf 4 -itself to complete the handshake with the active endpoint, perform a handshake -with the passive endpoint, and then forward packets between the endpoints. -.Pp -No packets are sent to the passive endpoint before the active endpoint has -completed the handshake, hence so-called SYN floods with spoofed source -addresses will not reach the passive endpoint, as the sender can't complete the -handshake. -.Pp -The proxy is transparent to both endpoints, they each see a single -connection from/to the other endpoint. -.Xr pf 4 -chooses random initial sequence numbers for both handshakes. -Once the handshakes are completed, the sequence number modulators -(see previous section) are used to translate further packets of the -connection. -Hence, -.Ar synproxy state -includes -.Ar modulate state -and -.Ar keep state . -.Pp -Rules with -.Ar synproxy -will not work if -.Xr pf 4 -operates on a -.Xr bridge 4 . -.Pp -Example: -.Bd -literal -offset indent -pass in proto tcp from any to any port www flags S/SA synproxy state -.Ed -.Sh STATEFUL TRACKING OPTIONS -All three of -.Ar keep state , -.Ar modulate state -and -.Ar synproxy state -support the following options: -.Pp -.Bl -tag -width xxxx -compact -.It Ar max <number> -Limits the number of concurrent states the rule may create. -When this limit is reached, further packets matching the rule that would -create state are dropped, until existing states time out. -.It Ar no-sync -Prevent state changes for states created by this rule from appearing on the -.Xr pfsync 4 -interface. -.It Ar <timeout> <seconds> -Changes the timeout values used for states created by this rule. -.Pp -When the -.Ar source-track -keyword is specified, the number of states per source IP is tracked. -The following limits can be set: -.Pp -.Bl -tag -width xxxx -compact -.It Ar max-src-nodes -Limits the maximum number of source addresses which can simultaneously -have state table entries. -.It Ar max-src-states -Limits the maximum number of simultaneous state entries that a single -source address can create with this rule. -.El -For a list of all valid timeout names, see -.Sx OPTIONS -above. -.Pp -Multiple options can be specified, separated by commas: -.Bd -literal -pass in proto tcp from any to any \e - port www flags S/SA keep state \e - (max 100, source-track rule, max-src-nodes 75, \e - max-src-states 3, tcp.established 60, tcp.closing 5) -.Ed -.El -.Sh OPERATING SYSTEM FINGERPRINTING -Passive OS Fingerprinting is a mechanism to inspect nuances of a TCP -connection's initial SYN packet and guess at the host's operating system. -Unfortunately these nuances are easily spoofed by an attacker so the -fingerprint is not useful in making security decisions. -But the fingerprint is typically accurate enough to make policy decisions -upon. -.Pp -The fingerprints may be specified by operating system class, by -version, or by subtype/patchlevel. -The class of an operating system is typically the vender or genre -and would be OpenBSD for the -.Xr pf 4 -firewall itself. -The version of the oldest available OpenBSD release on the main ftp site -would be 2.6 and the fingerprint would be written -.Pp -.Dl \&"OpenBSD 2.6\&" -.Pp -The subtype of an operating system is typically used to describe the -patchlevel if that patch led to changes in the TCP stack behavior. -In the case of OpenBSD, the only subtype is for a fingerprint that was -normalized by the -.Ar no-df -scrub option and would be specified as -.Pp -.Dl \&"OpenBSD 3.3 no-df\&" -.Pp -Fingerprints for most popular operating systems are provided by -.Xr pf.os 5 . -Once -.Xr pf 4 -is running, a complete list of known operating system fingerprints may -be listed by running: -.Pp -.Dl # pfctl -so -.Pp -Filter rules can enforce policy at any level of operating system specification -assuming a fingerprint is present. -Policy could limit traffic to approved operating systems or even ban traffic -from hosts that aren't at the latest service pack. -.Pp -The -.Ar unknown -class can also be used as the fingerprint which will match packets for -which no operating system fingerprint is known. -.Pp -Examples: -.Bd -literal -offset indent -pass out proto tcp from any os OpenBSD keep state -block out proto tcp from any os Doors -block out proto tcp from any os "Doors PT" -block out proto tcp from any os "Doors PT SP3" -block out from any os "unknown" -pass on lo0 proto tcp from any os "OpenBSD 3.3 lo0" keep state -.Ed -.Pp -Operating system fingerprinting is limited only to the TCP SYN packet. -This means that it will not work on other protocols and will not match -a currently established connection. -.Pp -Caveat: operating system fingerprints are occasionally wrong. -There are three problems: an attacker can trivially craft his packets to -appear as any operating system he chooses; -an operating system patch could change the stack behavior and no fingerprints -will match it until the database is updated; -and multiple operating systems may have the same fingerprint. -.Sh BLOCKING SPOOFED TRAFFIC -"Spoofing" is the faking of IP addresses, typically for malicious -purposes. -The -.Ar antispoof -directive expands to a set of filter rules which will block all -traffic with a source IP from the network(s) directly connected -to the specified interface(s) from entering the system through -any other interface. -.Pp -For example, the line -.Bd -literal -offset indent -antispoof for lo0 -.Ed -.Pp -expands to -.Bd -literal -offset indent -block drop in on ! lo0 inet from 127.0.0.1/8 to any -block drop in on ! lo0 inet6 from ::1 to any -.Ed -.Pp -For non-loopback interfaces, there are additional rules to block incoming -packets with a source IP address identical to the interface's IP(s). -For example, assuming the interface wi0 had an IP address of 10.0.0.1 and a -netmask of 255.255.255.0, -the line -.Bd -literal -offset indent -antispoof for wi0 inet -.Ed -.Pp -expands to -.Bd -literal -offset indent -block drop in on ! wi0 inet from 10.0.0.0/24 to any -block drop in inet from 10.0.0.1 to any -.Ed -.Pp -Caveat: Rules created by the -.Ar antispoof -directive interfere with packets sent over loopback interfaces -to local addresses. -One should pass these explicitly. -.Sh FRAGMENT HANDLING -The size of IP datagrams (packets) can be significantly larger than the -maximum transmission unit (MTU) of the network. -In cases when it is necessary or more efficient to send such large packets, -the large packet will be fragmented into many smaller packets that will each -fit onto the wire. -Unfortunately for a firewalling device, only the first logical fragment will -contain the necessary header information for the subprotocol that allows -.Xr pf 4 -to filter on things such as TCP ports or to perform NAT. -.Pp -Besides the use of -.Ar scrub -rules as described in -.Sx TRAFFIC NORMALIZATION -above, there are three options for handling fragments in the packet filter. -.Pp -One alternative is to filter individual fragments with filter rules. -If no -.Ar scrub -rule applies to a fragment, it is passed to the filter. -Filter rules with matching IP header parameters decide whether the -fragment is passed or blocked, in the same way as complete packets -are filtered. -Without reassembly, fragments can only be filtered based on IP header -fields (source/destination address, protocol), since subprotocol header -fields are not available (TCP/UDP port numbers, ICMP code/type). -The -.Ar fragment -option can be used to restrict filter rules to apply only to -fragments, but not complete packets. -Filter rules without the -.Ar fragment -option still apply to fragments, if they only specify IP header fields. -For instance, the rule -.Bd -literal -offset indent -pass in proto tcp from any to any port 80 -.Ed -.Pp -never applies to a fragment, even if the fragment is part of a TCP -packet with destination port 80, because without reassembly this information -is not available for each fragment. -This also means that fragments cannot create new or match existing -state table entries, which makes stateful filtering and address -translation (NAT, redirection) for fragments impossible. -.Pp -It's also possible to reassemble only certain fragments by specifying -source or destination addresses or protocols as parameters in -.Ar scrub -rules. -.Pp -In most cases, the benefits of reassembly outweigh the additional -memory cost, and it's recommended to use -.Ar scrub -rules to reassemble -all fragments via the -.Ar fragment reassemble -modifier. -.Pp -The memory allocated for fragment caching can be limited using -.Xr pfctl 8 . -Once this limit is reached, fragments that would have to be cached -are dropped until other entries time out. -The timeout value can also be adjusted. -.Pp -Currently, only IPv4 fragments are supported and IPv6 fragments -are blocked unconditionally. -.Sh ANCHORS AND NAMED RULESETS -Besides the main ruleset, -.Xr pfctl 8 -can load named rulesets into -.Ar anchor -attachment points. -An -.Ar anchor -contains a list of named rulesets. -An -.Ar anchor -has a name which specifies where -.Xr pfctl 8 -can be used to attach sub-rulesets. -A named ruleset contains filter and translation rules, like the -main ruleset. -The main ruleset can reference -.Ar anchor -attachment points -using the following kinds -of rules: -.Bl -tag -width xxxx -.It Ar nat-anchor <name> -Evaluates the -.Ar nat -rules of all named rulesets in the specified -.Ar anchor . -.It Ar rdr-anchor <name> -Evaluates the -.Ar rdr -rules of all named rulesets in the specified -.Ar anchor . -.It Ar binat-anchor <name> -Evaluates the -.Ar binat -rules of all named rulesets in the specified -.Ar anchor . -.It Ar anchor <name> -Evaluates the filter rules of all named rulesets in the specified -.Ar anchor . -.It Ar load anchor <name>:<ruleset> from <file> -Loads the rules from the specified file into the named -ruleset -.Ar <ruleset> -attached to the anchor -.Ar <name> . -.El -.Pp -When evaluation of the main ruleset reaches an -.Ar anchor -rule, -.Xr pf 4 -will proceed to evaluate all rules specified in the -named rulesets attached to that -.Ar anchor . -.Pp -Matching filter rules in named rulesets with the -.Ar quick -option and matching translation rules are final and abort the -evaluation of both the rules in the -.Ar anchor -and the main ruleset. -.Pp -Only the main ruleset can contain -.Ar anchor -rules. -.Pp -When an -.Ar anchor -contains more than one named ruleset, they are evaluated -in the alphabetical order of their names. -.Pp -Rules may contain -.Ar anchor -attachment points which do not contain any rules when the main ruleset -is loaded, and later such named rulesets can be manipulated through -.Xr pfctl 8 -without reloading the main ruleset. -For example, -.Bd -literal -offset indent -ext_if = \&"kue0\&" -block on $ext_if all -anchor spam -pass out on $ext_if all keep state -pass in on $ext_if proto tcp from any \e - to $ext_if port smtp keep state -.Ed -.Pp -blocks all packets on the external interface by default, then evaluates -all rulesets in the -.Ar anchor -named "spam", and finally passes all outgoing connections and -incoming connections to port 25. -.Bd -literal -offset indent -# echo \&"block in quick from 1.2.3.4 to any\&" \&| \e - pfctl -a spam:manual -f - -.Ed -.Pp -loads a single ruleset containing a single rule into the -.Ar anchor , -which blocks all packets from a specific address. -.Pp -The named ruleset can also be populated by adding a -.Ar load anchor -rule after the -.Ar anchor -rule: -.Bd -literal -offset indent -anchor spam -load anchor spam:manual from "/etc/pf-spam.conf" -.Ed -.Pp -When -.Xr pfctl 8 -loads -.Nm pf.conf , -it will also load all the rules from the file -.Pa /etc/pf-spam.conf -into the named ruleset. -.Pp -Optionally, -.Ar anchor -rules can specify the parameter's -direction, interface, address family, protocol and source/destination -address/port -using the same syntax as filter rules. -When parameters are used, the -.Ar anchor -rule is only evaluated for matching packets. -This allows conditional evaluation of named rulesets, like: -.Bd -literal -offset indent -block on $ext_if all -anchor spam proto tcp from any to any port smtp -pass out on $ext_if all keep state -pass in on $ext_if proto tcp from any to $ext_if port smtp keep state -.Ed -.Pp -The rules inside -.Ar anchor -spam are only evaluated for -.Ar tcp -packets with destination port 25. -Hence, -.Bd -literal -offset indent -# echo \&"block in quick from 1.2.3.4 to any" \&| \e - pfctl -a spam:manual -f - -.Ed -.Pp -will only block connections from 1.2.3.4 to port 25. -.Sh TRANSLATION EXAMPLES -This example maps incoming requests on port 80 to port 8080, on -which a daemon is running (because, for example, it is not run as root, -and therefore lacks permission to bind to port 80). -.Bd -literal -# use a macro for the interface name, so it can be changed easily -ext_if = \&"ne3\&" - -# map daemon on 8080 to appear to be on 80 -rdr on $ext_if proto tcp from any to any port 80 -> 127.0.0.1 port 8080 -.Ed -.Pp -If the -.Ar pass -modifier is given, packets matching the translation rule are passed without -inspecting the filter rules: -.Bd -literal -rdr pass on $ext_if proto tcp from any to any port 80 -> 127.0.0.1 \e - port 8080 -.Ed -.Pp -In the example below, vlan12 is configured as 192.168.168.1; -the machine translates all packets coming from 192.168.168.0/24 to 204.92.77.111 -when they are going out any interface except vlan12. -This has the net effect of making traffic from the 192.168.168.0/24 -network appear as though it is the Internet routable address -204.92.77.111 to nodes behind any interface on the router except -for the nodes on vlan12. -(Thus, 192.168.168.1 can talk to the 192.168.168.0/24 nodes.) -.Bd -literal -nat on ! vlan12 from 192.168.168.0/24 to any -> 204.92.77.111 -.Ed -.Pp -In the example below, the machine sits between a fake internal 144.19.74.* -network, and a routable external IP of 204.92.77.100. -The -.Ar no nat -rule excludes protocol AH from being translated. -.Bd -literal -# NO NAT -no nat on $ext_if proto ah from 144.19.74.0/24 to any -nat on $ext_if from 144.19.74.0/24 to any -> 204.92.77.100 -.Ed -.Pp -In the example below, packets bound for one specific server, as well as those -generated by the sysadmins are not proxied; all other connections are. -.Bd -literal -# NO RDR -no rdr on $int_if proto { tcp, udp } from any to $server port 80 -no rdr on $int_if proto { tcp, udp } from $sysadmins to any port 80 -rdr on $int_if proto { tcp, udp } from any to any port 80 -> 127.0.0.1 \e - port 80 -.Ed -.Pp -This longer example uses both a NAT and a redirection. -The external interface has the address 157.161.48.183. -On the internal interface, we are running -.Xr ftp-proxy 8 , -listening for outbound ftp sessions captured to port 8021. -.Bd -literal -# NAT -# Translate outgoing packets' source addresses (any protocol). -# In this case, any address but the gateway's external address is mapped. -nat on $ext_if inet from ! ($ext_if) to any -> ($ext_if) - -# NAT PROXYING -# Map outgoing packets' source port to an assigned proxy port instead of -# an arbitrary port. -# In this case, proxy outgoing isakmp with port 500 on the gateway. -nat on $ext_if inet proto udp from any port = isakmp to any -> ($ext_if) \e - port 500 - -# BINAT -# Translate outgoing packets' source address (any protocol). -# Translate incoming packets' destination address to an internal machine -# (bidirectional). -binat on $ext_if from 10.1.2.150 to any -> ($ext_if) - -# RDR -# Translate incoming packets' destination addresses. -# As an example, redirect a TCP and UDP port to an internal machine. -rdr on $ext_if inet proto tcp from any to ($ext_if) port 8080 \e - -> 10.1.2.151 port 22 -rdr on $ext_if inet proto udp from any to ($ext_if) port 8080 \e - -> 10.1.2.151 port 53 - -# RDR -# Translate outgoing ftp control connections to send them to localhost -# for proxying with ftp-proxy(8) running on port 8021. -rdr on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021 -.Ed -.Pp -In this example, a NAT gateway is set up to translate internal addresses -using a pool of public addresses (192.0.2.16/28) and to redirect -incoming web server connections to a group of web servers on the internal -network. -.Bd -literal -# NAT LOAD BALANCE -# Translate outgoing packets' source addresses using an address pool. -# A given source address is always translated to the same pool address by -# using the source-hash keyword. -nat on $ext_if inet from any to any -> 192.0.2.16/28 source-hash - -# RDR ROUND ROBIN -# Translate incoming web server connections to a group of web servers on -# the internal network. -rdr on $ext_if proto tcp from any to any port 80 \e - -> { 10.1.2.155, 10.1.2.160, 10.1.2.161 } round-robin -.Ed -.Sh FILTER EXAMPLES -.Bd -literal -# The external interface is kue0 -# (157.161.48.183, the only routable address) -# and the private network is 10.0.0.0/8, for which we are doing NAT. - -# use a macro for the interface name, so it can be changed easily -ext_if = \&"kue0\&" - -# normalize all incoming traffic -scrub in on $ext_if all fragment reassemble - -# block and log everything by default -block return log on $ext_if all - -# block anything coming from source we have no back routes for -block in from no-route to any - -# block and log outgoing packets that do not have our address as source, -# they are either spoofed or something is misconfigured (NAT disabled, -# for instance), we want to be nice and do not send out garbage. -block out log quick on $ext_if from ! 157.161.48.183 to any - -# silently drop broadcasts (cable modem noise) -block in quick on $ext_if from any to 255.255.255.255 - -# block and log incoming packets from reserved address space and invalid -# addresses, they are either spoofed or misconfigured, we cannot reply to -# them anyway (hence, no return-rst). -block in log quick on $ext_if from { 10.0.0.0/8, 172.16.0.0/12, \e - 192.168.0.0/16, 255.255.255.255/32 } to any - -# ICMP - -# pass out/in certain ICMP queries and keep state (ping) -# state matching is done on host addresses and ICMP id (not type/code), -# so replies (like 0/0 for 8/0) will match queries -# ICMP error messages (which always refer to a TCP/UDP packet) are -# handled by the TCP/UDP states -pass on $ext_if inet proto icmp all icmp-type 8 code 0 keep state - -# UDP - -# pass out all UDP connections and keep state -pass out on $ext_if proto udp all keep state - -# pass in certain UDP connections and keep state (DNS) -pass in on $ext_if proto udp from any to any port domain keep state - -# TCP - -# pass out all TCP connections and modulate state -pass out on $ext_if proto tcp all modulate state - -# pass in certain TCP connections and keep state (SSH, SMTP, DNS, IDENT) -pass in on $ext_if proto tcp from any to any port { ssh, smtp, domain, \e - auth } flags S/SA keep state - -# pass in data mode connections for ftp-proxy running on this host. -# (see ftp-proxy(8) for details) -pass in on $ext_if proto tcp from any to 157.161.48.183 port >= 49152 \e - flags S/SA keep state - -# Do not allow Windows 9x SMTP connections since they are typically -# a viral worm. Alternately we could limit these OSes to 1 connection each. -block in on $ext_if proto tcp from any os {"Windows 95", "Windows 98"} \e - to any port smtp - -# Packet Tagging - -# three interfaces: $int_if, $ext_if, and $wifi_if (wireless). NAT is -# being done on $ext_if for all outgoing packets. tag packets in on -# $int_if and pass those tagged packets out on $ext_if. all other -# outgoing packets (i.e., packets from the wireless network) are only -# permitted to access port 80. - -pass in on $int_if from any to any tag INTNET keep state -pass in on $wifi_if from any to any keep state - -block out on $ext_if from any to any -pass out quick on $ext_if tagged INTNET keep state -pass out on $ext_if from any to any port 80 keep state - -# tag incoming packets as they are redirected to spamd(8). use the tag -# to pass those packets through the packet filter. - -rdr on $ext_if inet proto tcp from <spammers> to port smtp \e - tag SPAMD -> 127.0.0.1 port spamd - -block in on $ext_if -pass in on $ext_if inet proto tcp tagged SPAMD keep state -.Ed -.Sh GRAMMAR -Syntax for -.Nm -in BNF: -.Bd -literal -line = ( option | pf-rule | nat-rule | binat-rule | rdr-rule | - antispoof-rule | altq-rule | queue-rule | anchor-rule | - trans-anchors | load-anchors | table-rule ) - -option = "set" ( [ "timeout" ( timeout | "{" timeout-list "}" ) ] | - [ "optimization" [ "default" | "normal" | - "high-latency" | "satellite" | - "aggressive" | "conservative" ] ] - [ "limit" ( limit-item | "{" limit-list "}" ) ] | - [ "loginterface" ( interface-name | "none" ) ] | - [ "block-policy" ( "drop" | "return" ) ] | - [ "state-policy" ( "if-bound" | "group-bound" | - "floating" ) ] - [ "require-order" ( "yes" | "no" ) ] - [ "fingerprints" filename ] | - [ "debug" ( "none" | "urgent" | "misc" | "loud" ) ] ) - -pf-rule = action [ ( "in" | "out" ) ] - [ "log" | "log-all" ] [ "quick" ] - [ "on" ifspec ] [ route ] [ af ] [ protospec ] - hosts [ filteropt-list ] - -filteropt-list = filteropt-list filteropt | filteropt -filteropt = user | group | flags | icmp-type | icmp6-type | tos | - ( "keep" | "modulate" | "synproxy" ) "state" - [ "(" state-opts ")" ] | - "fragment" | "no-df" | "min-ttl" number | - "max-mss" number | "random-id" | "reassemble tcp" | - fragmentation | "allow-opts" | - "label" string | "tag" string | [ ! ] "tagged" string - "queue" ( string | "(" string [ [ "," ] string ] ")" ) - -nat-rule = [ "no" ] "nat" [ "pass" ] [ "on" ifspec ] [ af ] - [ protospec ] hosts [ "tag" string ] - [ "->" ( redirhost | "{" redirhost-list "}" ) - [ portspec ] [ pooltype ] [ "static-port" ] ] - -binat-rule = [ "no" ] "binat" [ "pass" ] [ "on" interface-name ] - [ af ] [ "proto" ( proto-name | proto-number ) ] - "from" address [ "/" mask-bits ] "to" ipspec - [ "tag" string ] - [ "->" address [ "/" mask-bits ] ] - -rdr-rule = [ "no" ] "rdr" [ "pass" ] [ "on" ifspec ] [ af ] - [ protospec ] hosts [ "tag" string ] - [ "->" ( redirhost | "{" redirhost-list "}" ) - [ portspec ] [ pooltype ] ] - -antispoof-rule = "antispoof" [ "log" ] [ "quick" ] - "for" ( interface-name | "{" interface-list "}" ) - [ af ] [ "label" string ] - -table-rule = "table" "<" string ">" [ tableopts-list ] -tableopts-list = tableopts-list tableopts | tableopts -tableopts = "persist" | "const" | "file" string | - "{" [ tableaddr-list ] "}" -tableaddr-list = tableaddr-list [ "," ] tableaddr-spec | tableaddr-spec -tableaddr-spec = [ "!" ] tableaddr [ "/" mask-bits ] -tableaddr = hostname | ipv4-dotted-quad | ipv6-coloned-hex | - interface-name | "self" - -altq-rule = "altq on" interface-name queueopts-list - "queue" subqueue -queue-rule = "queue" string [ "on" interface-name ] queueopts-list - subqueue - -anchor-rule = "anchor" string [ ( "in" | "out" ) ] [ "on" ifspec ] - [ af ] [ "proto" ] [ protospec ] [ hosts ] - -trans-anchors = ( "nat-anchor" | "rdr-anchor" | "binat-anchor" ) string - [ "on" ifspec ] [ af ] [ "proto" ] [ protospec ] [ hosts ] - -load-anchor = "load anchor" anchorname:rulesetname "from" filename - -queueopts-list = queueopts-list queueopts | queueopts -queueopts = [ "bandwidth" bandwidth-spec ] | - [ "qlimit" number ] | [ "tbrsize" number ] | - [ "priority" number ] | [ schedulers ] -schedulers = ( cbq-def | priq-def | hfsc-def ) -bandwidth-spec = "number" ( "b" | "Kb" | "Mb" | "Gb" | "%" ) - -action = "pass" | "block" [ return ] | "scrub" -return = "drop" | "return" | "return-rst" [ "( ttl" number ")" ] | - "return-icmp" [ "(" icmpcode ["," icmp6code ] ")" ] | - "return-icmp6" [ "(" icmp6code ")" ] -icmpcode = ( icmp-code-name | icmp-code-number ) -icmp6code = ( icmp6-code-name | icmp6-code-number ) - -ifspec = ( [ "!" ] interface-name ) | "{" interface-list "}" -interface-list = [ "!" ] interface-name [ [ "," ] interface-list ] -route = "fastroute" | - ( "route-to" | "reply-to" | "dup-to" ) - ( routehost | "{" routehost-list "}" ) - [ pooltype ] -af = "inet" | "inet6" - -protospec = "proto" ( proto-name | proto-number | - "{" proto-list "}" ) -proto-list = ( proto-name | proto-number ) [ [ "," ] proto-list ] - -hosts = "all" | - "from" ( "any" | "no-route" | "self" | host | - "{" host-list "}" ) [ port ] [ os ] - "to" ( "any" | "no-route" | "self" | host | - "{" host-list "}" ) [ port ] - -ipspec = "any" | host | "{" host-list "}" -host = [ "!" ] ( address [ "/" mask-bits ] | "<" string ">" ) -redirhost = address [ "/" mask-bits ] -routehost = ( interface-name [ address [ "/" mask-bits ] ] ) -address = ( interface-name | "(" interface-name ")" | hostname | - ipv4-dotted-quad | ipv6-coloned-hex ) -host-list = host [ [ "," ] host-list ] -redirhost-list = redirhost [ [ "," ] redirhost-list ] -routehost-list = routehost [ [ "," ] routehost-list ] - -port = "port" ( unary-op | binary-op | "{" op-list "}" ) -portspec = "port" ( number | name ) [ ":" ( "*" | number | name ) ] -os = "os" ( os-name | "{" os-list "}" ) -user = "user" ( unary-op | binary-op | "{" op-list "}" ) -group = "group" ( unary-op | binary-op | "{" op-list "}" ) - -unary-op = [ "=" | "!=" | "<" | "<=" | ">" | ">=" ] - ( name | number ) -binary-op = number ( "<>" | "><" | ":" ) number -op-list = ( unary-op | binary-op ) [ [ "," ] op-list ] - -os-name = operating-system-name -os-list = os-name [ [ "," ] os-list ] - -flags = "flags" [ flag-set ] "/" flag-set -flag-set = [ "F" ] [ "S" ] [ "R" ] [ "P" ] [ "A" ] [ "U" ] [ "E" ] - [ "W" ] - -icmp-type = "icmp-type" ( icmp-type-code | "{" icmp-list "}" ) -icmp6-type = "icmp6-type" ( icmp-type-code | "{" icmp-list "}" ) -icmp-type-code = ( icmp-type-name | icmp-type-number ) - [ "code" ( icmp-code-name | icmp-code-number ) ] -icmp-list = icmp-type-code [ [ "," ] icmp-list ] - -tos = "tos" ( "lowdelay" | "throughput" | "reliability" | - [ "0x" ] number ) - -state-opts = state-opt [ [ "," ] state-opts ] -state-opt = ( "max" number | "no-sync" | timeout | - "source-track" [ ( "rule" | "global" ) ] | - "max-src-nodes" number | "max-src-states" number | - "if-bound" | "group-bound" | "floating" ) - -fragmentation = [ "fragment reassemble" | "fragment crop" | - "fragment drop-ovl" ] - -timeout-list = timeout [ [ "," ] timeout-list ] -timeout = ( "tcp.first" | "tcp.opening" | "tcp.established" | - "tcp.closing" | "tcp.finwait" | "tcp.closed" | - "udp.first" | "udp.single" | "udp.multiple" | - "icmp.first" | "icmp.error" | - "other.first" | "other.single" | "other.multiple" | - "frag" | "interval" | "src.track" | - "adaptive.start" | "adaptive.end" ) number - -limit-list = limit-item [ [ "," ] limit-list ] -limit-item = ( "states" | "frags" | "src-nodes" ) number - -pooltype = ( "bitmask" | "random" | - "source-hash" [ ( hex-key | string-key ) ] | - "round-robin" ) [ sticky-address ] - -subqueue = string | "{" queue-list "}" -queue-list = string [ [ "," ] string ] -cbq-def = "cbq" [ "(" cbq-opt [ [ "," ] cbq-opt ] ")" ] -priq-def = "priq" [ "(" priq-opt [ [ "," ] priq-opt ] ")" ] -hfsc-def = "hfsc" [ "(" hfsc-opt [ [ "," ] hfsc-opt ] ")" ] -cbq-opt = ( "default" | "borrow" | "red" | "ecn" | "rio" ) -priq-opt = ( "default" | "red" | "ecn" | "rio" ) -hfsc-opt = ( "default" | "red" | "ecn" | "rio" | - linkshare-sc | realtime-sc | upperlimit-sc ) -linkshare-sc = "linkshare" sc-spec -realtime-sc = "realtime" sc-spec -upperlimit-sc = "upperlimit" sc-spec -sc-spec = ( bandwidth-spec | - "(" bandwidth-spec number bandwidth-spec ")" ) -.Ed -.Sh FILES -.Bl -tag -width "/etc/protocols" -compact -.It Pa /etc/hosts -Host name database. -.It Pa /etc/pf.conf -Default location of the ruleset file. -.It Pa /etc/pf.os -Default location of OS fingerprints. -.It Pa /etc/protocols -Protocol name database. -.It Pa /etc/services -Service name database. -.It Pa /usr/share/pf -Example rulesets. -.El -.Sh SEE ALSO -.Xr icmp 4 , -.Xr icmp6 4 , -.Xr ip 4 , -.Xr ip6 4 , -.Xr pf 4 , -.Xr pfsync 4 , -.Xr tcp 4 , -.Xr udp 4 , -.Xr hosts 5 , -.Xr pf.os 5 , -.Xr protocols 5 , -.Xr services 5 , -.Xr ftp-proxy 8 , -.Xr pfctl 8 , -.Xr pflogd 8 -.Sh HISTORY -The -.Nm -file format first appeared in -.Ox 3.0 . diff --git a/contrib/pf/man/pf.os.5 b/contrib/pf/man/pf.os.5 deleted file mode 100644 index 9978174ba544..000000000000 --- a/contrib/pf/man/pf.os.5 +++ /dev/null @@ -1,242 +0,0 @@ -.\" $OpenBSD: pf.os.5,v 1.5 2003/10/25 07:55:27 jmc Exp $ -.\" -.\" Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.Dd August 18, 2003 -.Dt PF.OS 5 -.Os -.Sh NAME -.Nm pf.os -.Nd format of the operating system fingerprints file -.Sh DESCRIPTION -The -.Xr pf 4 -firewall and the -.Xr tcpdump 8 -program can both fingerprint the operating system of hosts that -originate an IPv4 TCP connection. -The file consists of newline-separated records, one per fingerprint, -containing nine colon -.Pq Ql \&: -separated fields. -These fields are as follows: -.Pp -.Bl -tag -width Description -offset indent -compact -.It window -The TCP window size. -.It TTL -The IP time to live. -.It df -The presence of the IPv4 don't fragment bit. -.It packet size -The size of the initial TCP packet. -.It TCP options -An ordered list of the TCP options. -.It class -The class of operating system. -.It version -The version of the operating system. -.It subtype -The subtype of patchlevel of the operating system. -.It description -The overall textual description of the operating system, version and subtype. -.El -.Pp -The -.Ar window -field corresponds to the th->th_win field in the TCP header and is the -source host's advertised TCP window size. -It may be between zero and 65,535 inclusive. -The window size may be given as a multiple of a constant by prepending -the size with a percent sign -.Sq % -and the value will be used as a modulus. -Three special values may be used for the window size: -.Pp -.Bl -tag -width xxx -offset indent -compact -.It * -An asterisk will wildcard the value so any window size will match. -.It S -Allow any window size which is a multiple of the maximum segment size (MSS). -.It T -Allow any window size which is a multiple of the maximum transmission unit -(MTU). -.El -.Pp -The -.Ar ttl -value is the initial time to live in the IP header. -The fingerprint code will account for the volatility of the packet's TTL -as it traverses a network. -.Pp -The -.Ar df -bit corresponds to the Don't Fragment bit in an IPv4 header. -It tells intermediate routers not to fragment the packet and is used for -path MTU discovery. -It may be either a zero or a one. -.Pp -The -.Ar packet size -is the literal size of the full IP packet and is a function of all of -the IP and TCP options. -.Pp -The -.Ar TCP options -field is an ordered list of the individual TCP options that appear in the -SYN packet. -Each option is described by a single character separated by a comma and -certain ones may include a value. -The options are: -.Pp -.Bl -tag -width Description -offset indent -compact -.It Mnnn -maximum segment size (MSS) option. -The value is the maximum packet size of the network link which may -include the -.Sq % -modulus or match all MSSes with the -.Sq * -value. -.It N -the NOP option (NO Operation). -.It T[0] -the timestamp option. -Certain operating systems always start with a zero timestamp in which -case a zero value is added to the option; otherwise no value is appended. -.It S -the Selective ACKnowledgement OK (SACKOK) option. -.It Wnnn -window scaling option. -The value is the size of the window scaling which may include the -.Sq % -modulus or match all window scalings with the -.Sq * -value. -.El -.Pp -No TCP options in the fingerprint may be given with a single dot -.Sq \&. . -.Pp -An example of OpenBSD's TCP options are: -.Pp -.Dl M*,N,N,S,N,W0,N,N,T -.Pp -The first option -.Ar M* -is the MSS option and will match all values. -The second and third options -.Ar N -will match two NOPs. -The fourth option -.Ar S -will match the SACKOK option. -The fifth -.Ar N -will match another NOP. -The sixth -.Ar W0 -will match a window scaling option with a zero scaling size. -The seventh and eighth -.Ar N -options will match two NOPs. -And the ninth and final option -.Ar T -will match the timestamp option with any time value. -.Pp -The TCP options in a fingerprint will only match packets with the -exact same TCP options in the same order. -.Pp -The -.Ar class -field is the class, genre or vender of the operating system. -.Pp -The -.Ar version -is the version of the operating system. -It is used to distinguish between different fingerprints of operating -systems of the same class but different versions. -.Pp -The -.Ar subtype -is the subtype or patch level of the operating system version. -It is used to distinguish between different fingerprints of operating -systems of the same class and same version but slightly different -patches or tweaking. -.Pp -The -.Ar description -is a general description of the operating system, its version, -patchlevel and any further useful details. -.Sh EXAMPLES -The fingerprint of a plain -.Ox 3.3 -host is: -.Bd -literal - 16384:64:1:64:M*,N,N,S,N,W0,N,N,T:OpenBSD:3.3::OpenBSD 3.3 -.Ed -.Pp -The fingerprint of an -.Ox 3.3 -host behind a PF scrubbing firewall with a no-df rule would be: -.Bd -literal - 16384:64:0:64:M*,N,N,S,N,W0,N,N,T:OpenBSD:3.3:!df:OpenBSD 3.3 scrub no-df -.Ed -.Pp -An absolutely braindead embedded operating system fingerprint could be: -.Bd -literal - 65535:255:0:40:.:DUMMY:1.1:p3:Dummy embedded OS v1.1p3 -.Ed -.Pp -The -.Xr tcpdump 8 -output of -.Bd -literal - # 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 - 534596083:534596083(0) win 57344 <mss 1460> (DF) [tos 0x10] \e - (ttl 64, id 11315) -.Ed -.Pp -almost translates into the following fingerprint -.Bd -literal - 57344:64:1:44:M1460: exampleOS:1.0::exampleOS 1.0 -.Ed -.Pp -.Xr tcpdump 8 -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 -.Xr pf 4 , -.Xr pf.conf 5 , -.Xr pfctl 8 , -.Xr tcpdump 8 diff --git a/contrib/pf/man/pflog.4 b/contrib/pf/man/pflog.4 deleted file mode 100644 index d7bee13a0835..000000000000 --- a/contrib/pf/man/pflog.4 +++ /dev/null @@ -1,89 +0,0 @@ -.\" $OpenBSD: pflog.4,v 1.7 2004/03/21 19:47:59 miod Exp $ -.\" -.\" Copyright (c) 2001 Tobias Weingartner -.\" 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. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -.\" -.Dd December 10, 2001 -.Dt PFLOG 4 -.Os -.Sh NAME -.Nm pflog -.Nd packet filter logging interface -.Sh SYNOPSIS -.Cd "pseudo-device pflog" -.Sh DESCRIPTION -The -.Nm pflog -interface is a pseudo-device which makes visible all packets logged by -the packet filter, -.Xr pf 4 . -Logged packets can easily be monitored in real -time by invoking -.Xr tcpdump 8 -on the -.Nm -interface, or stored to disk using -.Xr pflogd 8 . -.Pp -Each packet retrieved on this interface has a header associated -with it of length -.Dv PFLOG_HDRLEN . -This header documents the address family, interface name, rule -number, reason, action, and direction of the packet that was logged. -This structure, defined in -.Aq Pa net/if_pflog.h -looks like -.Bd -literal -offset indent -struct pfloghdr { - u_int8_t length; - sa_family_t af; - u_int8_t action; - u_int8_t reason; - char ifname[IFNAMSIZ]; - char ruleset[PF_RULESET_NAME_SIZE]; - u_int32_t rulenr; - u_int32_t subrulenr; - u_int8_t dir; - u_int8_t pad[3]; -}; -.Ed -.Sh EXAMPLES -.Bd -literal -offset indent -# ifconfig pflog0 up -# tcpdump -n -e -ttt -i pflog0 -.Ed -.Sh SEE ALSO -.Xr inet 4 , -.Xr inet6 4 , -.Xr netintro 4 , -.Xr pf 4 , -.Xr ifconfig 8 , -.Xr pflogd 8 , -.Xr tcpdump 8 -.Sh HISTORY -The -.Nm -device first appeared in -.Ox 3.0 . -.\" .Sh BUGS -.\" Anything here? diff --git a/contrib/pf/man/pfsync.4 b/contrib/pf/man/pfsync.4 deleted file mode 100644 index f7b39df4bcaa..000000000000 --- a/contrib/pf/man/pfsync.4 +++ /dev/null @@ -1,226 +0,0 @@ -.\" $OpenBSD: pfsync.4,v 1.16 2004/03/22 21:04:36 jmc Exp $ -.\" -.\" Copyright (c) 2002 Michael Shalayeff -.\" 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. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 MIND, -.\" 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. -.\" -.Dd November 29, 2002 -.Dt PFSYNC 4 -.Os -.Sh NAME -.Nm pfsync -.Nd packet filter states table logging interface -.Sh SYNOPSIS -.Cd "pseudo-device pfsync" -.Sh DESCRIPTION -The -.Nm -interface is a pseudo-device which exposes certain changes to the state -table used by -.Xr pf 4 . -State changes can be viewed by invoking -.Xr tcpdump 8 -on the -.Nm -interface. -If configured with a physical synchronisation interface, -.Nm -will also send state changes out on that interface using IP multicast, -and insert state changes received on that interface from other systems -into the state table. -.Pp -By default, all local changes to the state table are exposed via -.Nm . -However, state changes from packets received by -.Nm -over the network are not rebroadcast. -States created by a rule marked with the -.Ar no-sync -keyword are omitted from the -.Nm -interface (see -.Xr pf.conf 5 -for details). -.Pp -The -.Nm -interface will attempt to collapse multiple updates of the same -state into one message where possible. -The maximum number of times this can be done before the update is sent out -is controlled by the -.Ar maxupd -to ifconfig. -(see -.Xr ifconfig 8 -and the example below for more details) -.Pp -Each packet retrieved on this interface has a header associated -with it of length -.Dv PFSYNC_HDRLEN . -The header indicates the version of the protocol, address family, -action taken on the following states and the number of state -table entries attached in this packet. -This structure, defined in -.Aq Pa net/if_pfsync.h -looks like: -.Bd -literal -offset indent -struct pfsync_header { - u_int8_t version; - u_int8_t af; - u_int8_t action; - u_int8_t count; -}; -.Ed -.Sh NETWORK SYNCHRONISATION -States can be synchronised between two or more firewalls using this -interface, by specifying a synchronisation interface using -.Xr ifconfig 8 . -For example, the following command sets fxp0 as the synchronisation -interface. -.Bd -literal -offset indent -# ifconfig pfsync0 syncif fxp0 -.Ed -.Pp -State change messages are sent out on the synchronisation -interface using IP multicast packets. -The protocol is IP protocol 240, PFSYNC, and the multicast group -used is 224.0.0.240. -.Pp -It is important that the synchronisation interface be on a trusted -network as there is no authentication on the protocol and it would -be trivial to spoof packets which create states, bypassing the pf ruleset. -Ideally, this is a network dedicated to pfsync messages, -i.e. a crossover cable between two firewalls. -.Pp -There is a one-to-one correspondence between packets seen by -.Xr bpf 4 -on the -.Nm -interface, and packets sent out on the synchronisation interface, i.e.\& -a packet with 4 state deletion messages on -.Nm -means that the same 4 deletions were sent out on the synchronisation -interface. -However, the actual packet contents may differ as the messages -sent over the network are "compressed" where possible, containing -only the necessary information. -.Sh EXAMPLES -.Nm -and -.Xr carp 4 -can be used together to provide automatic failover of a pair of firewalls -configured in parallel. -One firewall handles all traffic \- if it dies or -is shut down, the second firewall takes over automatically. -.Pp -Both firewalls in this example have three -.Xr sis 4 -interfaces. -sis0 is the external interface, on the 10.0.0.0/24 subnet, sis1 is the -internal interface, on the 192.168.0.0/24 subnet, and sis2 is the -.Nm -interface, using the 192.168.254.0/24 subnet. -A crossover cable connects the two firewalls via their sis2 interfaces. -On all three interfaces, firewall A uses the .254 address, while firewall B -uses .253. -The interfaces are configured as follows (firewall A unless otherwise -indicated): -.Pp -.Pa /etc/hostname.sis0 : -.Bd -literal -offset indent -inet 10.0.0.254 255.255.255.0 NONE -.Ed -.Pp -.Pa /etc/hostname.sis1 : -.Bd -literal -offset indent -inet 192.168.0.254 255.255.255.0 NONE -.Ed -.Pp -.Pa /etc/hostname.sis2 : -.Bd -literal -offset indent -inet 192.168.254.254 255.255.255.0 NONE -.Ed -.Pp -.Pa /etc/hostname.carp0 : -.Bd -literal -offset indent -inet 10.0.0.1 255.255.255.0 10.0.0.255 vhid 1 pass foo -.Ed -.Pp -.Pa /etc/hostname.carp1 : -.Bd -literal -offset indent -inet 192.168.0.1 255.255.255.0 192.168.0.255 vhid 2 pass bar -.Ed -.Pp -.Pa /etc/hostname.pfsync0 : -.Bd -literal -offset indent -up syncif sis2 -.Ed -.Pp -.Xr pf 4 -must also be configured to allow -.Nm -and -.Xr carp 4 -traffic through. -The following should be added to the top of -.Pa /etc/pf.conf : -.Bd -literal -offset indent -pass quick on { sis2 } proto pfsync -pass on { sis0 sis1 } proto carp keep state -.Ed -.Pp -If it is preferable that one firewall handle the traffic, -the -.Ar advskew -on the backup firewall's -.Xr carp 4 -interfaces should be set to something higher than -the primary's. -For example, if firewall B is the backup, its -.Pa /etc/hostname.carp1 -would look like this: -.Bd -literal -offset indent -inet 192.168.0.1 255.255.255.0 192.168.0.255 vhid 2 pass bar \e - advskew 100 -.Ed -.Pp -The following must also be added to -.Pa /etc/sysctl.conf : -.Bd -literal -offset indent -net.inet.carp.preempt=1 -.Ed -.Sh SEE ALSO -.Xr bpf 4 , -.Xr inet 4 , -.Xr inet6 4 , -.Xr netintro 4 , -.Xr pf 4 , -.Xr hostname.if 5 , -.Xr pf.conf 5 , -.Xr protocols 5 , -.Xr ifconfig 8 , -.Xr tcpdump 8 -.Sh HISTORY -The -.Nm -device first appeared in -.Ox 3.3 . diff --git a/contrib/pf/pflogd/pflogd.8 b/contrib/pf/pflogd/pflogd.8 deleted file mode 100644 index ac8fe78aa0a7..000000000000 --- a/contrib/pf/pflogd/pflogd.8 +++ /dev/null @@ -1,192 +0,0 @@ -.\" $OpenBSD: pflogd.8,v 1.24 2004/01/16 10:45:49 jmc Exp $ -.\" -.\" Copyright (c) 2001 Can Erkin Acar. 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. 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 -.\" 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 AUTHOR 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. -.\" -.Dd July 9, 2001 -.Dt PFLOGD 8 -.Os -.Sh NAME -.Nm pflogd -.Nd packet filter logging daemon -.Sh SYNOPSIS -.Nm pflogd -.Op Fl Dx -.Op Fl d Ar delay -.Op Fl f Ar filename -.Op Fl s Ar snaplen -.Op Ar expression -.Sh DESCRIPTION -.Nm -is a background daemon which reads packets logged by -.Xr pf 4 -to the packet logging interface -.Pa pflog0 -and writes the packets to a logfile (normally -.Pa /var/log/pflog ) -in -.Xr tcpdump 8 -binary format. -These logs can be reviewed later using the -.Fl r -option of -.Xr tcpdump 8 , -hopefully offline in case there are bugs in the packet parsing code of -.Xr tcpdump 8 . -.Pp -.Nm -closes and then re-opens the log file when it receives -.Dv SIGHUP , -permitting -.Xr newsyslog 8 -to rotate logfiles automatically. -.Dv SIGALRM -causes -.Nm -to flush the current logfile buffers to the disk, thus making the most -recent logs available. -The buffers are also flushed every -.Ar delay -seconds. -.Pp -If the log file contains data after a restart or a -.Dv SIGHUP , -new logs are appended to the existing file. -If the existing log file was created with a different snaplen, -.Nm -temporarily uses the old snaplen to keep the log file consistent. -.Pp -.Nm -tries to preserve the integrity of the log file against I/O errors. -Furthermore, integrity of an existing log file is verified before -appending. -If there is an invalid log file or an I/O error, logging is suspended until a -.Dv SIGHUP -or a -.Dv SIGALRM -is received. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl D -Debugging mode. -.Nm -does not disassociate from the controlling terminal. -.It Fl d Ar delay -Time in seconds to delay between automatic flushes of the file. -This may be specified with a value between 5 and 3600 seconds. -If not specified, the default is 60 seconds. -.It Fl f Ar filename -Log output filename. -Default is -.Pa /var/log/pflog . -.It Fl s Ar snaplen -Analyze at most the first -.Ar snaplen -bytes of data from each packet rather than the default of 96. -The default of 96 is adequate for IP, ICMP, TCP, and UDP headers but may -truncate protocol information for other protocols. -Other file parsers may desire a higher snaplen. -.It Fl x -Check the integrity of an existing log file, and return. -.It Ar expression -Selects which packets will be dumped, using the regular language of -.Xr tcpdump 8 . -.El -.Sh FILES -.Bl -tag -width /var/run/pflogd.pid -compact -.It Pa /var/run/pflogd.pid -Process ID of the currently running -.Nm . -.It Pa /var/log/pflog -Default log file. -.El -.Sh EXAMPLES -Log specific tcp packets to a different log file with a large snaplen -(useful with a log-all rule to dump complete sessions): -.Bd -literal -offset indent -# pflogd -s 1600 -f suspicious.log port 80 and host evilhost -.Ed -.Pp -Display binary logs: -.Bd -literal -offset indent -# tcpdump -n -e -ttt -r /var/log/pflog -.Ed -.Pp -Display the logs in real time (this does not interfere with the -operation of -.Nm ) : -.Bd -literal -offset indent -# tcpdump -n -e -ttt -i pflog0 -.Ed -.Pp -Tcpdump has been extended to be able to filter on the pfloghdr -structure defined in -.Aq Ar net/if_pflog.h . -Tcpdump can restrict the output -to packets logged on a specified interface, a rule number, a reason, -a direction, an IP family or an action. -.Pp -.Bl -tag -width "reason match " -compact -.It ip -Address family equals IPv4. -.It ip6 -Address family equals IPv6. -.It ifname kue0 -Interface name equals "kue0". -.It on kue0 -Interface name equals "kue0". -.It rulenum 10 -Rule number equals 10. -.It reason match -Reason equals match. -Also accepts "bad-offset", "fragment", "short", "normalize" and "memory". -.It action pass -Action equals pass. -Also accepts "block". -.It inbound -The direction was inbound. -.It outbound -The direction was outbound. -.El -.Pp -Display the logs in real time of inbound packets that were blocked on -the wi0 interface: -.Bd -literal -offset indent -# tcpdump -n -e -ttt -i pflog0 inbound and action block and on wi0 -.Ed -.Sh SEE ALSO -.Xr pcap 3 , -.Xr pf 4 , -.Xr pflog 4 , -.Xr pf.conf 5 , -.Xr newsyslog 8 , -.Xr tcpdump 8 -.Sh HISTORY -The -.Nm -command appeared in -.Ox 3.0 . -.Sh AUTHORS -Can Erkin Acar diff --git a/contrib/pf/pflogd/pflogd.c b/contrib/pf/pflogd/pflogd.c deleted file mode 100644 index 7e19ae66ebdb..000000000000 --- a/contrib/pf/pflogd/pflogd.c +++ /dev/null @@ -1,643 +0,0 @@ -/* $OpenBSD: pflogd.c,v 1.27 2004/02/13 19:01:57 otto Exp $ */ - -/* - * Copyright (c) 2001 Theo de Raadt - * Copyright (c) 2001 Can Erkin Acar - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <pcap-int.h> -#include <pcap.h> -#include <syslog.h> -#include <signal.h> -#include <errno.h> -#include <stdarg.h> -#include <fcntl.h> -#include <util.h> -#include "pflogd.h" - -pcap_t *hpcap; -static FILE *dpcap; - -int Debug = 0; -static int snaplen = DEF_SNAPLEN; -static int cur_snaplen = DEF_SNAPLEN; - -volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup; - -char *filename = PFLOGD_LOG_FILE; -char *interface = PFLOGD_DEFAULT_IF; -char *filter = NULL; - -char errbuf[PCAP_ERRBUF_SIZE]; - -int log_debug = 0; -unsigned int delay = FLUSH_DELAY; - -char *copy_argv(char * const *); -void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *); -void dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *); -int flush_buffer(FILE *); -int init_pcap(void); -void logmsg(int, const char *, ...); -void purge_buffer(void); -int reset_dump(void); -int scan_dump(FILE *, off_t); -int set_snaplen(int); -void set_suspended(int); -void sig_alrm(int); -void sig_close(int); -void sig_hup(int); -void usage(void); - -/* buffer must always be greater than snaplen */ -static int bufpkt = 0; /* number of packets in buffer */ -static int buflen = 0; /* allocated size of buffer */ -static char *buffer = NULL; /* packet buffer */ -static char *bufpos = NULL; /* position in buffer */ -static int bufleft = 0; /* bytes left in buffer */ - -/* if error, stop logging but count dropped packets */ -static int suspended = -1; -static long packets_dropped = 0; - -void -set_suspended(int s) -{ - if (suspended == s) - return; - - suspended = s; - setproctitle("[%s] -s %d -f %s", - suspended ? "suspended" : "running", cur_snaplen, filename); -} - -char * -copy_argv(char * const *argv) -{ - size_t len = 0, n; - char *buf; - - if (argv == NULL) - return (NULL); - - for (n = 0; argv[n]; n++) - len += strlen(argv[n])+1; - if (len == 0) - return (NULL); - - buf = malloc(len); - if (buf == NULL) - return (NULL); - - strlcpy(buf, argv[0], len); - for (n = 1; argv[n]; n++) { - strlcat(buf, " ", len); - strlcat(buf, argv[n], len); - } - return (buf); -} - -void -logmsg(int pri, const char *message, ...) -{ - va_list ap; - va_start(ap, message); - - if (log_debug) { - vfprintf(stderr, message, ap); - fprintf(stderr, "\n"); - } else - vsyslog(pri, message, ap); - va_end(ap); -} - -__dead void -usage(void) -{ - fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename] "); - fprintf(stderr, "[-s snaplen] [expression]\n"); - exit(1); -} - -void -sig_close(int sig) -{ - gotsig_close = 1; -} - -void -sig_hup(int sig) -{ - gotsig_hup = 1; -} - -void -sig_alrm(int sig) -{ - gotsig_alrm = 1; -} - -void -set_pcap_filter(void) -{ - struct bpf_program bprog; - - if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0) - logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap)); - else { - if (pcap_setfilter(hpcap, &bprog) < 0) - logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap)); - pcap_freecode(&bprog); - } -} - -int -init_pcap(void) -{ - hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf); - if (hpcap == NULL) { - logmsg(LOG_ERR, "Failed to initialize: %s", errbuf); - return (-1); - } - - if (pcap_datalink(hpcap) != DLT_PFLOG) { - logmsg(LOG_ERR, "Invalid datalink type"); - pcap_close(hpcap); - hpcap = NULL; - return (-1); - } - - set_pcap_filter(); - - cur_snaplen = snaplen = pcap_snapshot(hpcap); - - /* lock */ - if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) { - logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno)); - return (-1); - } - - return (0); -} - -int -set_snaplen(int snap) -{ - if (priv_set_snaplen(snap)) - return (1); - - if (cur_snaplen > snap) - purge_buffer(); - - cur_snaplen = snap; - - return (0); -} - -int -reset_dump(void) -{ - struct pcap_file_header hdr; - struct stat st; - int fd; - FILE *fp; - - if (hpcap == NULL) - return (-1); - - if (dpcap) { - flush_buffer(dpcap); - fclose(dpcap); - dpcap = NULL; - } - - /* - * Basically reimplement pcap_dump_open() because it truncates - * files and duplicates headers and such. - */ - fd = priv_open_log(); - if (fd < 0) - return (1); - - fp = fdopen(fd, "a+"); - - if (fp == NULL) { - logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno)); - return (1); - } - if (fstat(fileno(fp), &st) == -1) { - logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno)); - return (1); - } - - /* set FILE unbuffered, we do our own buffering */ - if (setvbuf(fp, NULL, _IONBF, 0)) { - logmsg(LOG_ERR, "Failed to set output buffers"); - return (1); - } - -#define TCPDUMP_MAGIC 0xa1b2c3d4 - - if (st.st_size == 0) { - if (snaplen != cur_snaplen) { - logmsg(LOG_NOTICE, "Using snaplen %d", snaplen); - if (set_snaplen(snaplen)) { - logmsg(LOG_WARNING, - "Failed, using old settings"); - } - } - hdr.magic = TCPDUMP_MAGIC; - hdr.version_major = PCAP_VERSION_MAJOR; - hdr.version_minor = PCAP_VERSION_MINOR; - hdr.thiszone = hpcap->tzoff; - hdr.snaplen = hpcap->snapshot; - hdr.sigfigs = 0; - hdr.linktype = hpcap->linktype; - - if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) { - fclose(fp); - return (1); - } - } else if (scan_dump(fp, st.st_size)) { - /* XXX move file and continue? */ - fclose(fp); - return (1); - } - - dpcap = fp; - - set_suspended(0); - flush_buffer(fp); - - return (0); -} - -int -scan_dump(FILE *fp, off_t size) -{ - struct pcap_file_header hdr; - struct pcap_pkthdr ph; - off_t pos; - - /* - * Must read the file, compare the header against our new - * options (in particular, snaplen) and adjust our options so - * that we generate a correct file. Furthermore, check the file - * for consistency so that we can append safely. - * - * XXX this may take a long time for large logs. - */ - (void) fseek(fp, 0L, SEEK_SET); - - if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) { - logmsg(LOG_ERR, "Short file header"); - return (1); - } - - if (hdr.magic != TCPDUMP_MAGIC || - hdr.version_major != PCAP_VERSION_MAJOR || - hdr.version_minor != PCAP_VERSION_MINOR || - hdr.linktype != hpcap->linktype || - hdr.snaplen > PFLOGD_MAXSNAPLEN) { - logmsg(LOG_ERR, "Invalid/incompatible log file, move it away"); - return (1); - } - - pos = sizeof(hdr); - - while (!feof(fp)) { - off_t len = fread((char *)&ph, 1, sizeof(ph), fp); - if (len == 0) - break; - - if (len != sizeof(ph)) - goto error; - if (ph.caplen > hdr.snaplen || ph.caplen > PFLOGD_MAXSNAPLEN) - goto error; - pos += sizeof(ph) + ph.caplen; - if (pos > size) - goto error; - fseek(fp, ph.caplen, SEEK_CUR); - } - - if (pos != size) - goto error; - - if (hdr.snaplen != cur_snaplen) { - logmsg(LOG_WARNING, - "Existing file has different snaplen %u, using it", - hdr.snaplen); - if (set_snaplen(hdr.snaplen)) { - logmsg(LOG_WARNING, - "Failed, using old settings, offset %llu", - (unsigned long long) size); - } - } - - return (0); - - error: - logmsg(LOG_ERR, "Corrupted log file."); - return (1); -} - -/* dump a packet directly to the stream, which is unbuffered */ -void -dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) -{ - FILE *f = (FILE *)user; - - if (suspended) { - packets_dropped++; - return; - } - - if (fwrite((char *)h, sizeof(*h), 1, f) != 1) { - /* try to undo header to prevent corruption */ - off_t pos = ftello(f); - if (pos < sizeof(*h) || - ftruncate(fileno(f), pos - sizeof(*h))) { - logmsg(LOG_ERR, "Write failed, corrupted logfile!"); - set_suspended(1); - gotsig_close = 1; - return; - } - goto error; - } - - if (fwrite((char *)sp, h->caplen, 1, f) != 1) - goto error; - - return; - -error: - set_suspended(1); - packets_dropped ++; - logmsg(LOG_ERR, "Logging suspended: fwrite: %s", strerror(errno)); -} - -int -flush_buffer(FILE *f) -{ - off_t offset; - int len = bufpos - buffer; - - if (len <= 0) - return (0); - - offset = ftello(f); - if (offset == (off_t)-1) { - set_suspended(1); - logmsg(LOG_ERR, "Logging suspended: ftello: %s", - strerror(errno)); - return (1); - } - - if (fwrite(buffer, len, 1, f) != 1) { - set_suspended(1); - logmsg(LOG_ERR, "Logging suspended: fwrite: %s", - strerror(errno)); - ftruncate(fileno(f), offset); - return (1); - } - - set_suspended(0); - bufpos = buffer; - bufleft = buflen; - bufpkt = 0; - - return (0); -} - -void -purge_buffer(void) -{ - packets_dropped += bufpkt; - - set_suspended(0); - bufpos = buffer; - bufleft = buflen; - bufpkt = 0; -} - -/* append packet to the buffer, flushing if necessary */ -void -dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) -{ - FILE *f = (FILE *)user; - size_t len = sizeof(*h) + h->caplen; - - if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) { - logmsg(LOG_NOTICE, "invalid size %u (%u/%u), packet dropped", - len, cur_snaplen, snaplen); - packets_dropped++; - return; - } - - if (len <= bufleft) - goto append; - - if (suspended) { - packets_dropped++; - return; - } - - if (flush_buffer(f)) { - packets_dropped++; - return; - } - - if (len > bufleft) { - dump_packet_nobuf(user, h, sp); - return; - } - - append: - memcpy(bufpos, h, sizeof(*h)); - memcpy(bufpos + sizeof(*h), sp, h->caplen); - - bufpos += len; - bufleft -= len; - bufpkt++; - - return; -} - -int -main(int argc, char **argv) -{ - struct pcap_stat pstat; - int ch, np, Xflag = 0; - pcap_handler phandler = dump_packet; - - closefrom(STDERR_FILENO + 1); - - while ((ch = getopt(argc, argv, "Dxd:s:f:")) != -1) { - switch (ch) { - case 'D': - Debug = 1; - break; - case 'd': - delay = atoi(optarg); - if (delay < 5 || delay > 60*60) - usage(); - break; - case 'f': - filename = optarg; - break; - case 's': - snaplen = atoi(optarg); - if (snaplen <= 0) - snaplen = DEF_SNAPLEN; - if (snaplen > PFLOGD_MAXSNAPLEN) - snaplen = PFLOGD_MAXSNAPLEN; - break; - case 'x': - Xflag++; - break; - default: - usage(); - } - - } - - log_debug = Debug; - argc -= optind; - argv += optind; - - if (!Debug) { - openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON); - if (daemon(0, 0)) { - logmsg(LOG_WARNING, "Failed to become daemon: %s", - strerror(errno)); - } - pidfile(NULL); - } - - (void)umask(S_IRWXG | S_IRWXO); - - /* filter will be used by the privileged process */ - if (argc) { - filter = copy_argv(argv); - if (filter == NULL) - logmsg(LOG_NOTICE, "Failed to form filter expression"); - } - - /* initialize pcap before dropping privileges */ - if (init_pcap()) { - logmsg(LOG_ERR, "Exiting, init failure"); - exit(1); - } - - /* Privilege separation begins here */ - if (priv_init()) { - logmsg(LOG_ERR, "unable to privsep"); - exit(1); - } - - setproctitle("[initializing]"); - /* Process is now unprivileged and inside a chroot */ - signal(SIGTERM, sig_close); - signal(SIGINT, sig_close); - signal(SIGQUIT, sig_close); - signal(SIGALRM, sig_alrm); - signal(SIGHUP, sig_hup); - alarm(delay); - - buffer = malloc(PFLOGD_BUFSIZE); - - if (buffer == NULL) { - logmsg(LOG_WARNING, "Failed to allocate output buffer"); - phandler = dump_packet_nobuf; - } else { - bufleft = buflen = PFLOGD_BUFSIZE; - bufpos = buffer; - bufpkt = 0; - } - - if (reset_dump()) { - if (Xflag) - return (1); - - logmsg(LOG_ERR, "Logging suspended: open error"); - set_suspended(1); - } else if (Xflag) - return (0); - - while (1) { - np = pcap_dispatch(hpcap, PCAP_NUM_PKTS, - dump_packet, (u_char *)dpcap); - if (np < 0) - logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap)); - - if (gotsig_close) - break; - if (gotsig_hup) { - if (reset_dump()) { - logmsg(LOG_ERR, - "Logging suspended: open error"); - set_suspended(1); - } - gotsig_hup = 0; - } - - if (gotsig_alrm) { - if (dpcap) - flush_buffer(dpcap); - gotsig_alrm = 0; - alarm(delay); - } - } - - logmsg(LOG_NOTICE, "Exiting"); - if (dpcap) { - flush_buffer(dpcap); - fclose(dpcap); - } - purge_buffer(); - - if (pcap_stats(hpcap, &pstat) < 0) - logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap)); - else - logmsg(LOG_NOTICE, - "%u packets received, %u/%u dropped (kernel/pflogd)", - pstat.ps_recv, pstat.ps_drop, packets_dropped); - - pcap_close(hpcap); - if (!Debug) - closelog(); - return (0); -} diff --git a/contrib/pf/pflogd/pflogd.h b/contrib/pf/pflogd/pflogd.h deleted file mode 100644 index 3baecb66fe67..000000000000 --- a/contrib/pf/pflogd/pflogd.h +++ /dev/null @@ -1,47 +0,0 @@ -/* $OpenBSD: pflogd.h,v 1.2 2004/01/15 20:15:14 canacar Exp $ */ - -/* - * Copyright (c) 2003 Can Erkin Acar - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/limits.h> -#include <pcap.h> - -#define DEF_SNAPLEN 116 /* default plus allow for larger header of pflog */ -#define PCAP_TO_MS 500 /* pcap read timeout (ms) */ -#define PCAP_NUM_PKTS 1000 /* max number of packets to process at each loop */ -#define PCAP_OPT_FIL 1 /* filter optimization */ -#define FLUSH_DELAY 60 /* flush delay */ - -#define PFLOGD_LOG_FILE "/var/log/pflog" -#define PFLOGD_DEFAULT_IF "pflog0" - -#define PFLOGD_MAXSNAPLEN INT_MAX -#define PFLOGD_BUFSIZE 65536 /* buffer size for incoming packets */ - -void logmsg(int priority, const char *message, ...); - -/* Privilege separation */ -int priv_init(void); -int priv_set_snaplen(int snaplen); -int priv_open_log(void); -pcap_t *pcap_open_live_fd(int fd, int snaplen, char *ebuf); - -void set_pcap_filter(void); -/* File descriptor send/recv */ -void send_fd(int, int); -int receive_fd(int); - -extern int Debug; diff --git a/contrib/pf/pflogd/pidfile.c b/contrib/pf/pflogd/pidfile.c deleted file mode 100644 index 61eca262efe2..000000000000 --- a/contrib/pf/pflogd/pidfile.c +++ /dev/null @@ -1,121 +0,0 @@ -/* $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> -#if defined(__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); -} diff --git a/contrib/pf/pflogd/pidfile.h b/contrib/pf/pflogd/pidfile.h deleted file mode 100644 index 542325fdcdad..000000000000 --- a/contrib/pf/pflogd/pidfile.h +++ /dev/null @@ -1 +0,0 @@ -int pidfile(const char *); diff --git a/contrib/pf/pflogd/privsep.c b/contrib/pf/pflogd/privsep.c deleted file mode 100644 index 50807ada4e45..000000000000 --- a/contrib/pf/pflogd/privsep.c +++ /dev/null @@ -1,305 +0,0 @@ -/* $OpenBSD: privsep.c,v 1.8 2004/03/14 19:17:05 otto Exp $ */ - -/* - * Copyright (c) 2003 Can Erkin Acar - * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <sys/ioctl.h> - -#include <net/if.h> -#include <net/bpf.h> - -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <pcap.h> -#include <pcap-int.h> -#include <pwd.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include "pflogd.h" - -enum cmd_types { - PRIV_SET_SNAPLEN, /* set the snaplength */ - PRIV_OPEN_LOG /* open logfile for appending */ -}; - -static int priv_fd = -1; -static volatile pid_t child_pid = -1; - -volatile sig_atomic_t gotsig_chld = 0; - -static void sig_pass_to_chld(int); -static void sig_chld(int); -static int may_read(int, void *, size_t); -static void must_read(int, void *, size_t); -static void must_write(int, void *, size_t); -static int set_snaplen(int snap); - -/* bpf filter expression common to parent and child */ -extern char *filter; -extern char *errbuf; -extern char *filename; -extern pcap_t *hpcap; - -/* based on syslogd privsep */ -int -priv_init(void) -{ - int i, fd, socks[2], cmd; - int snaplen, ret; - struct passwd *pw; - - for (i = 1; i < _NSIG; i++) - signal(i, SIG_DFL); - - /* Create sockets */ - if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1) - err(1, "socketpair() failed"); - - pw = getpwnam("_pflogd"); - if (pw == NULL) - errx(1, "unknown user _pflogd"); - endpwent(); - - child_pid = fork(); - if (child_pid < 0) - err(1, "fork() failed"); - - if (!child_pid) { - gid_t gidset[1]; - - /* Child - drop privileges and return */ - if (chroot(pw->pw_dir) != 0) - err(1, "unable to chroot"); - if (chdir("/") != 0) - err(1, "unable to chdir"); - - gidset[0] = pw->pw_gid; - if (setgroups(1, gidset) == -1) - err(1, "setgroups() failed"); - if (setegid(pw->pw_gid) == -1) - err(1, "setegid() failed"); - if (setgid(pw->pw_gid) == -1) - err(1, "setgid() failed"); - if (seteuid(pw->pw_uid) == -1) - err(1, "seteuid() failed"); - if (setuid(pw->pw_uid) == -1) - err(1, "setuid() failed"); - close(socks[0]); - priv_fd = socks[1]; - return 0; - } - - /* Father */ - /* Pass ALRM/TERM/HUP through to child, and accept CHLD */ - signal(SIGALRM, sig_pass_to_chld); - signal(SIGTERM, sig_pass_to_chld); - signal(SIGHUP, sig_pass_to_chld); - signal(SIGCHLD, sig_chld); - - setproctitle("[priv]"); - close(socks[1]); - - while (!gotsig_chld) { - if (may_read(socks[0], &cmd, sizeof(int))) - break; - switch (cmd) { - case PRIV_SET_SNAPLEN: - logmsg(LOG_DEBUG, - "[priv]: msg PRIV_SET_SNAPLENGTH received"); - must_read(socks[0], &snaplen, sizeof(int)); - - ret = set_snaplen(snaplen); - if (ret) { - logmsg(LOG_NOTICE, - "[priv]: set_snaplen failed for snaplen %d", - snaplen); - } - - must_write(socks[0], &ret, sizeof(int)); - break; - - case PRIV_OPEN_LOG: - logmsg(LOG_DEBUG, - "[priv]: msg PRIV_OPEN_LOG received"); - /* create or append logs but do not follow symlinks */ - fd = open(filename, - O_RDWR|O_CREAT|O_APPEND|O_NONBLOCK|O_NOFOLLOW, - 0600); - if (fd < 0) - logmsg(LOG_NOTICE, - "[priv]: failed to open %s: %s", - filename, strerror(errno)); - send_fd(socks[0], fd); - close(fd); - break; - - default: - logmsg(LOG_ERR, "[priv]: unknown command %d", cmd); - _exit(1); - /* NOTREACHED */ - } - } - - _exit(1); -} - -/* this is called from parent */ -static int -set_snaplen(int snap) -{ - if (hpcap == NULL) - return (1); - - hpcap->snapshot = snap; - set_pcap_filter(); - - return 0; -} - - -/* - * send the snaplength to privileged process - */ -int -priv_set_snaplen(int snaplen) -{ - int cmd, ret; - - if (priv_fd < 0) - errx(1, "%s: called from privileged portion", __func__); - - cmd = PRIV_SET_SNAPLEN; - - must_write(priv_fd, &cmd, sizeof(int)); - must_write(priv_fd, &snaplen, sizeof(int)); - - must_read(priv_fd, &ret, sizeof(int)); - - /* also set hpcap->snapshot in child */ - if (ret == 0) - hpcap->snapshot = snaplen; - - return (ret); -} - -/* Open log-file */ -int -priv_open_log(void) -{ - int cmd, fd; - - if (priv_fd < 0) - errx(1, "%s: called from privileged portion\n", __func__); - - cmd = PRIV_OPEN_LOG; - must_write(priv_fd, &cmd, sizeof(int)); - fd = receive_fd(priv_fd); - - return (fd); -} - -/* If priv parent gets a TERM or HUP, pass it through to child instead */ -static void -sig_pass_to_chld(int sig) -{ - int oerrno = errno; - - if (child_pid != -1) - kill(child_pid, sig); - errno = oerrno; -} - -/* if parent gets a SIGCHLD, it will exit */ -static void -sig_chld(int sig) -{ - gotsig_chld = 1; -} - -/* Read all data or return 1 for error. */ -static int -may_read(int fd, void *buf, size_t n) -{ - char *s = buf; - ssize_t res, pos = 0; - - while (n > pos) { - res = read(fd, s + pos, n - pos); - switch (res) { - case -1: - if (errno == EINTR || errno == EAGAIN) - continue; - case 0: - return (1); - default: - pos += res; - } - } - return (0); -} - -/* Read data with the assertion that it all must come through, or - * else abort the process. Based on atomicio() from openssh. */ -static void -must_read(int fd, void *buf, size_t n) -{ - char *s = buf; - ssize_t res, pos = 0; - - while (n > pos) { - res = read(fd, s + pos, n - pos); - switch (res) { - case -1: - if (errno == EINTR || errno == EAGAIN) - continue; - case 0: - _exit(0); - default: - pos += res; - } - } -} - -/* Write data with the assertion that it all has to be written, or - * else abort the process. Based on atomicio() from openssh. */ -static void -must_write(int fd, void *buf, size_t n) -{ - char *s = buf; - ssize_t res, pos = 0; - - while (n > pos) { - res = write(fd, s + pos, n - pos); - switch (res) { - case -1: - if (errno == EINTR || errno == EAGAIN) - continue; - case 0: - _exit(0); - default: - pos += res; - } - } -} diff --git a/contrib/pf/pflogd/privsep_fdpass.c b/contrib/pf/pflogd/privsep_fdpass.c deleted file mode 100644 index 166b6930b3bd..000000000000 --- a/contrib/pf/pflogd/privsep_fdpass.c +++ /dev/null @@ -1,120 +0,0 @@ -/* $OpenBSD: privsep_fdpass.c,v 1.1 2003/10/22 18:51:55 canacar Exp $ */ - -/* - * Copyright 2001 Niels Provos <provos@citi.umich.edu> - * All rights reserved. - * - * Copyright (c) 2002 Matthieu Herrb - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include <sys/param.h> -#include <sys/uio.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include "pflogd.h" - -void -send_fd(int sock, int fd) -{ - struct msghdr msg; - char tmp[CMSG_SPACE(sizeof(int))]; - struct cmsghdr *cmsg; - struct iovec vec; - int result = 0; - ssize_t n; - - memset(&msg, 0, sizeof(msg)); - - if (fd >= 0) { - msg.msg_control = (caddr_t)tmp; - msg.msg_controllen = CMSG_LEN(sizeof(int)); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - *(int *)CMSG_DATA(cmsg) = fd; - } else { - result = errno; - } - - vec.iov_base = &result; - vec.iov_len = sizeof(int); - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - - if ((n = sendmsg(sock, &msg, 0)) == -1) - warn("%s: sendmsg(%d)", __func__, sock); - if (n != sizeof(int)) - warnx("%s: sendmsg: expected sent 1 got %ld", - __func__, (long)n); -} - -int -receive_fd(int sock) -{ - struct msghdr msg; - char tmp[CMSG_SPACE(sizeof(int))]; - struct cmsghdr *cmsg; - struct iovec vec; - ssize_t n; - int result; - int fd; - - memset(&msg, 0, sizeof(msg)); - vec.iov_base = &result; - vec.iov_len = sizeof(int); - msg.msg_iov = &vec; - msg.msg_iovlen = 1; - msg.msg_control = tmp; - msg.msg_controllen = sizeof(tmp); - - if ((n = recvmsg(sock, &msg, 0)) == -1) - warn("%s: recvmsg", __func__); - if (n != sizeof(int)) - warnx("%s: recvmsg: expected received 1 got %ld", - __func__, (long)n); - if (result == 0) { - cmsg = CMSG_FIRSTHDR(&msg); - if (cmsg->cmsg_type != SCM_RIGHTS) - warnx("%s: expected type %d got %d", __func__, - SCM_RIGHTS, cmsg->cmsg_type); - fd = (*(int *)CMSG_DATA(cmsg)); - return fd; - } else { - errno = result; - return -1; - } -} |