mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-01 08:27:59 +00:00
Vendor import of OpenBSD's pf userland as of OpenBSD 3.4
Approved by: bms(mentor), core(in general)
This commit is contained in:
commit
13b9f61009
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/pf/dist/; revision=126353
463
contrib/pf/authpf/authpf.8
Normal file
463
contrib/pf/authpf/authpf.8
Normal file
@ -0,0 +1,463 @@
|
||||
.\" $OpenBSD: authpf.8,v 1.30 2003/08/17 23:24:47 henning 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 PIDs of the
|
||||
.Nm
|
||||
processes.
|
||||
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
|
||||
\fBControl Files\fP - 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
|
||||
\fBDistributed Authentication\fP - 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
|
||||
\fBSSH Configuration\fP - 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
|
||||
\fBBanners\fP - 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
|
||||
\fBPacket Filter Rules\fP - 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.
|
||||
The examples below assume a switched wired net.
|
||||
.Pp
|
||||
Example
|
||||
.Pa /etc/pf.conf :
|
||||
.Bd -literal
|
||||
# by default we allow internal clients to talk to us using
|
||||
# ssh and use us as a dns server.
|
||||
internal_if=\&"fxp1\&"
|
||||
gateway_addr=\&"10.0.1.1\&"
|
||||
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
|
||||
Example
|
||||
.Pa /etc/authpf/authpf.rules :
|
||||
.Bd -literal
|
||||
# no real restrictions here, basically turn the network jack off or on.
|
||||
|
||||
external_if = \&"xl0\&"
|
||||
internal_if = \&"fxp0\&"
|
||||
|
||||
pass in log quick on $internal_if proto tcp from $user_ip to any \e
|
||||
keep state
|
||||
pass in quick on $internal_if from $user_ip to any
|
||||
.Ed
|
||||
.Pp
|
||||
Another example
|
||||
.Pa /etc/authpf/authpf.rules
|
||||
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
|
||||
.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.
|
871
contrib/pf/authpf/authpf.c
Normal file
871
contrib/pf/authpf/authpf.c
Normal file
@ -0,0 +1,871 @@
|
||||
/* $OpenBSD: authpf.c,v 1.68 2003/08/21 19:13:23 frantzen 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 "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;
|
||||
|
||||
if ((n = snprintf(rulesetname, sizeof(rulesetname), "%ld",
|
||||
(long)getpid())) < 0 || n >= sizeof(rulesetname)) {
|
||||
syslog(LOG_ERR, "pid too large for ruleset name");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config = fopen(PATH_CONFFILE, "r");
|
||||
|
||||
if ((cp = getenv("SSH_TTY")) == NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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());
|
||||
|
||||
if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser))
|
||||
do_death(0);
|
||||
|
||||
openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON);
|
||||
if (config == NULL || read_config(config))
|
||||
do_death(0);
|
||||
|
||||
if (remove_stale_rulesets())
|
||||
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(1);
|
||||
}
|
||||
|
||||
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;
|
||||
pid_t pid;
|
||||
|
||||
prs.nr = nr;
|
||||
if (ioctl(dev, DIOCGETRULESET, &prs))
|
||||
return (1);
|
||||
errno = 0;
|
||||
pid = strtoul(prs.name, &s, 10);
|
||||
if (!prs.name[0] || errno || *s)
|
||||
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;
|
||||
const int action[PF_RULESET_MAX] = { PF_SCRUB,
|
||||
PF_PASS, PF_NAT, PF_BINAT, PF_RDR };
|
||||
struct pfctl pf;
|
||||
struct pfioc_rule pr[PF_RULESET_MAX];
|
||||
int i;
|
||||
|
||||
if (luser == NULL || !luser[0] || strlen(luser) >=
|
||||
PF_RULESET_NAME_SIZE || 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;
|
||||
}
|
||||
|
||||
memset(&pf, 0, sizeof(pf));
|
||||
for (i = 0; i < PF_RULESET_MAX; ++i) {
|
||||
memset(&pr[i], 0, sizeof(pr[i]));
|
||||
pr[i].rule.action = action[i];
|
||||
strlcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor));
|
||||
strlcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset));
|
||||
if (ioctl(dev, DIOCBEGINRULES, &pr[i])) {
|
||||
syslog(LOG_ERR, "DIOCBEGINRULES %m");
|
||||
goto error;
|
||||
}
|
||||
pf.prule[i] = &pr[i];
|
||||
}
|
||||
|
||||
if (add) {
|
||||
if (symset("user_ip", ipsrc, 0) ||
|
||||
symset("user_id", luser, 0)) {
|
||||
syslog(LOG_ERR, "symset");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pf.dev = dev;
|
||||
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;
|
||||
}
|
||||
|
||||
for (i = 0; i < PF_RULESET_MAX; ++i)
|
||||
/*
|
||||
* ignore EINVAL on removal, it means the anchor was
|
||||
* already automatically removed by the kernel.
|
||||
*/
|
||||
if (ioctl(dev, DIOCCOMMITRULES, &pr[i]) &&
|
||||
(add || errno != EINVAL)) {
|
||||
syslog(LOG_ERR, "DIOCCOMMITRULES %m");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (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);
|
||||
|
||||
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)
|
||||
{
|
||||
struct pfioc_rule *pr;
|
||||
|
||||
switch (r->action) {
|
||||
case PF_PASS:
|
||||
case PF_DROP:
|
||||
pr = pf->prule[PF_RULESET_FILTER];
|
||||
break;
|
||||
case PF_SCRUB:
|
||||
pr = pf->prule[PF_RULESET_SCRUB];
|
||||
break;
|
||||
case PF_NAT:
|
||||
case PF_NONAT:
|
||||
pr = pf->prule[PF_RULESET_NAT];
|
||||
break;
|
||||
case PF_RDR:
|
||||
case PF_NORDR:
|
||||
pr = pf->prule[PF_RULESET_RDR];
|
||||
break;
|
||||
case PF_BINAT:
|
||||
case PF_NOBINAT:
|
||||
pr = pf->prule[PF_RULESET_BINAT];
|
||||
break;
|
||||
default:
|
||||
syslog(LOG_ERR, "invalid rule action %d", r->action);
|
||||
return (1);
|
||||
}
|
||||
if (pfctl_add_pool(pf, &r->rpool, r->af))
|
||||
return (1);
|
||||
pr->pool_ticket = pf->paddr.ticket;
|
||||
memcpy(&pr->rule, r, sizeof(pr->rule));
|
||||
if (ioctl(pf->dev, DIOCADDRULE, pr)) {
|
||||
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_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_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)
|
||||
{
|
||||
/* never called, no anchors inside anchors, but we need the stub */
|
||||
fprintf(stderr, "load anchor not supported from authpf\n");
|
||||
return (1);
|
||||
}
|
||||
|
37
contrib/pf/authpf/pathnames.h
Normal file
37
contrib/pf/authpf/pathnames.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* $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"
|
253
contrib/pf/ftp-proxy/ftp-proxy.8
Normal file
253
contrib/pf/ftp-proxy/ftp-proxy.8
Normal file
@ -0,0 +1,253 @@
|
||||
.\" $OpenBSD: ftp-proxy.8,v 1.37 2003/09/05 12:27:47 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 D Ar debuglevel
|
||||
.Op Fl g Ar group
|
||||
.Op Fl m Ar minport
|
||||
.Op Fl M Ar maxport
|
||||
.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 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 minport
|
||||
Specify the lower end of the port range the proxy will use for all
|
||||
data connections it establishes.
|
||||
The default is
|
||||
.Dv IPPORT_HIFIRSTAUTO
|
||||
defined in
|
||||
.Aq Pa netinet/in.h
|
||||
as 49152.
|
||||
.It Fl M Ar maxport
|
||||
Specify the upper end of the port range the proxy will use for the
|
||||
data connections it establishes.
|
||||
The default is
|
||||
.Dv IPPORT_HILASTAUTO
|
||||
defined in
|
||||
.Aq Pa netinet/in.h
|
||||
as 65535.
|
||||
.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 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.
|
1320
contrib/pf/ftp-proxy/ftp-proxy.c
Normal file
1320
contrib/pf/ftp-proxy/ftp-proxy.c
Normal file
File diff suppressed because it is too large
Load Diff
259
contrib/pf/ftp-proxy/getline.c
Normal file
259
contrib/pf/ftp-proxy/getline.c
Normal file
@ -0,0 +1,259 @@
|
||||
/* $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);
|
||||
}
|
||||
}
|
296
contrib/pf/ftp-proxy/util.c
Normal file
296
contrib/pf/ftp-proxy/util.c
Normal file
@ -0,0 +1,296 @@
|
||||
/* $OpenBSD: util.c,v 1.16 2003/06/28 01:04:57 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.
|
||||
* 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;
|
||||
|
||||
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;
|
||||
int slen, 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 (sap == NULL)
|
||||
sa.sin_addr.s_addr = INADDR_ANY;
|
||||
else
|
||||
sa.sin_addr.s_addr = sap->sin_addr.s_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);
|
||||
}
|
68
contrib/pf/ftp-proxy/util.h
Normal file
68
contrib/pf/ftp-proxy/util.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* $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;
|
||||
|
||||
|
703
contrib/pf/man/pf.4
Normal file
703
contrib/pf/man/pf.4
Normal file
@ -0,0 +1,703 @@
|
||||
.\" $OpenBSD: pf.4,v 1.37 2003/08/28 09:41:22 jmc 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 1"
|
||||
.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 "u_int32_t"
|
||||
Clears the buffer address pool
|
||||
and returns a ticket for subsequent DIOCADDADDR, DIOCADDRULE and
|
||||
DIOCCHANGERULE calls.
|
||||
.It Dv DIOCADDADDR Fa "struct pfioc_pooladdr"
|
||||
.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
|
||||
Adds pool address
|
||||
.Va addr
|
||||
to the buffer address pool to be used in the following
|
||||
DIOCADDRULE or DIOCCHANGERULE call.
|
||||
All other members of the structure are ignored.
|
||||
.It Dv DIOCBEGINRULES Fa "u_int32_t"
|
||||
Clears the inactive ruleset for the type of rule indicated by
|
||||
.Va rule.action
|
||||
and returns a ticket for subsequent
|
||||
DIOCADDRULE and DIOCCOMMITRULES calls.
|
||||
.It Dv DIOCADDRULE Fa "struct pfioc_rule"
|
||||
.Bd -literal
|
||||
struct pfioc_rule {
|
||||
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 DIOCBEGINRULES 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 DIOCCOMMITRULES Fa "u_int32_t"
|
||||
Switch inactive to active filter ruleset.
|
||||
Requires
|
||||
.Va ticket .
|
||||
.It Dv DIOCBEGINALTQS Fa "u_int32_t"
|
||||
Clears the inactive list of queues and returns a ticket for subsequent
|
||||
DIOCADDALTQ and DIOCCOMMITALTQS calls.
|
||||
.It Dv DIOCADDALTQ Fa "struct pfioc_altq"
|
||||
Adds
|
||||
.Bd -literal
|
||||
struct pfioc_altq {
|
||||
u_int32_t ticket;
|
||||
u_int32_t nr;
|
||||
struct pf_altq altq;
|
||||
};
|
||||
.Ed
|
||||
.It Dv DIOCCOMMITALTQS Fa "u_int32_t"
|
||||
Switch inactive to active list of queues.
|
||||
Requires
|
||||
.Va ticket .
|
||||
.It Dv DIOCGETRULES Fa "struct pfioc_rule"
|
||||
Returns
|
||||
.Va ticket
|
||||
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 DIOCCLRSTATES
|
||||
Clears the state table.
|
||||
.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;
|
||||
};
|
||||
.Ed
|
||||
.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 pcounters[2][2][3];
|
||||
u_int64_t bcounters[2][2];
|
||||
u_int32_t running;
|
||||
u_int32_t states;
|
||||
u_int32_t since;
|
||||
u_int32_t debug;
|
||||
};
|
||||
.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;
|
||||
u_int8_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 DIOCRINABEGIN Fa "struct pfioc_table"
|
||||
Starts a transaction with the inactive set of tables.
|
||||
Cleans up any leftover from a previously aborted transaction, and returns
|
||||
a new ticket.
|
||||
On exit, pfrio_ndel contains the number of leftover table deleted, and
|
||||
pfrio_ticket contains a valid ticket to use for the following two IOCTLs.
|
||||
.It Dv DIOCRINACOMMIT Fa "struct pfioc_table"
|
||||
Commit the inactive set of tables into the active set.
|
||||
While copying the addresses, do a best effort to keep statistics for
|
||||
addresses present before and after the commit.
|
||||
On entry, io->pfrio_ticket takes a valid ticket.
|
||||
On exit, io->pfrio_nadd and io->pfrio_nchange contain the number of tables
|
||||
added and altered by the commit operation.
|
||||
.It Dv DIOCRINADEFINE Fa "struct pfioc_table"
|
||||
Defines a table in the inactive set.
|
||||
On entry, pfrio_table contains the table id and pfrio_buffer[pfrio_size]
|
||||
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 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.
|
||||
.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 .
|
2486
contrib/pf/man/pf.conf.5
Normal file
2486
contrib/pf/man/pf.conf.5
Normal file
File diff suppressed because it is too large
Load Diff
242
contrib/pf/man/pf.os.5
Normal file
242
contrib/pf/man/pf.os.5
Normal file
@ -0,0 +1,242 @@
|
||||
.\" $OpenBSD: pf.os.5,v 1.4 2003/08/28 09:41:23 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 packets'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
|
88
contrib/pf/man/pflog.4
Normal file
88
contrib/pf/man/pflog.4
Normal file
@ -0,0 +1,88 @@
|
||||
.\" $OpenBSD: pflog.4,v 1.4 2003/09/22 04:53:15 jmc 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
|
||||
.Sy pseudo-device Nm pflog Em <number>
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm pflog
|
||||
interface is the interface the packet filter,
|
||||
.Xr pf 4 ,
|
||||
copies all the packets to which it has been configured to log.
|
||||
In this way, all logged packets can easily be monitored in real
|
||||
time by invoking
|
||||
.Xr tcpdump 8
|
||||
on the
|
||||
.Nm
|
||||
interface.
|
||||
.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?
|
80
contrib/pf/man/pfsync.4
Normal file
80
contrib/pf/man/pfsync.4
Normal file
@ -0,0 +1,80 @@
|
||||
.\" $OpenBSD: pfsync.4,v 1.6 2003/06/06 10:29:41 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
|
||||
.Sy pseudo-device Nm pfsync
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm pfsync
|
||||
interface is the interface to the packet filter,
|
||||
.Xr pf 4 ,
|
||||
exposing all the changes to the state table.
|
||||
This allows for both debugging of rulesets and monitoring
|
||||
for changes in the table by invoking
|
||||
.Xr tcpdump 8
|
||||
on the
|
||||
.Nm
|
||||
interface.
|
||||
.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 EXAMPLES
|
||||
.Bd -literal -offset indent
|
||||
# ifconfig pfsync0 up
|
||||
# tcpdump -s1500 -evtni pfsync0
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr inet 4 ,
|
||||
.Xr inet6 4 ,
|
||||
.Xr netintro 4 ,
|
||||
.Xr pf 4 ,
|
||||
.Xr ifconfig 8 ,
|
||||
.Xr tcpdump 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
device first appeared in
|
||||
.Ox 3.3 .
|
4489
contrib/pf/pfctl/parse.y
Normal file
4489
contrib/pf/pfctl/parse.y
Normal file
File diff suppressed because it is too large
Load Diff
279
contrib/pf/pfctl/pf_print_state.c
Normal file
279
contrib/pf/pfctl/pf_print_state.c
Normal file
@ -0,0 +1,279 @@
|
||||
/* $OpenBSD: pf_print_state.c,v 1.33 2003/07/06 22:01:28 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#define TCPSTATES
|
||||
#include <netinet/tcp_fsm.h>
|
||||
#include <net/pfvar.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pfctl_parser.h"
|
||||
#include "pfctl.h"
|
||||
|
||||
void print_name(struct pf_addr *, sa_family_t);
|
||||
|
||||
void
|
||||
print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose)
|
||||
{
|
||||
switch(addr->type) {
|
||||
case PF_ADDR_DYNIFTL:
|
||||
printf("(%s)", addr->v.ifname);
|
||||
break;
|
||||
case PF_ADDR_TABLE:
|
||||
if (verbose)
|
||||
if (addr->p.tblcnt == -1)
|
||||
printf("<%s:*>", addr->v.tblname);
|
||||
else
|
||||
printf("<%s:%d>", addr->v.tblname,
|
||||
addr->p.tblcnt);
|
||||
else
|
||||
printf("<%s>", addr->v.tblname);
|
||||
return;
|
||||
case PF_ADDR_ADDRMASK:
|
||||
if (PF_AZERO(&addr->v.a.addr, AF_INET6) &&
|
||||
PF_AZERO(&addr->v.a.mask, AF_INET6))
|
||||
printf("any");
|
||||
else {
|
||||
char buf[48];
|
||||
|
||||
if (inet_ntop(af, &addr->v.a.addr, buf,
|
||||
sizeof(buf)) == NULL)
|
||||
printf("?");
|
||||
else
|
||||
printf("%s", buf);
|
||||
}
|
||||
break;
|
||||
case PF_ADDR_NOROUTE:
|
||||
printf("no-route");
|
||||
return;
|
||||
default:
|
||||
printf("?");
|
||||
return;
|
||||
}
|
||||
if (! PF_AZERO(&addr->v.a.mask, af)) {
|
||||
int bits = unmask(&addr->v.a.mask, af);
|
||||
|
||||
if (bits != (af == AF_INET ? 32 : 128))
|
||||
printf("/%d", bits);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_name(struct pf_addr *addr, sa_family_t af)
|
||||
{
|
||||
char host[NI_MAXHOST];
|
||||
|
||||
strlcpy(host, "?", sizeof(host));
|
||||
switch (af) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in sin;
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr = addr->v4;
|
||||
getnameinfo((struct sockaddr *)&sin, sin.sin_len,
|
||||
host, sizeof(host), NULL, 0, NI_NOFQDN);
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 sin6;
|
||||
|
||||
memset(&sin6, 0, sizeof(sin6));
|
||||
sin6.sin6_len = sizeof(sin6);
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_addr = addr->v6;
|
||||
getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
|
||||
host, sizeof(host), NULL, 0, NI_NOFQDN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("%s", host);
|
||||
}
|
||||
|
||||
void
|
||||
print_host(struct pf_state_host *h, sa_family_t af, int opts)
|
||||
{
|
||||
u_int16_t p = ntohs(h->port);
|
||||
|
||||
if (opts & PF_OPT_USEDNS)
|
||||
print_name(&h->addr, af);
|
||||
else {
|
||||
struct pf_addr_wrap aw;
|
||||
|
||||
memset(&aw, 0, sizeof(aw));
|
||||
aw.v.a.addr = h->addr;
|
||||
if (af == AF_INET)
|
||||
aw.v.a.mask.addr32[0] = 0xffffffff;
|
||||
else
|
||||
memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask));
|
||||
print_addr(&aw, af, opts & PF_OPT_VERBOSE2);
|
||||
}
|
||||
|
||||
if (p) {
|
||||
if (af == AF_INET)
|
||||
printf(":%u", p);
|
||||
else
|
||||
printf("[%u]", p);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_seq(struct pf_state_peer *p)
|
||||
{
|
||||
if (p->seqdiff)
|
||||
printf("[%u + %u](+%u)", p->seqlo, p->seqhi - p->seqlo,
|
||||
p->seqdiff);
|
||||
else
|
||||
printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo);
|
||||
}
|
||||
|
||||
void
|
||||
print_state(struct pf_state *s, int opts)
|
||||
{
|
||||
struct pf_state_peer *src, *dst;
|
||||
struct protoent *p;
|
||||
int min, sec;
|
||||
|
||||
if (s->direction == PF_OUT) {
|
||||
src = &s->src;
|
||||
dst = &s->dst;
|
||||
} else {
|
||||
src = &s->dst;
|
||||
dst = &s->src;
|
||||
}
|
||||
if ((p = getprotobynumber(s->proto)) != NULL)
|
||||
printf("%s ", p->p_name);
|
||||
else
|
||||
printf("%u ", s->proto);
|
||||
if (PF_ANEQ(&s->lan.addr, &s->gwy.addr, s->af) ||
|
||||
(s->lan.port != s->gwy.port)) {
|
||||
print_host(&s->lan, s->af, opts);
|
||||
if (s->direction == PF_OUT)
|
||||
printf(" -> ");
|
||||
else
|
||||
printf(" <- ");
|
||||
}
|
||||
print_host(&s->gwy, s->af, opts);
|
||||
if (s->direction == PF_OUT)
|
||||
printf(" -> ");
|
||||
else
|
||||
printf(" <- ");
|
||||
print_host(&s->ext, s->af, opts);
|
||||
|
||||
printf(" ");
|
||||
if (s->proto == IPPROTO_TCP) {
|
||||
if (src->state <= TCPS_TIME_WAIT &&
|
||||
dst->state <= TCPS_TIME_WAIT)
|
||||
printf(" %s:%s\n", tcpstates[src->state],
|
||||
tcpstates[dst->state]);
|
||||
else if (src->state == PF_TCPS_PROXY_SRC ||
|
||||
dst->state == PF_TCPS_PROXY_SRC)
|
||||
printf(" PROXY:SRC\n");
|
||||
else if (src->state == PF_TCPS_PROXY_DST ||
|
||||
dst->state == PF_TCPS_PROXY_DST)
|
||||
printf(" PROXY:DST\n");
|
||||
else
|
||||
printf(" <BAD STATE LEVELS %u:%u>\n",
|
||||
src->state, dst->state);
|
||||
if (opts & PF_OPT_VERBOSE) {
|
||||
printf(" ");
|
||||
print_seq(src);
|
||||
if (src->wscale && dst->wscale)
|
||||
printf(" wscale %u",
|
||||
src->wscale & PF_WSCALE_MASK);
|
||||
printf(" ");
|
||||
print_seq(dst);
|
||||
if (src->wscale && dst->wscale)
|
||||
printf(" wscale %u",
|
||||
dst->wscale & PF_WSCALE_MASK);
|
||||
printf("\n");
|
||||
}
|
||||
} else if (s->proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES &&
|
||||
dst->state < PFUDPS_NSTATES) {
|
||||
const char *states[] = PFUDPS_NAMES;
|
||||
|
||||
printf(" %s:%s\n", states[src->state], states[dst->state]);
|
||||
} else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES &&
|
||||
dst->state < PFOTHERS_NSTATES) {
|
||||
/* XXX ICMP doesn't really have state levels */
|
||||
const char *states[] = PFOTHERS_NAMES;
|
||||
|
||||
printf(" %s:%s\n", states[src->state], states[dst->state]);
|
||||
} else {
|
||||
printf(" %u:%u\n", src->state, dst->state);
|
||||
}
|
||||
|
||||
if (opts & PF_OPT_VERBOSE) {
|
||||
sec = s->creation % 60;
|
||||
s->creation /= 60;
|
||||
min = s->creation % 60;
|
||||
s->creation /= 60;
|
||||
printf(" age %.2u:%.2u:%.2u", s->creation, min, sec);
|
||||
sec = s->expire % 60;
|
||||
s->expire /= 60;
|
||||
min = s->expire % 60;
|
||||
s->expire /= 60;
|
||||
printf(", expires in %.2u:%.2u:%.2u", s->expire, min, sec);
|
||||
printf(", %u:%u pkts, %u:%u bytes",
|
||||
s->packets[0], s->packets[1], s->bytes[0], s->bytes[1]);
|
||||
if (s->anchor.nr != -1)
|
||||
printf(", anchor %u", s->anchor.nr);
|
||||
if (s->rule.nr != -1)
|
||||
printf(", rule %u", s->rule.nr);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
unmask(struct pf_addr *m, sa_family_t af)
|
||||
{
|
||||
int i = 31, j = 0, b = 0;
|
||||
u_int32_t tmp;
|
||||
|
||||
while (j < 4 && m->addr32[j] == 0xffffffff) {
|
||||
b += 32;
|
||||
j++;
|
||||
}
|
||||
if (j < 4) {
|
||||
tmp = ntohl(m->addr32[j]);
|
||||
for (i = 31; tmp & (1 << i); --i)
|
||||
b++;
|
||||
}
|
||||
return (b);
|
||||
}
|
506
contrib/pf/pfctl/pfctl.8
Normal file
506
contrib/pf/pfctl/pfctl.8
Normal file
@ -0,0 +1,506 @@
|
||||
.\" $OpenBSD: pfctl.8,v 1.102 2003/09/18 09:18:51 jmc 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. 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 November 20, 2002
|
||||
.Dt PFCTL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm pfctl
|
||||
.Nd "control the packet filter (PF) and network address translation (NAT) device"
|
||||
.Sh SYNOPSIS
|
||||
.Nm pfctl
|
||||
.Bk -words
|
||||
.Op Fl AdeghnNqrROvz
|
||||
.Op Fl a Ar anchor Ns Op Ar :ruleset
|
||||
.Op Fl D Ar macro=value
|
||||
.Op Fl f Ar file
|
||||
.Op Fl F Ar modifier
|
||||
.Op Fl k Ar host
|
||||
.Op Fl s Ar modifier
|
||||
.Op Fl t Ar table
|
||||
.Op Fl T Ar command Op Ar address ...
|
||||
.Op Fl x Ar level
|
||||
.Ek
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility communicates with the packet filter device using the
|
||||
ioctl interface described in
|
||||
.Xr pf 4 .
|
||||
It allows ruleset and parameter configuration and retrieval of status
|
||||
information from the packet filter.
|
||||
.Pp
|
||||
Packet filtering restricts the types of packets that pass through
|
||||
network interfaces entering or leaving the host based on filter
|
||||
rules as described in
|
||||
.Xr pf.conf 5 .
|
||||
The packet filter can also replace addresses and ports of packets.
|
||||
Replacing source addresses and ports of outgoing packets is called
|
||||
NAT (Network Address Translation) and is used to connect an internal
|
||||
network (usually reserved address space) to an external one (the
|
||||
Internet) by making all connections to external hosts appear to
|
||||
come from the gateway.
|
||||
Replacing destination addresses and ports of incoming packets
|
||||
is used to redirect connections to different hosts and/or ports.
|
||||
A combination of both translations, bidirectional NAT, is also
|
||||
supported.
|
||||
Translation rules are described in
|
||||
.Xr pf.conf 5 .
|
||||
.Pp
|
||||
When the variable pf is set to YES in
|
||||
.Xr rc.conf 8 ,
|
||||
the rule file specified with the variable pf_rules
|
||||
is loaded automatically by the
|
||||
.Xr rc 8
|
||||
scripts and the packet filter is enabled.
|
||||
.Pp
|
||||
The packet filter does not itself forward packets between interfaces.
|
||||
Forwarding can be enabled by setting the
|
||||
.Xr sysctl 8
|
||||
variables
|
||||
.Em net.inet.ip.forwarding
|
||||
and/or
|
||||
.Em net.inet6.ip6.forwarding ,
|
||||
to 1.
|
||||
Set them permanently in
|
||||
.Xr sysctl.conf 5 .
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility provides several commands.
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl a Ar anchor Ns Op Ar :ruleset
|
||||
Apply flags
|
||||
.Fl f ,
|
||||
.Fl F
|
||||
and
|
||||
.Fl s
|
||||
only to the rules in the specified
|
||||
.Ar anchor
|
||||
and optional named ruleset
|
||||
.Ar ruleset .
|
||||
In addition to the main ruleset,
|
||||
.Nm
|
||||
can load and manipulate additional rulesets by name.
|
||||
Named rulesets are attached at
|
||||
.Ar anchor
|
||||
points, which are also referenced by name.
|
||||
Evaluation of
|
||||
.Ar anchor
|
||||
rules from the main ruleset is described in
|
||||
.Xr pf.conf 5 .
|
||||
For example, to show all filter rules inside anchor
|
||||
.Li foo :
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -a foo -s rules
|
||||
.Ed
|
||||
.Pp
|
||||
Private tables can also be put inside subrulesets, either by having table
|
||||
statements in the
|
||||
.Xr pf.conf 5
|
||||
file that is loaded in the anchor, or by using regular table commands as in:
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -a foo:bar -t mytable -T add 1.2.3.4 5.6.7.8
|
||||
.Ed
|
||||
.Pp
|
||||
When a rule referring to a table is loaded in an anchor, the rule will use the
|
||||
private table if one is defined, and then fallback to the table defined in the
|
||||
main ruleset, if there is one.
|
||||
This is similar to C rules for variables.
|
||||
It is possible to create distinct tables with the same name in the global
|
||||
ruleset and in an anchor, but this is often bad design and a warning will be
|
||||
issued in that case.
|
||||
.It Fl A
|
||||
Load only the queue rules present in the rule file.
|
||||
Other rules and options are ignored.
|
||||
.It Fl d
|
||||
Disable the packet filter.
|
||||
.It Fl D Ar macro=value
|
||||
Define
|
||||
.Ar macro
|
||||
to be set to
|
||||
.Ar value
|
||||
on the command line.
|
||||
Overrides the definition of
|
||||
.Ar macro
|
||||
in the ruleset.
|
||||
.It Fl e
|
||||
Enable the packet filter.
|
||||
.It Fl f Ar file
|
||||
Load the rules contained in
|
||||
.Ar file .
|
||||
This
|
||||
.Ar file
|
||||
may contain macros, tables, options, and normalization, queueing,
|
||||
translation, and filtering rules.
|
||||
With the exception of macros and tables, the statements must appear in that
|
||||
order.
|
||||
.It Fl F Ar modifier
|
||||
Flush the filter parameters specified by
|
||||
.Ar modifier
|
||||
(may be abbreviated):
|
||||
.Pp
|
||||
.Bl -tag -width xxxxxxxxxxxx -compact
|
||||
.It Fl F Ar nat
|
||||
Flush the NAT rules.
|
||||
.It Fl F Ar queue
|
||||
Flush the queue rules.
|
||||
.It Fl F Ar rules
|
||||
Flush the filter rules.
|
||||
.It Fl F Ar state
|
||||
Flush the state table (NAT and filter).
|
||||
.It Fl F Ar info
|
||||
Flush the filter information (statistics that are not bound to rules).
|
||||
.It Fl F Ar Tables
|
||||
Flush the tables.
|
||||
.It Fl F Ar osfp
|
||||
Flush the passive operating system fingerprints.
|
||||
.It Fl F Ar all
|
||||
Flush all of the above.
|
||||
.El
|
||||
.It Fl g
|
||||
Include output helpful for debugging.
|
||||
.It Fl k Ar host
|
||||
Kill all of the state entries originating from the specified
|
||||
.Ar host .
|
||||
A second
|
||||
.Fl k Ar host
|
||||
option may be specified, which will kill all the state entries
|
||||
from the first
|
||||
.Ar host
|
||||
to the second
|
||||
.Ar host .
|
||||
For example, to kill all of the state entries originating from
|
||||
.Li host :
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -k host
|
||||
.Ed
|
||||
.Pp
|
||||
To kill all of the state entries from
|
||||
.Li host1
|
||||
to
|
||||
.Li host2 :
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -k host1 -k host2
|
||||
.Ed
|
||||
.It Fl h
|
||||
Help.
|
||||
.It Fl n
|
||||
Do not actually load rules, just parse them.
|
||||
.It Fl N
|
||||
Load only the NAT rules present in the rule file.
|
||||
Other rules and options are ignored.
|
||||
.It Fl q
|
||||
Only print errors and warnings.
|
||||
.It Fl r
|
||||
Perform reverse DNS lookups on states when displaying them.
|
||||
.It Fl R
|
||||
Load only the filter rules present in the rule file.
|
||||
Other rules and options are ignored.
|
||||
.It Fl O
|
||||
Load only the options present in the rule file.
|
||||
Other rules and options are ignored.
|
||||
.It Fl s Ar modifier
|
||||
Show the filter parameters specified by
|
||||
.Ar modifier
|
||||
(may be abbreviated):
|
||||
.Pp
|
||||
.Bl -tag -width xxxxxxxxxxxx -compact
|
||||
.It Fl s Ar nat
|
||||
Show the currently loaded NAT rules.
|
||||
.It Fl s Ar queue
|
||||
Show the currently loaded queue rules.
|
||||
When used together with
|
||||
.Fl v ,
|
||||
per-queue statistics are also shown.
|
||||
When used together with
|
||||
.Fl v v ,
|
||||
.Nm
|
||||
will loop and show updated queue statistics every five seconds, including
|
||||
measured bandwidth and packets per second.
|
||||
.It Fl s Ar rules
|
||||
Show the currently loaded filter rules.
|
||||
When used together with
|
||||
.Fl v ,
|
||||
the per-rule statistics (number of evaluations,
|
||||
packets and bytes) are also shown.
|
||||
Note that the 'skip step' optimization done automatically by the kernel
|
||||
will skip evaluation of rules where possible.
|
||||
Packets passed statefully are counted in the rule that created the state
|
||||
(even though the rule isn't evaluated more than once for the entire
|
||||
connection).
|
||||
.It Fl s Ar Anchors
|
||||
Show the currently loaded anchors.
|
||||
If
|
||||
.Fl a Ar anchor
|
||||
is specified as well, the named rulesets currently loaded in the specified
|
||||
anchor are shown instead.
|
||||
.It Fl s Ar state
|
||||
Show the contents of the state table.
|
||||
.It Fl s Ar info
|
||||
Show filter information (statistics and counters).
|
||||
.It Fl s Ar labels
|
||||
Show per-rule statistics (label, evaluations, packets, bytes) of
|
||||
filter rules with labels, useful for accounting.
|
||||
.It Fl s Ar timeouts
|
||||
Show the current global timeouts.
|
||||
.It Fl s Ar memory
|
||||
Show the current pool memory hard limits.
|
||||
.It Fl s Ar Tables
|
||||
Show the list of tables.
|
||||
.It Fl s Ar osfp
|
||||
Show the list of operating system fingerprints.
|
||||
Can be used in combination with
|
||||
.Fl o Ar file
|
||||
to list the fingerprints in a
|
||||
.Xr pf.os 5
|
||||
file.
|
||||
.It Fl s Ar all
|
||||
Show all of the above.
|
||||
.El
|
||||
.It Fl t Ar table
|
||||
Specify the name of the table.
|
||||
.It Fl T Ar command Op Ar address ...
|
||||
Specify the
|
||||
.Ar command
|
||||
(may be abbreviated) to apply to the table.
|
||||
Commands include:
|
||||
.Pp
|
||||
.Bl -tag -width xxxxxxxxxxxx -compact
|
||||
.It Fl T Ar kill
|
||||
Kill a table.
|
||||
.It Fl T Ar flush
|
||||
Flush all addresses of a table.
|
||||
.It Fl T Ar add
|
||||
Add one or more addresses in a table.
|
||||
Automatically create a nonexisting table.
|
||||
.It Fl T Ar delete
|
||||
Delete one or more addresses from a table.
|
||||
.It Fl T Ar replace
|
||||
Replace the addresses of the table.
|
||||
Automatically create a nonexisting table.
|
||||
.It Fl T Ar show
|
||||
Show the content (addresses) of a table.
|
||||
.It Fl T Ar test
|
||||
Test if the given addresses match a table.
|
||||
.It Fl T Ar zero
|
||||
Clear all the statistics of a table.
|
||||
.It Fl T Ar load
|
||||
Load only the table definitions from
|
||||
.Xr pf.conf 5 .
|
||||
This is used in conjunction with the
|
||||
.Fl f
|
||||
flag, as in:
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -Tl -f pf.conf
|
||||
.Ed
|
||||
.El
|
||||
.Pp
|
||||
For the
|
||||
.Ar add ,
|
||||
.Ar delete ,
|
||||
.Ar replace
|
||||
and
|
||||
.Ar test
|
||||
commands, the list of addresses can be specified either directly on the command
|
||||
line and/or in an unformatted text file, using the
|
||||
.Fl f
|
||||
flag.
|
||||
Comments starting with a "#" are allowed in the text file.
|
||||
With these commands, the
|
||||
.Fl v
|
||||
flag can also be used once or twice, in which case
|
||||
.Nm pfctl
|
||||
will print the
|
||||
detailed result of the operation for each individual address, prefixed by
|
||||
one of the following letters:
|
||||
.Pp
|
||||
.Bl -tag -width XXX -compact
|
||||
.It A
|
||||
The address/network has been added.
|
||||
.It C
|
||||
The address/network has been changed (negated).
|
||||
.It D
|
||||
The address/network has been deleted.
|
||||
.It M
|
||||
The address matches (test operation only).
|
||||
.It X
|
||||
The address/network is duplicated and therefore ignored.
|
||||
.It Y
|
||||
The address/network cannot be added/deleted due to conflicting "!" attribute.
|
||||
.It Z
|
||||
The address/network has been cleared (statistics).
|
||||
.El
|
||||
.Pp
|
||||
Each table maintains a set of counters that can be retrieved using the
|
||||
.Fl v
|
||||
flag of
|
||||
.Nm pfctl .
|
||||
For example, the following commands define a wide open firewall which will keep
|
||||
track of packets going to or coming from the
|
||||
.Ox
|
||||
ftp server.
|
||||
The following commands configure the firewall and send 10 pings to the ftp
|
||||
server:
|
||||
.Bd -literal -offset indent
|
||||
# printf \&"table <test> { ftp.openbsd.org }\en \e
|
||||
\ \ pass out to <test> keep state\en" \&| pfctl -f-
|
||||
# ping -qc10 ftp.openbsd.org
|
||||
.Ed
|
||||
.Pp
|
||||
We can now use the table
|
||||
.Ar show
|
||||
command to output, for each address and packet direction, the number of packets
|
||||
and bytes that are being passed or blocked by rules referencing the table.
|
||||
The time at which the current accounting started is also shown with the
|
||||
.Ar Cleared
|
||||
line.
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -t test -vTshow
|
||||
\ \ \ 129.128.5.191
|
||||
\ \ \ \ Cleared: \ \ \ \ Thu Feb 13 18:55:18 2003
|
||||
\ \ \ \ In/Block: \ \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ In/Pass: \ \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ]
|
||||
\ \ \ \ Out/Block: \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ Out/Pass: \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ]
|
||||
.Ed
|
||||
.Pp
|
||||
Similarly, it is possible to view global information about the tables
|
||||
by using the
|
||||
.Fl v
|
||||
modifier twice and the
|
||||
.Ar show Tables
|
||||
command.
|
||||
This will display the number of addresses on each table,
|
||||
the number of rules which reference the table, and the global
|
||||
packet statistics for the whole table:
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -vvsTables
|
||||
--a-r- test
|
||||
\ \ \ \ Addresses: \ \ 1
|
||||
\ \ \ \ Cleared: \ \ \ \ Thu Feb 13 18:55:18 2003
|
||||
\ \ \ \ References: \ [ Anchors: 0 \ \ \ \ \ \ \ Rules: 1 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ Evaluations: [ NoMatch: 3496 \ \ \ \ Match: 1 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ In/Block: \ \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ In/Pass: \ \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ]
|
||||
\ \ \ \ In/XPass: \ \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ Out/Block: \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
\ \ \ \ Out/Pass: \ \ \ [ Packets: 10 \ \ \ \ \ \ Bytes: 840 \ \ \ \ \ ]
|
||||
\ \ \ \ Out/XPass: \ \ [ Packets: 0 \ \ \ \ \ \ \ Bytes: 0 \ \ \ \ \ \ \ ]
|
||||
.Ed
|
||||
.Pp
|
||||
As we can see here, only one packet - the initial ping request - matched the
|
||||
table; but all packets passing as the result of the state are correctly
|
||||
accounted for.
|
||||
Reloading the table(s) or ruleset will not affect packet accounting in any way.
|
||||
The two
|
||||
.Ar XPass
|
||||
counters are incremented instead of the
|
||||
.Ar Pass
|
||||
counters when a \&"stateful\&" packet is passed but doesn't match the table
|
||||
anymore.
|
||||
This will happen in our example if someone flushes the table while the ping
|
||||
command is running.
|
||||
.Pp
|
||||
When used with a single
|
||||
.Fl v ,
|
||||
.Nm pfctl
|
||||
will only display the first line containing the table flags and name.
|
||||
The flags are defined as follows:
|
||||
.Pp
|
||||
.Bl -tag -width XXX -compact
|
||||
.It c
|
||||
For constant tables, which cannot be altered outside
|
||||
.Xr pf.conf 5 .
|
||||
.It p
|
||||
For persistent tables, which don't get automatically flushed when no rules
|
||||
refer to them.
|
||||
.It a
|
||||
For tables which are part of the
|
||||
.Ar active
|
||||
tableset.
|
||||
Tables without this flag do not really exist, cannot contain addresses, and are
|
||||
only listed if the
|
||||
.Fl g
|
||||
flag is given.
|
||||
.It i
|
||||
For tables which are part of the
|
||||
.Ar inactive
|
||||
tableset.
|
||||
This flag can only be witnessed briefly during the loading of
|
||||
.Xr pf.conf 5 .
|
||||
.It r
|
||||
For tables which are referenced (used) by rules.
|
||||
.It h
|
||||
This flag is set when a table in the main ruleset is hidden by one or more
|
||||
tables of the same name in sub-rulesets (anchors).
|
||||
.El
|
||||
.It Fl v
|
||||
Produce more verbose output.
|
||||
A second use of
|
||||
.Fl v
|
||||
will produce even more verbose output including ruleset warnings.
|
||||
See previous section for its effect on table commands.
|
||||
.It Fl x Ar level
|
||||
Set the debug
|
||||
.Ar level
|
||||
(may be abbreviated) to one of the following:
|
||||
.Pp
|
||||
.Bl -tag -width xxxxxxxxxxxx -compact
|
||||
.It Fl x Ar none
|
||||
Don't generate debug messages.
|
||||
.It Fl x Ar urgent
|
||||
Generate debug messages only for serious errors.
|
||||
.It Fl x Ar misc
|
||||
Generate debug messages for various errors.
|
||||
.It Fl x Ar loud
|
||||
Generate debug messages for common conditions.
|
||||
.El
|
||||
.It Fl z
|
||||
Clear per-rule statistics.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width "/etc/pf.conf" -compact
|
||||
.It Pa /etc/pf.conf
|
||||
Packet filter rules file.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr pf 4 ,
|
||||
.Xr pf.conf 5 ,
|
||||
.Xr pf.os 5 ,
|
||||
.Xr sysctl.conf 5 ,
|
||||
.Xr ftp-proxy 8 ,
|
||||
.Xr rc 8 ,
|
||||
.Xr rc.conf 8 ,
|
||||
.Xr sysctl 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
program and the
|
||||
.Xr pf 4
|
||||
filter mechanism first appeared in
|
||||
.Ox 3.0 .
|
1626
contrib/pf/pfctl/pfctl.c
Normal file
1626
contrib/pf/pfctl/pfctl.c
Normal file
File diff suppressed because it is too large
Load Diff
115
contrib/pf/pfctl/pfctl.h
Normal file
115
contrib/pf/pfctl/pfctl.h
Normal file
@ -0,0 +1,115 @@
|
||||
/* $OpenBSD: pfctl.h,v 1.25 2003/08/29 21:47:36 cedric Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PFCTL_H_
|
||||
#define _PFCTL_H_
|
||||
|
||||
enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS, PFRB_MAX };
|
||||
struct pfr_buffer {
|
||||
int pfrb_type; /* type of content, see enum above */
|
||||
int pfrb_size; /* number of objects in buffer */
|
||||
int pfrb_msize; /* maximum number of objects in buffer */
|
||||
void *pfrb_caddr; /* malloc'ated memory area */
|
||||
};
|
||||
#define PFRB_FOREACH(var, buf) \
|
||||
for ((var) = pfr_buf_next((buf), NULL); \
|
||||
(var) != NULL; \
|
||||
(var) = pfr_buf_next((buf), (var)))
|
||||
|
||||
void pfr_set_fd(int);
|
||||
int pfr_get_fd(void);
|
||||
int pfr_clr_tables(struct pfr_table *, int *, int);
|
||||
int pfr_add_tables(struct pfr_table *, int, int *, int);
|
||||
int pfr_del_tables(struct pfr_table *, int, int *, int);
|
||||
int pfr_get_tables(struct pfr_table *, struct pfr_table *, int *, int);
|
||||
int pfr_get_tstats(struct pfr_table *, struct pfr_tstats *, int *, int);
|
||||
int pfr_clr_tstats(struct pfr_table *, int, int *, int);
|
||||
int pfr_clr_addrs(struct pfr_table *, int *, int);
|
||||
int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
|
||||
int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
|
||||
int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
|
||||
int *, int *, int *, int);
|
||||
int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int);
|
||||
int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int);
|
||||
int pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *, int);
|
||||
int pfr_tst_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
|
||||
int pfr_set_tflags(struct pfr_table *, int, int, int, int *, int *, int);
|
||||
int pfr_ina_begin(struct pfr_table *, int *, int *, int);
|
||||
int pfr_ina_commit(struct pfr_table *, int, int *, int *, int);
|
||||
int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *,
|
||||
int *, int, int);
|
||||
void pfr_buf_clear(struct pfr_buffer *);
|
||||
int pfr_buf_add(struct pfr_buffer *, const void *);
|
||||
void *pfr_buf_next(struct pfr_buffer *, const void *);
|
||||
int pfr_buf_grow(struct pfr_buffer *, int);
|
||||
int pfr_buf_load(struct pfr_buffer *, char *, int,
|
||||
int (*)(struct pfr_buffer *, char *, int));
|
||||
char *pfr_strerror(int);
|
||||
|
||||
int pfctl_clear_tables(const char *, const char *, int);
|
||||
int pfctl_show_tables(const char *, const char *, int);
|
||||
int pfctl_command_tables(int, char *[], char *, const char *, char *,
|
||||
const char *, const char *, int);
|
||||
int pfctl_show_altq(int, int, int);
|
||||
void warn_namespace_collision(const char *);
|
||||
|
||||
#ifndef DEFAULT_PRIORITY
|
||||
#define DEFAULT_PRIORITY 1
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_QLIMIT
|
||||
#define DEFAULT_QLIMIT 50
|
||||
#endif
|
||||
|
||||
/*
|
||||
* generalized service curve used for admission control
|
||||
*/
|
||||
struct segment {
|
||||
LIST_ENTRY(segment) _next;
|
||||
double x, y, d, m;
|
||||
};
|
||||
|
||||
int check_commit_altq(int, int);
|
||||
void pfaltq_store(struct pf_altq *);
|
||||
void pfaltq_free(struct pf_altq *);
|
||||
struct pf_altq *pfaltq_lookup(const char *);
|
||||
char *rate2str(double);
|
||||
|
||||
void print_addr(struct pf_addr_wrap *, sa_family_t, int);
|
||||
void print_host(struct pf_state_host *, sa_family_t, int);
|
||||
void print_seq(struct pf_state_peer *);
|
||||
void print_state(struct pf_state *, int);
|
||||
int unmask(struct pf_addr *, sa_family_t);
|
||||
|
||||
int pfctl_cmdline_symset(char *);
|
||||
|
||||
#endif /* _PFCTL_H_ */
|
1210
contrib/pf/pfctl/pfctl_altq.c
Normal file
1210
contrib/pf/pfctl/pfctl_altq.c
Normal file
File diff suppressed because it is too large
Load Diff
1093
contrib/pf/pfctl/pfctl_osfp.c
Normal file
1093
contrib/pf/pfctl/pfctl_osfp.c
Normal file
File diff suppressed because it is too large
Load Diff
1286
contrib/pf/pfctl/pfctl_parser.c
Normal file
1286
contrib/pf/pfctl/pfctl_parser.c
Normal file
File diff suppressed because it is too large
Load Diff
228
contrib/pf/pfctl/pfctl_parser.h
Normal file
228
contrib/pf/pfctl/pfctl_parser.h
Normal file
@ -0,0 +1,228 @@
|
||||
/* $OpenBSD: pfctl_parser.h,v 1.67 2003/08/21 19:12:09 frantzen Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PFCTL_PARSER_H_
|
||||
#define _PFCTL_PARSER_H_
|
||||
|
||||
#define PF_OSFP_FILE "/etc/pf.os"
|
||||
|
||||
#define PF_OPT_DISABLE 0x0001
|
||||
#define PF_OPT_ENABLE 0x0002
|
||||
#define PF_OPT_VERBOSE 0x0004
|
||||
#define PF_OPT_NOACTION 0x0008
|
||||
#define PF_OPT_QUIET 0x0010
|
||||
#define PF_OPT_CLRRULECTRS 0x0020
|
||||
#define PF_OPT_USEDNS 0x0040
|
||||
#define PF_OPT_VERBOSE2 0x0080
|
||||
#define PF_OPT_DUMMYACTION 0x0100
|
||||
#define PF_OPT_DEBUG 0x0200
|
||||
|
||||
#define PF_TH_ALL 0xFF
|
||||
|
||||
#define PF_NAT_PROXY_PORT_LOW 50001
|
||||
#define PF_NAT_PROXY_PORT_HIGH 65535
|
||||
|
||||
#define FCNT_NAMES { \
|
||||
"searches", \
|
||||
"inserts", \
|
||||
"removals", \
|
||||
NULL \
|
||||
}
|
||||
|
||||
struct pfctl {
|
||||
int dev;
|
||||
int opts;
|
||||
int loadopt;
|
||||
u_int32_t tticket; /* table ticket */
|
||||
int tdirty; /* kernel dirty */
|
||||
u_int32_t rule_nr;
|
||||
struct pfioc_pooladdr paddr;
|
||||
struct pfioc_rule *prule[PF_RULESET_MAX];
|
||||
struct pfioc_altq *paltq;
|
||||
struct pfioc_queue *pqueue;
|
||||
const char *anchor;
|
||||
const char *ruleset;
|
||||
};
|
||||
|
||||
enum pfctl_iflookup_mode {
|
||||
PFCTL_IFLOOKUP_HOST,
|
||||
PFCTL_IFLOOKUP_NET,
|
||||
PFCTL_IFLOOKUP_BCAST
|
||||
};
|
||||
|
||||
struct node_if {
|
||||
char ifname[IFNAMSIZ];
|
||||
u_int8_t not;
|
||||
u_int ifa_flags;
|
||||
struct node_if *next;
|
||||
struct node_if *tail;
|
||||
};
|
||||
|
||||
struct node_host {
|
||||
struct pf_addr_wrap addr;
|
||||
struct pf_addr bcast;
|
||||
sa_family_t af;
|
||||
u_int8_t not;
|
||||
u_int32_t ifindex; /* link-local IPv6 addrs */
|
||||
char *ifname;
|
||||
u_int ifa_flags;
|
||||
struct node_host *next;
|
||||
struct node_host *tail;
|
||||
};
|
||||
|
||||
struct node_os {
|
||||
char *os;
|
||||
pf_osfp_t fingerprint;
|
||||
struct node_os *next;
|
||||
struct node_os *tail;
|
||||
};
|
||||
|
||||
struct node_queue_bw {
|
||||
u_int32_t bw_absolute;
|
||||
u_int16_t bw_percent;
|
||||
};
|
||||
|
||||
struct node_hfsc_sc {
|
||||
struct node_queue_bw m1; /* slope of 1st segment; bps */
|
||||
u_int d; /* x-projection of m1; msec */
|
||||
struct node_queue_bw m2; /* slope of 2nd segment; bps */
|
||||
u_int8_t used;
|
||||
};
|
||||
|
||||
struct node_hfsc_opts {
|
||||
struct node_hfsc_sc realtime;
|
||||
struct node_hfsc_sc linkshare;
|
||||
struct node_hfsc_sc upperlimit;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct node_queue_opt {
|
||||
int qtype;
|
||||
union {
|
||||
struct cbq_opts cbq_opts;
|
||||
struct priq_opts priq_opts;
|
||||
struct node_hfsc_opts hfsc_opts;
|
||||
} data;
|
||||
};
|
||||
|
||||
SIMPLEQ_HEAD(node_tinithead, node_tinit);
|
||||
struct node_tinit { /* table initializer */
|
||||
SIMPLEQ_ENTRY(node_tinit) entries;
|
||||
struct node_host *host;
|
||||
char *file;
|
||||
};
|
||||
|
||||
struct pfr_buffer; /* forward definition */
|
||||
|
||||
int pfctl_rules(int, char *, int, char *, char *);
|
||||
|
||||
int pfctl_add_rule(struct pfctl *, struct pf_rule *);
|
||||
int pfctl_add_altq(struct pfctl *, struct pf_altq *);
|
||||
int pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t);
|
||||
void pfctl_clear_pool(struct pf_pool *);
|
||||
|
||||
int pfctl_set_timeout(struct pfctl *, const char *, int, int);
|
||||
int pfctl_set_optimization(struct pfctl *, const char *);
|
||||
int pfctl_set_limit(struct pfctl *, const char *, unsigned int);
|
||||
int pfctl_set_logif(struct pfctl *, char *);
|
||||
|
||||
int parse_rules(FILE *, struct pfctl *);
|
||||
int parse_flags(char *);
|
||||
int pfctl_load_anchors(int, int);
|
||||
|
||||
void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int);
|
||||
void print_rule(struct pf_rule *, int);
|
||||
void print_tabledef(const char *, int, int, struct node_tinithead *);
|
||||
void print_status(struct pf_status *);
|
||||
|
||||
int eval_pfaltq(struct pfctl *, struct pf_altq *, struct node_queue_bw *,
|
||||
struct node_queue_opt *);
|
||||
int eval_pfqueue(struct pfctl *, struct pf_altq *, struct node_queue_bw *,
|
||||
struct node_queue_opt *);
|
||||
|
||||
void print_altq(const struct pf_altq *, unsigned, struct node_queue_bw *,
|
||||
struct node_queue_opt *);
|
||||
void print_queue(const struct pf_altq *, unsigned, struct node_queue_bw *,
|
||||
int, struct node_queue_opt *);
|
||||
|
||||
int pfctl_define_table(char *, int, int, const char *, const char *,
|
||||
struct pfr_buffer *, u_int32_t);
|
||||
|
||||
void pfctl_clear_fingerprints(int, int);
|
||||
int pfctl_file_fingerprints(int, int, const char *);
|
||||
pf_osfp_t pfctl_get_fingerprint(const char *);
|
||||
int pfctl_load_fingerprints(int, int);
|
||||
char *pfctl_lookup_fingerprint(pf_osfp_t, char *, size_t);
|
||||
void pfctl_show_fingerprints(int);
|
||||
|
||||
|
||||
struct icmptypeent {
|
||||
const char *name;
|
||||
u_int8_t type;
|
||||
};
|
||||
|
||||
struct icmpcodeent {
|
||||
const char *name;
|
||||
u_int8_t type;
|
||||
u_int8_t code;
|
||||
};
|
||||
|
||||
const struct icmptypeent *geticmptypebynumber(u_int8_t, u_int8_t);
|
||||
const struct icmptypeent *geticmptypebyname(char *, u_int8_t);
|
||||
const struct icmpcodeent *geticmpcodebynumber(u_int8_t, u_int8_t, u_int8_t);
|
||||
const struct icmpcodeent *geticmpcodebyname(u_long, char *, u_int8_t);
|
||||
|
||||
struct pf_timeout {
|
||||
const char *name;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
#define PFCTL_FLAG_FILTER 0x02
|
||||
#define PFCTL_FLAG_NAT 0x04
|
||||
#define PFCTL_FLAG_OPTION 0x08
|
||||
#define PFCTL_FLAG_ALTQ 0x10
|
||||
#define PFCTL_FLAG_TABLE 0x20
|
||||
|
||||
extern const struct pf_timeout pf_timeouts[];
|
||||
|
||||
void set_ipmask(struct node_host *, u_int8_t);
|
||||
int check_netmask(struct node_host *, sa_family_t);
|
||||
void ifa_load(void);
|
||||
struct node_host *ifa_exists(const char *);
|
||||
struct node_host *ifa_lookup(const char *, enum pfctl_iflookup_mode);
|
||||
struct node_host *host(const char *);
|
||||
|
||||
int append_addr(struct pfr_buffer *, char *, int);
|
||||
int append_addr_host(struct pfr_buffer *,
|
||||
struct node_host *, int, int);
|
||||
|
||||
#endif /* _PFCTL_PARSER_H_ */
|
401
contrib/pf/pfctl/pfctl_qstats.c
Normal file
401
contrib/pf/pfctl/pfctl_qstats.c
Normal file
@ -0,0 +1,401 @@
|
||||
/* $OpenBSD: pfctl_qstats.c,v 1.24 2003/07/31 09:46:08 kjc Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) Henning Brauer <henning@openbsd.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/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/pfvar.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <altq/altq.h>
|
||||
#include <altq/altq_cbq.h>
|
||||
#include <altq/altq_priq.h>
|
||||
#include <altq/altq_hfsc.h>
|
||||
|
||||
#include "pfctl.h"
|
||||
#include "pfctl_parser.h"
|
||||
|
||||
union class_stats {
|
||||
class_stats_t cbq_stats;
|
||||
struct priq_classstats priq_stats;
|
||||
struct hfsc_classstats hfsc_stats;
|
||||
};
|
||||
|
||||
#define AVGN_MAX 8
|
||||
#define STAT_INTERVAL 5
|
||||
|
||||
struct queue_stats {
|
||||
union class_stats data;
|
||||
int avgn;
|
||||
double avg_bytes;
|
||||
double avg_packets;
|
||||
u_int64_t prev_bytes;
|
||||
u_int64_t prev_packets;
|
||||
};
|
||||
|
||||
struct pf_altq_node {
|
||||
struct pf_altq altq;
|
||||
struct pf_altq_node *next;
|
||||
struct pf_altq_node *children;
|
||||
struct queue_stats qstats;
|
||||
};
|
||||
|
||||
int pfctl_update_qstats(int, struct pf_altq_node **);
|
||||
void pfctl_insert_altq_node(struct pf_altq_node **,
|
||||
const struct pf_altq, const struct queue_stats);
|
||||
struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *,
|
||||
const char *, const char *);
|
||||
void pfctl_print_altq_node(int, const struct pf_altq_node *,
|
||||
unsigned, int);
|
||||
void print_cbqstats(struct queue_stats);
|
||||
void print_priqstats(struct queue_stats);
|
||||
void print_hfscstats(struct queue_stats);
|
||||
void pfctl_free_altq_node(struct pf_altq_node *);
|
||||
void pfctl_print_altq_nodestat(int,
|
||||
const struct pf_altq_node *);
|
||||
|
||||
void update_avg(struct pf_altq_node *);
|
||||
|
||||
int
|
||||
pfctl_show_altq(int dev, int opts, int verbose2)
|
||||
{
|
||||
struct pf_altq_node *root = NULL, *node;
|
||||
|
||||
if (pfctl_update_qstats(dev, &root))
|
||||
return (-1);
|
||||
|
||||
for (node = root; node != NULL; node = node->next)
|
||||
pfctl_print_altq_node(dev, node, 0, opts);
|
||||
|
||||
while (verbose2) {
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
sleep(STAT_INTERVAL);
|
||||
if (pfctl_update_qstats(dev, &root))
|
||||
return (-1);
|
||||
for (node = root; node != NULL; node = node->next)
|
||||
pfctl_print_altq_node(dev, node, 0, opts);
|
||||
}
|
||||
pfctl_free_altq_node(root);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_update_qstats(int dev, struct pf_altq_node **root)
|
||||
{
|
||||
struct pf_altq_node *node;
|
||||
struct pfioc_altq pa;
|
||||
struct pfioc_qstats pq;
|
||||
u_int32_t mnr, nr;
|
||||
struct queue_stats qstats;
|
||||
static u_int32_t last_ticket;
|
||||
|
||||
memset(&pa, 0, sizeof(pa));
|
||||
memset(&pq, 0, sizeof(pq));
|
||||
memset(&qstats, 0, sizeof(qstats));
|
||||
if (ioctl(dev, DIOCGETALTQS, &pa)) {
|
||||
warn("DIOCGETALTQS");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* if a new set is found, start over */
|
||||
if (pa.ticket != last_ticket && *root != NULL) {
|
||||
pfctl_free_altq_node(*root);
|
||||
*root = NULL;
|
||||
}
|
||||
last_ticket = pa.ticket;
|
||||
|
||||
mnr = pa.nr;
|
||||
for (nr = 0; nr < mnr; ++nr) {
|
||||
pa.nr = nr;
|
||||
if (ioctl(dev, DIOCGETALTQ, &pa)) {
|
||||
warn("DIOCGETALTQ");
|
||||
return (-1);
|
||||
}
|
||||
if (pa.altq.qid > 0) {
|
||||
pq.nr = nr;
|
||||
pq.ticket = pa.ticket;
|
||||
pq.buf = &qstats.data;
|
||||
pq.nbytes = sizeof(qstats.data);
|
||||
if (ioctl(dev, DIOCGETQSTATS, &pq)) {
|
||||
warn("DIOCGETQSTATS");
|
||||
return (-1);
|
||||
}
|
||||
if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
|
||||
pa.altq.ifname)) != NULL) {
|
||||
memcpy(&node->qstats.data, &qstats.data,
|
||||
sizeof(qstats.data));
|
||||
update_avg(node);
|
||||
} else {
|
||||
pfctl_insert_altq_node(root, pa.altq, qstats);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
pfctl_insert_altq_node(struct pf_altq_node **root,
|
||||
const struct pf_altq altq, const struct queue_stats qstats)
|
||||
{
|
||||
struct pf_altq_node *node;
|
||||
|
||||
node = calloc(1, sizeof(struct pf_altq_node));
|
||||
if (node == NULL)
|
||||
err(1, "pfctl_insert_altq_node: calloc");
|
||||
memcpy(&node->altq, &altq, sizeof(struct pf_altq));
|
||||
memcpy(&node->qstats, &qstats, sizeof(qstats));
|
||||
node->next = node->children = NULL;
|
||||
|
||||
if (*root == NULL)
|
||||
*root = node;
|
||||
else if (!altq.parent[0]) {
|
||||
struct pf_altq_node *prev = *root;
|
||||
|
||||
while (prev->next != NULL)
|
||||
prev = prev->next;
|
||||
prev->next = node;
|
||||
} else {
|
||||
struct pf_altq_node *parent;
|
||||
|
||||
parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
|
||||
if (parent == NULL)
|
||||
errx(1, "parent %s not found", altq.parent);
|
||||
if (parent->children == NULL)
|
||||
parent->children = node;
|
||||
else {
|
||||
struct pf_altq_node *prev = parent->children;
|
||||
|
||||
while (prev->next != NULL)
|
||||
prev = prev->next;
|
||||
prev->next = node;
|
||||
}
|
||||
}
|
||||
update_avg(node);
|
||||
}
|
||||
|
||||
struct pf_altq_node *
|
||||
pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
|
||||
const char *ifname)
|
||||
{
|
||||
struct pf_altq_node *node, *child;
|
||||
|
||||
for (node = root; node != NULL; node = node->next) {
|
||||
if (!strcmp(node->altq.qname, qname)
|
||||
&& !(strcmp(node->altq.ifname, ifname)))
|
||||
return (node);
|
||||
if (node->children != NULL) {
|
||||
child = pfctl_find_altq_node(node->children, qname,
|
||||
ifname);
|
||||
if (child != NULL)
|
||||
return (child);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pfctl_print_altq_node(int dev, const struct pf_altq_node *node, unsigned level,
|
||||
int opts)
|
||||
{
|
||||
const struct pf_altq_node *child;
|
||||
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
print_altq(&node->altq, level, NULL, NULL);
|
||||
|
||||
if (node->children != NULL) {
|
||||
printf("{");
|
||||
for (child = node->children; child != NULL;
|
||||
child = child->next) {
|
||||
printf("%s", child->altq.qname);
|
||||
if (child->next != NULL)
|
||||
printf(", ");
|
||||
}
|
||||
printf("}");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
pfctl_print_altq_nodestat(dev, node);
|
||||
|
||||
if (opts & PF_OPT_DEBUG)
|
||||
printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n", node->altq.qid,
|
||||
node->altq.ifname, rate2str((double)(node->altq.ifbandwidth)));
|
||||
|
||||
for (child = node->children; child != NULL;
|
||||
child = child->next)
|
||||
pfctl_print_altq_node(dev, child, level+1, opts);
|
||||
}
|
||||
|
||||
void
|
||||
pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
|
||||
{
|
||||
if (a->altq.qid == 0)
|
||||
return;
|
||||
|
||||
switch (a->altq.scheduler) {
|
||||
case ALTQT_CBQ:
|
||||
print_cbqstats(a->qstats);
|
||||
break;
|
||||
case ALTQT_PRIQ:
|
||||
print_priqstats(a->qstats);
|
||||
break;
|
||||
case ALTQT_HFSC:
|
||||
print_hfscstats(a->qstats);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_cbqstats(struct queue_stats cur)
|
||||
{
|
||||
printf(" [ pkts: %10llu bytes: %10llu "
|
||||
"dropped pkts: %6llu bytes: %6llu ]\n",
|
||||
cur.data.cbq_stats.xmit_cnt.packets,
|
||||
cur.data.cbq_stats.xmit_cnt.bytes,
|
||||
cur.data.cbq_stats.drop_cnt.packets,
|
||||
cur.data.cbq_stats.drop_cnt.bytes);
|
||||
printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
|
||||
cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
|
||||
cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
|
||||
|
||||
if (cur.avgn < 2)
|
||||
return;
|
||||
|
||||
printf(" [ measured: %7.1f packets/s, %s/s ]\n",
|
||||
cur.avg_packets / STAT_INTERVAL,
|
||||
rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
|
||||
}
|
||||
|
||||
void
|
||||
print_priqstats(struct queue_stats cur)
|
||||
{
|
||||
printf(" [ pkts: %10llu bytes: %10llu "
|
||||
"dropped pkts: %6llu bytes: %6llu ]\n",
|
||||
cur.data.priq_stats.xmitcnt.packets,
|
||||
cur.data.priq_stats.xmitcnt.bytes,
|
||||
cur.data.priq_stats.dropcnt.packets,
|
||||
cur.data.priq_stats.dropcnt.bytes);
|
||||
printf(" [ qlength: %3d/%3d ]\n",
|
||||
cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
|
||||
|
||||
if (cur.avgn < 2)
|
||||
return;
|
||||
|
||||
printf(" [ measured: %7.1f packets/s, %s/s ]\n",
|
||||
cur.avg_packets / STAT_INTERVAL,
|
||||
rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
|
||||
}
|
||||
|
||||
void
|
||||
print_hfscstats(struct queue_stats cur)
|
||||
{
|
||||
printf(" [ pkts: %10llu bytes: %10llu "
|
||||
"dropped pkts: %6llu bytes: %6llu ]\n",
|
||||
cur.data.hfsc_stats.xmit_cnt.packets,
|
||||
cur.data.hfsc_stats.xmit_cnt.bytes,
|
||||
cur.data.hfsc_stats.drop_cnt.packets,
|
||||
cur.data.hfsc_stats.drop_cnt.bytes);
|
||||
printf(" [ qlength: %3d/%3d ]\n",
|
||||
cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
|
||||
|
||||
if (cur.avgn < 2)
|
||||
return;
|
||||
|
||||
printf(" [ measured: %7.1f packets/s, %s/s ]\n",
|
||||
cur.avg_packets / STAT_INTERVAL,
|
||||
rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
|
||||
}
|
||||
|
||||
void
|
||||
pfctl_free_altq_node(struct pf_altq_node *node)
|
||||
{
|
||||
while (node != NULL) {
|
||||
struct pf_altq_node *prev;
|
||||
|
||||
if (node->children != NULL)
|
||||
pfctl_free_altq_node(node->children);
|
||||
prev = node;
|
||||
node = node->next;
|
||||
free(prev);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
update_avg(struct pf_altq_node *a)
|
||||
{
|
||||
struct queue_stats *qs;
|
||||
u_int64_t b, p;
|
||||
int n;
|
||||
|
||||
if (a->altq.qid == 0)
|
||||
return;
|
||||
|
||||
qs = &a->qstats;
|
||||
n = qs->avgn;
|
||||
|
||||
switch (a->altq.scheduler) {
|
||||
case ALTQT_CBQ:
|
||||
b = qs->data.cbq_stats.xmit_cnt.bytes;
|
||||
p = qs->data.cbq_stats.xmit_cnt.packets;
|
||||
break;
|
||||
case ALTQT_PRIQ:
|
||||
b = qs->data.priq_stats.xmitcnt.bytes;
|
||||
p = qs->data.priq_stats.xmitcnt.packets;
|
||||
break;
|
||||
case ALTQT_HFSC:
|
||||
b = qs->data.hfsc_stats.xmit_cnt.bytes;
|
||||
p = qs->data.hfsc_stats.xmit_cnt.packets;
|
||||
break;
|
||||
default:
|
||||
b = 0;
|
||||
p = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
qs->prev_bytes = b;
|
||||
qs->prev_packets = p;
|
||||
qs->avgn++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (b >= qs->prev_bytes)
|
||||
qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
|
||||
(b - qs->prev_bytes)) / n;
|
||||
|
||||
if (p >= qs->prev_packets)
|
||||
qs->avg_packets = ((qs->avg_packets * (n - 1)) +
|
||||
(p - qs->prev_packets)) / n;
|
||||
|
||||
qs->prev_bytes = b;
|
||||
qs->prev_packets = p;
|
||||
if (n < AVGN_MAX)
|
||||
qs->avgn++;
|
||||
}
|
639
contrib/pf/pfctl/pfctl_radix.c
Normal file
639
contrib/pf/pfctl/pfctl_radix.c
Normal file
@ -0,0 +1,639 @@
|
||||
/* $OpenBSD: pfctl_radix.c,v 1.21 2003/09/24 09:12:35 cedric Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Cedric Berger
|
||||
* 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/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/pfvar.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "pfctl.h"
|
||||
|
||||
#define BUF_SIZE 256
|
||||
|
||||
extern int dev;
|
||||
|
||||
static int pfr_next_token(char buf[], FILE *);
|
||||
|
||||
|
||||
int
|
||||
pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
if (filter != NULL)
|
||||
io.pfrio_table = *filter;
|
||||
if (ioctl(dev, DIOCRCLRTABLES, &io))
|
||||
return (-1);
|
||||
if (ndel != NULL)
|
||||
*ndel = io.pfrio_ndel;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (size < 0 || (size && tbl == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_buffer = tbl;
|
||||
io.pfrio_esize = sizeof(*tbl);
|
||||
io.pfrio_size = size;
|
||||
if (ioctl(dev, DIOCRADDTABLES, &io))
|
||||
return (-1);
|
||||
if (nadd != NULL)
|
||||
*nadd = io.pfrio_nadd;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (size < 0 || (size && tbl == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_buffer = tbl;
|
||||
io.pfrio_esize = sizeof(*tbl);
|
||||
io.pfrio_size = size;
|
||||
if (ioctl(dev, DIOCRDELTABLES, &io))
|
||||
return (-1);
|
||||
if (ndel != NULL)
|
||||
*ndel = io.pfrio_ndel;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
|
||||
int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
if (filter != NULL)
|
||||
io.pfrio_table = *filter;
|
||||
io.pfrio_buffer = tbl;
|
||||
io.pfrio_esize = sizeof(*tbl);
|
||||
io.pfrio_size = *size;
|
||||
if (ioctl(dev, DIOCRGETTABLES, &io))
|
||||
return (-1);
|
||||
*size = io.pfrio_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
|
||||
int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
if (filter != NULL)
|
||||
io.pfrio_table = *filter;
|
||||
io.pfrio_buffer = tbl;
|
||||
io.pfrio_esize = sizeof(*tbl);
|
||||
io.pfrio_size = *size;
|
||||
if (ioctl(dev, DIOCRGETTSTATS, &io))
|
||||
return (-1);
|
||||
*size = io.pfrio_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (tbl == NULL) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_table = *tbl;
|
||||
if (ioctl(dev, DIOCRCLRADDRS, &io))
|
||||
return (-1);
|
||||
if (ndel != NULL)
|
||||
*ndel = io.pfrio_ndel;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
int *nadd, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (tbl == NULL || size < 0 || (size && addr == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_table = *tbl;
|
||||
io.pfrio_buffer = addr;
|
||||
io.pfrio_esize = sizeof(*addr);
|
||||
io.pfrio_size = size;
|
||||
if (ioctl(dev, DIOCRADDADDRS, &io))
|
||||
return (-1);
|
||||
if (nadd != NULL)
|
||||
*nadd = io.pfrio_nadd;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
int *ndel, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (tbl == NULL || size < 0 || (size && addr == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_table = *tbl;
|
||||
io.pfrio_buffer = addr;
|
||||
io.pfrio_esize = sizeof(*addr);
|
||||
io.pfrio_size = size;
|
||||
if (ioctl(dev, DIOCRDELADDRS, &io))
|
||||
return (-1);
|
||||
if (ndel != NULL)
|
||||
*ndel = io.pfrio_ndel;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
int *size2, int *nadd, int *ndel, int *nchange, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (tbl == NULL || size < 0 || (size && addr == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_table = *tbl;
|
||||
io.pfrio_buffer = addr;
|
||||
io.pfrio_esize = sizeof(*addr);
|
||||
io.pfrio_size = size;
|
||||
io.pfrio_size2 = (size2 != NULL) ? *size2 : 0;
|
||||
if (ioctl(dev, DIOCRSETADDRS, &io))
|
||||
return (-1);
|
||||
if (nadd != NULL)
|
||||
*nadd = io.pfrio_nadd;
|
||||
if (ndel != NULL)
|
||||
*ndel = io.pfrio_ndel;
|
||||
if (nchange != NULL)
|
||||
*nchange = io.pfrio_nchange;
|
||||
if (size2 != NULL)
|
||||
*size2 = io.pfrio_size2;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
|
||||
int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (tbl == NULL || size == NULL || *size < 0 || (*size && addr == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_table = *tbl;
|
||||
io.pfrio_buffer = addr;
|
||||
io.pfrio_esize = sizeof(*addr);
|
||||
io.pfrio_size = *size;
|
||||
if (ioctl(dev, DIOCRGETADDRS, &io))
|
||||
return (-1);
|
||||
*size = io.pfrio_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
|
||||
int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (tbl == NULL || size == NULL || *size < 0 || (*size && addr == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_table = *tbl;
|
||||
io.pfrio_buffer = addr;
|
||||
io.pfrio_esize = sizeof(*addr);
|
||||
io.pfrio_size = *size;
|
||||
if (ioctl(dev, DIOCRGETASTATS, &io))
|
||||
return (-1);
|
||||
*size = io.pfrio_size;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
int *nzero, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (tbl == NULL || size < 0 || (size && addr == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_table = *tbl;
|
||||
io.pfrio_buffer = addr;
|
||||
io.pfrio_esize = sizeof(*addr);
|
||||
io.pfrio_size = size;
|
||||
if (ioctl(dev, DIOCRCLRASTATS, &io))
|
||||
return (-1);
|
||||
if (nzero != NULL)
|
||||
*nzero = io.pfrio_nzero;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (size < 0 || (size && !tbl)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_buffer = tbl;
|
||||
io.pfrio_esize = sizeof(*tbl);
|
||||
io.pfrio_size = size;
|
||||
if (ioctl(dev, DIOCRCLRTSTATS, &io))
|
||||
return (-1);
|
||||
if (nzero)
|
||||
*nzero = io.pfrio_nzero;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag,
|
||||
int *nchange, int *ndel, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (size < 0 || (size && !tbl)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_buffer = tbl;
|
||||
io.pfrio_esize = sizeof(*tbl);
|
||||
io.pfrio_size = size;
|
||||
io.pfrio_setflag = setflag;
|
||||
io.pfrio_clrflag = clrflag;
|
||||
if (ioctl(dev, DIOCRSETTFLAGS, &io))
|
||||
return (-1);
|
||||
if (nchange)
|
||||
*nchange = io.pfrio_nchange;
|
||||
if (ndel)
|
||||
*ndel = io.pfrio_ndel;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
int *nmatch, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (tbl == NULL || size < 0 || (size && addr == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_table = *tbl;
|
||||
io.pfrio_buffer = addr;
|
||||
io.pfrio_esize = sizeof(*addr);
|
||||
io.pfrio_size = size;
|
||||
if (ioctl(dev, DIOCRTSTADDRS, &io))
|
||||
return (-1);
|
||||
if (nmatch)
|
||||
*nmatch = io.pfrio_nmatch;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_ina_begin(struct pfr_table *trs, int *ticket, int *ndel, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
bzero(&io, sizeof io);
|
||||
if (trs != NULL)
|
||||
io.pfrio_table = *trs;
|
||||
io.pfrio_flags = flags;
|
||||
if (ioctl(dev, DIOCRINABEGIN, &io))
|
||||
return (-1);
|
||||
if (ndel != NULL)
|
||||
*ndel = io.pfrio_ndel;
|
||||
if (ticket != NULL)
|
||||
*ticket = io.pfrio_ticket;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_ina_commit(struct pfr_table *trs, int ticket, int *nadd, int *nchange,
|
||||
int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
bzero(&io, sizeof io);
|
||||
if (trs != NULL)
|
||||
io.pfrio_table = *trs;
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_ticket = ticket;
|
||||
if (ioctl(dev, DIOCRINACOMMIT, &io))
|
||||
return (-1);
|
||||
if (nadd != NULL)
|
||||
*nadd = io.pfrio_nadd;
|
||||
if (nchange != NULL)
|
||||
*nchange = io.pfrio_nchange;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
int *nadd, int *naddr, int ticket, int flags)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
|
||||
if (tbl == NULL || size < 0 || (size && addr == NULL)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfrio_flags = flags;
|
||||
io.pfrio_table = *tbl;
|
||||
io.pfrio_buffer = addr;
|
||||
io.pfrio_esize = sizeof(*addr);
|
||||
io.pfrio_size = size;
|
||||
io.pfrio_ticket = ticket;
|
||||
if (ioctl(dev, DIOCRINADEFINE, &io))
|
||||
return (-1);
|
||||
if (nadd != NULL)
|
||||
*nadd = io.pfrio_nadd;
|
||||
if (naddr != NULL)
|
||||
*naddr = io.pfrio_naddr;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* buffer management code */
|
||||
|
||||
size_t buf_esize[PFRB_MAX] = { 0,
|
||||
sizeof(struct pfr_table), sizeof(struct pfr_tstats),
|
||||
sizeof(struct pfr_addr), sizeof(struct pfr_astats),
|
||||
};
|
||||
|
||||
/*
|
||||
* add one element to the buffer
|
||||
*/
|
||||
int
|
||||
pfr_buf_add(struct pfr_buffer *b, const void *e)
|
||||
{
|
||||
size_t bs;
|
||||
|
||||
if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX ||
|
||||
e == NULL) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
bs = buf_esize[b->pfrb_type];
|
||||
if (b->pfrb_size == b->pfrb_msize)
|
||||
if (pfr_buf_grow(b, 0))
|
||||
return (-1);
|
||||
memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs);
|
||||
b->pfrb_size++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* return next element of the buffer (or first one if prev is NULL)
|
||||
* see PFRB_FOREACH macro
|
||||
*/
|
||||
void *
|
||||
pfr_buf_next(struct pfr_buffer *b, const void *prev)
|
||||
{
|
||||
size_t bs;
|
||||
|
||||
if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX)
|
||||
return (NULL);
|
||||
if (b->pfrb_size == 0)
|
||||
return (NULL);
|
||||
if (prev == NULL)
|
||||
return (b->pfrb_caddr);
|
||||
bs = buf_esize[b->pfrb_type];
|
||||
if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1)
|
||||
return (NULL);
|
||||
return (((caddr_t)prev) + bs);
|
||||
}
|
||||
|
||||
/*
|
||||
* minsize:
|
||||
* 0: make the buffer somewhat bigger
|
||||
* n: make room for "n" entries in the buffer
|
||||
*/
|
||||
int
|
||||
pfr_buf_grow(struct pfr_buffer *b, int minsize)
|
||||
{
|
||||
caddr_t p;
|
||||
size_t bs;
|
||||
|
||||
if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (minsize != 0 && minsize <= b->pfrb_msize)
|
||||
return (0);
|
||||
bs = buf_esize[b->pfrb_type];
|
||||
if (!b->pfrb_msize) {
|
||||
if (minsize < 64)
|
||||
minsize = 64;
|
||||
b->pfrb_caddr = calloc(bs, minsize);
|
||||
if (b->pfrb_caddr == NULL)
|
||||
return (-1);
|
||||
b->pfrb_msize = minsize;
|
||||
} else {
|
||||
if (minsize == 0)
|
||||
minsize = b->pfrb_msize * 2;
|
||||
if (minsize < 0 || minsize >= SIZE_T_MAX / bs) {
|
||||
/* msize overflow */
|
||||
errno = ENOMEM;
|
||||
return (-1);
|
||||
}
|
||||
p = realloc(b->pfrb_caddr, minsize * bs);
|
||||
if (p == NULL)
|
||||
return (-1);
|
||||
bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
|
||||
b->pfrb_caddr = p;
|
||||
b->pfrb_msize = minsize;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* reset buffer and free memory.
|
||||
*/
|
||||
void
|
||||
pfr_buf_clear(struct pfr_buffer *b)
|
||||
{
|
||||
if (b == NULL)
|
||||
return;
|
||||
if (b->pfrb_caddr != NULL)
|
||||
free(b->pfrb_caddr);
|
||||
b->pfrb_caddr = NULL;
|
||||
b->pfrb_size = b->pfrb_msize = 0;
|
||||
}
|
||||
|
||||
int
|
||||
pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork,
|
||||
int (*append_addr)(struct pfr_buffer *, char *, int))
|
||||
{
|
||||
FILE *fp;
|
||||
char buf[BUF_SIZE];
|
||||
int rv;
|
||||
|
||||
if (file == NULL)
|
||||
return (0);
|
||||
if (!strcmp(file, "-"))
|
||||
fp = stdin;
|
||||
else {
|
||||
fp = fopen(file, "r");
|
||||
if (fp == NULL)
|
||||
return (-1);
|
||||
}
|
||||
while ((rv = pfr_next_token(buf, fp)) == 1)
|
||||
if (append_addr(b, buf, nonetwork)) {
|
||||
rv = -1;
|
||||
break;
|
||||
}
|
||||
if (fp != stdin)
|
||||
fclose(fp);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
int
|
||||
pfr_next_token(char buf[BUF_SIZE], FILE *fp)
|
||||
{
|
||||
static char next_ch = ' ';
|
||||
int i = 0;
|
||||
|
||||
for (;;) {
|
||||
/* skip spaces */
|
||||
while (isspace(next_ch) && !feof(fp))
|
||||
next_ch = fgetc(fp);
|
||||
/* remove from '#' until end of line */
|
||||
if (next_ch == '#')
|
||||
while (!feof(fp)) {
|
||||
next_ch = fgetc(fp);
|
||||
if (next_ch == '\n')
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (feof(fp)) {
|
||||
next_ch = ' ';
|
||||
return (0);
|
||||
}
|
||||
do {
|
||||
if (i < BUF_SIZE)
|
||||
buf[i++] = next_ch;
|
||||
next_ch = fgetc(fp);
|
||||
} while (!feof(fp) && !isspace(next_ch));
|
||||
if (i >= BUF_SIZE) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
buf[i] = '\0';
|
||||
return (1);
|
||||
}
|
||||
|
||||
char *
|
||||
pfr_strerror(int errnum)
|
||||
{
|
||||
switch (errnum) {
|
||||
case ESRCH:
|
||||
return "Table does not exist";
|
||||
case ENOENT:
|
||||
return "Anchor or Ruleset does not exist";
|
||||
default:
|
||||
return strerror(errnum);
|
||||
}
|
||||
}
|
524
contrib/pf/pfctl/pfctl_table.c
Normal file
524
contrib/pf/pfctl/pfctl_table.c
Normal file
@ -0,0 +1,524 @@
|
||||
/* $OpenBSD: pfctl_table.c,v 1.50 2003/08/29 21:47:36 cedric Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Cedric Berger
|
||||
* 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/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/pfvar.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "pfctl_parser.h"
|
||||
#include "pfctl.h"
|
||||
|
||||
extern void usage(void);
|
||||
static int pfctl_table(int, char *[], char *, const char *, char *,
|
||||
const char *, const char *, int);
|
||||
static void print_table(struct pfr_table *, int, int);
|
||||
static void print_tstats(struct pfr_tstats *, int);
|
||||
static int load_addr(struct pfr_buffer *, int, char *[], char *, int);
|
||||
static void print_addrx(struct pfr_addr *, struct pfr_addr *, int);
|
||||
static void print_astats(struct pfr_astats *, int);
|
||||
static void radix_perror(void);
|
||||
static void xprintf(int, const char *, ...);
|
||||
|
||||
static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = {
|
||||
{ "In/Block:", "In/Pass:", "In/XPass:" },
|
||||
{ "Out/Block:", "Out/Pass:", "Out/XPass:" }
|
||||
};
|
||||
|
||||
#define RVTEST(fct) do { \
|
||||
if ((!(opts & PF_OPT_NOACTION) || \
|
||||
(opts & PF_OPT_DUMMYACTION)) && \
|
||||
(fct)) { \
|
||||
radix_perror(); \
|
||||
goto _error; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CREATE_TABLE do { \
|
||||
table.pfrt_flags |= PFR_TFLAG_PERSIST; \
|
||||
RVTEST(pfr_add_tables(&table, 1, &nadd, flags)); \
|
||||
if (nadd) { \
|
||||
warn_namespace_collision(table.pfrt_name); \
|
||||
xprintf(opts, "%d table created", nadd); \
|
||||
if (opts & PF_OPT_NOACTION) \
|
||||
return (0); \
|
||||
} \
|
||||
table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \
|
||||
} while(0)
|
||||
|
||||
int
|
||||
pfctl_clear_tables(const char *anchor, const char *ruleset, int opts)
|
||||
{
|
||||
return pfctl_table(0, NULL, NULL, "-F", NULL, anchor, ruleset, opts);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_show_tables(const char *anchor, const char *ruleset, int opts)
|
||||
{
|
||||
return pfctl_table(0, NULL, NULL, "-s", NULL, anchor, ruleset, opts);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_command_tables(int argc, char *argv[], char *tname,
|
||||
const char *command, char *file, const char *anchor, const char *ruleset,
|
||||
int opts)
|
||||
{
|
||||
if (tname == NULL || command == NULL)
|
||||
usage();
|
||||
return pfctl_table(argc, argv, tname, command, file, anchor, ruleset,
|
||||
opts);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_table(int argc, char *argv[], char *tname, const char *command,
|
||||
char *file, const char *anchor, const char *ruleset, int opts)
|
||||
{
|
||||
struct pfr_table table;
|
||||
struct pfr_buffer b, b2;
|
||||
struct pfr_addr *a, *a2;
|
||||
int nadd = 0, ndel = 0, nchange = 0, nzero = 0;
|
||||
int rv = 0, flags = 0, nmatch = 0;
|
||||
void *p;
|
||||
|
||||
if (command == NULL)
|
||||
usage();
|
||||
if (opts & PF_OPT_NOACTION)
|
||||
flags |= PFR_FLAG_DUMMY;
|
||||
|
||||
bzero(&b, sizeof(b));
|
||||
bzero(&b2, sizeof(b2));
|
||||
bzero(&table, sizeof(table));
|
||||
if (tname != NULL) {
|
||||
if (strlen(tname) >= PF_TABLE_NAME_SIZE)
|
||||
usage();
|
||||
if (strlcpy(table.pfrt_name, tname,
|
||||
sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name))
|
||||
errx(1, "pfctl_table: strlcpy");
|
||||
}
|
||||
if (strlcpy(table.pfrt_anchor, anchor,
|
||||
sizeof(table.pfrt_anchor)) >= sizeof(table.pfrt_anchor) ||
|
||||
strlcpy(table.pfrt_ruleset, ruleset,
|
||||
sizeof(table.pfrt_ruleset)) >= sizeof(table.pfrt_ruleset))
|
||||
errx(1, "pfctl_table: strlcpy");
|
||||
|
||||
if (!strcmp(command, "-F")) {
|
||||
if (argc || file != NULL)
|
||||
usage();
|
||||
RVTEST(pfr_clr_tables(&table, &ndel, flags));
|
||||
xprintf(opts, "%d tables deleted", ndel);
|
||||
} else if (!strcmp(command, "-s")) {
|
||||
b.pfrb_type = (opts & PF_OPT_VERBOSE2) ?
|
||||
PFRB_TSTATS : PFRB_TABLES;
|
||||
if (argc || file != NULL)
|
||||
usage();
|
||||
for (;;) {
|
||||
pfr_buf_grow(&b, b.pfrb_size);
|
||||
b.pfrb_size = b.pfrb_msize;
|
||||
if (opts & PF_OPT_VERBOSE2)
|
||||
RVTEST(pfr_get_tstats(&table,
|
||||
b.pfrb_caddr, &b.pfrb_size, flags));
|
||||
else
|
||||
RVTEST(pfr_get_tables(&table,
|
||||
b.pfrb_caddr, &b.pfrb_size, flags));
|
||||
if (b.pfrb_size <= b.pfrb_msize)
|
||||
break;
|
||||
}
|
||||
PFRB_FOREACH(p, &b)
|
||||
if (opts & PF_OPT_VERBOSE2)
|
||||
print_tstats(p, opts & PF_OPT_DEBUG);
|
||||
else
|
||||
print_table(p, opts & PF_OPT_VERBOSE,
|
||||
opts & PF_OPT_DEBUG);
|
||||
} else if (!strcmp(command, "kill")) {
|
||||
if (argc || file != NULL)
|
||||
usage();
|
||||
RVTEST(pfr_del_tables(&table, 1, &ndel, flags));
|
||||
xprintf(opts, "%d table deleted", ndel);
|
||||
} else if (!strcmp(command, "flush")) {
|
||||
if (argc || file != NULL)
|
||||
usage();
|
||||
RVTEST(pfr_clr_addrs(&table, &ndel, flags));
|
||||
xprintf(opts, "%d addresses deleted", ndel);
|
||||
} else if (!strcmp(command, "add")) {
|
||||
b.pfrb_type = PFRB_ADDRS;
|
||||
if (load_addr(&b, argc, argv, file, 0))
|
||||
goto _error;
|
||||
CREATE_TABLE;
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
flags |= PFR_FLAG_FEEDBACK;
|
||||
RVTEST(pfr_add_addrs(&table, b.pfrb_caddr, b.pfrb_size,
|
||||
&nadd, flags));
|
||||
xprintf(opts, "%d/%d addresses added", nadd, b.pfrb_size);
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
PFRB_FOREACH(a, &b)
|
||||
if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
|
||||
print_addrx(a, NULL,
|
||||
opts & PF_OPT_USEDNS);
|
||||
} else if (!strcmp(command, "delete")) {
|
||||
b.pfrb_type = PFRB_ADDRS;
|
||||
if (load_addr(&b, argc, argv, file, 0))
|
||||
goto _error;
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
flags |= PFR_FLAG_FEEDBACK;
|
||||
RVTEST(pfr_del_addrs(&table, b.pfrb_caddr, b.pfrb_size,
|
||||
&ndel, flags));
|
||||
xprintf(opts, "%d/%d addresses deleted", ndel, b.pfrb_size);
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
PFRB_FOREACH(a, &b)
|
||||
if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
|
||||
print_addrx(a, NULL,
|
||||
opts & PF_OPT_USEDNS);
|
||||
} else if (!strcmp(command, "replace")) {
|
||||
b.pfrb_type = PFRB_ADDRS;
|
||||
if (load_addr(&b, argc, argv, file, 0))
|
||||
goto _error;
|
||||
CREATE_TABLE;
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
flags |= PFR_FLAG_FEEDBACK;
|
||||
for (;;) {
|
||||
int sz2 = b.pfrb_msize;
|
||||
|
||||
RVTEST(pfr_set_addrs(&table, b.pfrb_caddr, b.pfrb_size,
|
||||
&sz2, &nadd, &ndel, &nchange, flags));
|
||||
if (sz2 <= b.pfrb_msize) {
|
||||
b.pfrb_size = sz2;
|
||||
break;
|
||||
} else
|
||||
pfr_buf_grow(&b, sz2);
|
||||
}
|
||||
if (nadd)
|
||||
xprintf(opts, "%d addresses added", nadd);
|
||||
if (ndel)
|
||||
xprintf(opts, "%d addresses deleted", ndel);
|
||||
if (nchange)
|
||||
xprintf(opts, "%d addresses changed", nchange);
|
||||
if (!nadd && !ndel && !nchange)
|
||||
xprintf(opts, "no changes");
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
PFRB_FOREACH(a, &b)
|
||||
if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
|
||||
print_addrx(a, NULL,
|
||||
opts & PF_OPT_USEDNS);
|
||||
} else if (!strcmp(command, "show")) {
|
||||
b.pfrb_type = (opts & PF_OPT_VERBOSE) ?
|
||||
PFRB_ASTATS : PFRB_ADDRS;
|
||||
if (argc || file != NULL)
|
||||
usage();
|
||||
for (;;) {
|
||||
pfr_buf_grow(&b, b.pfrb_size);
|
||||
b.pfrb_size = b.pfrb_msize;
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
RVTEST(pfr_get_astats(&table, b.pfrb_caddr,
|
||||
&b.pfrb_size, flags));
|
||||
else
|
||||
RVTEST(pfr_get_addrs(&table, b.pfrb_caddr,
|
||||
&b.pfrb_size, flags));
|
||||
if (b.pfrb_size <= b.pfrb_msize)
|
||||
break;
|
||||
}
|
||||
PFRB_FOREACH(p, &b)
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
print_astats(p, opts & PF_OPT_USEDNS);
|
||||
else
|
||||
print_addrx(p, NULL, opts & PF_OPT_USEDNS);
|
||||
} else if (!strcmp(command, "test")) {
|
||||
b.pfrb_type = PFRB_ADDRS;
|
||||
b2.pfrb_type = PFRB_ADDRS;
|
||||
|
||||
if (load_addr(&b, argc, argv, file, 1))
|
||||
goto _error;
|
||||
if (opts & PF_OPT_VERBOSE2) {
|
||||
flags |= PFR_FLAG_REPLACE;
|
||||
PFRB_FOREACH(a, &b)
|
||||
if (pfr_buf_add(&b2, a))
|
||||
err(1, "duplicate buffer");
|
||||
}
|
||||
RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size,
|
||||
&nmatch, flags));
|
||||
xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size);
|
||||
if (opts & PF_OPT_VERBOSE && !(opts & PF_OPT_VERBOSE2))
|
||||
PFRB_FOREACH(a, &b)
|
||||
if (a->pfra_fback == PFR_FB_MATCH)
|
||||
print_addrx(a, NULL,
|
||||
opts & PF_OPT_USEDNS);
|
||||
if (opts & PF_OPT_VERBOSE2) {
|
||||
a2 = NULL;
|
||||
PFRB_FOREACH(a, &b) {
|
||||
a2 = pfr_buf_next(&b2, a2);
|
||||
print_addrx(a2, a, opts & PF_OPT_USEDNS);
|
||||
}
|
||||
}
|
||||
if (nmatch < b.pfrb_size)
|
||||
rv = 2;
|
||||
} else if (!strcmp(command, "zero")) {
|
||||
if (argc || file != NULL)
|
||||
usage();
|
||||
flags |= PFR_FLAG_ADDRSTOO;
|
||||
RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags));
|
||||
xprintf(opts, "%d table/stats cleared", nzero);
|
||||
} else
|
||||
warnx("pfctl_table: unknown command '%s'", command);
|
||||
goto _cleanup;
|
||||
|
||||
_error:
|
||||
rv = -1;
|
||||
_cleanup:
|
||||
pfr_buf_clear(&b);
|
||||
pfr_buf_clear(&b2);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
void
|
||||
print_table(struct pfr_table *ta, int verbose, int debug)
|
||||
{
|
||||
if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE))
|
||||
return;
|
||||
if (verbose) {
|
||||
printf("%c%c%c%c%c%c\t%s",
|
||||
(ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-',
|
||||
(ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-',
|
||||
(ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-',
|
||||
(ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-',
|
||||
(ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-',
|
||||
(ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-',
|
||||
ta->pfrt_name);
|
||||
if (ta->pfrt_anchor[0])
|
||||
printf("\t%s", ta->pfrt_anchor);
|
||||
if (ta->pfrt_ruleset[0])
|
||||
printf(":%s", ta->pfrt_ruleset);
|
||||
puts("");
|
||||
} else
|
||||
puts(ta->pfrt_name);
|
||||
}
|
||||
|
||||
void
|
||||
print_tstats(struct pfr_tstats *ts, int debug)
|
||||
{
|
||||
time_t time = ts->pfrts_tzero;
|
||||
int dir, op;
|
||||
|
||||
if (!debug && !(ts->pfrts_flags & PFR_TFLAG_ACTIVE))
|
||||
return;
|
||||
print_table(&ts->pfrts_t, 1, debug);
|
||||
printf("\tAddresses: %d\n", ts->pfrts_cnt);
|
||||
printf("\tCleared: %s", ctime(&time));
|
||||
printf("\tReferences: [ Anchors: %-18d Rules: %-18d ]\n",
|
||||
ts->pfrts_refcnt[PFR_REFCNT_ANCHOR],
|
||||
ts->pfrts_refcnt[PFR_REFCNT_RULE]);
|
||||
printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n",
|
||||
ts->pfrts_nomatch, ts->pfrts_match);
|
||||
for (dir = 0; dir < PFR_DIR_MAX; dir++)
|
||||
for (op = 0; op < PFR_OP_TABLE_MAX; op++)
|
||||
printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
|
||||
stats_text[dir][op],
|
||||
ts->pfrts_packets[dir][op],
|
||||
ts->pfrts_bytes[dir][op]);
|
||||
}
|
||||
|
||||
int
|
||||
load_addr(struct pfr_buffer *b, int argc, char *argv[], char *file,
|
||||
int nonetwork)
|
||||
{
|
||||
while (argc--)
|
||||
if (append_addr(b, *argv++, nonetwork)) {
|
||||
if (errno)
|
||||
warn("cannot decode %s", argv[-1]);
|
||||
return (-1);
|
||||
}
|
||||
if (pfr_buf_load(b, file, nonetwork, append_addr)) {
|
||||
warn("cannot load %s", file);
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns)
|
||||
{
|
||||
char ch, buf[256] = "{error}";
|
||||
char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y' };
|
||||
unsigned int fback, hostnet;
|
||||
|
||||
fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback;
|
||||
ch = (fback < sizeof(fb)/sizeof(*fb)) ? fb[fback] : '?';
|
||||
hostnet = (ad->pfra_af == AF_INET6) ? 128 : 32;
|
||||
inet_ntop(ad->pfra_af, &ad->pfra_u, buf, sizeof(buf));
|
||||
printf("%c %c%s", ch, (ad->pfra_not?'!':' '), buf);
|
||||
if (ad->pfra_net < hostnet)
|
||||
printf("/%d", ad->pfra_net);
|
||||
if (rad != NULL && fback != PFR_FB_NONE) {
|
||||
if (strlcpy(buf, "{error}", sizeof(buf)) >= sizeof(buf))
|
||||
errx(1, "print_addrx: strlcpy");
|
||||
inet_ntop(rad->pfra_af, &rad->pfra_u, buf, sizeof(buf));
|
||||
printf("\t%c%s", (rad->pfra_not?'!':' '), buf);
|
||||
if (rad->pfra_net < hostnet)
|
||||
printf("/%d", rad->pfra_net);
|
||||
}
|
||||
if (rad != NULL && fback == PFR_FB_NONE)
|
||||
printf("\t nomatch");
|
||||
if (dns && ad->pfra_net == hostnet) {
|
||||
char host[NI_MAXHOST];
|
||||
union sockaddr_union sa;
|
||||
|
||||
strlcpy(host, "?", sizeof(host));
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.sa.sa_family = ad->pfra_af;
|
||||
if (sa.sa.sa_family == AF_INET) {
|
||||
sa.sa.sa_len = sizeof(sa.sin);
|
||||
sa.sin.sin_addr = ad->pfra_ip4addr;
|
||||
} else {
|
||||
sa.sa.sa_len = sizeof(sa.sin6);
|
||||
sa.sin6.sin6_addr = ad->pfra_ip6addr;
|
||||
}
|
||||
if (getnameinfo(&sa.sa, sa.sa.sa_len, host, sizeof(host),
|
||||
NULL, 0, NI_NAMEREQD) == 0)
|
||||
printf("\t(%s)", host);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
print_astats(struct pfr_astats *as, int dns)
|
||||
{
|
||||
time_t time = as->pfras_tzero;
|
||||
int dir, op;
|
||||
|
||||
print_addrx(&as->pfras_a, NULL, dns);
|
||||
printf("\tCleared: %s", ctime(&time));
|
||||
for (dir = 0; dir < PFR_DIR_MAX; dir++)
|
||||
for (op = 0; op < PFR_OP_ADDR_MAX; op++)
|
||||
printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
|
||||
stats_text[dir][op],
|
||||
as->pfras_packets[dir][op],
|
||||
as->pfras_bytes[dir][op]);
|
||||
}
|
||||
|
||||
void
|
||||
radix_perror(void)
|
||||
{
|
||||
extern char *__progname;
|
||||
fprintf(stderr, "%s: %s.\n", __progname, pfr_strerror(errno));
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
|
||||
const char *ruleset, struct pfr_buffer *ab, u_int32_t ticket)
|
||||
{
|
||||
struct pfr_table tbl;
|
||||
|
||||
bzero(&tbl, sizeof(tbl));
|
||||
if (strlcpy(tbl.pfrt_name, name,
|
||||
sizeof(tbl.pfrt_name)) >= sizeof(tbl.pfrt_name) ||
|
||||
strlcpy(tbl.pfrt_anchor, anchor,
|
||||
sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor) ||
|
||||
strlcpy(tbl.pfrt_ruleset, ruleset,
|
||||
sizeof(tbl.pfrt_ruleset)) >= sizeof(tbl.pfrt_ruleset))
|
||||
errx(1, "pfctl_define_table: strlcpy");
|
||||
tbl.pfrt_flags = flags;
|
||||
|
||||
return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL,
|
||||
NULL, ticket, addrs ? PFR_FLAG_ADDRSTOO : 0);
|
||||
}
|
||||
|
||||
void
|
||||
warn_namespace_collision(const char *filter)
|
||||
{
|
||||
struct pfr_buffer b;
|
||||
struct pfr_table *t;
|
||||
const char *name = NULL, *lastcoll;
|
||||
int coll = 0;
|
||||
|
||||
bzero(&b, sizeof(b));
|
||||
b.pfrb_type = PFRB_TABLES;
|
||||
for (;;) {
|
||||
pfr_buf_grow(&b, b.pfrb_size);
|
||||
b.pfrb_size = b.pfrb_msize;
|
||||
if (pfr_get_tables(NULL, b.pfrb_caddr,
|
||||
&b.pfrb_size, PFR_FLAG_ALLRSETS))
|
||||
err(1, "pfr_get_tables");
|
||||
if (b.pfrb_size <= b.pfrb_msize)
|
||||
break;
|
||||
}
|
||||
PFRB_FOREACH(t, &b) {
|
||||
if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE))
|
||||
continue;
|
||||
if (filter != NULL && strcmp(filter, t->pfrt_name))
|
||||
continue;
|
||||
if (!t->pfrt_anchor[0])
|
||||
name = t->pfrt_name;
|
||||
else if (name != NULL && !strcmp(name, t->pfrt_name)) {
|
||||
coll++;
|
||||
lastcoll = name;
|
||||
name = NULL;
|
||||
}
|
||||
}
|
||||
if (coll == 1)
|
||||
warnx("warning: namespace collision with <%s> global table.",
|
||||
lastcoll);
|
||||
else if (coll > 1)
|
||||
warnx("warning: namespace collisions with %d global tables.",
|
||||
coll);
|
||||
pfr_buf_clear(&b);
|
||||
}
|
||||
|
||||
void
|
||||
xprintf(int opts, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (opts & PF_OPT_QUIET)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (opts & PF_OPT_DUMMYACTION)
|
||||
fprintf(stderr, " (dummy).\n");
|
||||
else if (opts & PF_OPT_NOACTION)
|
||||
fprintf(stderr, " (syntax only).\n");
|
||||
else
|
||||
fprintf(stderr, ".\n");
|
||||
}
|
179
contrib/pf/pflogd/pflogd.8
Normal file
179
contrib/pf/pflogd/pflogd.8
Normal file
@ -0,0 +1,179 @@
|
||||
.\" $OpenBSD: pflogd.8,v 1.22 2003/06/03 13:16:08 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 D
|
||||
.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
|
||||
.Va SIGHUP ,
|
||||
permitting
|
||||
.Xr newsyslog 8
|
||||
to rotate logfiles automatically.
|
||||
.Va 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
|
||||
.Va 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
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl d Ar delay
|
||||
Time in seconds to delay between automatic flushes of the file.
|
||||
This may be specified with a value between 5 and 3600 seconds.
|
||||
If not specified, the default is 60 seconds.
|
||||
.It Fl D
|
||||
Debugging mode.
|
||||
.Nm
|
||||
does not disassociate from the controlling terminal.
|
||||
.It Fl 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 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 pflogd .
|
||||
.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 pflogd):
|
||||
.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
|
400
contrib/pf/pflogd/pflogd.c
Normal file
400
contrib/pf/pflogd/pflogd.c
Normal file
@ -0,0 +1,400 @@
|
||||
/* $OpenBSD: pflogd.c,v 1.21 2003/08/22 21:50:34 david 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/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>
|
||||
|
||||
#define DEF_SNAPLEN 116 /* default plus allow for larger header of pflog */
|
||||
#define PCAP_TO_MS 500 /* pcap read timeout (ms) */
|
||||
#define PCAP_NUM_PKTS 1000 /* max number of packets to process at each loop */
|
||||
#define PCAP_OPT_FIL 0 /* filter optimization */
|
||||
#define FLUSH_DELAY 60 /* flush delay */
|
||||
|
||||
#define PFLOGD_LOG_FILE "/var/log/pflog"
|
||||
#define PFLOGD_DEFAULT_IF "pflog0"
|
||||
|
||||
pcap_t *hpcap;
|
||||
pcap_dumper_t *dpcap;
|
||||
|
||||
int Debug = 0;
|
||||
int 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 *argv);
|
||||
int init_pcap(void);
|
||||
void logmsg(int priority, const char *message, ...);
|
||||
int reset_dump(void);
|
||||
void sig_alrm(int);
|
||||
void sig_close(int);
|
||||
void sig_hup(int);
|
||||
void usage(void);
|
||||
|
||||
|
||||
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 [-D] [-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;
|
||||
}
|
||||
|
||||
int
|
||||
init_pcap(void)
|
||||
{
|
||||
struct bpf_program bprog;
|
||||
pcap_t *oldhpcap = hpcap;
|
||||
|
||||
hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
|
||||
if (hpcap == NULL) {
|
||||
logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
|
||||
hpcap = oldhpcap;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
|
||||
logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
|
||||
else if (pcap_setfilter(hpcap, &bprog) < 0)
|
||||
logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
|
||||
if (filter != NULL)
|
||||
free(filter);
|
||||
|
||||
if (pcap_datalink(hpcap) != DLT_PFLOG) {
|
||||
logmsg(LOG_ERR, "Invalid datalink type");
|
||||
pcap_close(hpcap);
|
||||
hpcap = oldhpcap;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (oldhpcap)
|
||||
pcap_close(oldhpcap);
|
||||
|
||||
snaplen = pcap_snapshot(hpcap);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
reset_dump(void)
|
||||
{
|
||||
struct pcap_file_header hdr;
|
||||
struct stat st;
|
||||
int tmpsnap;
|
||||
FILE *fp;
|
||||
|
||||
if (hpcap == NULL)
|
||||
return (1);
|
||||
if (dpcap) {
|
||||
pcap_dump_close(dpcap);
|
||||
dpcap = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Basically reimplement pcap_dump_open() because it truncates
|
||||
* files and duplicates headers and such.
|
||||
*/
|
||||
fp = fopen(filename, "a+");
|
||||
if (fp == NULL) {
|
||||
snprintf(hpcap->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
|
||||
filename, pcap_strerror(errno));
|
||||
logmsg(LOG_ERR, "Error: %s", pcap_geterr(hpcap));
|
||||
return (1);
|
||||
}
|
||||
if (fstat(fileno(fp), &st) == -1) {
|
||||
snprintf(hpcap->errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
|
||||
filename, pcap_strerror(errno));
|
||||
logmsg(LOG_ERR, "Error: %s", pcap_geterr(hpcap));
|
||||
return (1);
|
||||
}
|
||||
|
||||
dpcap = (pcap_dumper_t *)fp;
|
||||
|
||||
#define TCPDUMP_MAGIC 0xa1b2c3d4
|
||||
|
||||
if (st.st_size == 0) {
|
||||
if (snaplen != pcap_snapshot(hpcap)) {
|
||||
logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
|
||||
if (init_pcap()) {
|
||||
logmsg(LOG_ERR, "Failed to initialize");
|
||||
if (hpcap == NULL) return (-1);
|
||||
logmsg(LOG_NOTICE, "Using old settings");
|
||||
}
|
||||
}
|
||||
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) {
|
||||
dpcap = NULL;
|
||||
fclose(fp);
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Must read the file, compare the header against our new
|
||||
* options (in particular, snaplen) and adjust our options so
|
||||
* that we generate a correct file.
|
||||
*/
|
||||
(void) fseek(fp, 0L, SEEK_SET);
|
||||
if (fread((char *)&hdr, sizeof(hdr), 1, fp) == 1) {
|
||||
if (hdr.magic != TCPDUMP_MAGIC ||
|
||||
hdr.version_major != PCAP_VERSION_MAJOR ||
|
||||
hdr.version_minor != PCAP_VERSION_MINOR ||
|
||||
hdr.linktype != hpcap->linktype) {
|
||||
logmsg(LOG_ERR,
|
||||
"Invalid/incompatible log file, move it away");
|
||||
fclose(fp);
|
||||
return (1);
|
||||
}
|
||||
if (hdr.snaplen != snaplen) {
|
||||
logmsg(LOG_WARNING,
|
||||
"Existing file specifies a snaplen of %u, using it",
|
||||
hdr.snaplen);
|
||||
tmpsnap = snaplen;
|
||||
snaplen = hdr.snaplen;
|
||||
if (init_pcap()) {
|
||||
logmsg(LOG_ERR, "Failed to re-initialize");
|
||||
if (hpcap == 0)
|
||||
return (-1);
|
||||
logmsg(LOG_NOTICE,
|
||||
"Using old settings, offset: %llu",
|
||||
(unsigned long long)st.st_size);
|
||||
}
|
||||
snaplen = tmpsnap;
|
||||
}
|
||||
}
|
||||
|
||||
(void) fseek(fp, 0L, SEEK_END);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct pcap_stat pstat;
|
||||
int ch, np;
|
||||
|
||||
while ((ch = getopt(argc, argv, "Dd: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;
|
||||
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);
|
||||
|
||||
signal(SIGTERM, sig_close);
|
||||
signal(SIGINT, sig_close);
|
||||
signal(SIGQUIT, sig_close);
|
||||
signal(SIGALRM, sig_alrm);
|
||||
signal(SIGHUP, sig_hup);
|
||||
alarm(delay);
|
||||
|
||||
if (argc) {
|
||||
filter = copy_argv(argv);
|
||||
if (filter == NULL)
|
||||
logmsg(LOG_NOTICE, "Failed to form filter expression");
|
||||
}
|
||||
|
||||
if (init_pcap()) {
|
||||
logmsg(LOG_ERR, "Exiting, init failure");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (reset_dump()) {
|
||||
logmsg(LOG_ERR, "Failed to open log file %s", filename);
|
||||
pcap_close(hpcap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
np = pcap_dispatch(hpcap, PCAP_NUM_PKTS, pcap_dump, (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, "Failed to open log file!");
|
||||
break;
|
||||
}
|
||||
logmsg(LOG_NOTICE, "Reopened logfile");
|
||||
gotsig_hup = 0;
|
||||
}
|
||||
|
||||
if (gotsig_alrm) {
|
||||
/* XXX pcap_dumper is an incomplete type which libpcap
|
||||
* casts to a FILE* currently. For now it is safe to
|
||||
* make the same assumption, however this may change
|
||||
* in the future.
|
||||
*/
|
||||
if (dpcap) {
|
||||
if (fflush((FILE *)dpcap) == EOF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
gotsig_alrm = 0;
|
||||
alarm(delay);
|
||||
}
|
||||
}
|
||||
|
||||
logmsg(LOG_NOTICE, "Exiting due to signal");
|
||||
if (dpcap)
|
||||
pcap_dump_close(dpcap);
|
||||
|
||||
if (pcap_stats(hpcap, &pstat) < 0)
|
||||
logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap));
|
||||
else
|
||||
logmsg(LOG_NOTICE, "%u packets received, %u dropped",
|
||||
pstat.ps_recv, pstat.ps_drop);
|
||||
|
||||
pcap_close(hpcap);
|
||||
if (!Debug)
|
||||
closelog();
|
||||
return (0);
|
||||
}
|
Loading…
Reference in New Issue
Block a user