Import pf userland from OpenBSD 4.1 and (for ftp-proxy) libevent 1.3b as
a local lib.
This commit is contained in:
parent
61a1372b41
commit
67ecd4f3a4
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/pf/dist/; revision=171169
@ -1,28 +1,18 @@
|
||||
.\" $OpenBSD: authpf.8,v 1.38 2005/01/04 09:57:04 jmc Exp $
|
||||
.\" $OpenBSD: authpf.8,v 1.43 2007/02/24 17:21:04 beck Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2002 Bob Beck (beck@openbsd.org>. All rights reserved.
|
||||
.\" Copyright (c) 1998-2007 Bob Beck (beck@openbsd.org>. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" 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.
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\" 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 January 10, 2002
|
||||
.Dt AUTHPF 8
|
||||
@ -225,8 +215,11 @@ 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.
|
||||
Also note that
|
||||
Also note that the various SSH tunnelling mechanisms,
|
||||
such as
|
||||
.Ar AllowTcpForwarding
|
||||
and
|
||||
.Ar PermitTunnel ,
|
||||
should be disabled for
|
||||
.Nm
|
||||
users to prevent them from circumventing restrictions imposed by the
|
||||
@ -424,8 +417,7 @@ TCP connections.
|
||||
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 log quick on $internal_if proto tcp from $user_ip to any
|
||||
pass in quick on $internal_if from $user_ip to any
|
||||
.Ed
|
||||
.Pp
|
||||
@ -440,16 +432,15 @@ 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
|
||||
-> 127.0.0.1 port 8021
|
||||
|
||||
# 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
|
||||
port { 21, 22, 80, 443 }
|
||||
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 udp from $user_ip to $ipsec_gw port = isakmp
|
||||
pass in quick proto esp from $user_ip to $ipsec_gw
|
||||
.Ed
|
||||
.Pp
|
||||
@ -464,7 +455,7 @@ int_if = "fxp0"
|
||||
# nat and tag connections...
|
||||
nat on $ext_if from $user_ip to any tag $user_ip -> $ext_addr
|
||||
pass in quick on $int_if from $user_ip to any
|
||||
pass out log quick on $ext_if tagged $user_ip keep state
|
||||
pass out log quick on $ext_if tagged $user_ip
|
||||
.Ed
|
||||
.Pp
|
||||
With the above rules added by
|
||||
@ -490,7 +481,7 @@ lines will give SMTP and IMAP access to logged in users:
|
||||
.Bd -literal
|
||||
table <authpf_users> persist
|
||||
pass in on $ext_if proto tcp from <authpf_users> \e
|
||||
to port { smtp imap } keep state
|
||||
to port { smtp imap }
|
||||
.Ed
|
||||
.Pp
|
||||
It is also possible to use the "authpf_users"
|
||||
@ -516,6 +507,7 @@ rdr-anchor "authpf/*" from <authpf_users>
|
||||
.Sh SEE ALSO
|
||||
.Xr pf 4 ,
|
||||
.Xr pf.conf 5 ,
|
||||
.Xr securelevel 7 ,
|
||||
.Xr ftp-proxy 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
|
@ -1,28 +1,19 @@
|
||||
/* $OpenBSD: authpf.c,v 1.89 2005/02/10 04:24:15 joel Exp $ */
|
||||
/* $OpenBSD: authpf.c,v 1.104 2007/02/24 17:35:08 beck Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1998 - 2002 Bob Beck (beck@openbsd.org).
|
||||
* Copyright (C) 1998 - 2007 Bob Beck (beck@openbsd.org).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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>
|
||||
@ -50,15 +41,13 @@
|
||||
|
||||
#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 int change_table(int, const char *, const char *);
|
||||
static int change_table(int, const char *);
|
||||
static void authpf_kill_states(void);
|
||||
|
||||
int dev; /* pf device */
|
||||
@ -67,7 +56,6 @@ char rulesetname[MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 2];
|
||||
char tablename[PF_TABLE_NAME_SIZE] = "authpf_users";
|
||||
|
||||
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. */
|
||||
@ -92,11 +80,16 @@ main(int argc, char *argv[])
|
||||
struct in6_addr ina;
|
||||
struct passwd *pw;
|
||||
char *cp;
|
||||
gid_t gid;
|
||||
uid_t uid;
|
||||
char *shell;
|
||||
login_cap_t *lc;
|
||||
|
||||
config = fopen(PATH_CONFFILE, "r");
|
||||
if (config == NULL) {
|
||||
syslog(LOG_ERR, "can not open %s (%m)", PATH_CONFFILE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((cp = getenv("SSH_TTY")) == NULL) {
|
||||
syslog(LOG_ERR, "non-interactive session connection for authpf");
|
||||
@ -133,7 +126,6 @@ main(int argc, char *argv[])
|
||||
|
||||
uid = getuid();
|
||||
pw = getpwuid(uid);
|
||||
endpwent();
|
||||
if (pw == NULL) {
|
||||
syslog(LOG_ERR, "cannot find user for uid %u", uid);
|
||||
goto die;
|
||||
@ -246,6 +238,8 @@ main(int argc, char *argv[])
|
||||
if (++lockcnt > 10) {
|
||||
syslog(LOG_ERR, "cannot kill previous authpf (pid %d)",
|
||||
otherpid);
|
||||
fclose(pidfp);
|
||||
pidfp = NULL;
|
||||
goto dogdeath;
|
||||
}
|
||||
sleep(1);
|
||||
@ -255,12 +249,22 @@ main(int argc, char *argv[])
|
||||
* it's lock, giving us a chance to get it now
|
||||
*/
|
||||
fclose(pidfp);
|
||||
pidfp = NULL;
|
||||
} while (1);
|
||||
|
||||
/* revoke privs */
|
||||
seteuid(getuid());
|
||||
setuid(getuid());
|
||||
/* whack the group list */
|
||||
gid = getegid();
|
||||
if (setgroups(1, &gid) == -1) {
|
||||
syslog(LOG_INFO, "setgroups: %s", strerror(errno));
|
||||
do_death(0);
|
||||
}
|
||||
|
||||
/* revoke privs */
|
||||
uid = getuid();
|
||||
if (setresuid(uid, uid, uid) == -1) {
|
||||
syslog(LOG_INFO, "setresuid: %s", strerror(errno));
|
||||
do_death(0);
|
||||
}
|
||||
openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON);
|
||||
|
||||
if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) {
|
||||
@ -268,8 +272,8 @@ main(int argc, char *argv[])
|
||||
do_death(0);
|
||||
}
|
||||
|
||||
if (config == NULL || read_config(config)) {
|
||||
syslog(LOG_INFO, "bad or nonexistent %s", PATH_CONFFILE);
|
||||
if (read_config(config)) {
|
||||
syslog(LOG_ERR, "invalid config file %s", PATH_CONFFILE);
|
||||
do_death(0);
|
||||
}
|
||||
|
||||
@ -288,7 +292,7 @@ main(int argc, char *argv[])
|
||||
printf("Unable to modify filters\r\n");
|
||||
do_death(0);
|
||||
}
|
||||
if (change_table(1, luser, ipsrc) == -1) {
|
||||
if (change_table(1, ipsrc) == -1) {
|
||||
printf("Unable to modify table\r\n");
|
||||
change_filter(0, luser, ipsrc);
|
||||
do_death(0);
|
||||
@ -299,7 +303,7 @@ main(int argc, char *argv[])
|
||||
signal(SIGALRM, need_death);
|
||||
signal(SIGPIPE, need_death);
|
||||
signal(SIGHUP, need_death);
|
||||
signal(SIGSTOP, need_death);
|
||||
signal(SIGQUIT, need_death);
|
||||
signal(SIGTSTP, need_death);
|
||||
while (1) {
|
||||
printf("\r\nHello %s. ", luser);
|
||||
@ -547,9 +551,11 @@ check_luser(char *luserdir, char *luser)
|
||||
while (fputs(tmp, stdout) != EOF && !feof(f)) {
|
||||
if (fgets(tmp, sizeof(tmp), f) == NULL) {
|
||||
fflush(stdout);
|
||||
fclose(f);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
fflush(stdout);
|
||||
return (0);
|
||||
@ -633,6 +639,7 @@ change_filter(int add, const char *luser, const char *ipsrc)
|
||||
char *fdpath = NULL, *userstr = NULL, *ipstr = NULL;
|
||||
char *rsn = NULL, *fn = NULL;
|
||||
pid_t pid;
|
||||
gid_t gid;
|
||||
int s;
|
||||
|
||||
if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) {
|
||||
@ -672,8 +679,14 @@ change_filter(int add, const char *luser, const char *ipsrc)
|
||||
|
||||
switch (pid = fork()) {
|
||||
case -1:
|
||||
err(1, "fork failed");
|
||||
syslog(LOG_ERR, "fork failed");
|
||||
goto error;
|
||||
case 0:
|
||||
/* revoke group privs before exec */
|
||||
gid = getgid();
|
||||
if (setregid(gid, gid) == -1) {
|
||||
err(1, "setregid");
|
||||
}
|
||||
execvp(PATH_PFCTL, pargv);
|
||||
warn("exec of %s failed", PATH_PFCTL);
|
||||
_exit(1);
|
||||
@ -682,11 +695,9 @@ change_filter(int add, const char *luser, const char *ipsrc)
|
||||
/* parent */
|
||||
waitpid(pid, &s, 0);
|
||||
if (s != 0) {
|
||||
if (WIFEXITED(s)) {
|
||||
syslog(LOG_ERR, "pfctl exited abnormally");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (add) {
|
||||
gettimeofday(&Tstart, NULL);
|
||||
@ -701,16 +712,10 @@ change_filter(int add, const char *luser, const char *ipsrc)
|
||||
syslog(LOG_ERR, "malloc failed");
|
||||
error:
|
||||
free(fdpath);
|
||||
fdpath = NULL;
|
||||
free(rsn);
|
||||
rsn = NULL;
|
||||
free(userstr);
|
||||
userstr = NULL;
|
||||
free(ipstr);
|
||||
ipstr = NULL;
|
||||
free(fn);
|
||||
fn = NULL;
|
||||
infile = NULL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -718,13 +723,14 @@ change_filter(int add, const char *luser, const char *ipsrc)
|
||||
* Add/remove this IP from the "authpf_users" table.
|
||||
*/
|
||||
static int
|
||||
change_table(int add, const char *luser, const char *ipsrc)
|
||||
change_table(int add, const char *ipsrc)
|
||||
{
|
||||
struct pfioc_table io;
|
||||
struct pfr_addr addr;
|
||||
|
||||
bzero(&io, sizeof(io));
|
||||
strlcpy(io.pfrio_table.pfrt_name, tablename, sizeof(io.pfrio_table));
|
||||
strlcpy(io.pfrio_table.pfrt_name, tablename,
|
||||
sizeof(io.pfrio_table.pfrt_name));
|
||||
io.pfrio_buffer = &addr;
|
||||
io.pfrio_esize = sizeof(addr);
|
||||
io.pfrio_size = 1;
|
||||
@ -813,13 +819,11 @@ do_death(int active)
|
||||
|
||||
if (active) {
|
||||
change_filter(0, luser, ipsrc);
|
||||
change_table(0, luser, ipsrc);
|
||||
change_table(0, ipsrc);
|
||||
authpf_kill_states();
|
||||
remove_stale_rulesets();
|
||||
}
|
||||
if (pidfp)
|
||||
ftruncate(fileno(pidfp), 0);
|
||||
if (pidfile[0])
|
||||
if (pidfile[0] && (pidfp != NULL))
|
||||
if (unlink(pidfile) == -1)
|
||||
syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile);
|
||||
exit(ret);
|
||||
|
387
contrib/pf/ftp-proxy/filter.c
Normal file
387
contrib/pf/ftp-proxy/filter.c
Normal file
@ -0,0 +1,387 @@
|
||||
/* $OpenBSD: filter.c,v 1.5 2006/12/01 07:31:21 camield Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/pfvar.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "filter.h"
|
||||
|
||||
/* From netinet/in.h, but only _KERNEL_ gets them. */
|
||||
#define satosin(sa) ((struct sockaddr_in *)(sa))
|
||||
#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
|
||||
|
||||
enum { TRANS_FILTER = 0, TRANS_NAT, TRANS_RDR, TRANS_SIZE };
|
||||
|
||||
int prepare_rule(u_int32_t, int, struct sockaddr *, struct sockaddr *,
|
||||
u_int16_t);
|
||||
int server_lookup4(struct sockaddr_in *, struct sockaddr_in *,
|
||||
struct sockaddr_in *);
|
||||
int server_lookup6(struct sockaddr_in6 *, struct sockaddr_in6 *,
|
||||
struct sockaddr_in6 *);
|
||||
|
||||
static struct pfioc_pooladdr pfp;
|
||||
static struct pfioc_rule pfr;
|
||||
static struct pfioc_trans pft;
|
||||
static struct pfioc_trans_e pfte[TRANS_SIZE];
|
||||
static int dev, rule_log;
|
||||
static char *qname;
|
||||
|
||||
int
|
||||
add_filter(u_int32_t id, u_int8_t dir, struct sockaddr *src,
|
||||
struct sockaddr *dst, u_int16_t d_port)
|
||||
{
|
||||
if (!src || !dst || !d_port) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (prepare_rule(id, PF_RULESET_FILTER, src, dst, d_port) == -1)
|
||||
return (-1);
|
||||
|
||||
pfr.rule.direction = dir;
|
||||
if (ioctl(dev, DIOCADDRULE, &pfr) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
add_nat(u_int32_t id, struct sockaddr *src, struct sockaddr *dst,
|
||||
u_int16_t d_port, struct sockaddr *nat, u_int16_t nat_range_low,
|
||||
u_int16_t nat_range_high)
|
||||
{
|
||||
if (!src || !dst || !d_port || !nat || !nat_range_low ||
|
||||
(src->sa_family != nat->sa_family)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (prepare_rule(id, PF_RULESET_NAT, src, dst, d_port) == -1)
|
||||
return (-1);
|
||||
|
||||
if (nat->sa_family == AF_INET) {
|
||||
memcpy(&pfp.addr.addr.v.a.addr.v4,
|
||||
&satosin(nat)->sin_addr.s_addr, 4);
|
||||
memset(&pfp.addr.addr.v.a.mask.addr8, 255, 4);
|
||||
} else {
|
||||
memcpy(&pfp.addr.addr.v.a.addr.v6,
|
||||
&satosin6(nat)->sin6_addr.s6_addr, 16);
|
||||
memset(&pfp.addr.addr.v.a.mask.addr8, 255, 16);
|
||||
}
|
||||
if (ioctl(dev, DIOCADDADDR, &pfp) == -1)
|
||||
return (-1);
|
||||
|
||||
pfr.rule.rpool.proxy_port[0] = nat_range_low;
|
||||
pfr.rule.rpool.proxy_port[1] = nat_range_high;
|
||||
if (ioctl(dev, DIOCADDRULE, &pfr) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
add_rdr(u_int32_t id, struct sockaddr *src, struct sockaddr *dst,
|
||||
u_int16_t d_port, struct sockaddr *rdr, u_int16_t rdr_port)
|
||||
{
|
||||
if (!src || !dst || !d_port || !rdr || !rdr_port ||
|
||||
(src->sa_family != rdr->sa_family)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (prepare_rule(id, PF_RULESET_RDR, src, dst, d_port) == -1)
|
||||
return (-1);
|
||||
|
||||
if (rdr->sa_family == AF_INET) {
|
||||
memcpy(&pfp.addr.addr.v.a.addr.v4,
|
||||
&satosin(rdr)->sin_addr.s_addr, 4);
|
||||
memset(&pfp.addr.addr.v.a.mask.addr8, 255, 4);
|
||||
} else {
|
||||
memcpy(&pfp.addr.addr.v.a.addr.v6,
|
||||
&satosin6(rdr)->sin6_addr.s6_addr, 16);
|
||||
memset(&pfp.addr.addr.v.a.mask.addr8, 255, 16);
|
||||
}
|
||||
if (ioctl(dev, DIOCADDADDR, &pfp) == -1)
|
||||
return (-1);
|
||||
|
||||
pfr.rule.rpool.proxy_port[0] = rdr_port;
|
||||
if (ioctl(dev, DIOCADDRULE, &pfr) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
do_commit(void)
|
||||
{
|
||||
if (ioctl(dev, DIOCXCOMMIT, &pft) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
do_rollback(void)
|
||||
{
|
||||
if (ioctl(dev, DIOCXROLLBACK, &pft) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
init_filter(char *opt_qname, int opt_verbose)
|
||||
{
|
||||
struct pf_status status;
|
||||
|
||||
qname = opt_qname;
|
||||
|
||||
if (opt_verbose == 1)
|
||||
rule_log = PF_LOG;
|
||||
else if (opt_verbose == 2)
|
||||
rule_log = PF_LOG_ALL;
|
||||
|
||||
dev = open("/dev/pf", O_RDWR);
|
||||
if (dev == -1)
|
||||
err(1, "/dev/pf");
|
||||
if (ioctl(dev, DIOCGETSTATUS, &status) == -1)
|
||||
err(1, "DIOCGETSTATUS");
|
||||
if (!status.running)
|
||||
errx(1, "pf is disabled");
|
||||
}
|
||||
|
||||
int
|
||||
prepare_commit(u_int32_t id)
|
||||
{
|
||||
char an[PF_ANCHOR_NAME_SIZE];
|
||||
int i;
|
||||
|
||||
memset(&pft, 0, sizeof pft);
|
||||
pft.size = TRANS_SIZE;
|
||||
pft.esize = sizeof pfte[0];
|
||||
pft.array = pfte;
|
||||
|
||||
snprintf(an, PF_ANCHOR_NAME_SIZE, "%s/%d.%d", FTP_PROXY_ANCHOR,
|
||||
getpid(), id);
|
||||
for (i = 0; i < TRANS_SIZE; i++) {
|
||||
memset(&pfte[i], 0, sizeof pfte[0]);
|
||||
strlcpy(pfte[i].anchor, an, PF_ANCHOR_NAME_SIZE);
|
||||
switch (i) {
|
||||
case TRANS_FILTER:
|
||||
pfte[i].rs_num = PF_RULESET_FILTER;
|
||||
break;
|
||||
case TRANS_NAT:
|
||||
pfte[i].rs_num = PF_RULESET_NAT;
|
||||
break;
|
||||
case TRANS_RDR:
|
||||
pfte[i].rs_num = PF_RULESET_RDR;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (ioctl(dev, DIOCXBEGIN, &pft) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
prepare_rule(u_int32_t id, int rs_num, struct sockaddr *src,
|
||||
struct sockaddr *dst, u_int16_t d_port)
|
||||
{
|
||||
char an[PF_ANCHOR_NAME_SIZE];
|
||||
|
||||
if ((src->sa_family != AF_INET && src->sa_family != AF_INET6) ||
|
||||
(src->sa_family != dst->sa_family)) {
|
||||
errno = EPROTONOSUPPORT;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memset(&pfp, 0, sizeof pfp);
|
||||
memset(&pfr, 0, sizeof pfr);
|
||||
snprintf(an, PF_ANCHOR_NAME_SIZE, "%s/%d.%d", FTP_PROXY_ANCHOR,
|
||||
getpid(), id);
|
||||
strlcpy(pfp.anchor, an, PF_ANCHOR_NAME_SIZE);
|
||||
strlcpy(pfr.anchor, an, PF_ANCHOR_NAME_SIZE);
|
||||
|
||||
switch (rs_num) {
|
||||
case PF_RULESET_FILTER:
|
||||
pfr.ticket = pfte[TRANS_FILTER].ticket;
|
||||
break;
|
||||
case PF_RULESET_NAT:
|
||||
pfr.ticket = pfte[TRANS_NAT].ticket;
|
||||
break;
|
||||
case PF_RULESET_RDR:
|
||||
pfr.ticket = pfte[TRANS_RDR].ticket;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (ioctl(dev, DIOCBEGINADDRS, &pfp) == -1)
|
||||
return (-1);
|
||||
pfr.pool_ticket = pfp.ticket;
|
||||
|
||||
/* Generic for all rule types. */
|
||||
pfr.rule.af = src->sa_family;
|
||||
pfr.rule.proto = IPPROTO_TCP;
|
||||
pfr.rule.src.addr.type = PF_ADDR_ADDRMASK;
|
||||
pfr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
|
||||
if (src->sa_family == AF_INET) {
|
||||
memcpy(&pfr.rule.src.addr.v.a.addr.v4,
|
||||
&satosin(src)->sin_addr.s_addr, 4);
|
||||
memset(&pfr.rule.src.addr.v.a.mask.addr8, 255, 4);
|
||||
memcpy(&pfr.rule.dst.addr.v.a.addr.v4,
|
||||
&satosin(dst)->sin_addr.s_addr, 4);
|
||||
memset(&pfr.rule.dst.addr.v.a.mask.addr8, 255, 4);
|
||||
} else {
|
||||
memcpy(&pfr.rule.src.addr.v.a.addr.v6,
|
||||
&satosin6(src)->sin6_addr.s6_addr, 16);
|
||||
memset(&pfr.rule.src.addr.v.a.mask.addr8, 255, 16);
|
||||
memcpy(&pfr.rule.dst.addr.v.a.addr.v6,
|
||||
&satosin6(dst)->sin6_addr.s6_addr, 16);
|
||||
memset(&pfr.rule.dst.addr.v.a.mask.addr8, 255, 16);
|
||||
}
|
||||
pfr.rule.dst.port_op = PF_OP_EQ;
|
||||
pfr.rule.dst.port[0] = htons(d_port);
|
||||
|
||||
switch (rs_num) {
|
||||
case PF_RULESET_FILTER:
|
||||
/*
|
||||
* pass quick [log] inet[6] proto tcp \
|
||||
* from $src to $dst port = $d_port flags S/SA keep state
|
||||
* (max 1) [queue qname]
|
||||
*/
|
||||
pfr.rule.action = PF_PASS;
|
||||
pfr.rule.quick = 1;
|
||||
pfr.rule.log = rule_log;
|
||||
pfr.rule.keep_state = 1;
|
||||
pfr.rule.flags = TH_SYN;
|
||||
pfr.rule.flagset = (TH_SYN|TH_ACK);
|
||||
pfr.rule.max_states = 1;
|
||||
if (qname != NULL)
|
||||
strlcpy(pfr.rule.qname, qname, sizeof pfr.rule.qname);
|
||||
break;
|
||||
case PF_RULESET_NAT:
|
||||
/*
|
||||
* nat inet[6] proto tcp from $src to $dst port $d_port -> $nat
|
||||
*/
|
||||
pfr.rule.action = PF_NAT;
|
||||
break;
|
||||
case PF_RULESET_RDR:
|
||||
/*
|
||||
* rdr inet[6] proto tcp from $src to $dst port $d_port -> $rdr
|
||||
*/
|
||||
pfr.rule.action = PF_RDR;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
server_lookup(struct sockaddr *client, struct sockaddr *proxy,
|
||||
struct sockaddr *server)
|
||||
{
|
||||
if (client->sa_family == AF_INET)
|
||||
return (server_lookup4(satosin(client), satosin(proxy),
|
||||
satosin(server)));
|
||||
|
||||
if (client->sa_family == AF_INET6)
|
||||
return (server_lookup6(satosin6(client), satosin6(proxy),
|
||||
satosin6(server)));
|
||||
|
||||
errno = EPROTONOSUPPORT;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
server_lookup4(struct sockaddr_in *client, struct sockaddr_in *proxy,
|
||||
struct sockaddr_in *server)
|
||||
{
|
||||
struct pfioc_natlook pnl;
|
||||
|
||||
memset(&pnl, 0, sizeof pnl);
|
||||
pnl.direction = PF_OUT;
|
||||
pnl.af = AF_INET;
|
||||
pnl.proto = IPPROTO_TCP;
|
||||
memcpy(&pnl.saddr.v4, &client->sin_addr.s_addr, sizeof pnl.saddr.v4);
|
||||
memcpy(&pnl.daddr.v4, &proxy->sin_addr.s_addr, sizeof pnl.daddr.v4);
|
||||
pnl.sport = client->sin_port;
|
||||
pnl.dport = proxy->sin_port;
|
||||
|
||||
if (ioctl(dev, DIOCNATLOOK, &pnl) == -1)
|
||||
return (-1);
|
||||
|
||||
memset(server, 0, sizeof(struct sockaddr_in));
|
||||
server->sin_len = sizeof(struct sockaddr_in);
|
||||
server->sin_family = AF_INET;
|
||||
memcpy(&server->sin_addr.s_addr, &pnl.rdaddr.v4,
|
||||
sizeof server->sin_addr.s_addr);
|
||||
server->sin_port = pnl.rdport;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
server_lookup6(struct sockaddr_in6 *client, struct sockaddr_in6 *proxy,
|
||||
struct sockaddr_in6 *server)
|
||||
{
|
||||
struct pfioc_natlook pnl;
|
||||
|
||||
memset(&pnl, 0, sizeof pnl);
|
||||
pnl.direction = PF_OUT;
|
||||
pnl.af = AF_INET6;
|
||||
pnl.proto = IPPROTO_TCP;
|
||||
memcpy(&pnl.saddr.v6, &client->sin6_addr.s6_addr, sizeof pnl.saddr.v6);
|
||||
memcpy(&pnl.daddr.v6, &proxy->sin6_addr.s6_addr, sizeof pnl.daddr.v6);
|
||||
pnl.sport = client->sin6_port;
|
||||
pnl.dport = proxy->sin6_port;
|
||||
|
||||
if (ioctl(dev, DIOCNATLOOK, &pnl) == -1)
|
||||
return (-1);
|
||||
|
||||
memset(server, 0, sizeof(struct sockaddr_in6));
|
||||
server->sin6_len = sizeof(struct sockaddr_in6);
|
||||
server->sin6_family = AF_INET6;
|
||||
memcpy(&server->sin6_addr.s6_addr, &pnl.rdaddr.v6,
|
||||
sizeof server->sin6_addr);
|
||||
server->sin6_port = pnl.rdport;
|
||||
|
||||
return (0);
|
||||
}
|
31
contrib/pf/ftp-proxy/filter.h
Normal file
31
contrib/pf/ftp-proxy/filter.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* $OpenBSD: filter.h,v 1.3 2005/06/07 14:12:07 camield Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define FTP_PROXY_ANCHOR "ftp-proxy"
|
||||
|
||||
int add_filter(u_int32_t, u_int8_t, struct sockaddr *, struct sockaddr *,
|
||||
u_int16_t);
|
||||
int add_nat(u_int32_t, struct sockaddr *, struct sockaddr *, u_int16_t,
|
||||
struct sockaddr *, u_int16_t, u_int16_t);
|
||||
int add_rdr(u_int32_t, struct sockaddr *, struct sockaddr *, u_int16_t,
|
||||
struct sockaddr *, u_int16_t);
|
||||
int do_commit(void);
|
||||
int do_rollback(void);
|
||||
void init_filter(char *, int);
|
||||
int prepare_commit(u_int32_t);
|
||||
int server_lookup(struct sockaddr *, struct sockaddr *, struct sockaddr *);
|
@ -1,293 +1,183 @@
|
||||
.\" $OpenBSD: ftp-proxy.8,v 1.42 2004/11/19 00:47:23 jmc Exp $
|
||||
.\" $OpenBSD: ftp-proxy.8,v 1.7 2006/12/30 13:01:54 camield Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1996-2001
|
||||
.\" Obtuse Systems Corporation, All rights reserved.
|
||||
.\" Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
|
||||
.\"
|
||||
.\" 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.
|
||||
.\" 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.
|
||||
.\"
|
||||
.\" 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.
|
||||
.\" 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 17, 2001
|
||||
.Dd November 28, 2004
|
||||
.Dt FTP-PROXY 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ftp-proxy
|
||||
.Nd Internet File Transfer Protocol proxy server
|
||||
.Nd Internet File Transfer Protocol proxy daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm ftp-proxy
|
||||
.Bk -words
|
||||
.Op Fl AnrVw
|
||||
.Op Fl 6Adrv
|
||||
.Op Fl a Ar address
|
||||
.Op Fl D Ar debuglevel
|
||||
.Op Fl g Ar group
|
||||
.Op Fl M Ar maxport
|
||||
.Op Fl m Ar minport
|
||||
.Op Fl R Ar address[:port]
|
||||
.Op Fl S Ar address
|
||||
.Op Fl b Ar address
|
||||
.Op Fl D Ar level
|
||||
.Op Fl m Ar maxsessions
|
||||
.Op Fl P Ar port
|
||||
.Op Fl p Ar port
|
||||
.Op Fl q Ar queue
|
||||
.Op Fl R Ar address
|
||||
.Op Fl t Ar timeout
|
||||
.Op Fl u Ar user
|
||||
.Ek
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a proxy for the Internet File Transfer Protocol.
|
||||
The proxy uses
|
||||
FTP control connections should be redirected into the proxy using the
|
||||
.Xr pf 4
|
||||
and expects to have the FTP control connection as described in
|
||||
.Xr services 5
|
||||
redirected to it via a
|
||||
.Ar rdr
|
||||
command, after which the proxy connects to the server on behalf of
|
||||
the client.
|
||||
.Pp
|
||||
The proxy allows data connections to pass, rewriting and redirecting
|
||||
them so that the right addresses are used.
|
||||
All connections from the client to the server have their source
|
||||
address rewritten so they appear to come from the proxy.
|
||||
Consequently, all connections from the server to the proxy have
|
||||
their destination address rewritten, so they are redirected to the
|
||||
client.
|
||||
The proxy uses the
|
||||
.Xr pf 4
|
||||
.Em rdr
|
||||
command.
|
||||
An example of how to do that is further down in this document.
|
||||
.Ar anchor
|
||||
facility for this.
|
||||
.Pp
|
||||
Assuming the FTP control connection is from $client to $server, the
|
||||
proxy connected to the server using the $proxy source address, and
|
||||
$port is negotiated, then
|
||||
.Nm ftp-proxy
|
||||
adds the following rules to the various anchors.
|
||||
(These example rules use inet, but the proxy also supports inet6.)
|
||||
.Pp
|
||||
In case of active mode (PORT or EPRT):
|
||||
.Bd -literal -offset 2n
|
||||
rdr from $server to $proxy port $port -> $client
|
||||
pass quick inet proto tcp \e
|
||||
from $server to $client port $port
|
||||
.Ed
|
||||
.Pp
|
||||
In case of passive mode (PASV or EPSV):
|
||||
.Bd -literal -offset 2n
|
||||
nat from $client to $server port $port -> $proxy
|
||||
pass in quick inet proto tcp \e
|
||||
from $client to $server port $port
|
||||
pass out quick inet proto tcp \e
|
||||
from $proxy to $server port $port
|
||||
.Ed
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl 6
|
||||
IPv6 mode.
|
||||
The proxy will expect and use IPv6 addresses for all communication.
|
||||
Only the extended FTP modes EPSV and EPRT are allowed with IPv6.
|
||||
The proxy is in IPv4 mode by default.
|
||||
.It Fl A
|
||||
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.
|
||||
Only permit anonymous FTP connections.
|
||||
Either user "ftp" or user "anonymous" is allowed.
|
||||
.It Fl a Ar address
|
||||
Specify the local IP address to use in
|
||||
.Xr bind 2
|
||||
as the source for connections made by
|
||||
.Nm ftp-proxy
|
||||
when connecting to destination FTP servers.
|
||||
This may be necessary if the interface address of
|
||||
your default route is not reachable from the destinations
|
||||
.Nm
|
||||
is attempting connections to, or this address is different from the one
|
||||
connections are being NATed to.
|
||||
In the usual case this means that
|
||||
.Ar address
|
||||
should be a publicly visible IP address assigned to one of
|
||||
the interfaces on the machine running
|
||||
.Nm
|
||||
and should be the same address to which you are translating traffic
|
||||
if you are using the
|
||||
.Fl n
|
||||
option.
|
||||
.It Fl D Ar debuglevel
|
||||
Specify a debug level, where the proxy emits verbose debug output
|
||||
into
|
||||
.Xr syslogd 8
|
||||
at level
|
||||
.Dv LOG_DEBUG .
|
||||
Meaningful values of debuglevel are 0-3, where 0 is no debug output and
|
||||
3 is lots of debug output, the default being 0.
|
||||
.It Fl g Ar group
|
||||
Specify the named group to drop group privileges to, after doing
|
||||
.Xr pf 4
|
||||
lookups which require root.
|
||||
By default,
|
||||
.Nm
|
||||
uses the default group of the user it drops privilege to.
|
||||
.It Fl M Ar maxport
|
||||
Specify the upper end of the port range the proxy will use for the
|
||||
data connections it establishes.
|
||||
The default is
|
||||
.Dv IPPORT_HILASTAUTO
|
||||
defined in
|
||||
.Aq Pa netinet/in.h
|
||||
as 65535.
|
||||
.It Fl m Ar minport
|
||||
Specify the lower end of the port range the proxy will use for all
|
||||
data connections it establishes.
|
||||
The default is
|
||||
.Dv IPPORT_HIFIRSTAUTO
|
||||
defined in
|
||||
.Aq Pa netinet/in.h
|
||||
as 49152.
|
||||
.It Fl n
|
||||
Activate network address translation
|
||||
.Pq NAT
|
||||
mode.
|
||||
In this mode, the proxy will not attempt to proxy passive mode
|
||||
.Pq PASV or EPSV
|
||||
data connections.
|
||||
In order for this to work, the machine running the proxy will need to
|
||||
be forwarding packets and doing network address translation to allow
|
||||
the outbound passive connections from the client to reach the server.
|
||||
See
|
||||
.Xr pf.conf 5
|
||||
for more details on NAT.
|
||||
The proxy only ignores passive mode data connections when using this flag;
|
||||
it will still proxy PORT and EPRT mode data connections.
|
||||
Without this flag,
|
||||
.Nm
|
||||
does not require any IP forwarding or NAT beyond the
|
||||
.Em rdr
|
||||
necessary to capture the FTP control connection.
|
||||
.It Fl R Ar address:[port]
|
||||
Reverse proxy mode for FTP servers running behind a NAT gateway.
|
||||
In this mode, no redirection is needed.
|
||||
The proxy is run from
|
||||
.Xr inetd 8
|
||||
on the port that external clients connect to (usually 21).
|
||||
Control connections and passive data connections are forwarded
|
||||
to the server.
|
||||
The proxy will use this as the source address for the control
|
||||
connection to a server.
|
||||
.It Fl b Ar address
|
||||
Address where the proxy will listen for redirected control connections.
|
||||
The default is 127.0.0.1, or ::1 in IPv6 mode.
|
||||
.It Fl D Ar level
|
||||
Debug level, ranging from 0 to 7.
|
||||
Higher is more verbose.
|
||||
The default is 5.
|
||||
(These levels correspond to the
|
||||
.Xr syslog 3
|
||||
levels.)
|
||||
.It Fl d
|
||||
Do not daemonize.
|
||||
The process will stay in the foreground, logging to standard error.
|
||||
.It Fl m Ar maxsessions
|
||||
Maximum number of concurrent FTP sessions.
|
||||
When the proxy reaches this limit, new connections are denied.
|
||||
The default is 100 sessions.
|
||||
The limit can be lowered to a minimum of 1, or raised to a maximum of 500.
|
||||
.It Fl P Ar port
|
||||
Fixed server port.
|
||||
Only used in combination with
|
||||
.Fl R .
|
||||
The default is port 21.
|
||||
.It Fl p Ar port
|
||||
Port where the proxy will listen for redirected connections.
|
||||
The default is port 8021.
|
||||
.It Fl q Ar queue
|
||||
Create rules with queue
|
||||
.Ar queue
|
||||
appended, so that data connections can be queued.
|
||||
.It Fl R Ar address
|
||||
Fixed server address, also known as reverse mode.
|
||||
The proxy will always connect to the same server, regardless of
|
||||
where the client wanted to connect to (before it was redirected).
|
||||
Use this option to proxy for a server behind NAT, or to forward all
|
||||
connections to another proxy.
|
||||
.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 S Ar address
|
||||
Source address to use for data connections made by the proxy.
|
||||
Useful when there are multiple addresses (aliases) available
|
||||
to the proxy.
|
||||
Clients may expect data connections to have the same source
|
||||
address as the control connections, and reject or drop other
|
||||
connections.
|
||||
Rewrite sourceport to 20 in active mode to suit ancient clients that insist
|
||||
on this RFC property.
|
||||
.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.
|
||||
Number of seconds that the control connection can be idle, before the
|
||||
proxy will disconnect.
|
||||
The maximum is 86400 seconds, which is also the default.
|
||||
Do not set this too low, because the control connection is usually
|
||||
idle when large data transfers are taking place.
|
||||
.It Fl v
|
||||
Set the 'log' flag on pf rules committed by
|
||||
.Nm .
|
||||
Use twice to set the 'log-all' flag.
|
||||
The pf rules do not log by default.
|
||||
.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
|
||||
.Sh CONFIGURATION
|
||||
To make use of the proxy,
|
||||
.Xr pf.conf 5
|
||||
rule such as
|
||||
needs the following rules.
|
||||
All anchors are mandatory.
|
||||
Adjust the rules as needed.
|
||||
.Pp
|
||||
In the NAT section:
|
||||
.Bd -literal -offset 2n
|
||||
int_if = \&"xl0\&"
|
||||
rdr pass on $int_if proto tcp from any to any port 21 -> 127.0.0.1 port 8021
|
||||
nat-anchor "ftp-proxy/*"
|
||||
rdr-anchor "ftp-proxy/*"
|
||||
rdr pass on $int_if proto tcp from $lan to any port 21 -> \e
|
||||
127.0.0.1 port 8021
|
||||
.Ed
|
||||
.Pp
|
||||
.Xr inetd 8
|
||||
must then be configured to run
|
||||
.Nm
|
||||
on the port from above using
|
||||
In the rule section:
|
||||
.Bd -literal -offset 2n
|
||||
127.0.0.1:8021 stream tcp nowait root /usr/libexec/ftp-proxy ftp-proxy
|
||||
anchor "ftp-proxy/*"
|
||||
pass out proto tcp from $proxy to any port 21
|
||||
.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.
|
||||
.Sh CAVEATS
|
||||
.Xr pf 4
|
||||
does not allow the ruleset to be modified if the system is running at a
|
||||
.Xr securelevel 7
|
||||
higher than 1.
|
||||
At that level
|
||||
.Nm ftp-proxy
|
||||
cannot add rules to the anchors and FTP data connections may get blocked.
|
||||
.Pp
|
||||
IPv6 is not yet supported.
|
||||
Negotiated data connection ports below 1024 are not allowed.
|
||||
.Pp
|
||||
The negotiated IP address for active modes is ignored for security
|
||||
reasons.
|
||||
This makes third party file transfers impossible.
|
||||
.Pp
|
||||
.Nm ftp-proxy
|
||||
chroots to "/var/empty" and changes to user "proxy" to drop privileges.
|
||||
|
File diff suppressed because it is too large
Load Diff
456
contrib/pf/libevent/buffer.c
Normal file
456
contrib/pf/libevent/buffer.c
Normal file
@ -0,0 +1,456 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VASPRINTF
|
||||
/* If we have vasprintf, we need to define this before we include stdio.h. */
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "event.h"
|
||||
|
||||
struct evbuffer *
|
||||
evbuffer_new(void)
|
||||
{
|
||||
struct evbuffer *buffer;
|
||||
|
||||
buffer = calloc(1, sizeof(struct evbuffer));
|
||||
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
void
|
||||
evbuffer_free(struct evbuffer *buffer)
|
||||
{
|
||||
if (buffer->orig_buffer != NULL)
|
||||
free(buffer->orig_buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a destructive add. The data from one buffer moves into
|
||||
* the other buffer.
|
||||
*/
|
||||
|
||||
#define SWAP(x,y) do { \
|
||||
(x)->buffer = (y)->buffer; \
|
||||
(x)->orig_buffer = (y)->orig_buffer; \
|
||||
(x)->misalign = (y)->misalign; \
|
||||
(x)->totallen = (y)->totallen; \
|
||||
(x)->off = (y)->off; \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* Short cut for better performance */
|
||||
if (outbuf->off == 0) {
|
||||
struct evbuffer tmp;
|
||||
size_t oldoff = inbuf->off;
|
||||
|
||||
/* Swap them directly */
|
||||
SWAP(&tmp, outbuf);
|
||||
SWAP(outbuf, inbuf);
|
||||
SWAP(inbuf, &tmp);
|
||||
|
||||
/*
|
||||
* Optimization comes with a price; we need to notify the
|
||||
* buffer if necessary of the changes. oldoff is the amount
|
||||
* of data that we tranfered from inbuf to outbuf
|
||||
*/
|
||||
if (inbuf->off != oldoff && inbuf->cb != NULL)
|
||||
(*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
|
||||
if (oldoff && outbuf->cb != NULL)
|
||||
(*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
|
||||
if (res == 0) {
|
||||
/* We drain the input buffer on success */
|
||||
evbuffer_drain(inbuf, inbuf->off);
|
||||
}
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
|
||||
{
|
||||
char *buffer;
|
||||
size_t space;
|
||||
size_t oldoff = buf->off;
|
||||
int sz;
|
||||
va_list aq;
|
||||
|
||||
for (;;) {
|
||||
buffer = (char *)buf->buffer + buf->off;
|
||||
space = buf->totallen - buf->misalign - buf->off;
|
||||
|
||||
#ifndef va_copy
|
||||
#define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list))
|
||||
#endif
|
||||
va_copy(aq, ap);
|
||||
|
||||
#ifdef WIN32
|
||||
sz = vsnprintf(buffer, space - 1, fmt, aq);
|
||||
buffer[space - 1] = '\0';
|
||||
#else
|
||||
sz = vsnprintf(buffer, space, fmt, aq);
|
||||
#endif
|
||||
|
||||
va_end(aq);
|
||||
|
||||
if (sz == -1)
|
||||
return (-1);
|
||||
if (sz < space) {
|
||||
buf->off += sz;
|
||||
if (buf->cb != NULL)
|
||||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
|
||||
return (sz);
|
||||
}
|
||||
if (evbuffer_expand(buf, sz + 1) == -1)
|
||||
return (-1);
|
||||
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
int
|
||||
evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
|
||||
{
|
||||
int res = -1;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
res = evbuffer_add_vprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/* Reads data from an event buffer and drains the bytes read */
|
||||
|
||||
int
|
||||
evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
|
||||
{
|
||||
size_t nread = datlen;
|
||||
if (nread >= buf->off)
|
||||
nread = buf->off;
|
||||
|
||||
memcpy(data, buf->buffer, nread);
|
||||
evbuffer_drain(buf, nread);
|
||||
|
||||
return (nread);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
|
||||
* The returned buffer needs to be freed by the called.
|
||||
*/
|
||||
|
||||
char *
|
||||
evbuffer_readline(struct evbuffer *buffer)
|
||||
{
|
||||
u_char *data = EVBUFFER_DATA(buffer);
|
||||
size_t len = EVBUFFER_LENGTH(buffer);
|
||||
char *line;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (data[i] == '\r' || data[i] == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == len)
|
||||
return (NULL);
|
||||
|
||||
if ((line = malloc(i + 1)) == NULL) {
|
||||
fprintf(stderr, "%s: out of memory\n", __func__);
|
||||
evbuffer_drain(buffer, i);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
memcpy(line, data, i);
|
||||
line[i] = '\0';
|
||||
|
||||
/*
|
||||
* Some protocols terminate a line with '\r\n', so check for
|
||||
* that, too.
|
||||
*/
|
||||
if ( i < len - 1 ) {
|
||||
char fch = data[i], sch = data[i+1];
|
||||
|
||||
/* Drain one more character if needed */
|
||||
if ( (sch == '\r' || sch == '\n') && sch != fch )
|
||||
i += 1;
|
||||
}
|
||||
|
||||
evbuffer_drain(buffer, i + 1);
|
||||
|
||||
return (line);
|
||||
}
|
||||
|
||||
/* Adds data to an event buffer */
|
||||
|
||||
static inline void
|
||||
evbuffer_align(struct evbuffer *buf)
|
||||
{
|
||||
memmove(buf->orig_buffer, buf->buffer, buf->off);
|
||||
buf->buffer = buf->orig_buffer;
|
||||
buf->misalign = 0;
|
||||
}
|
||||
|
||||
/* Expands the available space in the event buffer to at least datlen */
|
||||
|
||||
int
|
||||
evbuffer_expand(struct evbuffer *buf, size_t datlen)
|
||||
{
|
||||
size_t need = buf->misalign + buf->off + datlen;
|
||||
|
||||
/* If we can fit all the data, then we don't have to do anything */
|
||||
if (buf->totallen >= need)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* If the misalignment fulfills our data needs, we just force an
|
||||
* alignment to happen. Afterwards, we have enough space.
|
||||
*/
|
||||
if (buf->misalign >= datlen) {
|
||||
evbuffer_align(buf);
|
||||
} else {
|
||||
void *newbuf;
|
||||
size_t length = buf->totallen;
|
||||
|
||||
if (length < 256)
|
||||
length = 256;
|
||||
while (length < need)
|
||||
length <<= 1;
|
||||
|
||||
if (buf->orig_buffer != buf->buffer)
|
||||
evbuffer_align(buf);
|
||||
if ((newbuf = realloc(buf->buffer, length)) == NULL)
|
||||
return (-1);
|
||||
|
||||
buf->orig_buffer = buf->buffer = newbuf;
|
||||
buf->totallen = length;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
|
||||
{
|
||||
size_t need = buf->misalign + buf->off + datlen;
|
||||
size_t oldoff = buf->off;
|
||||
|
||||
if (buf->totallen < need) {
|
||||
if (evbuffer_expand(buf, datlen) == -1)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memcpy(buf->buffer + buf->off, data, datlen);
|
||||
buf->off += datlen;
|
||||
|
||||
if (datlen && buf->cb != NULL)
|
||||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
evbuffer_drain(struct evbuffer *buf, size_t len)
|
||||
{
|
||||
size_t oldoff = buf->off;
|
||||
|
||||
if (len >= buf->off) {
|
||||
buf->off = 0;
|
||||
buf->buffer = buf->orig_buffer;
|
||||
buf->misalign = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
buf->buffer += len;
|
||||
buf->misalign += len;
|
||||
|
||||
buf->off -= len;
|
||||
|
||||
done:
|
||||
/* Tell someone about changes in this buffer */
|
||||
if (buf->off != oldoff && buf->cb != NULL)
|
||||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads data from a file descriptor into a buffer.
|
||||
*/
|
||||
|
||||
#define EVBUFFER_MAX_READ 4096
|
||||
|
||||
int
|
||||
evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
|
||||
{
|
||||
u_char *p;
|
||||
size_t oldoff = buf->off;
|
||||
int n = EVBUFFER_MAX_READ;
|
||||
#ifdef WIN32
|
||||
DWORD dwBytesRead;
|
||||
#endif
|
||||
|
||||
#ifdef FIONREAD
|
||||
if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) {
|
||||
n = EVBUFFER_MAX_READ;
|
||||
} else if (n > EVBUFFER_MAX_READ && n > howmuch) {
|
||||
/*
|
||||
* It's possible that a lot of data is available for
|
||||
* reading. We do not want to exhaust resources
|
||||
* before the reader has a chance to do something
|
||||
* about it. If the reader does not tell us how much
|
||||
* data we should read, we artifically limit it.
|
||||
*/
|
||||
if (n > buf->totallen << 2)
|
||||
n = buf->totallen << 2;
|
||||
if (n < EVBUFFER_MAX_READ)
|
||||
n = EVBUFFER_MAX_READ;
|
||||
}
|
||||
#endif
|
||||
if (howmuch < 0 || howmuch > n)
|
||||
howmuch = n;
|
||||
|
||||
/* If we don't have FIONREAD, we might waste some space here */
|
||||
if (evbuffer_expand(buf, howmuch) == -1)
|
||||
return (-1);
|
||||
|
||||
/* We can append new data at this point */
|
||||
p = buf->buffer + buf->off;
|
||||
|
||||
#ifndef WIN32
|
||||
n = read(fd, p, howmuch);
|
||||
if (n == -1)
|
||||
return (-1);
|
||||
if (n == 0)
|
||||
return (0);
|
||||
#else
|
||||
n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL);
|
||||
if (n == 0)
|
||||
return (-1);
|
||||
if (dwBytesRead == 0)
|
||||
return (0);
|
||||
n = dwBytesRead;
|
||||
#endif
|
||||
|
||||
buf->off += n;
|
||||
|
||||
/* Tell someone about changes in this buffer */
|
||||
if (buf->off != oldoff && buf->cb != NULL)
|
||||
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
int
|
||||
evbuffer_write(struct evbuffer *buffer, int fd)
|
||||
{
|
||||
int n;
|
||||
#ifdef WIN32
|
||||
DWORD dwBytesWritten;
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
n = write(fd, buffer->buffer, buffer->off);
|
||||
if (n == -1)
|
||||
return (-1);
|
||||
if (n == 0)
|
||||
return (0);
|
||||
#else
|
||||
n = WriteFile((HANDLE)fd, buffer->buffer, buffer->off, &dwBytesWritten, NULL);
|
||||
if (n == 0)
|
||||
return (-1);
|
||||
if (dwBytesWritten == 0)
|
||||
return (0);
|
||||
n = dwBytesWritten;
|
||||
#endif
|
||||
evbuffer_drain(buffer, n);
|
||||
|
||||
return (n);
|
||||
}
|
||||
|
||||
u_char *
|
||||
evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)
|
||||
{
|
||||
size_t remain = buffer->off;
|
||||
u_char *search = buffer->buffer;
|
||||
u_char *p;
|
||||
|
||||
while ((p = memchr(search, *what, remain)) != NULL) {
|
||||
remain = buffer->off - (size_t)(search - buffer->buffer);
|
||||
if (remain < len)
|
||||
break;
|
||||
if (memcmp(p, what, len) == 0)
|
||||
return (p);
|
||||
search = p + 1;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void evbuffer_setcb(struct evbuffer *buffer,
|
||||
void (*cb)(struct evbuffer *, size_t, size_t, void *),
|
||||
void *cbarg)
|
||||
{
|
||||
buffer->cb = cb;
|
||||
buffer->cbarg = cbarg;
|
||||
}
|
413
contrib/pf/libevent/evbuffer.c
Normal file
413
contrib/pf/libevent/evbuffer.c
Normal file
@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#include "event.h"
|
||||
|
||||
/* prototypes */
|
||||
|
||||
void bufferevent_setwatermark(struct bufferevent *, short, size_t, size_t);
|
||||
void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *);
|
||||
|
||||
static int
|
||||
bufferevent_add(struct event *ev, int timeout)
|
||||
{
|
||||
struct timeval tv, *ptv = NULL;
|
||||
|
||||
if (timeout) {
|
||||
timerclear(&tv);
|
||||
tv.tv_sec = timeout;
|
||||
ptv = &tv;
|
||||
}
|
||||
|
||||
return (event_add(ev, ptv));
|
||||
}
|
||||
|
||||
/*
|
||||
* This callback is executed when the size of the input buffer changes.
|
||||
* We use it to apply back pressure on the reading side.
|
||||
*/
|
||||
|
||||
void
|
||||
bufferevent_read_pressure_cb(struct evbuffer *buf, size_t old, size_t now,
|
||||
void *arg) {
|
||||
struct bufferevent *bufev = arg;
|
||||
/*
|
||||
* If we are below the watermark then reschedule reading if it's
|
||||
* still enabled.
|
||||
*/
|
||||
if (bufev->wm_read.high == 0 || now < bufev->wm_read.high) {
|
||||
evbuffer_setcb(buf, NULL, NULL);
|
||||
|
||||
if (bufev->enabled & EV_READ)
|
||||
bufferevent_add(&bufev->ev_read, bufev->timeout_read);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bufferevent_readcb(int fd, short event, void *arg)
|
||||
{
|
||||
struct bufferevent *bufev = arg;
|
||||
int res = 0;
|
||||
short what = EVBUFFER_READ;
|
||||
size_t len;
|
||||
int howmuch = -1;
|
||||
|
||||
if (event == EV_TIMEOUT) {
|
||||
what |= EVBUFFER_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a high watermark configured then we don't want to
|
||||
* read more data than would make us reach the watermark.
|
||||
*/
|
||||
if (bufev->wm_read.high != 0)
|
||||
howmuch = bufev->wm_read.high;
|
||||
|
||||
res = evbuffer_read(bufev->input, fd, howmuch);
|
||||
if (res == -1) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
goto reschedule;
|
||||
/* error case */
|
||||
what |= EVBUFFER_ERROR;
|
||||
} else if (res == 0) {
|
||||
/* eof case */
|
||||
what |= EVBUFFER_EOF;
|
||||
}
|
||||
|
||||
if (res <= 0)
|
||||
goto error;
|
||||
|
||||
bufferevent_add(&bufev->ev_read, bufev->timeout_read);
|
||||
|
||||
/* See if this callbacks meets the water marks */
|
||||
len = EVBUFFER_LENGTH(bufev->input);
|
||||
if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
|
||||
return;
|
||||
if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) {
|
||||
struct evbuffer *buf = bufev->input;
|
||||
event_del(&bufev->ev_read);
|
||||
|
||||
/* Now schedule a callback for us */
|
||||
evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Invoke the user callback - must always be called last */
|
||||
if (bufev->readcb != NULL)
|
||||
(*bufev->readcb)(bufev, bufev->cbarg);
|
||||
return;
|
||||
|
||||
reschedule:
|
||||
bufferevent_add(&bufev->ev_read, bufev->timeout_read);
|
||||
return;
|
||||
|
||||
error:
|
||||
(*bufev->errorcb)(bufev, what, bufev->cbarg);
|
||||
}
|
||||
|
||||
static void
|
||||
bufferevent_writecb(int fd, short event, void *arg)
|
||||
{
|
||||
struct bufferevent *bufev = arg;
|
||||
int res = 0;
|
||||
short what = EVBUFFER_WRITE;
|
||||
|
||||
if (event == EV_TIMEOUT) {
|
||||
what |= EVBUFFER_TIMEOUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (EVBUFFER_LENGTH(bufev->output)) {
|
||||
res = evbuffer_write(bufev->output, fd);
|
||||
if (res == -1) {
|
||||
#ifndef WIN32
|
||||
/*todo. evbuffer uses WriteFile when WIN32 is set. WIN32 system calls do not
|
||||
*set errno. thus this error checking is not portable*/
|
||||
if (errno == EAGAIN ||
|
||||
errno == EINTR ||
|
||||
errno == EINPROGRESS)
|
||||
goto reschedule;
|
||||
/* error case */
|
||||
what |= EVBUFFER_ERROR;
|
||||
|
||||
#else
|
||||
goto reschedule;
|
||||
#endif
|
||||
|
||||
} else if (res == 0) {
|
||||
/* eof case */
|
||||
what |= EVBUFFER_EOF;
|
||||
}
|
||||
if (res <= 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (EVBUFFER_LENGTH(bufev->output) != 0)
|
||||
bufferevent_add(&bufev->ev_write, bufev->timeout_write);
|
||||
|
||||
/*
|
||||
* Invoke the user callback if our buffer is drained or below the
|
||||
* low watermark.
|
||||
*/
|
||||
if (bufev->writecb != NULL &&
|
||||
EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
|
||||
(*bufev->writecb)(bufev, bufev->cbarg);
|
||||
|
||||
return;
|
||||
|
||||
reschedule:
|
||||
if (EVBUFFER_LENGTH(bufev->output) != 0)
|
||||
bufferevent_add(&bufev->ev_write, bufev->timeout_write);
|
||||
return;
|
||||
|
||||
error:
|
||||
(*bufev->errorcb)(bufev, what, bufev->cbarg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new buffered event object.
|
||||
*
|
||||
* The read callback is invoked whenever we read new data.
|
||||
* The write callback is invoked whenever the output buffer is drained.
|
||||
* The error callback is invoked on a write/read error or on EOF.
|
||||
*
|
||||
* Both read and write callbacks maybe NULL. The error callback is not
|
||||
* allowed to be NULL and have to be provided always.
|
||||
*/
|
||||
|
||||
struct bufferevent *
|
||||
bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb,
|
||||
everrorcb errorcb, void *cbarg)
|
||||
{
|
||||
struct bufferevent *bufev;
|
||||
|
||||
if ((bufev = calloc(1, sizeof(struct bufferevent))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if ((bufev->input = evbuffer_new()) == NULL) {
|
||||
free(bufev);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((bufev->output = evbuffer_new()) == NULL) {
|
||||
evbuffer_free(bufev->input);
|
||||
free(bufev);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
|
||||
event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
|
||||
|
||||
bufev->readcb = readcb;
|
||||
bufev->writecb = writecb;
|
||||
bufev->errorcb = errorcb;
|
||||
|
||||
bufev->cbarg = cbarg;
|
||||
|
||||
/*
|
||||
* Set to EV_WRITE so that using bufferevent_write is going to
|
||||
* trigger a callback. Reading needs to be explicitly enabled
|
||||
* because otherwise no data will be available.
|
||||
*/
|
||||
bufev->enabled = EV_WRITE;
|
||||
|
||||
return (bufev);
|
||||
}
|
||||
|
||||
int
|
||||
bufferevent_priority_set(struct bufferevent *bufev, int priority)
|
||||
{
|
||||
if (event_priority_set(&bufev->ev_read, priority) == -1)
|
||||
return (-1);
|
||||
if (event_priority_set(&bufev->ev_write, priority) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Closing the file descriptor is the responsibility of the caller */
|
||||
|
||||
void
|
||||
bufferevent_free(struct bufferevent *bufev)
|
||||
{
|
||||
event_del(&bufev->ev_read);
|
||||
event_del(&bufev->ev_write);
|
||||
|
||||
evbuffer_free(bufev->input);
|
||||
evbuffer_free(bufev->output);
|
||||
|
||||
free(bufev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 0 on success;
|
||||
* -1 on failure.
|
||||
*/
|
||||
|
||||
int
|
||||
bufferevent_write(struct bufferevent *bufev, void *data, size_t size)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = evbuffer_add(bufev->output, data, size);
|
||||
|
||||
if (res == -1)
|
||||
return (res);
|
||||
|
||||
/* If everything is okay, we need to schedule a write */
|
||||
if (size > 0 && (bufev->enabled & EV_WRITE))
|
||||
bufferevent_add(&bufev->ev_write, bufev->timeout_write);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = bufferevent_write(bufev, buf->buffer, buf->off);
|
||||
if (res != -1)
|
||||
evbuffer_drain(buf, buf->off);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
size_t
|
||||
bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
|
||||
{
|
||||
struct evbuffer *buf = bufev->input;
|
||||
|
||||
if (buf->off < size)
|
||||
size = buf->off;
|
||||
|
||||
/* Copy the available data to the user buffer */
|
||||
memcpy(data, buf->buffer, size);
|
||||
|
||||
if (size)
|
||||
evbuffer_drain(buf, size);
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
||||
int
|
||||
bufferevent_enable(struct bufferevent *bufev, short event)
|
||||
{
|
||||
if (event & EV_READ) {
|
||||
if (bufferevent_add(&bufev->ev_read, bufev->timeout_read) == -1)
|
||||
return (-1);
|
||||
}
|
||||
if (event & EV_WRITE) {
|
||||
if (bufferevent_add(&bufev->ev_write, bufev->timeout_write) == -1)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
bufev->enabled |= event;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
bufferevent_disable(struct bufferevent *bufev, short event)
|
||||
{
|
||||
if (event & EV_READ) {
|
||||
if (event_del(&bufev->ev_read) == -1)
|
||||
return (-1);
|
||||
}
|
||||
if (event & EV_WRITE) {
|
||||
if (event_del(&bufev->ev_write) == -1)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
bufev->enabled &= ~event;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the read and write timeout for a buffered event.
|
||||
*/
|
||||
|
||||
void
|
||||
bufferevent_settimeout(struct bufferevent *bufev,
|
||||
int timeout_read, int timeout_write) {
|
||||
bufev->timeout_read = timeout_read;
|
||||
bufev->timeout_write = timeout_write;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the water marks
|
||||
*/
|
||||
|
||||
void
|
||||
bufferevent_setwatermark(struct bufferevent *bufev, short events,
|
||||
size_t lowmark, size_t highmark)
|
||||
{
|
||||
if (events & EV_READ) {
|
||||
bufev->wm_read.low = lowmark;
|
||||
bufev->wm_read.high = highmark;
|
||||
}
|
||||
|
||||
if (events & EV_WRITE) {
|
||||
bufev->wm_write.low = lowmark;
|
||||
bufev->wm_write.high = highmark;
|
||||
}
|
||||
|
||||
/* If the watermarks changed then see if we should call read again */
|
||||
bufferevent_read_pressure_cb(bufev->input,
|
||||
0, EVBUFFER_LENGTH(bufev->input), bufev);
|
||||
}
|
||||
|
||||
int
|
||||
bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = event_base_set(base, &bufev->ev_read);
|
||||
if (res == -1)
|
||||
return (res);
|
||||
|
||||
res = event_base_set(base, &bufev->ev_write);
|
||||
return (res);
|
||||
}
|
56
contrib/pf/libevent/event-internal.h
Normal file
56
contrib/pf/libevent/event-internal.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _EVENT_INTERNAL_H_
|
||||
#define _EVENT_INTERNAL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct event_base {
|
||||
const struct eventop *evsel;
|
||||
void *evbase;
|
||||
int event_count; /* counts number of total events */
|
||||
int event_count_active; /* counts number of active events */
|
||||
|
||||
int event_gotterm; /* Set to terminate loop */
|
||||
|
||||
/* active event management */
|
||||
struct event_list **activequeues;
|
||||
int nactivequeues;
|
||||
|
||||
struct event_list eventqueue;
|
||||
struct timeval event_tv;
|
||||
|
||||
RB_HEAD(event_tree, event) timetree;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVENT_INTERNAL_H_ */
|
878
contrib/pf/libevent/event.c
Normal file
878
contrib/pf/libevent/event.c
Normal file
@ -0,0 +1,878 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include "misc.h"
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/tree.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/_time.h>
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "event.h"
|
||||
#include "event-internal.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifdef HAVE_EVENT_PORTS
|
||||
extern const struct eventop evportops;
|
||||
#endif
|
||||
#ifdef HAVE_SELECT
|
||||
extern const struct eventop selectops;
|
||||
#endif
|
||||
#ifdef HAVE_POLL
|
||||
extern const struct eventop pollops;
|
||||
#endif
|
||||
#ifdef HAVE_RTSIG
|
||||
extern const struct eventop rtsigops;
|
||||
#endif
|
||||
#ifdef HAVE_EPOLL
|
||||
extern const struct eventop epollops;
|
||||
#endif
|
||||
#ifdef HAVE_WORKING_KQUEUE
|
||||
extern const struct eventop kqops;
|
||||
#endif
|
||||
#ifdef HAVE_DEVPOLL
|
||||
extern const struct eventop devpollops;
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
extern const struct eventop win32ops;
|
||||
#endif
|
||||
|
||||
/* In order of preference */
|
||||
const struct eventop *eventops[] = {
|
||||
#ifdef HAVE_EVENT_PORTS
|
||||
&evportops,
|
||||
#endif
|
||||
#ifdef HAVE_WORKING_KQUEUE
|
||||
&kqops,
|
||||
#endif
|
||||
#ifdef HAVE_EPOLL
|
||||
&epollops,
|
||||
#endif
|
||||
#ifdef HAVE_DEVPOLL
|
||||
&devpollops,
|
||||
#endif
|
||||
#ifdef HAVE_RTSIG
|
||||
&rtsigops,
|
||||
#endif
|
||||
#ifdef HAVE_POLL
|
||||
&pollops,
|
||||
#endif
|
||||
#ifdef HAVE_SELECT
|
||||
&selectops,
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
&win32ops,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Global state */
|
||||
struct event_list signalqueue;
|
||||
|
||||
struct event_base *current_base = NULL;
|
||||
|
||||
/* Handle signals - This is a deprecated interface */
|
||||
int (*event_sigcb)(void); /* Signal callback when gotsig is set */
|
||||
volatile sig_atomic_t event_gotsig; /* Set in signal handler */
|
||||
|
||||
/* Prototypes */
|
||||
static void event_queue_insert(struct event_base *, struct event *, int);
|
||||
static void event_queue_remove(struct event_base *, struct event *, int);
|
||||
static int event_haveevents(struct event_base *);
|
||||
|
||||
static void event_process_active(struct event_base *);
|
||||
|
||||
static int timeout_next(struct event_base *, struct timeval *);
|
||||
static void timeout_process(struct event_base *);
|
||||
static void timeout_correct(struct event_base *, struct timeval *);
|
||||
|
||||
static int
|
||||
compare(struct event *a, struct event *b)
|
||||
{
|
||||
if (timercmp(&a->ev_timeout, &b->ev_timeout, <))
|
||||
return (-1);
|
||||
else if (timercmp(&a->ev_timeout, &b->ev_timeout, >))
|
||||
return (1);
|
||||
if (a < b)
|
||||
return (-1);
|
||||
else if (a > b)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
gettime(struct timeval *tp)
|
||||
{
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
struct timespec ts;
|
||||
|
||||
#ifdef HAVE_CLOCK_MONOTONIC
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
|
||||
#else
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
|
||||
#endif
|
||||
return (-1);
|
||||
tp->tv_sec = ts.tv_sec;
|
||||
tp->tv_usec = ts.tv_nsec / 1000;
|
||||
#else
|
||||
gettimeofday(tp, NULL);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare);
|
||||
|
||||
RB_GENERATE(event_tree, event, ev_timeout_node, compare);
|
||||
|
||||
|
||||
void *
|
||||
event_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((current_base = calloc(1, sizeof(struct event_base))) == NULL)
|
||||
event_err(1, "%s: calloc");
|
||||
|
||||
event_sigcb = NULL;
|
||||
event_gotsig = 0;
|
||||
gettime(¤t_base->event_tv);
|
||||
|
||||
RB_INIT(¤t_base->timetree);
|
||||
TAILQ_INIT(¤t_base->eventqueue);
|
||||
TAILQ_INIT(&signalqueue);
|
||||
|
||||
current_base->evbase = NULL;
|
||||
for (i = 0; eventops[i] && !current_base->evbase; i++) {
|
||||
current_base->evsel = eventops[i];
|
||||
|
||||
current_base->evbase = current_base->evsel->init();
|
||||
}
|
||||
|
||||
if (current_base->evbase == NULL)
|
||||
event_errx(1, "%s: no event mechanism available", __func__);
|
||||
|
||||
if (getenv("EVENT_SHOW_METHOD"))
|
||||
event_msgx("libevent using: %s\n",
|
||||
current_base->evsel->name);
|
||||
|
||||
/* allocate a single active event queue */
|
||||
event_base_priority_init(current_base, 1);
|
||||
|
||||
return (current_base);
|
||||
}
|
||||
|
||||
void
|
||||
event_base_free(struct event_base *base)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (base == NULL && current_base)
|
||||
base = current_base;
|
||||
if (base == current_base)
|
||||
current_base = NULL;
|
||||
|
||||
assert(base);
|
||||
assert(TAILQ_EMPTY(&base->eventqueue));
|
||||
for (i=0; i < base->nactivequeues; ++i)
|
||||
assert(TAILQ_EMPTY(base->activequeues[i]));
|
||||
|
||||
assert(RB_EMPTY(&base->timetree));
|
||||
|
||||
for (i = 0; i < base->nactivequeues; ++i)
|
||||
free(base->activequeues[i]);
|
||||
free(base->activequeues);
|
||||
|
||||
if (base->evsel->dealloc != NULL)
|
||||
base->evsel->dealloc(base->evbase);
|
||||
|
||||
free(base);
|
||||
}
|
||||
|
||||
int
|
||||
event_priority_init(int npriorities)
|
||||
{
|
||||
return event_base_priority_init(current_base, npriorities);
|
||||
}
|
||||
|
||||
int
|
||||
event_base_priority_init(struct event_base *base, int npriorities)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (base->event_count_active)
|
||||
return (-1);
|
||||
|
||||
if (base->nactivequeues && npriorities != base->nactivequeues) {
|
||||
for (i = 0; i < base->nactivequeues; ++i) {
|
||||
free(base->activequeues[i]);
|
||||
}
|
||||
free(base->activequeues);
|
||||
}
|
||||
|
||||
/* Allocate our priority queues */
|
||||
base->nactivequeues = npriorities;
|
||||
base->activequeues = (struct event_list **)calloc(base->nactivequeues,
|
||||
npriorities * sizeof(struct event_list *));
|
||||
if (base->activequeues == NULL)
|
||||
event_err(1, "%s: calloc", __func__);
|
||||
|
||||
for (i = 0; i < base->nactivequeues; ++i) {
|
||||
base->activequeues[i] = malloc(sizeof(struct event_list));
|
||||
if (base->activequeues[i] == NULL)
|
||||
event_err(1, "%s: malloc", __func__);
|
||||
TAILQ_INIT(base->activequeues[i]);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
event_haveevents(struct event_base *base)
|
||||
{
|
||||
return (base->event_count > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Active events are stored in priority queues. Lower priorities are always
|
||||
* process before higher priorities. Low priority events can starve high
|
||||
* priority ones.
|
||||
*/
|
||||
|
||||
static void
|
||||
event_process_active(struct event_base *base)
|
||||
{
|
||||
struct event *ev;
|
||||
struct event_list *activeq = NULL;
|
||||
int i;
|
||||
short ncalls;
|
||||
|
||||
if (!base->event_count_active)
|
||||
return;
|
||||
|
||||
for (i = 0; i < base->nactivequeues; ++i) {
|
||||
if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
|
||||
activeq = base->activequeues[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(activeq != NULL);
|
||||
|
||||
for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
|
||||
event_queue_remove(base, ev, EVLIST_ACTIVE);
|
||||
|
||||
/* Allows deletes to work */
|
||||
ncalls = ev->ev_ncalls;
|
||||
ev->ev_pncalls = &ncalls;
|
||||
while (ncalls) {
|
||||
ncalls--;
|
||||
ev->ev_ncalls = ncalls;
|
||||
(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
|
||||
if (event_gotsig)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait continously for events. We exit only if no events are left.
|
||||
*/
|
||||
|
||||
int
|
||||
event_dispatch(void)
|
||||
{
|
||||
return (event_loop(0));
|
||||
}
|
||||
|
||||
int
|
||||
event_base_dispatch(struct event_base *event_base)
|
||||
{
|
||||
return (event_base_loop(event_base, 0));
|
||||
}
|
||||
|
||||
static void
|
||||
event_loopexit_cb(int fd, short what, void *arg)
|
||||
{
|
||||
struct event_base *base = arg;
|
||||
base->event_gotterm = 1;
|
||||
}
|
||||
|
||||
/* not thread safe */
|
||||
|
||||
int
|
||||
event_loopexit(struct timeval *tv)
|
||||
{
|
||||
return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
|
||||
current_base, tv));
|
||||
}
|
||||
|
||||
int
|
||||
event_base_loopexit(struct event_base *event_base, struct timeval *tv)
|
||||
{
|
||||
return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
|
||||
event_base, tv));
|
||||
}
|
||||
|
||||
/* not thread safe */
|
||||
|
||||
int
|
||||
event_loop(int flags)
|
||||
{
|
||||
return event_base_loop(current_base, flags);
|
||||
}
|
||||
|
||||
int
|
||||
event_base_loop(struct event_base *base, int flags)
|
||||
{
|
||||
const struct eventop *evsel = base->evsel;
|
||||
void *evbase = base->evbase;
|
||||
struct timeval tv;
|
||||
int res, done;
|
||||
|
||||
done = 0;
|
||||
while (!done) {
|
||||
/* Calculate the initial events that we are waiting for */
|
||||
if (evsel->recalc(base, evbase, 0) == -1)
|
||||
return (-1);
|
||||
|
||||
/* Terminate the loop if we have been asked to */
|
||||
if (base->event_gotterm) {
|
||||
base->event_gotterm = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* You cannot use this interface for multi-threaded apps */
|
||||
while (event_gotsig) {
|
||||
event_gotsig = 0;
|
||||
if (event_sigcb) {
|
||||
res = (*event_sigcb)();
|
||||
if (res == -1) {
|
||||
errno = EINTR;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if time is running backwards */
|
||||
gettime(&tv);
|
||||
if (timercmp(&tv, &base->event_tv, <)) {
|
||||
struct timeval off;
|
||||
event_debug(("%s: time is running backwards, corrected",
|
||||
__func__));
|
||||
timersub(&base->event_tv, &tv, &off);
|
||||
timeout_correct(base, &off);
|
||||
}
|
||||
base->event_tv = tv;
|
||||
|
||||
if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK))
|
||||
timeout_next(base, &tv);
|
||||
else
|
||||
timerclear(&tv);
|
||||
|
||||
/* If we have no events, we just exit */
|
||||
if (!event_haveevents(base)) {
|
||||
event_debug(("%s: no events registered.", __func__));
|
||||
return (1);
|
||||
}
|
||||
|
||||
res = evsel->dispatch(base, evbase, &tv);
|
||||
|
||||
if (res == -1)
|
||||
return (-1);
|
||||
|
||||
timeout_process(base);
|
||||
|
||||
if (base->event_count_active) {
|
||||
event_process_active(base);
|
||||
if (!base->event_count_active && (flags & EVLOOP_ONCE))
|
||||
done = 1;
|
||||
} else if (flags & EVLOOP_NONBLOCK)
|
||||
done = 1;
|
||||
}
|
||||
|
||||
event_debug(("%s: asked to terminate loop.", __func__));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Sets up an event for processing once */
|
||||
|
||||
struct event_once {
|
||||
struct event ev;
|
||||
|
||||
void (*cb)(int, short, void *);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
/* One-time callback, it deletes itself */
|
||||
|
||||
static void
|
||||
event_once_cb(int fd, short events, void *arg)
|
||||
{
|
||||
struct event_once *eonce = arg;
|
||||
|
||||
(*eonce->cb)(fd, events, eonce->arg);
|
||||
free(eonce);
|
||||
}
|
||||
|
||||
/* Schedules an event once */
|
||||
|
||||
int
|
||||
event_once(int fd, short events,
|
||||
void (*callback)(int, short, void *), void *arg, struct timeval *tv)
|
||||
{
|
||||
struct event_once *eonce;
|
||||
struct timeval etv;
|
||||
int res;
|
||||
|
||||
/* We cannot support signals that just fire once */
|
||||
if (events & EV_SIGNAL)
|
||||
return (-1);
|
||||
|
||||
if ((eonce = calloc(1, sizeof(struct event_once))) == NULL)
|
||||
return (-1);
|
||||
|
||||
eonce->cb = callback;
|
||||
eonce->arg = arg;
|
||||
|
||||
if (events == EV_TIMEOUT) {
|
||||
if (tv == NULL) {
|
||||
timerclear(&etv);
|
||||
tv = &etv;
|
||||
}
|
||||
|
||||
evtimer_set(&eonce->ev, event_once_cb, eonce);
|
||||
} else if (events & (EV_READ|EV_WRITE)) {
|
||||
events &= EV_READ|EV_WRITE;
|
||||
|
||||
event_set(&eonce->ev, fd, events, event_once_cb, eonce);
|
||||
} else {
|
||||
/* Bad event combination */
|
||||
free(eonce);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
res = event_add(&eonce->ev, tv);
|
||||
if (res != 0) {
|
||||
free(eonce);
|
||||
return (res);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
event_set(struct event *ev, int fd, short events,
|
||||
void (*callback)(int, short, void *), void *arg)
|
||||
{
|
||||
/* Take the current base - caller needs to set the real base later */
|
||||
ev->ev_base = current_base;
|
||||
|
||||
ev->ev_callback = callback;
|
||||
ev->ev_arg = arg;
|
||||
ev->ev_fd = fd;
|
||||
ev->ev_events = events;
|
||||
ev->ev_flags = EVLIST_INIT;
|
||||
ev->ev_ncalls = 0;
|
||||
ev->ev_pncalls = NULL;
|
||||
|
||||
/* by default, we put new events into the middle priority */
|
||||
ev->ev_pri = current_base->nactivequeues/2;
|
||||
}
|
||||
|
||||
int
|
||||
event_base_set(struct event_base *base, struct event *ev)
|
||||
{
|
||||
/* Only innocent events may be assigned to a different base */
|
||||
if (ev->ev_flags != EVLIST_INIT)
|
||||
return (-1);
|
||||
|
||||
ev->ev_base = base;
|
||||
ev->ev_pri = base->nactivequeues/2;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set's the priority of an event - if an event is already scheduled
|
||||
* changing the priority is going to fail.
|
||||
*/
|
||||
|
||||
int
|
||||
event_priority_set(struct event *ev, int pri)
|
||||
{
|
||||
if (ev->ev_flags & EVLIST_ACTIVE)
|
||||
return (-1);
|
||||
if (pri < 0 || pri >= ev->ev_base->nactivequeues)
|
||||
return (-1);
|
||||
|
||||
ev->ev_pri = pri;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if a specific event is pending or scheduled.
|
||||
*/
|
||||
|
||||
int
|
||||
event_pending(struct event *ev, short event, struct timeval *tv)
|
||||
{
|
||||
struct timeval now, res;
|
||||
int flags = 0;
|
||||
|
||||
if (ev->ev_flags & EVLIST_INSERTED)
|
||||
flags |= (ev->ev_events & (EV_READ|EV_WRITE));
|
||||
if (ev->ev_flags & EVLIST_ACTIVE)
|
||||
flags |= ev->ev_res;
|
||||
if (ev->ev_flags & EVLIST_TIMEOUT)
|
||||
flags |= EV_TIMEOUT;
|
||||
if (ev->ev_flags & EVLIST_SIGNAL)
|
||||
flags |= EV_SIGNAL;
|
||||
|
||||
event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL);
|
||||
|
||||
/* See if there is a timeout that we should report */
|
||||
if (tv != NULL && (flags & event & EV_TIMEOUT)) {
|
||||
gettime(&now);
|
||||
timersub(&ev->ev_timeout, &now, &res);
|
||||
/* correctly remap to real time */
|
||||
gettimeofday(&now, NULL);
|
||||
timeradd(&now, &res, tv);
|
||||
}
|
||||
|
||||
return (flags & event);
|
||||
}
|
||||
|
||||
int
|
||||
event_add(struct event *ev, struct timeval *tv)
|
||||
{
|
||||
struct event_base *base = ev->ev_base;
|
||||
const struct eventop *evsel = base->evsel;
|
||||
void *evbase = base->evbase;
|
||||
|
||||
event_debug((
|
||||
"event_add: event: %p, %s%s%scall %p",
|
||||
ev,
|
||||
ev->ev_events & EV_READ ? "EV_READ " : " ",
|
||||
ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
|
||||
tv ? "EV_TIMEOUT " : " ",
|
||||
ev->ev_callback));
|
||||
|
||||
assert(!(ev->ev_flags & ~EVLIST_ALL));
|
||||
|
||||
if (tv != NULL) {
|
||||
struct timeval now;
|
||||
|
||||
if (ev->ev_flags & EVLIST_TIMEOUT)
|
||||
event_queue_remove(base, ev, EVLIST_TIMEOUT);
|
||||
|
||||
/* Check if it is active due to a timeout. Rescheduling
|
||||
* this timeout before the callback can be executed
|
||||
* removes it from the active list. */
|
||||
if ((ev->ev_flags & EVLIST_ACTIVE) &&
|
||||
(ev->ev_res & EV_TIMEOUT)) {
|
||||
/* See if we are just active executing this
|
||||
* event in a loop
|
||||
*/
|
||||
if (ev->ev_ncalls && ev->ev_pncalls) {
|
||||
/* Abort loop */
|
||||
*ev->ev_pncalls = 0;
|
||||
}
|
||||
|
||||
event_queue_remove(base, ev, EVLIST_ACTIVE);
|
||||
}
|
||||
|
||||
gettime(&now);
|
||||
timeradd(&now, tv, &ev->ev_timeout);
|
||||
|
||||
event_debug((
|
||||
"event_add: timeout in %d seconds, call %p",
|
||||
tv->tv_sec, ev->ev_callback));
|
||||
|
||||
event_queue_insert(base, ev, EVLIST_TIMEOUT);
|
||||
}
|
||||
|
||||
if ((ev->ev_events & (EV_READ|EV_WRITE)) &&
|
||||
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
|
||||
event_queue_insert(base, ev, EVLIST_INSERTED);
|
||||
|
||||
return (evsel->add(evbase, ev));
|
||||
} else if ((ev->ev_events & EV_SIGNAL) &&
|
||||
!(ev->ev_flags & EVLIST_SIGNAL)) {
|
||||
event_queue_insert(base, ev, EVLIST_SIGNAL);
|
||||
|
||||
return (evsel->add(evbase, ev));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
event_del(struct event *ev)
|
||||
{
|
||||
struct event_base *base;
|
||||
const struct eventop *evsel;
|
||||
void *evbase;
|
||||
|
||||
event_debug(("event_del: %p, callback %p",
|
||||
ev, ev->ev_callback));
|
||||
|
||||
/* An event without a base has not been added */
|
||||
if (ev->ev_base == NULL)
|
||||
return (-1);
|
||||
|
||||
base = ev->ev_base;
|
||||
evsel = base->evsel;
|
||||
evbase = base->evbase;
|
||||
|
||||
assert(!(ev->ev_flags & ~EVLIST_ALL));
|
||||
|
||||
/* See if we are just active executing this event in a loop */
|
||||
if (ev->ev_ncalls && ev->ev_pncalls) {
|
||||
/* Abort loop */
|
||||
*ev->ev_pncalls = 0;
|
||||
}
|
||||
|
||||
if (ev->ev_flags & EVLIST_TIMEOUT)
|
||||
event_queue_remove(base, ev, EVLIST_TIMEOUT);
|
||||
|
||||
if (ev->ev_flags & EVLIST_ACTIVE)
|
||||
event_queue_remove(base, ev, EVLIST_ACTIVE);
|
||||
|
||||
if (ev->ev_flags & EVLIST_INSERTED) {
|
||||
event_queue_remove(base, ev, EVLIST_INSERTED);
|
||||
return (evsel->del(evbase, ev));
|
||||
} else if (ev->ev_flags & EVLIST_SIGNAL) {
|
||||
event_queue_remove(base, ev, EVLIST_SIGNAL);
|
||||
return (evsel->del(evbase, ev));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
event_active(struct event *ev, int res, short ncalls)
|
||||
{
|
||||
/* We get different kinds of events, add them together */
|
||||
if (ev->ev_flags & EVLIST_ACTIVE) {
|
||||
ev->ev_res |= res;
|
||||
return;
|
||||
}
|
||||
|
||||
ev->ev_res = res;
|
||||
ev->ev_ncalls = ncalls;
|
||||
ev->ev_pncalls = NULL;
|
||||
event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
|
||||
}
|
||||
|
||||
int
|
||||
timeout_next(struct event_base *base, struct timeval *tv)
|
||||
{
|
||||
struct timeval dflt = TIMEOUT_DEFAULT;
|
||||
|
||||
struct timeval now;
|
||||
struct event *ev;
|
||||
|
||||
if ((ev = RB_MIN(event_tree, &base->timetree)) == NULL) {
|
||||
*tv = dflt;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (gettime(&now) == -1)
|
||||
return (-1);
|
||||
|
||||
if (timercmp(&ev->ev_timeout, &now, <=)) {
|
||||
timerclear(tv);
|
||||
return (0);
|
||||
}
|
||||
|
||||
timersub(&ev->ev_timeout, &now, tv);
|
||||
|
||||
assert(tv->tv_sec >= 0);
|
||||
assert(tv->tv_usec >= 0);
|
||||
|
||||
event_debug(("timeout_next: in %d seconds", tv->tv_sec));
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
timeout_correct(struct event_base *base, struct timeval *off)
|
||||
{
|
||||
struct event *ev;
|
||||
|
||||
/*
|
||||
* We can modify the key element of the node without destroying
|
||||
* the key, beause we apply it to all in the right order.
|
||||
*/
|
||||
RB_FOREACH(ev, event_tree, &base->timetree)
|
||||
timersub(&ev->ev_timeout, off, &ev->ev_timeout);
|
||||
}
|
||||
|
||||
void
|
||||
timeout_process(struct event_base *base)
|
||||
{
|
||||
struct timeval now;
|
||||
struct event *ev, *next;
|
||||
|
||||
gettime(&now);
|
||||
|
||||
for (ev = RB_MIN(event_tree, &base->timetree); ev; ev = next) {
|
||||
if (timercmp(&ev->ev_timeout, &now, >))
|
||||
break;
|
||||
next = RB_NEXT(event_tree, &base->timetree, ev);
|
||||
|
||||
event_queue_remove(base, ev, EVLIST_TIMEOUT);
|
||||
|
||||
/* delete this event from the I/O queues */
|
||||
event_del(ev);
|
||||
|
||||
event_debug(("timeout_process: call %p",
|
||||
ev->ev_callback));
|
||||
event_active(ev, EV_TIMEOUT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
event_queue_remove(struct event_base *base, struct event *ev, int queue)
|
||||
{
|
||||
int docount = 1;
|
||||
|
||||
if (!(ev->ev_flags & queue))
|
||||
event_errx(1, "%s: %p(fd %d) not on queue %x", __func__,
|
||||
ev, ev->ev_fd, queue);
|
||||
|
||||
if (ev->ev_flags & EVLIST_INTERNAL)
|
||||
docount = 0;
|
||||
|
||||
if (docount)
|
||||
base->event_count--;
|
||||
|
||||
ev->ev_flags &= ~queue;
|
||||
switch (queue) {
|
||||
case EVLIST_ACTIVE:
|
||||
if (docount)
|
||||
base->event_count_active--;
|
||||
TAILQ_REMOVE(base->activequeues[ev->ev_pri],
|
||||
ev, ev_active_next);
|
||||
break;
|
||||
case EVLIST_SIGNAL:
|
||||
TAILQ_REMOVE(&signalqueue, ev, ev_signal_next);
|
||||
break;
|
||||
case EVLIST_TIMEOUT:
|
||||
RB_REMOVE(event_tree, &base->timetree, ev);
|
||||
break;
|
||||
case EVLIST_INSERTED:
|
||||
TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
|
||||
break;
|
||||
default:
|
||||
event_errx(1, "%s: unknown queue %x", __func__, queue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
event_queue_insert(struct event_base *base, struct event *ev, int queue)
|
||||
{
|
||||
int docount = 1;
|
||||
|
||||
if (ev->ev_flags & queue) {
|
||||
/* Double insertion is possible for active events */
|
||||
if (queue & EVLIST_ACTIVE)
|
||||
return;
|
||||
|
||||
event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,
|
||||
ev, ev->ev_fd, queue);
|
||||
}
|
||||
|
||||
if (ev->ev_flags & EVLIST_INTERNAL)
|
||||
docount = 0;
|
||||
|
||||
if (docount)
|
||||
base->event_count++;
|
||||
|
||||
ev->ev_flags |= queue;
|
||||
switch (queue) {
|
||||
case EVLIST_ACTIVE:
|
||||
if (docount)
|
||||
base->event_count_active++;
|
||||
TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
|
||||
ev,ev_active_next);
|
||||
break;
|
||||
case EVLIST_SIGNAL:
|
||||
TAILQ_INSERT_TAIL(&signalqueue, ev, ev_signal_next);
|
||||
break;
|
||||
case EVLIST_TIMEOUT: {
|
||||
struct event *tmp = RB_INSERT(event_tree, &base->timetree, ev);
|
||||
assert(tmp == NULL);
|
||||
break;
|
||||
}
|
||||
case EVLIST_INSERTED:
|
||||
TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
|
||||
break;
|
||||
default:
|
||||
event_errx(1, "%s: unknown queue %x", __func__, queue);
|
||||
}
|
||||
}
|
||||
|
||||
/* Functions for debugging */
|
||||
|
||||
const char *
|
||||
event_get_version(void)
|
||||
{
|
||||
return (VERSION);
|
||||
}
|
||||
|
||||
/*
|
||||
* No thread-safe interface needed - the information should be the same
|
||||
* for all threads.
|
||||
*/
|
||||
|
||||
const char *
|
||||
event_get_method(void)
|
||||
{
|
||||
return (current_base->evsel->name);
|
||||
}
|
341
contrib/pf/libevent/event.h
Normal file
341
contrib/pf/libevent/event.h
Normal file
@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _EVENT_H_
|
||||
#define _EVENT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
typedef unsigned char u_char;
|
||||
typedef unsigned short u_short;
|
||||
#endif
|
||||
|
||||
#define EVLIST_TIMEOUT 0x01
|
||||
#define EVLIST_INSERTED 0x02
|
||||
#define EVLIST_SIGNAL 0x04
|
||||
#define EVLIST_ACTIVE 0x08
|
||||
#define EVLIST_INTERNAL 0x10
|
||||
#define EVLIST_INIT 0x80
|
||||
|
||||
/* EVLIST_X_ Private space: 0x1000-0xf000 */
|
||||
#define EVLIST_ALL (0xf000 | 0x9f)
|
||||
|
||||
#define EV_TIMEOUT 0x01
|
||||
#define EV_READ 0x02
|
||||
#define EV_WRITE 0x04
|
||||
#define EV_SIGNAL 0x08
|
||||
#define EV_PERSIST 0x10 /* Persistant event */
|
||||
|
||||
/* Fix so that ppl dont have to run with <sys/queue.h> */
|
||||
#ifndef TAILQ_ENTRY
|
||||
#define _EVENT_DEFINED_TQENTRY
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
#endif /* !TAILQ_ENTRY */
|
||||
#ifndef RB_ENTRY
|
||||
#define _EVENT_DEFINED_RBENTRY
|
||||
#define RB_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *rbe_left; /* left element */ \
|
||||
struct type *rbe_right; /* right element */ \
|
||||
struct type *rbe_parent; /* parent element */ \
|
||||
int rbe_color; /* node color */ \
|
||||
}
|
||||
#endif /* !RB_ENTRY */
|
||||
|
||||
struct event_base;
|
||||
struct event {
|
||||
TAILQ_ENTRY (event) ev_next;
|
||||
TAILQ_ENTRY (event) ev_active_next;
|
||||
TAILQ_ENTRY (event) ev_signal_next;
|
||||
RB_ENTRY (event) ev_timeout_node;
|
||||
|
||||
struct event_base *ev_base;
|
||||
int ev_fd;
|
||||
short ev_events;
|
||||
short ev_ncalls;
|
||||
short *ev_pncalls; /* Allows deletes in callback */
|
||||
|
||||
struct timeval ev_timeout;
|
||||
|
||||
int ev_pri; /* smaller numbers are higher priority */
|
||||
|
||||
void (*ev_callback)(int, short, void *arg);
|
||||
void *ev_arg;
|
||||
|
||||
int ev_res; /* result passed to event callback */
|
||||
int ev_flags;
|
||||
};
|
||||
|
||||
#define EVENT_SIGNAL(ev) (int)(ev)->ev_fd
|
||||
#define EVENT_FD(ev) (int)(ev)->ev_fd
|
||||
|
||||
/*
|
||||
* Key-Value pairs. Can be used for HTTP headers but also for
|
||||
* query argument parsing.
|
||||
*/
|
||||
struct evkeyval {
|
||||
TAILQ_ENTRY(evkeyval) next;
|
||||
|
||||
char *key;
|
||||
char *value;
|
||||
};
|
||||
|
||||
#ifdef _EVENT_DEFINED_TQENTRY
|
||||
#undef TAILQ_ENTRY
|
||||
struct event_list;
|
||||
struct evkeyvalq;
|
||||
#undef _EVENT_DEFINED_TQENTRY
|
||||
#else
|
||||
TAILQ_HEAD (event_list, event);
|
||||
TAILQ_HEAD (evkeyvalq, evkeyval);
|
||||
#endif /* _EVENT_DEFINED_TQENTRY */
|
||||
#ifdef _EVENT_DEFINED_RBENTRY
|
||||
#undef RB_ENTRY
|
||||
#undef _EVENT_DEFINED_RBENTRY
|
||||
#endif /* _EVENT_DEFINED_RBENTRY */
|
||||
|
||||
struct eventop {
|
||||
char *name;
|
||||
void *(*init)(void);
|
||||
int (*add)(void *, struct event *);
|
||||
int (*del)(void *, struct event *);
|
||||
int (*recalc)(struct event_base *, void *, int);
|
||||
int (*dispatch)(struct event_base *, void *, struct timeval *);
|
||||
void (*dealloc)(void *);
|
||||
};
|
||||
|
||||
#define TIMEOUT_DEFAULT {5, 0}
|
||||
|
||||
void *event_init(void);
|
||||
int event_dispatch(void);
|
||||
int event_base_dispatch(struct event_base *);
|
||||
void event_base_free(struct event_base *);
|
||||
|
||||
#define _EVENT_LOG_DEBUG 0
|
||||
#define _EVENT_LOG_MSG 1
|
||||
#define _EVENT_LOG_WARN 2
|
||||
#define _EVENT_LOG_ERR 3
|
||||
typedef void (*event_log_cb)(int severity, const char *msg);
|
||||
void event_set_log_callback(event_log_cb cb);
|
||||
|
||||
/* Associate a different event base with an event */
|
||||
int event_base_set(struct event_base *, struct event *);
|
||||
|
||||
#define EVLOOP_ONCE 0x01
|
||||
#define EVLOOP_NONBLOCK 0x02
|
||||
int event_loop(int);
|
||||
int event_base_loop(struct event_base *, int);
|
||||
int event_loopexit(struct timeval *); /* Causes the loop to exit */
|
||||
int event_base_loopexit(struct event_base *, struct timeval *);
|
||||
|
||||
#define evtimer_add(ev, tv) event_add(ev, tv)
|
||||
#define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
|
||||
#define evtimer_del(ev) event_del(ev)
|
||||
#define evtimer_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv)
|
||||
#define evtimer_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
|
||||
|
||||
#define timeout_add(ev, tv) event_add(ev, tv)
|
||||
#define timeout_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
|
||||
#define timeout_del(ev) event_del(ev)
|
||||
#define timeout_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv)
|
||||
#define timeout_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
|
||||
|
||||
#define signal_add(ev, tv) event_add(ev, tv)
|
||||
#define signal_set(ev, x, cb, arg) \
|
||||
event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
|
||||
#define signal_del(ev) event_del(ev)
|
||||
#define signal_pending(ev, tv) event_pending(ev, EV_SIGNAL, tv)
|
||||
#define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
|
||||
|
||||
void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
|
||||
int event_once(int, short, void (*)(int, short, void *), void *, struct timeval *);
|
||||
|
||||
int event_add(struct event *, struct timeval *);
|
||||
int event_del(struct event *);
|
||||
void event_active(struct event *, int, short);
|
||||
|
||||
int event_pending(struct event *, short, struct timeval *);
|
||||
|
||||
#ifdef WIN32
|
||||
#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE)
|
||||
#else
|
||||
#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
|
||||
#endif
|
||||
|
||||
/* Some simple debugging functions */
|
||||
const char *event_get_version(void);
|
||||
const char *event_get_method(void);
|
||||
|
||||
/* These functions deal with event priorities */
|
||||
|
||||
int event_priority_init(int);
|
||||
int event_base_priority_init(struct event_base *, int);
|
||||
int event_priority_set(struct event *, int);
|
||||
|
||||
/* These functions deal with buffering input and output */
|
||||
|
||||
struct evbuffer {
|
||||
u_char *buffer;
|
||||
u_char *orig_buffer;
|
||||
|
||||
size_t misalign;
|
||||
size_t totallen;
|
||||
size_t off;
|
||||
|
||||
void (*cb)(struct evbuffer *, size_t, size_t, void *);
|
||||
void *cbarg;
|
||||
};
|
||||
|
||||
/* Just for error reporting - use other constants otherwise */
|
||||
#define EVBUFFER_READ 0x01
|
||||
#define EVBUFFER_WRITE 0x02
|
||||
#define EVBUFFER_EOF 0x10
|
||||
#define EVBUFFER_ERROR 0x20
|
||||
#define EVBUFFER_TIMEOUT 0x40
|
||||
|
||||
struct bufferevent;
|
||||
typedef void (*evbuffercb)(struct bufferevent *, void *);
|
||||
typedef void (*everrorcb)(struct bufferevent *, short what, void *);
|
||||
|
||||
struct event_watermark {
|
||||
size_t low;
|
||||
size_t high;
|
||||
};
|
||||
|
||||
struct bufferevent {
|
||||
struct event ev_read;
|
||||
struct event ev_write;
|
||||
|
||||
struct evbuffer *input;
|
||||
struct evbuffer *output;
|
||||
|
||||
struct event_watermark wm_read;
|
||||
struct event_watermark wm_write;
|
||||
|
||||
evbuffercb readcb;
|
||||
evbuffercb writecb;
|
||||
everrorcb errorcb;
|
||||
void *cbarg;
|
||||
|
||||
int timeout_read; /* in seconds */
|
||||
int timeout_write; /* in seconds */
|
||||
|
||||
short enabled; /* events that are currently enabled */
|
||||
};
|
||||
|
||||
struct bufferevent *bufferevent_new(int fd,
|
||||
evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
|
||||
int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev);
|
||||
int bufferevent_priority_set(struct bufferevent *bufev, int pri);
|
||||
void bufferevent_free(struct bufferevent *bufev);
|
||||
int bufferevent_write(struct bufferevent *bufev, void *data, size_t size);
|
||||
int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
|
||||
size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
|
||||
int bufferevent_enable(struct bufferevent *bufev, short event);
|
||||
int bufferevent_disable(struct bufferevent *bufev, short event);
|
||||
void bufferevent_settimeout(struct bufferevent *bufev,
|
||||
int timeout_read, int timeout_write);
|
||||
|
||||
#define EVBUFFER_LENGTH(x) (x)->off
|
||||
#define EVBUFFER_DATA(x) (x)->buffer
|
||||
#define EVBUFFER_INPUT(x) (x)->input
|
||||
#define EVBUFFER_OUTPUT(x) (x)->output
|
||||
|
||||
struct evbuffer *evbuffer_new(void);
|
||||
void evbuffer_free(struct evbuffer *);
|
||||
int evbuffer_expand(struct evbuffer *, size_t);
|
||||
int evbuffer_add(struct evbuffer *, const void *, size_t);
|
||||
int evbuffer_remove(struct evbuffer *, void *, size_t);
|
||||
char *evbuffer_readline(struct evbuffer *);
|
||||
int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);
|
||||
int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...);
|
||||
int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap);
|
||||
void evbuffer_drain(struct evbuffer *, size_t);
|
||||
int evbuffer_write(struct evbuffer *, int);
|
||||
int evbuffer_read(struct evbuffer *, int, int);
|
||||
u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t);
|
||||
void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_t, void *), void *);
|
||||
|
||||
/*
|
||||
* Marshaling tagged data - We assume that all tags are inserted in their
|
||||
* numeric order - so that unknown tags will always be higher than the
|
||||
* known ones - and we can just ignore the end of an event buffer.
|
||||
*/
|
||||
|
||||
void evtag_init(void);
|
||||
|
||||
void evtag_marshal(struct evbuffer *evbuf, u_int8_t tag, const void *data,
|
||||
u_int32_t len);
|
||||
|
||||
void encode_int(struct evbuffer *evbuf, u_int32_t number);
|
||||
|
||||
void evtag_marshal_int(struct evbuffer *evbuf, u_int8_t tag,
|
||||
u_int32_t integer);
|
||||
|
||||
void evtag_marshal_string(struct evbuffer *buf, u_int8_t tag,
|
||||
const char *string);
|
||||
|
||||
void evtag_marshal_timeval(struct evbuffer *evbuf, u_int8_t tag,
|
||||
struct timeval *tv);
|
||||
|
||||
void evtag_test(void);
|
||||
|
||||
int evtag_unmarshal(struct evbuffer *src, u_int8_t *ptag,
|
||||
struct evbuffer *dst);
|
||||
int evtag_peek(struct evbuffer *evbuf, u_int8_t *ptag);
|
||||
int evtag_peek_length(struct evbuffer *evbuf, u_int32_t *plength);
|
||||
int evtag_payload_length(struct evbuffer *evbuf, u_int32_t *plength);
|
||||
int evtag_consume(struct evbuffer *evbuf);
|
||||
|
||||
int evtag_unmarshal_int(struct evbuffer *evbuf, u_int8_t need_tag,
|
||||
u_int32_t *pinteger);
|
||||
|
||||
int evtag_unmarshal_fixed(struct evbuffer *src, u_int8_t need_tag, void *data,
|
||||
size_t len);
|
||||
|
||||
int evtag_unmarshal_string(struct evbuffer *evbuf, u_int8_t need_tag,
|
||||
char **pstring);
|
||||
|
||||
int evtag_unmarshal_timeval(struct evbuffer *evbuf, u_int8_t need_tag,
|
||||
struct timeval *ptv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EVENT_H_ */
|
35
contrib/pf/libevent/evsignal.h
Normal file
35
contrib/pf/libevent/evsignal.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _EVSIGNAL_H_
|
||||
#define _EVSIGNAL_H_
|
||||
|
||||
void evsignal_init(void);
|
||||
void evsignal_process(void);
|
||||
int evsignal_add(struct event *);
|
||||
int evsignal_del(struct event *);
|
||||
|
||||
#endif /* _EVSIGNAL_H_ */
|
413
contrib/pf/libevent/kqueue.c
Normal file
413
contrib/pf/libevent/kqueue.c
Normal file
@ -0,0 +1,413 @@
|
||||
/* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/_time.h>
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
#include <sys/event.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
|
||||
#define INTPTR(x) (intptr_t)x
|
||||
#else
|
||||
#define INTPTR(x) x
|
||||
#endif
|
||||
|
||||
#include "event.h"
|
||||
#include "log.h"
|
||||
|
||||
#define EVLIST_X_KQINKERNEL 0x1000
|
||||
|
||||
#define NEVENT 64
|
||||
|
||||
struct kqop {
|
||||
struct kevent *changes;
|
||||
int nchanges;
|
||||
struct kevent *events;
|
||||
int nevents;
|
||||
int kq;
|
||||
};
|
||||
|
||||
void *kq_init (void);
|
||||
int kq_add (void *, struct event *);
|
||||
int kq_del (void *, struct event *);
|
||||
int kq_recalc (struct event_base *, void *, int);
|
||||
int kq_dispatch (struct event_base *, void *, struct timeval *);
|
||||
int kq_insert (struct kqop *, struct kevent *);
|
||||
void kq_dealloc (void *);
|
||||
|
||||
const struct eventop kqops = {
|
||||
"kqueue",
|
||||
kq_init,
|
||||
kq_add,
|
||||
kq_del,
|
||||
kq_recalc,
|
||||
kq_dispatch,
|
||||
kq_dealloc
|
||||
};
|
||||
|
||||
void *
|
||||
kq_init(void)
|
||||
{
|
||||
int kq;
|
||||
struct kqop *kqueueop;
|
||||
|
||||
/* Disable kqueue when this environment variable is set */
|
||||
if (getenv("EVENT_NOKQUEUE"))
|
||||
return (NULL);
|
||||
|
||||
if (!(kqueueop = calloc(1, sizeof(struct kqop))))
|
||||
return (NULL);
|
||||
|
||||
/* Initalize the kernel queue */
|
||||
|
||||
if ((kq = kqueue()) == -1) {
|
||||
event_warn("kqueue");
|
||||
free (kqueueop);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
kqueueop->kq = kq;
|
||||
|
||||
/* Initalize fields */
|
||||
kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
|
||||
if (kqueueop->changes == NULL) {
|
||||
free (kqueueop);
|
||||
return (NULL);
|
||||
}
|
||||
kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
|
||||
if (kqueueop->events == NULL) {
|
||||
free (kqueueop->changes);
|
||||
free (kqueueop);
|
||||
return (NULL);
|
||||
}
|
||||
kqueueop->nevents = NEVENT;
|
||||
|
||||
/* Check for Mac OS X kqueue bug. */
|
||||
kqueueop->changes[0].ident = -1;
|
||||
kqueueop->changes[0].filter = EVFILT_READ;
|
||||
kqueueop->changes[0].flags = EV_ADD;
|
||||
/*
|
||||
* If kqueue works, then kevent will succeed, and it will
|
||||
* stick an error in events[0]. If kqueue is broken, then
|
||||
* kevent will fail.
|
||||
*/
|
||||
if (kevent(kq,
|
||||
kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
|
||||
kqueueop->events[0].ident != -1 ||
|
||||
kqueueop->events[0].flags != EV_ERROR) {
|
||||
event_warn("%s: detected broken kqueue; not using.", __func__);
|
||||
free(kqueueop->changes);
|
||||
free(kqueueop->events);
|
||||
free(kqueueop);
|
||||
close(kq);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (kqueueop);
|
||||
}
|
||||
|
||||
int
|
||||
kq_recalc(struct event_base *base, void *arg, int max)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
kq_insert(struct kqop *kqop, struct kevent *kev)
|
||||
{
|
||||
int nevents = kqop->nevents;
|
||||
|
||||
if (kqop->nchanges == nevents) {
|
||||
struct kevent *newchange;
|
||||
struct kevent *newresult;
|
||||
|
||||
nevents *= 2;
|
||||
|
||||
newchange = realloc(kqop->changes,
|
||||
nevents * sizeof(struct kevent));
|
||||
if (newchange == NULL) {
|
||||
event_warn("%s: malloc", __func__);
|
||||
return (-1);
|
||||
}
|
||||
kqop->changes = newchange;
|
||||
|
||||
newresult = realloc(kqop->events,
|
||||
nevents * sizeof(struct kevent));
|
||||
|
||||
/*
|
||||
* If we fail, we don't have to worry about freeing,
|
||||
* the next realloc will pick it up.
|
||||
*/
|
||||
if (newresult == NULL) {
|
||||
event_warn("%s: malloc", __func__);
|
||||
return (-1);
|
||||
}
|
||||
kqop->events = newresult;
|
||||
|
||||
kqop->nevents = nevents;
|
||||
}
|
||||
|
||||
memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
|
||||
|
||||
event_debug(("%s: fd %d %s%s",
|
||||
__func__, kev->ident,
|
||||
kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
|
||||
kev->flags == EV_DELETE ? " (del)" : ""));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
kq_sighandler(int sig)
|
||||
{
|
||||
/* Do nothing here */
|
||||
}
|
||||
|
||||
int
|
||||
kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
|
||||
{
|
||||
struct kqop *kqop = arg;
|
||||
struct kevent *changes = kqop->changes;
|
||||
struct kevent *events = kqop->events;
|
||||
struct event *ev;
|
||||
struct timespec ts;
|
||||
int i, res;
|
||||
|
||||
TIMEVAL_TO_TIMESPEC(tv, &ts);
|
||||
|
||||
res = kevent(kqop->kq, changes, kqop->nchanges,
|
||||
events, kqop->nevents, &ts);
|
||||
kqop->nchanges = 0;
|
||||
if (res == -1) {
|
||||
if (errno != EINTR) {
|
||||
event_warn("kevent");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
event_debug(("%s: kevent reports %d", __func__, res));
|
||||
|
||||
for (i = 0; i < res; i++) {
|
||||
int which = 0;
|
||||
|
||||
if (events[i].flags & EV_ERROR) {
|
||||
/*
|
||||
* Error messages that can happen, when a delete fails.
|
||||
* EBADF happens when the file discriptor has been
|
||||
* closed,
|
||||
* ENOENT when the file discriptor was closed and
|
||||
* then reopened.
|
||||
* EINVAL for some reasons not understood; EINVAL
|
||||
* should not be returned ever; but FreeBSD does :-\
|
||||
* An error is also indicated when a callback deletes
|
||||
* an event we are still processing. In that case
|
||||
* the data field is set to ENOENT.
|
||||
*/
|
||||
if (events[i].data == EBADF ||
|
||||
events[i].data == EINVAL ||
|
||||
events[i].data == ENOENT)
|
||||
continue;
|
||||
errno = events[i].data;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ev = (struct event *)events[i].udata;
|
||||
|
||||
if (events[i].filter == EVFILT_READ) {
|
||||
which |= EV_READ;
|
||||
} else if (events[i].filter == EVFILT_WRITE) {
|
||||
which |= EV_WRITE;
|
||||
} else if (events[i].filter == EVFILT_SIGNAL) {
|
||||
which |= EV_SIGNAL;
|
||||
}
|
||||
|
||||
if (!which)
|
||||
continue;
|
||||
|
||||
if (!(ev->ev_events & EV_PERSIST))
|
||||
event_del(ev);
|
||||
|
||||
event_active(ev, which,
|
||||
ev->ev_events & EV_SIGNAL ? events[i].data : 1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
kq_add(void *arg, struct event *ev)
|
||||
{
|
||||
struct kqop *kqop = arg;
|
||||
struct kevent kev;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL) {
|
||||
int nsignal = EVENT_SIGNAL(ev);
|
||||
|
||||
memset(&kev, 0, sizeof(kev));
|
||||
kev.ident = nsignal;
|
||||
kev.filter = EVFILT_SIGNAL;
|
||||
kev.flags = EV_ADD;
|
||||
if (!(ev->ev_events & EV_PERSIST))
|
||||
kev.flags |= EV_ONESHOT;
|
||||
kev.udata = INTPTR(ev);
|
||||
|
||||
if (kq_insert(kqop, &kev) == -1)
|
||||
return (-1);
|
||||
|
||||
if (signal(nsignal, kq_sighandler) == SIG_ERR)
|
||||
return (-1);
|
||||
|
||||
ev->ev_flags |= EVLIST_X_KQINKERNEL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (ev->ev_events & EV_READ) {
|
||||
memset(&kev, 0, sizeof(kev));
|
||||
kev.ident = ev->ev_fd;
|
||||
kev.filter = EVFILT_READ;
|
||||
#ifdef NOTE_EOF
|
||||
/* Make it behave like select() and poll() */
|
||||
kev.fflags = NOTE_EOF;
|
||||
#endif
|
||||
kev.flags = EV_ADD;
|
||||
if (!(ev->ev_events & EV_PERSIST))
|
||||
kev.flags |= EV_ONESHOT;
|
||||
kev.udata = INTPTR(ev);
|
||||
|
||||
if (kq_insert(kqop, &kev) == -1)
|
||||
return (-1);
|
||||
|
||||
ev->ev_flags |= EVLIST_X_KQINKERNEL;
|
||||
}
|
||||
|
||||
if (ev->ev_events & EV_WRITE) {
|
||||
memset(&kev, 0, sizeof(kev));
|
||||
kev.ident = ev->ev_fd;
|
||||
kev.filter = EVFILT_WRITE;
|
||||
kev.flags = EV_ADD;
|
||||
if (!(ev->ev_events & EV_PERSIST))
|
||||
kev.flags |= EV_ONESHOT;
|
||||
kev.udata = INTPTR(ev);
|
||||
|
||||
if (kq_insert(kqop, &kev) == -1)
|
||||
return (-1);
|
||||
|
||||
ev->ev_flags |= EVLIST_X_KQINKERNEL;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
kq_del(void *arg, struct event *ev)
|
||||
{
|
||||
struct kqop *kqop = arg;
|
||||
struct kevent kev;
|
||||
|
||||
if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
|
||||
return (0);
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL) {
|
||||
int nsignal = EVENT_SIGNAL(ev);
|
||||
|
||||
memset(&kev, 0, sizeof(kev));
|
||||
kev.ident = nsignal;
|
||||
kev.filter = EVFILT_SIGNAL;
|
||||
kev.flags = EV_DELETE;
|
||||
|
||||
if (kq_insert(kqop, &kev) == -1)
|
||||
return (-1);
|
||||
|
||||
if (signal(nsignal, SIG_DFL) == SIG_ERR)
|
||||
return (-1);
|
||||
|
||||
ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (ev->ev_events & EV_READ) {
|
||||
memset(&kev, 0, sizeof(kev));
|
||||
kev.ident = ev->ev_fd;
|
||||
kev.filter = EVFILT_READ;
|
||||
kev.flags = EV_DELETE;
|
||||
|
||||
if (kq_insert(kqop, &kev) == -1)
|
||||
return (-1);
|
||||
|
||||
ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
|
||||
}
|
||||
|
||||
if (ev->ev_events & EV_WRITE) {
|
||||
memset(&kev, 0, sizeof(kev));
|
||||
kev.ident = ev->ev_fd;
|
||||
kev.filter = EVFILT_WRITE;
|
||||
kev.flags = EV_DELETE;
|
||||
|
||||
if (kq_insert(kqop, &kev) == -1)
|
||||
return (-1);
|
||||
|
||||
ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
kq_dealloc(void *arg)
|
||||
{
|
||||
struct kqop *kqop = arg;
|
||||
|
||||
if (kqop->changes)
|
||||
free(kqop->changes);
|
||||
if (kqop->events)
|
||||
free(kqop->events);
|
||||
if (kqop->kq)
|
||||
close(kqop->kq);
|
||||
memset(kqop, 0, sizeof(struct kqop));
|
||||
free(kqop);
|
||||
}
|
219
contrib/pf/libevent/log.c
Normal file
219
contrib/pf/libevent/log.c
Normal file
@ -0,0 +1,219 @@
|
||||
/* $OpenBSD: err.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
|
||||
|
||||
/*
|
||||
* log.c
|
||||
*
|
||||
* Based on err.c, which was adapted from OpenBSD libc *err* *warn* code.
|
||||
*
|
||||
* Copyright (c) 2005 Nick Mathewson <nickm@freehaven.net>
|
||||
*
|
||||
* Copyright (c) 2000 Dug Song <dugsong@monkey.org>
|
||||
*
|
||||
* Copyright (c) 1993
|
||||
* The 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include "misc.h"
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/tree.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/_time.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "event.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
static void _warn_helper(int severity, int log_errno, const char *fmt,
|
||||
va_list ap);
|
||||
static void event_log(int severity, const char *msg);
|
||||
|
||||
static int
|
||||
event_vsnprintf(char *str, size_t size, const char *format, va_list args)
|
||||
{
|
||||
int r;
|
||||
if (size == 0)
|
||||
return -1;
|
||||
#ifdef WIN32
|
||||
r = _vsnprintf(str, size, format, args);
|
||||
#else
|
||||
r = vsnprintf(str, size, format, args);
|
||||
#endif
|
||||
str[size-1] = '\0';
|
||||
if (r < 0 || ((size_t)r) >= size) {
|
||||
/* different platforms behave differently on overflow;
|
||||
* handle both kinds. */
|
||||
return -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
event_snprintf(char *str, size_t size, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int r;
|
||||
va_start(ap, format);
|
||||
r = event_vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
event_err(int eval, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_warn_helper(_EVENT_LOG_ERR, errno, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(eval);
|
||||
}
|
||||
|
||||
void
|
||||
event_warn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_warn_helper(_EVENT_LOG_WARN, errno, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
event_errx(int eval, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_warn_helper(_EVENT_LOG_ERR, -1, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(eval);
|
||||
}
|
||||
|
||||
void
|
||||
event_warnx(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_warn_helper(_EVENT_LOG_WARN, -1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
event_msgx(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_warn_helper(_EVENT_LOG_MSG, -1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
_event_debugx(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_warn_helper(_EVENT_LOG_DEBUG, -1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void
|
||||
_warn_helper(int severity, int log_errno, const char *fmt, va_list ap)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t len;
|
||||
|
||||
if (fmt != NULL)
|
||||
event_vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
else
|
||||
buf[0] = '\0';
|
||||
|
||||
if (log_errno >= 0) {
|
||||
len = strlen(buf);
|
||||
if (len < sizeof(buf) - 3) {
|
||||
event_snprintf(buf + len, sizeof(buf) - len, ": %s",
|
||||
strerror(log_errno));
|
||||
}
|
||||
}
|
||||
|
||||
event_log(severity, buf);
|
||||
}
|
||||
|
||||
static event_log_cb log_fn = NULL;
|
||||
|
||||
void
|
||||
event_set_log_callback(event_log_cb cb)
|
||||
{
|
||||
log_fn = cb;
|
||||
}
|
||||
|
||||
static void
|
||||
event_log(int severity, const char *msg)
|
||||
{
|
||||
if (log_fn)
|
||||
log_fn(severity, msg);
|
||||
else {
|
||||
const char *severity_str;
|
||||
switch (severity) {
|
||||
case _EVENT_LOG_DEBUG:
|
||||
severity_str = "debug";
|
||||
break;
|
||||
case _EVENT_LOG_MSG:
|
||||
severity_str = "msg";
|
||||
break;
|
||||
case _EVENT_LOG_WARN:
|
||||
severity_str = "warn";
|
||||
break;
|
||||
case _EVENT_LOG_ERR:
|
||||
severity_str = "err";
|
||||
break;
|
||||
default:
|
||||
severity_str = "???";
|
||||
break;
|
||||
}
|
||||
(void)fprintf(stderr, "[%s] %s\n", severity_str, msg);
|
||||
}
|
||||
}
|
43
contrib/pf/libevent/log.h
Normal file
43
contrib/pf/libevent/log.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _LOG_H_
|
||||
#define _LOG_H_
|
||||
|
||||
void event_err(int eval, const char *fmt, ...);
|
||||
void event_warn(const char *fmt, ...);
|
||||
void event_errx(int eval, const char *fmt, ...);
|
||||
void event_warnx(const char *fmt, ...);
|
||||
void event_msgx(const char *fmt, ...);
|
||||
void _event_debugx(const char *fmt, ...);
|
||||
|
||||
#ifdef USE_DEBUG
|
||||
#define event_debug(x) _event_debugx x
|
||||
#else
|
||||
#define event_debug(x) do {;} while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
388
contrib/pf/libevent/poll.c
Normal file
388
contrib/pf/libevent/poll.c
Normal file
@ -0,0 +1,388 @@
|
||||
/* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/_time.h>
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
#include <sys/tree.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifdef CHECK_INVARIANTS
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include "event.h"
|
||||
#include "event-internal.h"
|
||||
#include "evsignal.h"
|
||||
#include "log.h"
|
||||
|
||||
extern volatile sig_atomic_t evsignal_caught;
|
||||
|
||||
struct pollop {
|
||||
int event_count; /* Highest number alloc */
|
||||
int nfds; /* Size of event_* */
|
||||
int fd_count; /* Size of idxplus1_by_fd */
|
||||
struct pollfd *event_set;
|
||||
struct event **event_r_back;
|
||||
struct event **event_w_back;
|
||||
int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
|
||||
* that 0 (which is easy to memset) can mean
|
||||
* "no entry." */
|
||||
};
|
||||
|
||||
void *poll_init (void);
|
||||
int poll_add (void *, struct event *);
|
||||
int poll_del (void *, struct event *);
|
||||
int poll_recalc (struct event_base *, void *, int);
|
||||
int poll_dispatch (struct event_base *, void *, struct timeval *);
|
||||
void poll_dealloc (void *);
|
||||
|
||||
const struct eventop pollops = {
|
||||
"poll",
|
||||
poll_init,
|
||||
poll_add,
|
||||
poll_del,
|
||||
poll_recalc,
|
||||
poll_dispatch,
|
||||
poll_dealloc
|
||||
};
|
||||
|
||||
void *
|
||||
poll_init(void)
|
||||
{
|
||||
struct pollop *pollop;
|
||||
|
||||
/* Disable poll when this environment variable is set */
|
||||
if (getenv("EVENT_NOPOLL"))
|
||||
return (NULL);
|
||||
|
||||
if (!(pollop = calloc(1, sizeof(struct pollop))))
|
||||
return (NULL);
|
||||
|
||||
evsignal_init();
|
||||
|
||||
return (pollop);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called with the highest fd that we know about. If it is 0, completely
|
||||
* recalculate everything.
|
||||
*/
|
||||
|
||||
int
|
||||
poll_recalc(struct event_base *base, void *arg, int max)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef CHECK_INVARIANTS
|
||||
static void
|
||||
poll_check_ok(struct pollop *pop)
|
||||
{
|
||||
int i, idx;
|
||||
struct event *ev;
|
||||
|
||||
for (i = 0; i < pop->fd_count; ++i) {
|
||||
idx = pop->idxplus1_by_fd[i]-1;
|
||||
if (idx < 0)
|
||||
continue;
|
||||
assert(pop->event_set[idx].fd == i);
|
||||
if (pop->event_set[idx].events & POLLIN) {
|
||||
ev = pop->event_r_back[idx];
|
||||
assert(ev);
|
||||
assert(ev->ev_events & EV_READ);
|
||||
assert(ev->ev_fd == i);
|
||||
}
|
||||
if (pop->event_set[idx].events & POLLOUT) {
|
||||
ev = pop->event_w_back[idx];
|
||||
assert(ev);
|
||||
assert(ev->ev_events & EV_WRITE);
|
||||
assert(ev->ev_fd == i);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < pop->nfds; ++i) {
|
||||
struct pollfd *pfd = &pop->event_set[i];
|
||||
assert(pop->idxplus1_by_fd[pfd->fd] == i+1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define poll_check_ok(pop)
|
||||
#endif
|
||||
|
||||
int
|
||||
poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
|
||||
{
|
||||
int res, i, sec, nfds;
|
||||
struct pollop *pop = arg;
|
||||
|
||||
poll_check_ok(pop);
|
||||
sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
|
||||
nfds = pop->nfds;
|
||||
res = poll(pop->event_set, nfds, sec);
|
||||
|
||||
if (res == -1) {
|
||||
if (errno != EINTR) {
|
||||
event_warn("poll");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
evsignal_process();
|
||||
return (0);
|
||||
} else if (evsignal_caught)
|
||||
evsignal_process();
|
||||
|
||||
event_debug(("%s: poll reports %d", __func__, res));
|
||||
|
||||
if (res == 0)
|
||||
return (0);
|
||||
|
||||
for (i = 0; i < nfds; i++) {
|
||||
int what = pop->event_set[i].revents;
|
||||
struct event *r_ev = NULL, *w_ev = NULL;
|
||||
if (!what)
|
||||
continue;
|
||||
|
||||
res = 0;
|
||||
|
||||
/* If the file gets closed notify */
|
||||
if (what & (POLLHUP|POLLERR))
|
||||
what |= POLLIN|POLLOUT;
|
||||
if (what & POLLIN) {
|
||||
res |= EV_READ;
|
||||
r_ev = pop->event_r_back[i];
|
||||
}
|
||||
if (what & POLLOUT) {
|
||||
res |= EV_WRITE;
|
||||
w_ev = pop->event_w_back[i];
|
||||
}
|
||||
if (res == 0)
|
||||
continue;
|
||||
|
||||
if (r_ev && (res & r_ev->ev_events)) {
|
||||
if (!(r_ev->ev_events & EV_PERSIST))
|
||||
event_del(r_ev);
|
||||
event_active(r_ev, res & r_ev->ev_events, 1);
|
||||
}
|
||||
if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
|
||||
if (!(w_ev->ev_events & EV_PERSIST))
|
||||
event_del(w_ev);
|
||||
event_active(w_ev, res & w_ev->ev_events, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
poll_add(void *arg, struct event *ev)
|
||||
{
|
||||
struct pollop *pop = arg;
|
||||
struct pollfd *pfd = NULL;
|
||||
int i;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
return (evsignal_add(ev));
|
||||
if (!(ev->ev_events & (EV_READ|EV_WRITE)))
|
||||
return (0);
|
||||
|
||||
poll_check_ok(pop);
|
||||
if (pop->nfds + 1 >= pop->event_count) {
|
||||
struct pollfd *tmp_event_set;
|
||||
struct event **tmp_event_r_back;
|
||||
struct event **tmp_event_w_back;
|
||||
int tmp_event_count;
|
||||
|
||||
if (pop->event_count < 32)
|
||||
tmp_event_count = 32;
|
||||
else
|
||||
tmp_event_count = pop->event_count * 2;
|
||||
|
||||
/* We need more file descriptors */
|
||||
tmp_event_set = realloc(pop->event_set,
|
||||
tmp_event_count * sizeof(struct pollfd));
|
||||
if (tmp_event_set == NULL) {
|
||||
event_warn("realloc");
|
||||
return (-1);
|
||||
}
|
||||
pop->event_set = tmp_event_set;
|
||||
|
||||
tmp_event_r_back = realloc(pop->event_r_back,
|
||||
tmp_event_count * sizeof(struct event *));
|
||||
if (tmp_event_r_back == NULL) {
|
||||
/* event_set overallocated; that's okay. */
|
||||
event_warn("realloc");
|
||||
return (-1);
|
||||
}
|
||||
pop->event_r_back = tmp_event_r_back;
|
||||
|
||||
tmp_event_w_back = realloc(pop->event_w_back,
|
||||
tmp_event_count * sizeof(struct event *));
|
||||
if (tmp_event_w_back == NULL) {
|
||||
/* event_set and event_r_back overallocated; that's
|
||||
* okay. */
|
||||
event_warn("realloc");
|
||||
return (-1);
|
||||
}
|
||||
pop->event_w_back = tmp_event_w_back;
|
||||
|
||||
pop->event_count = tmp_event_count;
|
||||
}
|
||||
if (ev->ev_fd >= pop->fd_count) {
|
||||
int *tmp_idxplus1_by_fd;
|
||||
int new_count;
|
||||
if (pop->fd_count < 32)
|
||||
new_count = 32;
|
||||
else
|
||||
new_count = pop->fd_count * 2;
|
||||
while (new_count <= ev->ev_fd)
|
||||
new_count *= 2;
|
||||
tmp_idxplus1_by_fd =
|
||||
realloc(pop->idxplus1_by_fd, new_count * sizeof(int));
|
||||
if (tmp_idxplus1_by_fd == NULL) {
|
||||
event_warn("realloc");
|
||||
return (-1);
|
||||
}
|
||||
pop->idxplus1_by_fd = tmp_idxplus1_by_fd;
|
||||
memset(pop->idxplus1_by_fd + pop->fd_count,
|
||||
0, sizeof(int)*(new_count - pop->fd_count));
|
||||
pop->fd_count = new_count;
|
||||
}
|
||||
|
||||
i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
|
||||
if (i >= 0) {
|
||||
pfd = &pop->event_set[i];
|
||||
} else {
|
||||
i = pop->nfds++;
|
||||
pfd = &pop->event_set[i];
|
||||
pfd->events = 0;
|
||||
pfd->fd = ev->ev_fd;
|
||||
pop->event_w_back[i] = pop->event_r_back[i] = NULL;
|
||||
pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
|
||||
}
|
||||
|
||||
pfd->revents = 0;
|
||||
if (ev->ev_events & EV_WRITE) {
|
||||
pfd->events |= POLLOUT;
|
||||
pop->event_w_back[i] = ev;
|
||||
}
|
||||
if (ev->ev_events & EV_READ) {
|
||||
pfd->events |= POLLIN;
|
||||
pop->event_r_back[i] = ev;
|
||||
}
|
||||
poll_check_ok(pop);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Nothing to be done here.
|
||||
*/
|
||||
|
||||
int
|
||||
poll_del(void *arg, struct event *ev)
|
||||
{
|
||||
struct pollop *pop = arg;
|
||||
struct pollfd *pfd = NULL;
|
||||
int i;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
return (evsignal_del(ev));
|
||||
|
||||
if (!(ev->ev_events & (EV_READ|EV_WRITE)))
|
||||
return (0);
|
||||
|
||||
poll_check_ok(pop);
|
||||
i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
|
||||
if (i < 0)
|
||||
return (-1);
|
||||
|
||||
/* Do we still want to read or write? */
|
||||
pfd = &pop->event_set[i];
|
||||
if (ev->ev_events & EV_READ) {
|
||||
pfd->events &= ~POLLIN;
|
||||
pop->event_r_back[i] = NULL;
|
||||
}
|
||||
if (ev->ev_events & EV_WRITE) {
|
||||
pfd->events &= ~POLLOUT;
|
||||
pop->event_w_back[i] = NULL;
|
||||
}
|
||||
poll_check_ok(pop);
|
||||
if (pfd->events)
|
||||
/* Another event cares about that fd. */
|
||||
return (0);
|
||||
|
||||
/* Okay, so we aren't interested in that fd anymore. */
|
||||
pop->idxplus1_by_fd[ev->ev_fd] = 0;
|
||||
|
||||
--pop->nfds;
|
||||
if (i != pop->nfds) {
|
||||
/*
|
||||
* Shift the last pollfd down into the now-unoccupied
|
||||
* position.
|
||||
*/
|
||||
memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
|
||||
sizeof(struct pollfd));
|
||||
pop->event_r_back[i] = pop->event_r_back[pop->nfds];
|
||||
pop->event_w_back[i] = pop->event_w_back[pop->nfds];
|
||||
pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
|
||||
}
|
||||
|
||||
poll_check_ok(pop);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
poll_dealloc(void *arg)
|
||||
{
|
||||
struct pollop *pop = arg;
|
||||
|
||||
if (pop->event_set)
|
||||
free(pop->event_set);
|
||||
if (pop->event_r_back)
|
||||
free(pop->event_r_back);
|
||||
if (pop->event_w_back)
|
||||
free(pop->event_w_back);
|
||||
if (pop->idxplus1_by_fd)
|
||||
free(pop->idxplus1_by_fd);
|
||||
|
||||
memset(pop, 0, sizeof(struct pollop));
|
||||
free(pop);
|
||||
}
|
370
contrib/pf/libevent/select.c
Normal file
370
contrib/pf/libevent/select.c
Normal file
@ -0,0 +1,370 @@
|
||||
/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/_time.h>
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
#include <sys/tree.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifdef CHECK_INVARIANTS
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include "event.h"
|
||||
#include "event-internal.h"
|
||||
#include "evsignal.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifndef howmany
|
||||
#define howmany(x, y) (((x)+((y)-1))/(y))
|
||||
#endif
|
||||
|
||||
extern volatile sig_atomic_t evsignal_caught;
|
||||
|
||||
struct selectop {
|
||||
int event_fds; /* Highest fd in fd set */
|
||||
int event_fdsz;
|
||||
fd_set *event_readset_in;
|
||||
fd_set *event_writeset_in;
|
||||
fd_set *event_readset_out;
|
||||
fd_set *event_writeset_out;
|
||||
struct event **event_r_by_fd;
|
||||
struct event **event_w_by_fd;
|
||||
};
|
||||
|
||||
void *select_init (void);
|
||||
int select_add (void *, struct event *);
|
||||
int select_del (void *, struct event *);
|
||||
int select_recalc (struct event_base *, void *, int);
|
||||
int select_dispatch (struct event_base *, void *, struct timeval *);
|
||||
void select_dealloc (void *);
|
||||
|
||||
const struct eventop selectops = {
|
||||
"select",
|
||||
select_init,
|
||||
select_add,
|
||||
select_del,
|
||||
select_recalc,
|
||||
select_dispatch,
|
||||
select_dealloc
|
||||
};
|
||||
|
||||
static int select_resize(struct selectop *sop, int fdsz);
|
||||
|
||||
void *
|
||||
select_init(void)
|
||||
{
|
||||
struct selectop *sop;
|
||||
|
||||
/* Disable select when this environment variable is set */
|
||||
if (getenv("EVENT_NOSELECT"))
|
||||
return (NULL);
|
||||
|
||||
if (!(sop = calloc(1, sizeof(struct selectop))))
|
||||
return (NULL);
|
||||
|
||||
select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask));
|
||||
|
||||
evsignal_init();
|
||||
|
||||
return (sop);
|
||||
}
|
||||
|
||||
#ifdef CHECK_INVARIANTS
|
||||
static void
|
||||
check_selectop(struct selectop *sop)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<=sop->event_fds;++i) {
|
||||
if (FD_ISSET(i, sop->event_readset_in)) {
|
||||
assert(sop->event_r_by_fd[i]);
|
||||
assert(sop->event_r_by_fd[i]->ev_events & EV_READ);
|
||||
assert(sop->event_r_by_fd[i]->ev_fd == i);
|
||||
} else {
|
||||
assert(! sop->event_r_by_fd[i]);
|
||||
}
|
||||
if (FD_ISSET(i, sop->event_writeset_in)) {
|
||||
assert(sop->event_w_by_fd[i]);
|
||||
assert(sop->event_w_by_fd[i]->ev_events & EV_WRITE);
|
||||
assert(sop->event_w_by_fd[i]->ev_fd == i);
|
||||
} else {
|
||||
assert(! sop->event_w_by_fd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
#define check_selectop(sop) do { (void) sop; } while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Called with the highest fd that we know about. If it is 0, completely
|
||||
* recalculate everything.
|
||||
*/
|
||||
|
||||
int
|
||||
select_recalc(struct event_base *base, void *arg, int max)
|
||||
{
|
||||
struct selectop *sop = arg;
|
||||
|
||||
check_selectop(sop);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
select_dispatch(struct event_base *base, void *arg, struct timeval *tv)
|
||||
{
|
||||
int res, i;
|
||||
struct selectop *sop = arg;
|
||||
|
||||
check_selectop(sop);
|
||||
|
||||
memcpy(sop->event_readset_out, sop->event_readset_in,
|
||||
sop->event_fdsz);
|
||||
memcpy(sop->event_writeset_out, sop->event_writeset_in,
|
||||
sop->event_fdsz);
|
||||
|
||||
res = select(sop->event_fds + 1, sop->event_readset_out,
|
||||
sop->event_writeset_out, NULL, tv);
|
||||
|
||||
check_selectop(sop);
|
||||
|
||||
if (res == -1) {
|
||||
if (errno != EINTR) {
|
||||
event_warn("select");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
evsignal_process();
|
||||
return (0);
|
||||
} else if (evsignal_caught)
|
||||
evsignal_process();
|
||||
|
||||
event_debug(("%s: select reports %d", __func__, res));
|
||||
|
||||
check_selectop(sop);
|
||||
for (i = 0; i <= sop->event_fds; ++i) {
|
||||
struct event *r_ev = NULL, *w_ev = NULL;
|
||||
res = 0;
|
||||
if (FD_ISSET(i, sop->event_readset_out)) {
|
||||
r_ev = sop->event_r_by_fd[i];
|
||||
res |= EV_READ;
|
||||
}
|
||||
if (FD_ISSET(i, sop->event_writeset_out)) {
|
||||
w_ev = sop->event_w_by_fd[i];
|
||||
res |= EV_WRITE;
|
||||
}
|
||||
if (r_ev && (res & r_ev->ev_events)) {
|
||||
if (!(r_ev->ev_events & EV_PERSIST))
|
||||
event_del(r_ev);
|
||||
event_active(r_ev, res & r_ev->ev_events, 1);
|
||||
}
|
||||
if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
|
||||
if (!(w_ev->ev_events & EV_PERSIST))
|
||||
event_del(w_ev);
|
||||
event_active(w_ev, res & w_ev->ev_events, 1);
|
||||
}
|
||||
}
|
||||
check_selectop(sop);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
select_resize(struct selectop *sop, int fdsz)
|
||||
{
|
||||
int n_events, n_events_old;
|
||||
|
||||
fd_set *readset_in = NULL;
|
||||
fd_set *writeset_in = NULL;
|
||||
fd_set *readset_out = NULL;
|
||||
fd_set *writeset_out = NULL;
|
||||
struct event **r_by_fd = NULL;
|
||||
struct event **w_by_fd = NULL;
|
||||
|
||||
n_events = (fdsz/sizeof(fd_mask)) * NFDBITS;
|
||||
n_events_old = (sop->event_fdsz/sizeof(fd_mask)) * NFDBITS;
|
||||
|
||||
if (sop->event_readset_in)
|
||||
check_selectop(sop);
|
||||
|
||||
if ((readset_in = realloc(sop->event_readset_in, fdsz)) == NULL)
|
||||
goto error;
|
||||
sop->event_readset_in = readset_in;
|
||||
if ((readset_out = realloc(sop->event_readset_out, fdsz)) == NULL)
|
||||
goto error;
|
||||
sop->event_readset_out = readset_out;
|
||||
if ((writeset_in = realloc(sop->event_writeset_in, fdsz)) == NULL)
|
||||
goto error;
|
||||
sop->event_writeset_in = writeset_in;
|
||||
if ((writeset_out = realloc(sop->event_writeset_out, fdsz)) == NULL)
|
||||
goto error;
|
||||
sop->event_writeset_out = writeset_out;
|
||||
if ((r_by_fd = realloc(sop->event_r_by_fd,
|
||||
n_events*sizeof(struct event*))) == NULL)
|
||||
goto error;
|
||||
sop->event_r_by_fd = r_by_fd;
|
||||
if ((w_by_fd = realloc(sop->event_w_by_fd,
|
||||
n_events * sizeof(struct event*))) == NULL)
|
||||
goto error;
|
||||
sop->event_w_by_fd = w_by_fd;
|
||||
|
||||
memset((char *)sop->event_readset_in + sop->event_fdsz, 0,
|
||||
fdsz - sop->event_fdsz);
|
||||
memset((char *)sop->event_writeset_in + sop->event_fdsz, 0,
|
||||
fdsz - sop->event_fdsz);
|
||||
memset(sop->event_r_by_fd + n_events_old, 0,
|
||||
(n_events-n_events_old) * sizeof(struct event*));
|
||||
memset(sop->event_w_by_fd + n_events_old, 0,
|
||||
(n_events-n_events_old) * sizeof(struct event*));
|
||||
|
||||
sop->event_fdsz = fdsz;
|
||||
check_selectop(sop);
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
event_warn("malloc");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
select_add(void *arg, struct event *ev)
|
||||
{
|
||||
struct selectop *sop = arg;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
return (evsignal_add(ev));
|
||||
|
||||
check_selectop(sop);
|
||||
/*
|
||||
* Keep track of the highest fd, so that we can calculate the size
|
||||
* of the fd_sets for select(2)
|
||||
*/
|
||||
if (sop->event_fds < ev->ev_fd) {
|
||||
int fdsz = sop->event_fdsz;
|
||||
|
||||
if (fdsz < sizeof(fd_mask))
|
||||
fdsz = sizeof(fd_mask);
|
||||
|
||||
while (fdsz <
|
||||
(howmany(ev->ev_fd + 1, NFDBITS) * sizeof(fd_mask)))
|
||||
fdsz *= 2;
|
||||
|
||||
if (fdsz != sop->event_fdsz) {
|
||||
if (select_resize(sop, fdsz)) {
|
||||
check_selectop(sop);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
sop->event_fds = ev->ev_fd;
|
||||
}
|
||||
|
||||
if (ev->ev_events & EV_READ) {
|
||||
FD_SET(ev->ev_fd, sop->event_readset_in);
|
||||
sop->event_r_by_fd[ev->ev_fd] = ev;
|
||||
}
|
||||
if (ev->ev_events & EV_WRITE) {
|
||||
FD_SET(ev->ev_fd, sop->event_writeset_in);
|
||||
sop->event_w_by_fd[ev->ev_fd] = ev;
|
||||
}
|
||||
check_selectop(sop);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Nothing to be done here.
|
||||
*/
|
||||
|
||||
int
|
||||
select_del(void *arg, struct event *ev)
|
||||
{
|
||||
struct selectop *sop = arg;
|
||||
|
||||
check_selectop(sop);
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
return (evsignal_del(ev));
|
||||
|
||||
if (sop->event_fds < ev->ev_fd) {
|
||||
check_selectop(sop);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (ev->ev_events & EV_READ) {
|
||||
FD_CLR(ev->ev_fd, sop->event_readset_in);
|
||||
sop->event_r_by_fd[ev->ev_fd] = NULL;
|
||||
}
|
||||
|
||||
if (ev->ev_events & EV_WRITE) {
|
||||
FD_CLR(ev->ev_fd, sop->event_writeset_in);
|
||||
sop->event_w_by_fd[ev->ev_fd] = NULL;
|
||||
}
|
||||
|
||||
check_selectop(sop);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
select_dealloc(void *arg)
|
||||
{
|
||||
struct selectop *sop = arg;
|
||||
|
||||
if (sop->event_readset_in)
|
||||
free(sop->event_readset_in);
|
||||
if (sop->event_writeset_in)
|
||||
free(sop->event_writeset_in);
|
||||
if (sop->event_readset_out)
|
||||
free(sop->event_readset_out);
|
||||
if (sop->event_writeset_out)
|
||||
free(sop->event_writeset_out);
|
||||
if (sop->event_r_by_fd)
|
||||
free(sop->event_r_by_fd);
|
||||
if (sop->event_w_by_fd)
|
||||
free(sop->event_w_by_fd);
|
||||
|
||||
memset(sop, 0, sizeof(struct selectop));
|
||||
free(sop);
|
||||
}
|
180
contrib/pf/libevent/signal.c
Normal file
180
contrib/pf/libevent/signal.c
Normal file
@ -0,0 +1,180 @@
|
||||
/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
|
||||
* 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.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <sys/_time.h>
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "event.h"
|
||||
#include "evsignal.h"
|
||||
#include "log.h"
|
||||
|
||||
extern struct event_list signalqueue;
|
||||
|
||||
static sig_atomic_t evsigcaught[NSIG];
|
||||
volatile sig_atomic_t evsignal_caught = 0;
|
||||
|
||||
static struct event ev_signal;
|
||||
static int ev_signal_pair[2];
|
||||
static int ev_signal_added;
|
||||
|
||||
static void evsignal_handler(int sig);
|
||||
|
||||
/* Callback for when the signal handler write a byte to our signaling socket */
|
||||
static void
|
||||
evsignal_cb(int fd, short what, void *arg)
|
||||
{
|
||||
static char signals[100];
|
||||
struct event *ev = arg;
|
||||
ssize_t n;
|
||||
|
||||
n = read(fd, signals, sizeof(signals));
|
||||
if (n == -1)
|
||||
event_err(1, "%s: read", __func__);
|
||||
event_add(ev, NULL);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETFD
|
||||
#define FD_CLOSEONEXEC(x) do { \
|
||||
if (fcntl(x, F_SETFD, 1) == -1) \
|
||||
event_warn("fcntl(%d, F_SETFD)", x); \
|
||||
} while (0)
|
||||
#else
|
||||
#define FD_CLOSEONEXEC(x)
|
||||
#endif
|
||||
|
||||
void
|
||||
evsignal_init(void)
|
||||
{
|
||||
/*
|
||||
* Our signal handler is going to write to one end of the socket
|
||||
* pair to wake up our event loop. The event loop then scans for
|
||||
* signals that got delivered.
|
||||
*/
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1)
|
||||
event_err(1, "%s: socketpair", __func__);
|
||||
|
||||
FD_CLOSEONEXEC(ev_signal_pair[0]);
|
||||
FD_CLOSEONEXEC(ev_signal_pair[1]);
|
||||
|
||||
fcntl(ev_signal_pair[0], F_SETFL, O_NONBLOCK);
|
||||
|
||||
event_set(&ev_signal, ev_signal_pair[1], EV_READ,
|
||||
evsignal_cb, &ev_signal);
|
||||
ev_signal.ev_flags |= EVLIST_INTERNAL;
|
||||
}
|
||||
|
||||
int
|
||||
evsignal_add(struct event *ev)
|
||||
{
|
||||
int evsignal;
|
||||
struct sigaction sa;
|
||||
|
||||
if (ev->ev_events & (EV_READ|EV_WRITE))
|
||||
event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
|
||||
evsignal = EVENT_SIGNAL(ev);
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = evsignal_handler;
|
||||
sigfillset(&sa.sa_mask);
|
||||
sa.sa_flags |= SA_RESTART;
|
||||
|
||||
if (sigaction(evsignal, &sa, NULL) == -1)
|
||||
return (-1);
|
||||
|
||||
if (!ev_signal_added) {
|
||||
ev_signal_added = 1;
|
||||
event_add(&ev_signal, NULL);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Nothing to be done here.
|
||||
*/
|
||||
|
||||
int
|
||||
evsignal_del(struct event *ev)
|
||||
{
|
||||
int evsignal;
|
||||
|
||||
evsignal = EVENT_SIGNAL(ev);
|
||||
|
||||
return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
evsignal_handler(int sig)
|
||||
{
|
||||
int save_errno = errno;
|
||||
|
||||
evsigcaught[sig]++;
|
||||
evsignal_caught = 1;
|
||||
|
||||
/* Wake up our notification mechanism */
|
||||
write(ev_signal_pair[0], "a", 1);
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
void
|
||||
evsignal_process(void)
|
||||
{
|
||||
struct event *ev;
|
||||
sig_atomic_t ncalls;
|
||||
|
||||
evsignal_caught = 0;
|
||||
TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
|
||||
ncalls = evsigcaught[EVENT_SIGNAL(ev)];
|
||||
if (ncalls) {
|
||||
if (!(ev->ev_events & EV_PERSIST))
|
||||
event_del(ev);
|
||||
event_active(ev, EV_SIGNAL, ncalls);
|
||||
evsigcaught[EVENT_SIGNAL(ev)] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: pf.4,v 1.54 2004/12/22 17:17:55 dhartmei Exp $
|
||||
.\" $OpenBSD: pf.4,v 1.58 2007/02/09 11:39:06 henning Exp $
|
||||
.\"
|
||||
.\" Copyright (C) 2001, Kjell Wooding. All rights reserved.
|
||||
.\"
|
||||
@ -184,6 +184,11 @@ using the
|
||||
obtained through a preceding
|
||||
.Dv DIOCGETRULES
|
||||
call.
|
||||
If
|
||||
.Va action
|
||||
is set to
|
||||
.Dv PF_GET_CLR_CNTR ,
|
||||
the per-rule statistics on the requested rule are cleared.
|
||||
.It Dv DIOCGETADDRS Fa "struct pfioc_pooladdr *pp"
|
||||
Get a
|
||||
.Va ticket
|
||||
@ -346,6 +351,7 @@ struct pf_status {
|
||||
u_int32_t debug;
|
||||
u_int32_t hostid;
|
||||
char ifname[IFNAMSIZ];
|
||||
u_int8_t pf_chksum[MD5_DIGEST_LENGTH];
|
||||
};
|
||||
.Ed
|
||||
.It Dv DIOCCLRSTATUS
|
||||
@ -389,19 +395,14 @@ struct pfioc_states {
|
||||
.Pp
|
||||
If
|
||||
.Va ps_len
|
||||
is zero, all states will be gathered into
|
||||
.Va pf_states
|
||||
and
|
||||
is non-zero on entry, as many states as possible that can fit into this
|
||||
size will be copied into the supplied buffer
|
||||
.Va ps_states .
|
||||
On exit,
|
||||
.Va ps_len
|
||||
will be set to the size they take in memory (i.e.,
|
||||
is always set to the total size required to hold all state table entries
|
||||
(i.e., it is set to
|
||||
.Li sizeof(struct pf_state) * nr ) .
|
||||
If
|
||||
.Va ps_len
|
||||
is non-zero, as many states that can fit into
|
||||
.Va ps_len
|
||||
as possible will be gathered, and
|
||||
.Va ps_len
|
||||
will be updated to the size those rules take in memory.
|
||||
.It Dv DIOCCHANGERULE Fa "struct pfioc_rule *pcr"
|
||||
Add or remove the
|
||||
.Va rule
|
||||
@ -483,7 +484,8 @@ struct pfioc_limit {
|
||||
unsigned limit;
|
||||
};
|
||||
|
||||
enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS };
|
||||
enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS,
|
||||
PF_LIMIT_TABLES, PF_LIMIT_TABLE_ENTRIES, PF_LIMIT_MAX };
|
||||
.Ed
|
||||
.It Dv DIOCGETLIMIT Fa "struct pfioc_limit *pl"
|
||||
Get the hard
|
||||
@ -521,10 +523,15 @@ struct pfioc_table {
|
||||
.It Dv DIOCRADDTABLES Fa "struct pfioc_table *io"
|
||||
Create one or more tables.
|
||||
On entry,
|
||||
.Va pfrio_buffer[pfrio_size]
|
||||
contains a table of
|
||||
.Vt pfr_table
|
||||
structures.
|
||||
.Va pfrio_buffer
|
||||
must point to an array of
|
||||
.Vt struct pfr_table
|
||||
containing at least
|
||||
.Vt pfrio_size
|
||||
elements.
|
||||
.Vt pfrio_esize
|
||||
must be the size of
|
||||
.Vt struct pfr_table .
|
||||
On exit,
|
||||
.Va pfrio_nadd
|
||||
contains the number of tables effectively created.
|
||||
@ -539,12 +546,17 @@ struct pfr_table {
|
||||
.It Dv DIOCRDELTABLES Fa "struct pfioc_table *io"
|
||||
Delete one or more tables.
|
||||
On entry,
|
||||
.Va pfrio_buffer[pfrio_size]
|
||||
contains a table of
|
||||
.Vt pfr_table
|
||||
structures.
|
||||
.Va pfrio_buffer
|
||||
must point to an array of
|
||||
.Vt struct pfr_table
|
||||
containing at least
|
||||
.Vt pfrio_size
|
||||
elements.
|
||||
.Vt pfrio_esize
|
||||
must be the size of
|
||||
.Vt struct pfr_table .
|
||||
On exit,
|
||||
.Va pfrio_nadd
|
||||
.Va pfrio_ndel
|
||||
contains the number of tables effectively deleted.
|
||||
.It Dv DIOCRGETTABLES Fa "struct pfioc_table *io"
|
||||
Get the list of all tables.
|
||||
@ -583,10 +595,15 @@ struct pfr_tstats {
|
||||
.It Dv DIOCRCLRTSTATS Fa "struct pfioc_table *io"
|
||||
Clear the statistics of one or more tables.
|
||||
On entry,
|
||||
.Va pfrio_buffer[pfrio_size]
|
||||
contains a table of
|
||||
.Vt pfr_table
|
||||
structures.
|
||||
.Va pfrio_buffer
|
||||
must point to an array of
|
||||
.Vt struct pfr_table
|
||||
containing at least
|
||||
.Vt pfrio_size
|
||||
elements.
|
||||
.Vt pfrio_esize
|
||||
must be the size of
|
||||
.Vt struct pfr_table .
|
||||
On exit,
|
||||
.Va pfrio_nzero
|
||||
contains the number of tables effectively cleared.
|
||||
@ -603,10 +620,15 @@ Add one or more addresses to a table.
|
||||
On entry,
|
||||
.Va pfrio_table
|
||||
contains the table ID and
|
||||
.Va pfrio_buffer[pfrio_size]
|
||||
contains the list of
|
||||
.Vt pfr_addr
|
||||
structures to add.
|
||||
.Va pfrio_buffer
|
||||
must point to an array of
|
||||
.Vt struct pfr_addr
|
||||
containing at least
|
||||
.Vt pfrio_size
|
||||
elements to add to the table.
|
||||
.Vt pfrio_esize
|
||||
must be the size of
|
||||
.Vt struct pfr_addr .
|
||||
On exit,
|
||||
.Va pfrio_nadd
|
||||
contains the number of addresses effectively added.
|
||||
@ -629,10 +651,15 @@ Delete one or more addresses from a table.
|
||||
On entry,
|
||||
.Va pfrio_table
|
||||
contains the table ID and
|
||||
.Va pfrio_buffer[pfrio_size]
|
||||
contains the list of
|
||||
.Vt pfr_addr
|
||||
structures to delete.
|
||||
.Va pfrio_buffer
|
||||
must point to an array of
|
||||
.Vt struct pfr_addr
|
||||
containing at least
|
||||
.Vt pfrio_size
|
||||
elements to delete from the table.
|
||||
.Vt pfrio_esize
|
||||
must be the size of
|
||||
.Vt struct pfr_addr .
|
||||
On exit,
|
||||
.Va pfrio_ndel
|
||||
contains the number of addresses effectively deleted.
|
||||
@ -643,10 +670,15 @@ This is the most complicated command, which uses all the structure members.
|
||||
On entry,
|
||||
.Va pfrio_table
|
||||
contains the table ID and
|
||||
.Va pfrio_buffer[pfrio_size]
|
||||
contains the new list of
|
||||
.Vt pfr_addr
|
||||
structures.
|
||||
.Va pfrio_buffer
|
||||
must point to an array of
|
||||
.Vt struct pfr_addr
|
||||
containing at least
|
||||
.Vt pfrio_size
|
||||
elements which become the new contents of the table.
|
||||
.Vt pfrio_esize
|
||||
must be the size of
|
||||
.Vt struct pfr_addr .
|
||||
Additionally, if
|
||||
.Va pfrio_size2
|
||||
is non-zero,
|
||||
@ -701,10 +733,15 @@ Clear the statistics of one or more addresses.
|
||||
On entry,
|
||||
.Va pfrio_table
|
||||
contains the table ID and
|
||||
.Va pfrio_buffer[pfrio_size]
|
||||
contains a table of
|
||||
.Vt pfr_addr
|
||||
structures to clear.
|
||||
.Va pfrio_buffer
|
||||
must point to an array of
|
||||
.Vt struct pfr_addr
|
||||
containing at least
|
||||
.Vt pfrio_size
|
||||
elements to be cleared from the table.
|
||||
.Vt pfrio_esize
|
||||
must be the size of
|
||||
.Vt struct pfr_addr .
|
||||
On exit,
|
||||
.Va pfrio_nzero
|
||||
contains the number of addresses effectively cleared.
|
||||
@ -713,13 +750,18 @@ Test if the given addresses match a table.
|
||||
On entry,
|
||||
.Va pfrio_table
|
||||
contains the table ID and
|
||||
.Va pfrio_buffer[pfrio_size]
|
||||
contains a table of
|
||||
.Vt pfr_addr
|
||||
structures to test.
|
||||
.Va pfrio_buffer
|
||||
must point to an array of
|
||||
.Vt struct pfr_addr
|
||||
containing at least
|
||||
.Vt pfrio_size
|
||||
elements, each of which will be tested for a match in the table.
|
||||
.Vt pfrio_esize
|
||||
must be the size of
|
||||
.Vt struct pfr_addr .
|
||||
On exit, the kernel updates the
|
||||
.Vt pfr_addr
|
||||
table by setting the
|
||||
array by setting the
|
||||
.Va pfra_fback
|
||||
member appropriately.
|
||||
.It Dv DIOCRSETTFLAGS Fa "struct pfioc_table *io"
|
||||
@ -729,14 +771,19 @@ or
|
||||
.Dv PFR_TFLAG_PERSIST
|
||||
flags of a table.
|
||||
On entry,
|
||||
.Va pfrio_buffer[pfrio_size]
|
||||
contains a table of
|
||||
.Vt pfr_table
|
||||
structures, and
|
||||
.Va pfrio_buffer
|
||||
must point to an array of
|
||||
.Vt struct pfr_table
|
||||
containing at least
|
||||
.Vt pfrio_size
|
||||
elements.
|
||||
.Va pfrio_esize
|
||||
must be the size of
|
||||
.Vt struct pfr_table .
|
||||
.Va pfrio_setflag
|
||||
contains the flags to add, while
|
||||
must contain the flags to add, while
|
||||
.Va pfrio_clrflag
|
||||
contains the flags to remove.
|
||||
must contain the flags to remove.
|
||||
On exit,
|
||||
.Va pfrio_nchange
|
||||
and
|
||||
@ -751,7 +798,7 @@ On entry,
|
||||
.Va pfrio_table
|
||||
contains the table ID and
|
||||
.Va pfrio_buffer[pfrio_size]
|
||||
contains the list of
|
||||
contains an array of
|
||||
.Vt pfr_addr
|
||||
structures to put in the table.
|
||||
A valid ticket must also be supplied to
|
||||
@ -953,10 +1000,6 @@ struct pfioc_iface {
|
||||
int pfiio_nzero;
|
||||
int pfiio_flags;
|
||||
};
|
||||
|
||||
#define PFI_FLAG_GROUP 0x0001 /* gets groups of interfaces */
|
||||
#define PFI_FLAG_INSTANCE 0x0002 /* gets single interfaces */
|
||||
#define PFI_FLAG_ALLMASK 0x0003
|
||||
.Ed
|
||||
.Pp
|
||||
If not empty,
|
||||
@ -966,61 +1009,45 @@ can be used to restrict the search to a specific interface or driver.
|
||||
is the user-supplied buffer for returning the data.
|
||||
On entry,
|
||||
.Va pfiio_size
|
||||
represents the number of
|
||||
.Va pfi_if
|
||||
contains the number of
|
||||
.Vt pfi_kif
|
||||
entries that can fit into the buffer.
|
||||
The kernel will replace this value by the real number of entries it wants
|
||||
to return.
|
||||
.Va pfiio_esize
|
||||
should be set to
|
||||
.Li sizeof(struct pfi_if) .
|
||||
.Va pfiio_flags
|
||||
should be set to
|
||||
.Dv PFI_FLAG_GROUP ,
|
||||
.Dv PFI_FLAG_INSTANCE ,
|
||||
or both, to tell the kernel to return a group of interfaces
|
||||
(drivers, like "fxp"), real interface instances (like "fxp1") or both.
|
||||
.Li sizeof(struct pfi_kif) .
|
||||
.Pp
|
||||
The data is returned in the
|
||||
.Vt pfi_if
|
||||
.Vt pfi_kif
|
||||
structure described below:
|
||||
.Bd -literal
|
||||
struct pfi_if {
|
||||
char pfif_name[IFNAMSIZ];
|
||||
u_int64_t pfif_packets[2][2][2];
|
||||
u_int64_t pfif_bytes[2][2][2];
|
||||
u_int64_t pfif_addcnt;
|
||||
u_int64_t pfif_delcnt;
|
||||
long pfif_tzero;
|
||||
int pfif_states;
|
||||
int pfif_rules;
|
||||
int pfif_flags;
|
||||
struct pfi_kif {
|
||||
RB_ENTRY(pfi_kif) pfik_tree;
|
||||
char pfik_name[IFNAMSIZ];
|
||||
u_int64_t pfik_packets[2][2][2];
|
||||
u_int64_t pfik_bytes[2][2][2];
|
||||
u_int32_t pfik_tzero;
|
||||
int pfik_flags;
|
||||
struct pf_state_tree_lan_ext pfik_lan_ext;
|
||||
struct pf_state_tree_ext_gwy pfik_ext_gwy;
|
||||
TAILQ_ENTRY(pfi_kif) pfik_w_states;
|
||||
void *pfik_ah_cookie;
|
||||
struct ifnet *pfik_ifp;
|
||||
struct ifg_group *pfik_group;
|
||||
int pfik_states;
|
||||
int pfik_rules;
|
||||
TAILQ_HEAD(, pfi_dynaddr) pfik_dynaddrs;
|
||||
};
|
||||
|
||||
#define PFI_IFLAG_GROUP 0x0001 /* group of interfaces */
|
||||
#define PFI_IFLAG_INSTANCE 0x0002 /* single instance */
|
||||
#define PFI_IFLAG_CLONABLE 0x0010 /* clonable group */
|
||||
#define PFI_IFLAG_DYNAMIC 0x0020 /* dynamic group */
|
||||
#define PFI_IFLAG_ATTACHED 0x0040 /* interface attached */
|
||||
.Ed
|
||||
.It Dv DIOCICLRISTATS Fa "struct pfioc_iface *io"
|
||||
Clear the statistics counters of one or more interfaces.
|
||||
.Va pfiio_name
|
||||
and
|
||||
.Va pfiio_flags
|
||||
can be used to select which interfaces need to be cleared.
|
||||
The filtering process is the same as for
|
||||
.Dv DIOCIGETIFACES .
|
||||
.Va pfiio_nzero
|
||||
will be set by the kernel to the number of interfaces and drivers
|
||||
that have been cleared.
|
||||
.It Dv DIOCSETIFFLAG Fa "struct pfioc_iface *io"
|
||||
Set the user setable flags (described below) of the pf internal interface
|
||||
description.
|
||||
Set the user setable flags (described above) of the
|
||||
.Nm
|
||||
internal interface description.
|
||||
The filtering process is the same as for
|
||||
.Dv DIOCIGETIFACES .
|
||||
.Bd -literal
|
||||
#define PFI_IFLAG_SKIP 0x0100 /* skip interface */
|
||||
#define PFI_IFLAG_SETABLE_MASK 0x0100 /* mask */
|
||||
#define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */
|
||||
.Ed
|
||||
.It Dv DIOCCLRIFFLAG Fa "struct pfioc_iface *io"
|
||||
Works as
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: pf.os.5,v 1.6 2004/03/31 11:13:03 dhartmei Exp $
|
||||
.\" $OpenBSD: pf.os.5,v 1.7 2005/11/16 20:07:18 stevesk Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org>
|
||||
.\"
|
||||
@ -204,37 +204,15 @@ The
|
||||
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
|
||||
03:13:48.118526 10.0.0.1.3377 > 10.0.0.2.80: S [tcp sum ok] \e
|
||||
534596083:534596083(0) win 57344 <mss 1460> (DF) [tos 0x10] \e
|
||||
(ttl 64, id 11315)
|
||||
(ttl 64, id 11315, len 44)
|
||||
.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 ,
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: pflog.4,v 1.7 2004/03/21 19:47:59 miod Exp $
|
||||
.\" $OpenBSD: pflog.4,v 1.9 2006/10/25 12:51:31 jmc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2001 Tobias Weingartner
|
||||
.\" All rights reserved.
|
||||
@ -45,6 +45,14 @@ on the
|
||||
interface, or stored to disk using
|
||||
.Xr pflogd 8 .
|
||||
.Pp
|
||||
The pflog0 interface is created automatically at boot if both
|
||||
.Xr pf 4
|
||||
and
|
||||
.Xr pflogd 8
|
||||
are enabled;
|
||||
further instances can be created using
|
||||
.Xr ifconfig 8 .
|
||||
.Pp
|
||||
Each packet retrieved on this interface has a header associated
|
||||
with it of length
|
||||
.Dv PFLOG_HDRLEN .
|
||||
@ -63,14 +71,22 @@ struct pfloghdr {
|
||||
char ruleset[PF_RULESET_NAME_SIZE];
|
||||
u_int32_t rulenr;
|
||||
u_int32_t subrulenr;
|
||||
uid_t uid;
|
||||
pid_t pid;
|
||||
uid_t rule_uid;
|
||||
pid_t rule_pid;
|
||||
u_int8_t dir;
|
||||
u_int8_t pad[3];
|
||||
};
|
||||
.Ed
|
||||
.Sh EXAMPLES
|
||||
Create a
|
||||
.Nm
|
||||
interface
|
||||
and monitor all packets logged on it:
|
||||
.Bd -literal -offset indent
|
||||
# ifconfig pflog0 up
|
||||
# tcpdump -n -e -ttt -i pflog0
|
||||
# ifconfig pflog1 up
|
||||
# tcpdump -n -e -ttt -i pflog1
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr inet 4 ,
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: pfsync.4,v 1.22 2005/02/24 15:53:17 jmc Exp $
|
||||
.\" $OpenBSD: pfsync.4,v 1.24 2006/10/23 07:05:49 jmc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2002 Michael Shalayeff
|
||||
.\" Copyright (c) 2003-2004 Ryan McBride
|
||||
@ -200,7 +200,7 @@ The following should be added to the top of
|
||||
.Pa /etc/pf.conf :
|
||||
.Bd -literal -offset indent
|
||||
pass quick on { sis2 } proto pfsync
|
||||
pass on { sis0 sis1 } proto carp keep state
|
||||
pass on { sis0 sis1 } proto carp
|
||||
.Ed
|
||||
.Pp
|
||||
If it is preferable that one firewall handle the traffic,
|
||||
@ -236,6 +236,7 @@ net.inet.carp.preempt=1
|
||||
.Xr pf.conf 5 ,
|
||||
.Xr protocols 5 ,
|
||||
.Xr ifconfig 8 ,
|
||||
.Xr ifstated 8 ,
|
||||
.Xr tcpdump 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pf_print_state.c,v 1.40 2004/12/10 22:13:26 henning Exp $ */
|
||||
/* $OpenBSD: pf_print_state.c,v 1.44 2007/03/01 17:20:53 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Daniel Hartmeier
|
||||
@ -96,6 +96,9 @@ print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose)
|
||||
case PF_ADDR_NOROUTE:
|
||||
printf("no-route");
|
||||
return;
|
||||
case PF_ADDR_URPFFAILED:
|
||||
printf("urpf-failed");
|
||||
return;
|
||||
case PF_ADDR_RTLABEL:
|
||||
printf("route \"%s\"", addr->v.rtlabelname);
|
||||
return;
|
||||
@ -274,7 +277,7 @@ print_state(struct pf_state *s, int opts)
|
||||
min = s->expire % 60;
|
||||
s->expire /= 60;
|
||||
printf(", expires in %.2u:%.2u:%.2u", s->expire, min, sec);
|
||||
printf(", %u:%u pkts, %u:%u bytes",
|
||||
printf(", %llu:%llu pkts, %llu:%llu bytes",
|
||||
s->packets[0], s->packets[1], s->bytes[0], s->bytes[1]);
|
||||
if (s->anchor.nr != -1)
|
||||
printf(", anchor %u", s->anchor.nr);
|
||||
@ -287,8 +290,9 @@ print_state(struct pf_state *s, int opts)
|
||||
printf("\n");
|
||||
}
|
||||
if (opts & PF_OPT_VERBOSE2) {
|
||||
printf(" id: %016llx creatorid: %08x\n",
|
||||
betoh64(s->id), ntohl(s->creatorid));
|
||||
printf(" id: %016llx creatorid: %08x%s\n",
|
||||
betoh64(s->id), ntohl(s->creatorid),
|
||||
((s->sync_flags & PFSTATE_NOSYNC) ? " (no-sync)" : ""));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: pfctl.8,v 1.118 2005/01/05 23:41:45 jmc Exp $
|
||||
.\" $OpenBSD: pfctl.8,v 1.128 2007/01/30 21:01:56 jmc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2001 Kjell Wooding. All rights reserved.
|
||||
.\"
|
||||
@ -33,23 +33,23 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm pfctl
|
||||
.Bk -words
|
||||
.Op Fl AdeghmNnOoqRrvz
|
||||
.Op Fl AdeghmNnOqRrvz
|
||||
.Op Fl a Ar anchor
|
||||
.Xo
|
||||
.Oo Fl D
|
||||
.Ar macro Ns = Ns Ar value Oc
|
||||
.Xc
|
||||
.Oo Fl D Ar macro Ns =
|
||||
.Ar value Oc
|
||||
.Op Fl F Ar modifier
|
||||
.Op Fl f Ar file
|
||||
.Op Fl i Ar interface
|
||||
.Op Fl k Ar host
|
||||
.Op Fl K Ar host | network
|
||||
.Op Fl k Ar host | network
|
||||
.Op Fl o Op Ar level
|
||||
.Op Fl p Ar device
|
||||
.Op Fl s Ar modifier
|
||||
.Oo Xo
|
||||
.Oo
|
||||
.Fl t Ar table
|
||||
.Fl T Ar command
|
||||
.Op Ar address ... Oc
|
||||
.Xc
|
||||
.Op Ar address ...
|
||||
.Oc
|
||||
.Op Fl x Ar level
|
||||
.Ek
|
||||
.Sh DESCRIPTION
|
||||
@ -138,8 +138,10 @@ rules from the main ruleset is described in
|
||||
For example, the following will show all filter rules (see the
|
||||
.Fl s
|
||||
flag below) inside the anchor
|
||||
.Li authpf/smith(1234) ,
|
||||
which would have been created for user smith by
|
||||
.Dq authpf/smith(1234) ,
|
||||
which would have been created for user
|
||||
.Dq smith
|
||||
by
|
||||
.Xr authpf 8 ,
|
||||
PID 1234:
|
||||
.Bd -literal -offset indent
|
||||
@ -161,6 +163,27 @@ This is similar to C rules for variable scope.
|
||||
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.
|
||||
.Pp
|
||||
By default, recursive inline printing of anchors applies only to unnamed
|
||||
anchors specified inline in the ruleset.
|
||||
If the anchor name is terminated with a
|
||||
.Sq *
|
||||
character, the
|
||||
.Fl s
|
||||
flag will recursively print all anchors in a brace delimited block.
|
||||
For example the following will print the
|
||||
.Dq authpf
|
||||
ruleset recursively:
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -a 'authpf/*' -sr
|
||||
.Ed
|
||||
.Pp
|
||||
To print the main ruleset recursively, specify only
|
||||
.Sq *
|
||||
as the anchor name:
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -a '*' -sr
|
||||
.Ed
|
||||
.It Fl D Ar macro Ns = Ns Ar value
|
||||
Define
|
||||
.Ar macro
|
||||
@ -215,29 +238,49 @@ Help.
|
||||
.It Fl i Ar interface
|
||||
Restrict the operation to the given
|
||||
.Ar interface .
|
||||
.It Fl k Ar host
|
||||
.It Fl K Ar host | network
|
||||
Kill all of the source tracking entries originating from the specified
|
||||
.Ar host
|
||||
or
|
||||
.Ar network .
|
||||
A second
|
||||
.Fl K Ar host
|
||||
or
|
||||
.Fl K Ar network
|
||||
option may be specified, which will kill all the source tracking
|
||||
entries from the first host/network to the second.
|
||||
.It Fl k Ar host | network
|
||||
Kill all of the state entries originating from the specified
|
||||
.Ar host .
|
||||
.Ar host
|
||||
or
|
||||
.Ar network .
|
||||
A second
|
||||
.Fl k Ar host
|
||||
or
|
||||
.Fl k Ar network
|
||||
option may be specified, which will kill all the state entries
|
||||
from the first
|
||||
.Ar host
|
||||
to the second
|
||||
.Ar host .
|
||||
from the first host/network to the second.
|
||||
For example, to kill all of the state entries originating from
|
||||
.Li host :
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -k host
|
||||
.Ed
|
||||
.Dq host :
|
||||
.Pp
|
||||
.Dl # pfctl -k host
|
||||
.Pp
|
||||
To kill all of the state entries from
|
||||
.Li host1
|
||||
.Dq host1
|
||||
to
|
||||
.Li host2 :
|
||||
.Bd -literal -offset indent
|
||||
# pfctl -k host1 -k host2
|
||||
.Ed
|
||||
.Dq host2 :
|
||||
.Pp
|
||||
.Dl # pfctl -k host1 -k host2
|
||||
.Pp
|
||||
To kill all states originating from 192.168.1.0/24 to 172.16.0.0/16:
|
||||
.Pp
|
||||
.Dl # pfctl -k 192.168.1.0/24 -k 172.16.0.0/16
|
||||
.Pp
|
||||
A network prefix length of 0 can be used as a wildcard.
|
||||
To kill all states with the target
|
||||
.Dq host2 :
|
||||
.Pp
|
||||
.Dl # pfctl -k 0.0.0.0/0 -k host2
|
||||
.It Fl m
|
||||
Merge in explicitly given options without resetting those
|
||||
which are omitted.
|
||||
@ -253,11 +296,22 @@ Do not actually load rules, just parse them.
|
||||
.It Fl O
|
||||
Load only the options present in the rule file.
|
||||
Other rules and options are ignored.
|
||||
.It Fl o
|
||||
Enable the ruleset optimizer.
|
||||
.It Fl o Op Ar level
|
||||
Control the ruleset optimizer.
|
||||
The ruleset optimizer attempts to improve rulesets by removing rule
|
||||
duplication and making better use of rule ordering.
|
||||
Specifically, it does four things:
|
||||
.Pp
|
||||
.Bl -tag -width xxxxxxxxxxxx -compact
|
||||
.It Fl o Cm none
|
||||
Disable the ruleset optimizer.
|
||||
.It Fl o Cm basic
|
||||
Enable basic ruleset optimizations.
|
||||
.It Fl o Cm profile
|
||||
Enable basic ruleset optimizations with profiling.
|
||||
.El
|
||||
.Pp
|
||||
.Cm basic
|
||||
optimization does does four things:
|
||||
.Pp
|
||||
.Bl -enum -compact
|
||||
.It
|
||||
@ -270,10 +324,10 @@ combine multiple rules into a table when advantageous
|
||||
re-order the rules to improve evaluation performance
|
||||
.El
|
||||
.Pp
|
||||
A second
|
||||
.Fl o
|
||||
may be specified to use the currently loaded ruleset as a feedback profile
|
||||
to tailor the optimization of the
|
||||
If
|
||||
.Cm profile
|
||||
is specified, the currently loaded ruleset will be examined as a feedback
|
||||
profile to tailor the optimization of the
|
||||
.Ar quick
|
||||
rules to the actual network behavior.
|
||||
.Pp
|
||||
@ -286,6 +340,14 @@ the ruleset optimizer should not be used or a
|
||||
.Ar label
|
||||
field should be added to all of the accounting rules to act as optimization
|
||||
barriers.
|
||||
.Pp
|
||||
To retain compatibility with previous behaviour, a single
|
||||
.Fl o
|
||||
without any options will enable
|
||||
.Cm basic
|
||||
optimizations, and a second
|
||||
.Fl o
|
||||
will enable profiling.
|
||||
.It Fl p Ar device
|
||||
Use the device file
|
||||
.Ar device
|
||||
@ -350,7 +412,8 @@ When used together with
|
||||
.Fl v ,
|
||||
source tracking statistics are also shown.
|
||||
.It Fl s Cm labels
|
||||
Show per-rule statistics (label, evaluations, packets, bytes) of
|
||||
Show per-rule statistics (label, evaluations, packets total, bytes total,
|
||||
packets in, bytes in, packets out, bytes out) of
|
||||
filter rules with labels, useful for accounting.
|
||||
.It Fl s Cm timeouts
|
||||
Show the current global timeouts.
|
||||
@ -362,8 +425,11 @@ Show the list of tables.
|
||||
Show the list of operating system fingerprints.
|
||||
.It Fl s Cm Interfaces
|
||||
Show the list of interfaces and interface drivers available to PF.
|
||||
When used together with a double
|
||||
When used together with
|
||||
.Fl v ,
|
||||
it additionally lists which interfaces have skip rules activated.
|
||||
When used together with
|
||||
.Fl vv ,
|
||||
interface statistics are also shown.
|
||||
.Fl i
|
||||
can be used to select an interface or a group of interfaces.
|
||||
@ -387,6 +453,13 @@ Add one or more addresses in a table.
|
||||
Automatically create a nonexisting table.
|
||||
.It Fl T Cm delete
|
||||
Delete one or more addresses from a table.
|
||||
.It Fl T Cm expire Ar number
|
||||
Delete addresses which had their statistics cleared more than
|
||||
.Ar number
|
||||
seconds ago.
|
||||
For entries which have never had their statistics cleared,
|
||||
.Ar number
|
||||
refers to the time they were added to the table.
|
||||
.It Fl T Cm replace
|
||||
Replace the addresses of the table.
|
||||
Automatically create a nonexisting table.
|
||||
@ -463,7 +536,7 @@ 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-
|
||||
pass out to <test>\en" | pfctl -f-
|
||||
# ping -qc10 ftp.openbsd.org
|
||||
.Ed
|
||||
.Pp
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pfctl.h,v 1.37 2005/01/05 18:23:10 mcbride Exp $ */
|
||||
/* $OpenBSD: pfctl.h,v 1.40 2007/02/09 11:25:27 henning Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Daniel Hartmeier
|
||||
@ -33,6 +33,8 @@
|
||||
#ifndef _PFCTL_H_
|
||||
#define _PFCTL_H_
|
||||
|
||||
enum pfctl_show { PFCTL_SHOW_RULES, PFCTL_SHOW_LABELS, PFCTL_SHOW_NOTHING };
|
||||
|
||||
enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS,
|
||||
PFRB_IFACES, PFRB_TRANS, PFRB_MAX };
|
||||
struct pfr_buffer {
|
||||
@ -73,7 +75,7 @@ int pfr_buf_grow(struct pfr_buffer *, int);
|
||||
int pfr_buf_load(struct pfr_buffer *, char *, int,
|
||||
int (*)(struct pfr_buffer *, char *, int));
|
||||
char *pfr_strerror(int);
|
||||
int pfi_get_ifaces(const char *, struct pfi_if *, int *, int);
|
||||
int pfi_get_ifaces(const char *, struct pfi_kif *, int *);
|
||||
int pfi_clr_istats(const char *, int *, int);
|
||||
|
||||
void pfctl_print_title(char *);
|
||||
@ -106,7 +108,6 @@ extern int loadopt;
|
||||
|
||||
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);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pfctl_altq.c,v 1.86 2005/02/28 14:04:51 henning Exp $ */
|
||||
/* $OpenBSD: pfctl_altq.c,v 1.91 2006/11/28 00:08:50 henning Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002
|
||||
@ -93,21 +93,6 @@ pfaltq_store(struct pf_altq *a)
|
||||
TAILQ_INSERT_TAIL(&altqs, altq, entries);
|
||||
}
|
||||
|
||||
void
|
||||
pfaltq_free(struct pf_altq *a)
|
||||
{
|
||||
struct pf_altq *altq;
|
||||
|
||||
TAILQ_FOREACH(altq, &altqs, entries) {
|
||||
if (strncmp(a->ifname, altq->ifname, IFNAMSIZ) == 0 &&
|
||||
strncmp(a->qname, altq->qname, PF_QNAME_SIZE) == 0) {
|
||||
TAILQ_REMOVE(&altqs, altq, entries);
|
||||
free(altq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct pf_altq *
|
||||
pfaltq_lookup(const char *ifname)
|
||||
{
|
||||
@ -157,7 +142,7 @@ print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw,
|
||||
struct node_queue_opt *qopts)
|
||||
{
|
||||
if (a->qname[0] != 0) {
|
||||
print_queue(a, level, bw, 0, qopts);
|
||||
print_queue(a, level, bw, 1, qopts);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -238,8 +223,8 @@ eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
|
||||
pa->ifbandwidth = bw->bw_absolute;
|
||||
else
|
||||
if ((rate = getifspeed(pa->ifname)) == 0) {
|
||||
fprintf(stderr, "cannot determine interface bandwidth "
|
||||
"for %s, specify an absolute bandwidth\n",
|
||||
fprintf(stderr, "interface %s does not know its bandwidth, "
|
||||
"please specify an absolute bandwidth\n",
|
||||
pa->ifname);
|
||||
errors++;
|
||||
} else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0)
|
||||
@ -490,10 +475,7 @@ cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa)
|
||||
maxidle = ptime * maxidle;
|
||||
else
|
||||
maxidle = ptime * maxidle_s;
|
||||
if (minburst)
|
||||
offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom);
|
||||
else
|
||||
offtime = cptime;
|
||||
minidle = -((double)opts->maxpktsize * (double)nsPerByte);
|
||||
|
||||
/* scale parameters */
|
||||
@ -698,8 +680,8 @@ eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
|
||||
}
|
||||
|
||||
if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) ||
|
||||
(opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) ||
|
||||
(opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0)) {
|
||||
(opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) ||
|
||||
(opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) {
|
||||
warnx("m1 must be zero for convex curve: %s", pa->qname);
|
||||
return (-1);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pfctl_optimize.c,v 1.5 2005/01/03 15:18:10 frantzen Exp $ */
|
||||
/* $OpenBSD: pfctl_optimize.c,v 1.13 2006/10/31 14:17:45 mcbride Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org>
|
||||
@ -109,6 +109,10 @@ struct pf_rule_field {
|
||||
PF_RULE_FIELD(prob, BARRIER),
|
||||
PF_RULE_FIELD(max_states, BARRIER),
|
||||
PF_RULE_FIELD(max_src_nodes, BARRIER),
|
||||
PF_RULE_FIELD(max_src_states, BARRIER),
|
||||
PF_RULE_FIELD(max_src_conn, BARRIER),
|
||||
PF_RULE_FIELD(max_src_conn_rate, BARRIER),
|
||||
PF_RULE_FIELD(anchor, BARRIER), /* for now */
|
||||
|
||||
/*
|
||||
* These fields must be the same between all rules in the same superblock.
|
||||
@ -120,10 +124,18 @@ struct pf_rule_field {
|
||||
PF_RULE_FIELD(tagname, BREAK),
|
||||
PF_RULE_FIELD(keep_state, BREAK),
|
||||
PF_RULE_FIELD(qname, BREAK),
|
||||
PF_RULE_FIELD(pqname, BREAK),
|
||||
PF_RULE_FIELD(rt, BREAK),
|
||||
PF_RULE_FIELD(allow_opts, BREAK),
|
||||
PF_RULE_FIELD(rule_flag, BREAK),
|
||||
PF_RULE_FIELD(action, BREAK),
|
||||
PF_RULE_FIELD(log, BREAK),
|
||||
PF_RULE_FIELD(quick, BREAK),
|
||||
PF_RULE_FIELD(return_ttl, BREAK),
|
||||
PF_RULE_FIELD(overload_tblname, BREAK),
|
||||
PF_RULE_FIELD(flush, BREAK),
|
||||
PF_RULE_FIELD(rpool, BREAK),
|
||||
PF_RULE_FIELD(logif, BREAK),
|
||||
|
||||
/*
|
||||
* Any fields not listed in this structure act as BREAK fields
|
||||
@ -137,7 +149,7 @@ struct pf_rule_field {
|
||||
*/
|
||||
PF_RULE_FIELD(af, NOMERGE),
|
||||
PF_RULE_FIELD(ifnot, NOMERGE),
|
||||
PF_RULE_FIELD(ifname, NOMERGE),
|
||||
PF_RULE_FIELD(ifname, NOMERGE), /* hack for IF groups */
|
||||
PF_RULE_FIELD(match_tag_not, NOMERGE),
|
||||
PF_RULE_FIELD(match_tagname, NOMERGE),
|
||||
PF_RULE_FIELD(os_fingerprint, NOMERGE),
|
||||
@ -170,7 +182,6 @@ struct pf_rule_field {
|
||||
PF_RULE_FIELD(packets, DC),
|
||||
PF_RULE_FIELD(bytes, DC),
|
||||
PF_RULE_FIELD(kif, DC),
|
||||
PF_RULE_FIELD(anchor, DC),
|
||||
PF_RULE_FIELD(states, DC),
|
||||
PF_RULE_FIELD(src_nodes, DC),
|
||||
PF_RULE_FIELD(nr, DC),
|
||||
@ -179,6 +190,9 @@ struct pf_rule_field {
|
||||
PF_RULE_FIELD(pqid, DC),
|
||||
PF_RULE_FIELD(anchor_relative, DC),
|
||||
PF_RULE_FIELD(anchor_wildcard, DC),
|
||||
PF_RULE_FIELD(tag, DC),
|
||||
PF_RULE_FIELD(match_tag, DC),
|
||||
PF_RULE_FIELD(overload_tbl, DC),
|
||||
|
||||
/* These fields should never be set in a PASS/BLOCK rule */
|
||||
PF_RULE_FIELD(natpass, NEVER),
|
||||
@ -198,6 +212,7 @@ void comparable_rule(struct pf_rule *, const struct pf_rule *, int);
|
||||
int construct_superblocks(struct pfctl *, struct pf_opt_queue *,
|
||||
struct superblocks *);
|
||||
void exclude_supersets(struct pf_rule *, struct pf_rule *);
|
||||
int interface_group(const char *);
|
||||
int load_feedback_profile(struct pfctl *, struct superblocks *);
|
||||
int optimize_superblock(struct pfctl *, struct superblock *);
|
||||
int pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *);
|
||||
@ -240,25 +255,52 @@ int table_identifier;
|
||||
|
||||
|
||||
int
|
||||
pfctl_optimize_rules(struct pfctl *pf)
|
||||
pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset *rs)
|
||||
{
|
||||
struct superblocks superblocks;
|
||||
struct pf_opt_queue opt_queue;
|
||||
struct superblock *block;
|
||||
struct pf_opt_rule *por;
|
||||
int nr;
|
||||
struct pf_rule *r;
|
||||
struct pf_rulequeue *old_rules;
|
||||
|
||||
DEBUG("optimizing ruleset");
|
||||
memset(&table_buffer, 0, sizeof(table_buffer));
|
||||
skip_init();
|
||||
TAILQ_INIT(&opt_queue);
|
||||
|
||||
if (TAILQ_FIRST(&pf->opt_queue))
|
||||
nr = TAILQ_FIRST(&pf->opt_queue)->por_rule.nr;
|
||||
old_rules = rs->rules[PF_RULESET_FILTER].active.ptr;
|
||||
rs->rules[PF_RULESET_FILTER].active.ptr =
|
||||
rs->rules[PF_RULESET_FILTER].inactive.ptr;
|
||||
rs->rules[PF_RULESET_FILTER].inactive.ptr = old_rules;
|
||||
|
||||
/*
|
||||
* XXX expanding the pf_opt_rule format throughout pfctl might allow
|
||||
* us to avoid all this copying.
|
||||
*/
|
||||
while ((r = TAILQ_FIRST(rs->rules[PF_RULESET_FILTER].inactive.ptr))
|
||||
!= NULL) {
|
||||
TAILQ_REMOVE(rs->rules[PF_RULESET_FILTER].inactive.ptr, r,
|
||||
entries);
|
||||
if ((por = calloc(1, sizeof(*por))) == NULL)
|
||||
err(1, "calloc");
|
||||
memcpy(&por->por_rule, r, sizeof(*r));
|
||||
if (TAILQ_FIRST(&r->rpool.list) != NULL) {
|
||||
TAILQ_INIT(&por->por_rule.rpool.list);
|
||||
pfctl_move_pool(&r->rpool, &por->por_rule.rpool);
|
||||
} else
|
||||
bzero(&por->por_rule.rpool,
|
||||
sizeof(por->por_rule.rpool));
|
||||
|
||||
|
||||
TAILQ_INSERT_TAIL(&opt_queue, por, por_entry);
|
||||
}
|
||||
|
||||
TAILQ_INIT(&superblocks);
|
||||
if (construct_superblocks(pf, &pf->opt_queue, &superblocks))
|
||||
if (construct_superblocks(pf, &opt_queue, &superblocks))
|
||||
goto error;
|
||||
|
||||
if (pf->opts & PF_OPT_OPTIMIZE_PROFILE) {
|
||||
if (pf->optimize & PF_OPTIMIZE_PROFILE) {
|
||||
if (load_feedback_profile(pf, &superblocks))
|
||||
goto error;
|
||||
}
|
||||
@ -268,24 +310,21 @@ pfctl_optimize_rules(struct pfctl *pf)
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Optimizations are done so we turn off the optimization flag and
|
||||
* put the rules right back into the regular codepath.
|
||||
*/
|
||||
pf->opts &= ~PF_OPT_OPTIMIZE;
|
||||
|
||||
rs->anchor->refcnt = 0;
|
||||
while ((block = TAILQ_FIRST(&superblocks))) {
|
||||
TAILQ_REMOVE(&superblocks, block, sb_entry);
|
||||
|
||||
while ((por = TAILQ_FIRST(&block->sb_rules))) {
|
||||
TAILQ_REMOVE(&block->sb_rules, por, por_entry);
|
||||
por->por_rule.nr = nr++;
|
||||
if (pfctl_add_rule(pf, &por->por_rule,
|
||||
por->por_anchor)) {
|
||||
free(por);
|
||||
goto error;
|
||||
}
|
||||
por->por_rule.nr = rs->anchor->refcnt++;
|
||||
if ((r = calloc(1, sizeof(*r))) == NULL)
|
||||
err(1, "calloc");
|
||||
memcpy(r, &por->por_rule, sizeof(*r));
|
||||
TAILQ_INIT(&r->rpool.list);
|
||||
pfctl_move_pool(&por->por_rule.rpool, &r->rpool);
|
||||
TAILQ_INSERT_TAIL(
|
||||
rs->rules[PF_RULESET_FILTER].active.ptr,
|
||||
r, entries);
|
||||
free(por);
|
||||
}
|
||||
free(block);
|
||||
@ -294,8 +333,8 @@ pfctl_optimize_rules(struct pfctl *pf)
|
||||
return (0);
|
||||
|
||||
error:
|
||||
while ((por = TAILQ_FIRST(&pf->opt_queue))) {
|
||||
TAILQ_REMOVE(&pf->opt_queue, por, por_entry);
|
||||
while ((por = TAILQ_FIRST(&opt_queue))) {
|
||||
TAILQ_REMOVE(&opt_queue, por, por_entry);
|
||||
if (por->por_src_tbl) {
|
||||
pfr_buf_clear(por->por_src_tbl->pt_buf);
|
||||
free(por->por_src_tbl->pt_buf);
|
||||
@ -364,7 +403,8 @@ optimize_superblock(struct pfctl *pf, struct superblock *block)
|
||||
printf("--- Superblock ---\n");
|
||||
TAILQ_FOREACH(por, &block->sb_rules, por_entry) {
|
||||
printf(" ");
|
||||
print_rule(&por->por_rule, por->por_anchor, 1);
|
||||
print_rule(&por->por_rule, por->por_rule.anchor ?
|
||||
por->por_rule.anchor->name : "", 1);
|
||||
}
|
||||
#endif /* OPT_DEBUG */
|
||||
|
||||
@ -373,7 +413,7 @@ optimize_superblock(struct pfctl *pf, struct superblock *block)
|
||||
return (1);
|
||||
if (combine_rules(pf, block))
|
||||
return (1);
|
||||
if ((pf->opts & PF_OPT_OPTIMIZE_PROFILE) &&
|
||||
if ((pf->optimize & PF_OPTIMIZE_PROFILE) &&
|
||||
TAILQ_FIRST(&block->sb_rules)->por_rule.quick &&
|
||||
block->sb_profiled_block) {
|
||||
if (block_feedback(pf, block))
|
||||
@ -780,14 +820,16 @@ block_feedback(struct pfctl *pf, struct superblock *block)
|
||||
*/
|
||||
TAILQ_FOREACH(por1, &block->sb_profiled_block->sb_rules, por_entry) {
|
||||
comparable_rule(&a, &por1->por_rule, DC);
|
||||
total_count += por1->por_rule.packets;
|
||||
total_count += por1->por_rule.packets[0] +
|
||||
por1->por_rule.packets[1];
|
||||
TAILQ_FOREACH(por2, &block->sb_rules, por_entry) {
|
||||
if (por2->por_profile_count)
|
||||
continue;
|
||||
comparable_rule(&b, &por2->por_rule, DC);
|
||||
if (memcmp(&a, &b, sizeof(a)) == 0) {
|
||||
por2->por_profile_count =
|
||||
por1->por_rule.packets;
|
||||
por1->por_rule.packets[0] +
|
||||
por1->por_rule.packets[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -851,6 +893,7 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
|
||||
|
||||
DEBUG("Loading %d active rules for a feedback profile", mnr);
|
||||
for (nr = 0; nr < mnr; ++nr) {
|
||||
struct pf_ruleset *rs;
|
||||
if ((por = calloc(1, sizeof(*por))) == NULL) {
|
||||
warn("calloc");
|
||||
return (1);
|
||||
@ -861,8 +904,8 @@ load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
|
||||
return (1);
|
||||
}
|
||||
memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule));
|
||||
strlcpy(por->por_anchor, pr.anchor_call,
|
||||
sizeof(por->por_anchor));
|
||||
rs = pf_find_or_create_ruleset(pr.anchor_call);
|
||||
por->por_rule.anchor = rs->anchor;
|
||||
if (TAILQ_EMPTY(&por->por_rule.rpool.list))
|
||||
memset(&por->por_rule.rpool, 0,
|
||||
sizeof(por->por_rule.rpool));
|
||||
@ -1045,6 +1088,7 @@ skip_cmp_dst_addr(struct pf_rule *a, struct pf_rule *b)
|
||||
return (1);
|
||||
return (0);
|
||||
case PF_ADDR_NOROUTE:
|
||||
case PF_ADDR_URPFFAILED:
|
||||
return (0);
|
||||
case PF_ADDR_TABLE:
|
||||
return (strcmp(a->dst.addr.v.tblname, b->dst.addr.v.tblname));
|
||||
@ -1116,6 +1160,7 @@ skip_cmp_src_addr(struct pf_rule *a, struct pf_rule *b)
|
||||
return (1);
|
||||
return (0);
|
||||
case PF_ADDR_NOROUTE:
|
||||
case PF_ADDR_URPFFAILED:
|
||||
return (0);
|
||||
case PF_ADDR_TABLE:
|
||||
return (strcmp(a->src.addr.v.tblname, b->src.addr.v.tblname));
|
||||
@ -1267,8 +1312,8 @@ pf_opt_create_table(struct pfctl *pf, struct pf_opt_tbl *tbl)
|
||||
tablenum++;
|
||||
|
||||
|
||||
if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, pf->anchor,
|
||||
tbl->pt_buf, pf->tticket)) {
|
||||
if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1,
|
||||
pf->anchor->name, tbl->pt_buf, pf->anchor->ruleset.tticket)) {
|
||||
warn("failed to create table %s", tbl->pt_name);
|
||||
return (1);
|
||||
}
|
||||
@ -1367,15 +1412,34 @@ superblock_inclusive(struct superblock *block, struct pf_opt_rule *por)
|
||||
}
|
||||
}
|
||||
|
||||
/* 'anchor' heads and per-rule src-track are also hard breaks */
|
||||
if (por->por_anchor[0] != '\0' ||
|
||||
(por->por_rule.rule_flag & PFRULE_RULESRCTRACK))
|
||||
/* per-rule src-track is also a hard break */
|
||||
if (por->por_rule.rule_flag & PFRULE_RULESRCTRACK)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Have to handle interface groups seperately. Consider the following
|
||||
* rules:
|
||||
* block on EXTIFS to any port 22
|
||||
* pass on em0 to any port 22
|
||||
* (where EXTIFS is an arbitrary interface group)
|
||||
* The optimizer may decide to re-order the pass rule in front of the
|
||||
* block rule. But what if EXTIFS includes em0??? Such a reordering
|
||||
* would change the meaning of the ruleset.
|
||||
* We can't just lookup the EXTIFS group and check if em0 is a member
|
||||
* because the user is allowed to add interfaces to a group during
|
||||
* runtime.
|
||||
* Ergo interface groups become a defacto superblock break :-(
|
||||
*/
|
||||
if (interface_group(por->por_rule.ifname) ||
|
||||
interface_group(TAILQ_FIRST(&block->sb_rules)->por_rule.ifname)) {
|
||||
if (strcasecmp(por->por_rule.ifname,
|
||||
TAILQ_FIRST(&block->sb_rules)->por_rule.ifname) != 0)
|
||||
return (0);
|
||||
}
|
||||
|
||||
comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE);
|
||||
comparable_rule(&b, &por->por_rule, NOMERGE);
|
||||
if (strcmp(TAILQ_FIRST(&block->sb_rules)->por_anchor,
|
||||
por->por_anchor) == 0 && memcmp(&a, &b, sizeof(a)) == 0)
|
||||
if (memcmp(&a, &b, sizeof(a)) == 0)
|
||||
return (1);
|
||||
|
||||
#ifdef OPT_DEBUG
|
||||
@ -1418,6 +1482,24 @@ superblock_inclusive(struct superblock *block, struct pf_opt_rule *por)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Figure out if an interface name is an actual interface or actually a
|
||||
* group of interfaces.
|
||||
*/
|
||||
int
|
||||
interface_group(const char *ifname)
|
||||
{
|
||||
if (ifname == NULL || !ifname[0])
|
||||
return (0);
|
||||
|
||||
/* Real interfaces must end in a number, interface groups do not */
|
||||
if (isdigit(ifname[strlen(ifname) - 1]))
|
||||
return (0);
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Make a rule that can directly compared by memcmp()
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pfctl_osfp.c,v 1.12 2005/02/17 13:18:00 aaron Exp $ */
|
||||
/* $OpenBSD: pfctl_osfp.c,v 1.15 2006/12/13 05:10:15 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.org>
|
||||
@ -23,6 +23,10 @@
|
||||
#include <net/if.h>
|
||||
#include <net/pfvar.h>
|
||||
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
@ -240,6 +244,10 @@ pfctl_file_fingerprints(int dev, int opts, const char *fp_filename)
|
||||
sizeof(fp.fp_os.fp_subtype_nm));
|
||||
|
||||
add_fingerprint(dev, opts, &fp);
|
||||
|
||||
fp.fp_flags |= (PF_OSFP_DF | PF_OSFP_INET6);
|
||||
fp.fp_psize += sizeof(struct ip6_hdr) - sizeof(struct ip);
|
||||
add_fingerprint(dev, opts, &fp);
|
||||
}
|
||||
|
||||
if (class)
|
||||
@ -250,6 +258,8 @@ pfctl_file_fingerprints(int dev, int opts, const char *fp_filename)
|
||||
free(subtype);
|
||||
if (desc)
|
||||
free(desc);
|
||||
if (tcpopts)
|
||||
free(tcpopts);
|
||||
|
||||
fclose(in);
|
||||
|
||||
@ -762,7 +772,6 @@ sort_name_list(int opts, struct name_list *nml)
|
||||
LIST_INSERT_AFTER(nmlast, nm, nm_entry);
|
||||
nmlast = nm;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse the next integer in a formatted config file line */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pfctl_parser.c,v 1.211 2004/12/07 10:33:41 dhartmei Exp $ */
|
||||
/* $OpenBSD: pfctl_parser.c,v 1.234 2006/10/31 23:46:24 mcbride Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Daniel Hartmeier
|
||||
@ -54,6 +54,7 @@
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pfctl_parser.h"
|
||||
#include "pfctl.h"
|
||||
@ -66,6 +67,7 @@ void print_fromto(struct pf_rule_addr *, pf_osfp_t,
|
||||
struct pf_rule_addr *, u_int8_t, u_int8_t, int);
|
||||
int ifa_skip_if(const char *filter, struct node_host *p);
|
||||
|
||||
struct node_host *ifa_grouplookup(const char *, int);
|
||||
struct node_host *host_if(const char *, int);
|
||||
struct node_host *host_v4(const char *, int);
|
||||
struct node_host *host_v6(const char *, int);
|
||||
@ -482,6 +484,8 @@ print_status(struct pf_status *s, int opts)
|
||||
char statline[80], *running;
|
||||
time_t runtime;
|
||||
int i;
|
||||
char buf[PF_MD5_DIGEST_LENGTH * 2 + 1];
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
|
||||
runtime = time(NULL) - s->since;
|
||||
running = s->running ? "Enabled" : "Disabled";
|
||||
@ -515,7 +519,18 @@ print_status(struct pf_status *s, int opts)
|
||||
printf("%15s\n\n", "Debug: Loud");
|
||||
break;
|
||||
}
|
||||
printf("Hostid: 0x%08x\n\n", ntohl(s->hostid));
|
||||
|
||||
if (opts & PF_OPT_VERBOSE) {
|
||||
printf("Hostid: 0x%08x\n", ntohl(s->hostid));
|
||||
|
||||
for (i = 0; i < PF_MD5_DIGEST_LENGTH; i++) {
|
||||
buf[i + i] = hex[s->pf_chksum[i] >> 4];
|
||||
buf[i + i + 1] = hex[s->pf_chksum[i] & 0x0f];
|
||||
}
|
||||
buf[i + i] = '\0';
|
||||
printf("Checksum: 0x%s\n\n", buf);
|
||||
}
|
||||
|
||||
if (s->ifname[0] != 0) {
|
||||
printf("Interface Stats for %-16s %5s %16s\n",
|
||||
s->ifname, "IPv4", "IPv6");
|
||||
@ -623,7 +638,9 @@ print_src_node(struct pf_src_node *sn, int opts)
|
||||
printf(", expires in %.2u:%.2u:%.2u",
|
||||
sn->expire, min, sec);
|
||||
}
|
||||
printf(", %u pkts, %u bytes", sn->packets, sn->bytes);
|
||||
printf(", %llu pkts, %llu bytes",
|
||||
sn->packets[0] + sn->packets[1],
|
||||
sn->bytes[0] + sn->bytes[1]);
|
||||
switch (sn->ruletype) {
|
||||
case PF_NAT:
|
||||
if (sn->rule.nr != -1)
|
||||
@ -656,10 +673,13 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
|
||||
printf("@%d ", r->nr);
|
||||
if (r->action > PF_NORDR)
|
||||
printf("action(%d)", r->action);
|
||||
else if (anchor_call[0])
|
||||
else if (anchor_call[0]) {
|
||||
if (anchor_call[0] == '_') {
|
||||
printf("%s", anchortypes[r->action]);
|
||||
} else
|
||||
printf("%s \"%s\"", anchortypes[r->action],
|
||||
anchor_call);
|
||||
else {
|
||||
} else {
|
||||
printf("%s", actiontypes[r->action]);
|
||||
if (r->natpass)
|
||||
printf(" pass");
|
||||
@ -714,10 +734,22 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
|
||||
printf(" in");
|
||||
else if (r->direction == PF_OUT)
|
||||
printf(" out");
|
||||
if (r->log == 1)
|
||||
if (r->log) {
|
||||
printf(" log");
|
||||
else if (r->log == 2)
|
||||
printf(" log-all");
|
||||
if (r->log & ~PF_LOG || r->logif) {
|
||||
int count = 0;
|
||||
|
||||
printf(" (");
|
||||
if (r->log & PF_LOG_ALL)
|
||||
printf("%sall", count++ ? ", " : "");
|
||||
if (r->log & PF_LOG_SOCKET_LOOKUP)
|
||||
printf("%suser", count++ ? ", " : "");
|
||||
if (r->logif)
|
||||
printf("%sto pflog%u", count++ ? ", " : "",
|
||||
r->logif);
|
||||
printf(")");
|
||||
}
|
||||
}
|
||||
if (r->quick)
|
||||
printf(" quick");
|
||||
if (r->ifname[0]) {
|
||||
@ -767,7 +799,11 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
|
||||
print_flags(r->flags);
|
||||
printf("/");
|
||||
print_flags(r->flagset);
|
||||
}
|
||||
} else if (r->action == PF_PASS &&
|
||||
(!r->proto || r->proto == IPPROTO_TCP) &&
|
||||
!(r->rule_flag & PFRULE_FRAGMENT) &&
|
||||
!anchor_call[0] && r->keep_state)
|
||||
printf(" flags any");
|
||||
if (r->type) {
|
||||
const struct icmptypeent *it;
|
||||
|
||||
@ -792,7 +828,9 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
|
||||
}
|
||||
if (r->tos)
|
||||
printf(" tos 0x%2.2x", r->tos);
|
||||
if (r->keep_state == PF_STATE_NORMAL)
|
||||
if (!r->keep_state && r->action == PF_PASS && !anchor_call[0])
|
||||
printf(" no state");
|
||||
else if (r->keep_state == PF_STATE_NORMAL)
|
||||
printf(" keep state");
|
||||
else if (r->keep_state == PF_STATE_MODULATE)
|
||||
printf(" modulate state");
|
||||
@ -820,7 +858,7 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
|
||||
opts = 1;
|
||||
if (r->rule_flag & PFRULE_SRCTRACK)
|
||||
opts = 1;
|
||||
if (r->rule_flag & (PFRULE_IFBOUND | PFRULE_GRBOUND))
|
||||
if (r->rule_flag & PFRULE_IFBOUND)
|
||||
opts = 1;
|
||||
for (i = 0; !opts && i < PFTM_MAX; ++i)
|
||||
if (r->timeout[i])
|
||||
@ -888,12 +926,6 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
|
||||
printf("if-bound");
|
||||
opts = 0;
|
||||
}
|
||||
if (r->rule_flag & PFRULE_GRBOUND) {
|
||||
if (!opts)
|
||||
printf(", ");
|
||||
printf("group-bound");
|
||||
opts = 0;
|
||||
}
|
||||
for (i = 0; i < PFTM_MAX; ++i)
|
||||
if (r->timeout[i]) {
|
||||
int j;
|
||||
@ -901,12 +933,13 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
|
||||
if (!opts)
|
||||
printf(", ");
|
||||
opts = 0;
|
||||
for (j = 0; j < sizeof(pf_timeouts) /
|
||||
sizeof(pf_timeouts[0]); ++j)
|
||||
for (j = 0; pf_timeouts[j].name != NULL;
|
||||
++j)
|
||||
if (pf_timeouts[j].timeout == i)
|
||||
break;
|
||||
printf("%s %u", j == PFTM_MAX ? "inv.timeout" :
|
||||
pf_timeouts[j].name, r->timeout[i]);
|
||||
printf("%s %u", pf_timeouts[j].name == NULL ?
|
||||
"inv.timeout" : pf_timeouts[j].name,
|
||||
r->timeout[i]);
|
||||
}
|
||||
printf(")");
|
||||
}
|
||||
@ -946,13 +979,14 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
|
||||
printf(" !");
|
||||
printf(" tagged %s", r->match_tagname);
|
||||
}
|
||||
if (r->rtableid != -1)
|
||||
printf(" rtable %u", r->rtableid);
|
||||
if (!anchor_call[0] && (r->action == PF_NAT ||
|
||||
r->action == PF_BINAT || r->action == PF_RDR)) {
|
||||
printf(" -> ");
|
||||
print_pool(&r->rpool, r->rpool.proxy_port[0],
|
||||
r->rpool.proxy_port[1], r->af, r->action);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
@ -1145,13 +1179,31 @@ ifa_load(void)
|
||||
}
|
||||
|
||||
struct node_host *
|
||||
ifa_exists(const char *ifa_name, int group_ok)
|
||||
ifa_exists(const char *ifa_name)
|
||||
{
|
||||
struct node_host *n;
|
||||
struct ifgroupreq ifgr;
|
||||
int s;
|
||||
|
||||
if (iftab == NULL)
|
||||
ifa_load();
|
||||
|
||||
/* check wether this is a group */
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
err(1, "socket");
|
||||
bzero(&ifgr, sizeof(ifgr));
|
||||
strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
|
||||
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == 0) {
|
||||
/* fake a node_host */
|
||||
if ((n = calloc(1, sizeof(*n))) == NULL)
|
||||
err(1, "calloc");
|
||||
if ((n->ifname = strdup(ifa_name)) == NULL)
|
||||
err(1, "strdup");
|
||||
close(s);
|
||||
return (n);
|
||||
}
|
||||
close(s);
|
||||
|
||||
for (n = iftab; n; n = n->next) {
|
||||
if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
|
||||
return (n);
|
||||
@ -1160,6 +1212,47 @@ ifa_exists(const char *ifa_name, int group_ok)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct node_host *
|
||||
ifa_grouplookup(const char *ifa_name, int flags)
|
||||
{
|
||||
struct ifg_req *ifg;
|
||||
struct ifgroupreq ifgr;
|
||||
int s, len;
|
||||
struct node_host *n, *h = NULL;
|
||||
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
err(1, "socket");
|
||||
bzero(&ifgr, sizeof(ifgr));
|
||||
strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
|
||||
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
|
||||
close(s);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
len = ifgr.ifgr_len;
|
||||
if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
|
||||
err(1, "calloc");
|
||||
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
|
||||
err(1, "SIOCGIFGMEMB");
|
||||
|
||||
for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
|
||||
ifg++) {
|
||||
len -= sizeof(struct ifg_req);
|
||||
if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL)
|
||||
continue;
|
||||
if (h == NULL)
|
||||
h = n;
|
||||
else {
|
||||
h->tail->next = n;
|
||||
h->tail = n->tail;
|
||||
}
|
||||
}
|
||||
free(ifgr.ifgr_groups);
|
||||
close(s);
|
||||
|
||||
return (h);
|
||||
}
|
||||
|
||||
struct node_host *
|
||||
ifa_lookup(const char *ifa_name, int flags)
|
||||
{
|
||||
@ -1167,6 +1260,9 @@ ifa_lookup(const char *ifa_name, int flags)
|
||||
int got4 = 0, got6 = 0;
|
||||
const char *last_if = NULL;
|
||||
|
||||
if ((h = ifa_grouplookup(ifa_name, flags)) != NULL)
|
||||
return (h);
|
||||
|
||||
if (!strncmp(ifa_name, "self", IFNAMSIZ))
|
||||
ifa_name = NULL;
|
||||
|
||||
@ -1344,7 +1440,7 @@ host_if(const char *s, int mask)
|
||||
free(ps);
|
||||
return (NULL);
|
||||
}
|
||||
if (ifa_exists(ps, 1) || !strncmp(ps, "self", IFNAMSIZ)) {
|
||||
if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) {
|
||||
/* interface with this name exists */
|
||||
h = ifa_lookup(ps, flags);
|
||||
for (n = h; n != NULL && mask > -1; n = n->next)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pfctl_parser.h,v 1.80 2005/02/07 18:18:14 david Exp $ */
|
||||
/* $OpenBSD: pfctl_parser.h,v 1.86 2006/10/31 23:46:25 mcbride Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Daniel Hartmeier
|
||||
@ -47,14 +47,17 @@
|
||||
#define PF_OPT_DEBUG 0x0200
|
||||
#define PF_OPT_SHOWALL 0x0400
|
||||
#define PF_OPT_OPTIMIZE 0x0800
|
||||
#define PF_OPT_OPTIMIZE_PROFILE 0x1000
|
||||
#define PF_OPT_MERGE 0x2000
|
||||
#define PF_OPT_RECURSE 0x4000
|
||||
|
||||
#define PF_TH_ALL 0xFF
|
||||
|
||||
#define PF_NAT_PROXY_PORT_LOW 50001
|
||||
#define PF_NAT_PROXY_PORT_HIGH 65535
|
||||
|
||||
#define PF_OPTIMIZE_BASIC 0x0001
|
||||
#define PF_OPTIMIZE_PROFILE 0x0002
|
||||
|
||||
#define FCNT_NAMES { \
|
||||
"searches", \
|
||||
"inserts", \
|
||||
@ -63,24 +66,25 @@
|
||||
}
|
||||
|
||||
struct pfr_buffer; /* forward definition */
|
||||
struct pf_opt_rule;
|
||||
TAILQ_HEAD(pf_opt_queue, pf_opt_rule);
|
||||
|
||||
|
||||
struct pfctl {
|
||||
int dev;
|
||||
int opts;
|
||||
int optimize;
|
||||
int loadopt;
|
||||
u_int32_t tticket; /* table ticket */
|
||||
int asd; /* anchor stack depth */
|
||||
int bn; /* brace number */
|
||||
int brace;
|
||||
int tdirty; /* kernel dirty */
|
||||
u_int32_t rule_nr;
|
||||
#define PFCTL_ANCHOR_STACK_DEPTH 64
|
||||
struct pf_anchor *astack[PFCTL_ANCHOR_STACK_DEPTH];
|
||||
struct pfioc_pooladdr paddr;
|
||||
struct pfioc_altq *paltq;
|
||||
struct pfioc_queue *pqueue;
|
||||
struct pfr_buffer *trans;
|
||||
const char *anchor;
|
||||
struct pf_anchor *anchor, *alast;
|
||||
const char *ruleset;
|
||||
struct pf_opt_queue opt_queue;
|
||||
|
||||
/* 'set foo' options */
|
||||
u_int32_t timeout[PFTM_MAX];
|
||||
@ -117,10 +121,6 @@ struct node_host {
|
||||
struct node_host *next;
|
||||
struct node_host *tail;
|
||||
};
|
||||
/* special flags used by ifa_exists */
|
||||
#define PF_IFA_FLAG_GROUP 0x10000
|
||||
#define PF_IFA_FLAG_DYNAMIC 0x20000
|
||||
#define PF_IFA_FLAG_CLONABLE 0x40000
|
||||
|
||||
struct node_os {
|
||||
char *os;
|
||||
@ -180,19 +180,20 @@ struct pf_opt_rule {
|
||||
struct pf_rule por_rule;
|
||||
struct pf_opt_tbl *por_src_tbl;
|
||||
struct pf_opt_tbl *por_dst_tbl;
|
||||
char por_anchor[MAXPATHLEN];
|
||||
u_int64_t por_profile_count;
|
||||
TAILQ_ENTRY(pf_opt_rule) por_entry;
|
||||
TAILQ_ENTRY(pf_opt_rule) por_skip_entry[PF_SKIP_COUNT];
|
||||
};
|
||||
|
||||
TAILQ_HEAD(pf_opt_queue, pf_opt_rule);
|
||||
|
||||
int pfctl_rules(int, char *, int, char *, struct pfr_buffer *);
|
||||
int pfctl_optimize_rules(struct pfctl *);
|
||||
int pfctl_rules(int, char *, FILE *, int, int, char *, struct pfr_buffer *);
|
||||
int pfctl_optimize_ruleset(struct pfctl *, struct pf_ruleset *);
|
||||
|
||||
int pfctl_add_rule(struct pfctl *, struct pf_rule *, const char *);
|
||||
int pfctl_add_altq(struct pfctl *, struct pf_altq *);
|
||||
int pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t);
|
||||
void pfctl_move_pool(struct pf_pool *, struct pf_pool *);
|
||||
void pfctl_clear_pool(struct pf_pool *);
|
||||
|
||||
int pfctl_set_timeout(struct pfctl *, const char *, int, int);
|
||||
@ -205,7 +206,7 @@ int pfctl_set_interface_flags(struct pfctl *, char *, int, int);
|
||||
|
||||
int parse_rules(FILE *, struct pfctl *);
|
||||
int parse_flags(char *);
|
||||
int pfctl_load_anchors(int, int, struct pfr_buffer *);
|
||||
int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *);
|
||||
|
||||
void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int);
|
||||
void print_src_node(struct pf_src_node *, int);
|
||||
@ -267,7 +268,7 @@ void set_ipmask(struct node_host *, u_int8_t);
|
||||
int check_netmask(struct node_host *, sa_family_t);
|
||||
int unmask(struct pf_addr *, sa_family_t);
|
||||
void ifa_load(void);
|
||||
struct node_host *ifa_exists(const char *, int);
|
||||
struct node_host *ifa_exists(const char *);
|
||||
struct node_host *ifa_lookup(const char *, int);
|
||||
struct node_host *host(const char *);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pfctl_radix.c,v 1.26 2004/06/14 20:44:22 cedric Exp $ */
|
||||
/* $OpenBSD: pfctl_radix.c,v 1.27 2005/05/21 21:03:58 henning Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Cedric Berger
|
||||
@ -421,7 +421,7 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
|
||||
/* interface management code */
|
||||
|
||||
int
|
||||
pfi_get_ifaces(const char *filter, struct pfi_if *buf, int *size, int flags)
|
||||
pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
|
||||
{
|
||||
struct pfioc_iface io;
|
||||
|
||||
@ -430,7 +430,6 @@ pfi_get_ifaces(const char *filter, struct pfi_if *buf, int *size, int flags)
|
||||
return (-1);
|
||||
}
|
||||
bzero(&io, sizeof io);
|
||||
io.pfiio_flags = flags;
|
||||
if (filter != NULL)
|
||||
if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
|
||||
sizeof(io.pfiio_name)) {
|
||||
@ -451,7 +450,7 @@ pfi_get_ifaces(const char *filter, struct pfi_if *buf, int *size, int flags)
|
||||
size_t buf_esize[PFRB_MAX] = { 0,
|
||||
sizeof(struct pfr_table), sizeof(struct pfr_tstats),
|
||||
sizeof(struct pfr_addr), sizeof(struct pfr_astats),
|
||||
sizeof(struct pfi_if), sizeof(struct pfioc_trans_e)
|
||||
sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pfctl_table.c,v 1.62 2004/12/22 17:17:55 dhartmei Exp $ */
|
||||
/* $OpenBSD: pfctl_table.c,v 1.66 2007/03/01 17:20:54 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002 Cedric Berger
|
||||
@ -61,8 +61,7 @@ static void print_addrx(struct pfr_addr *, struct pfr_addr *, int);
|
||||
static void print_astats(struct pfr_astats *, int);
|
||||
static void radix_perror(void);
|
||||
static void xprintf(int, const char *, ...);
|
||||
static void print_iface(struct pfi_if *, int);
|
||||
static void oprintf(int, int, const char *, int *, int);
|
||||
static void print_iface(struct pfi_kif *, int);
|
||||
|
||||
static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = {
|
||||
{ "In/Block:", "In/Pass:", "In/XPass:" },
|
||||
@ -175,7 +174,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
|
||||
break;
|
||||
}
|
||||
|
||||
if (opts & PF_OPT_SHOWALL && b.pfrb_size > 0)
|
||||
if ((opts & PF_OPT_SHOWALL) && b.pfrb_size > 0)
|
||||
pfctl_print_title("TABLES:");
|
||||
|
||||
PFRB_FOREACH(p, &b)
|
||||
@ -254,6 +253,42 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
|
||||
if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
|
||||
print_addrx(a, NULL,
|
||||
opts & PF_OPT_USEDNS);
|
||||
} else if (!strcmp(command, "expire")) {
|
||||
const char *errstr;
|
||||
u_int lifetime;
|
||||
|
||||
b.pfrb_type = PFRB_ASTATS;
|
||||
b2.pfrb_type = PFRB_ADDRS;
|
||||
if (argc != 1 || file != NULL)
|
||||
usage();
|
||||
lifetime = strtonum(*argv, 0, UINT_MAX, &errstr);
|
||||
if (errstr)
|
||||
errx(1, "expiry time: %s", errstr);
|
||||
for (;;) {
|
||||
pfr_buf_grow(&b, b.pfrb_size);
|
||||
b.pfrb_size = b.pfrb_msize;
|
||||
RVTEST(pfr_get_astats(&table, b.pfrb_caddr,
|
||||
&b.pfrb_size, flags));
|
||||
if (b.pfrb_size <= b.pfrb_msize)
|
||||
break;
|
||||
}
|
||||
PFRB_FOREACH(p, &b)
|
||||
if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero >
|
||||
lifetime)
|
||||
if (pfr_buf_add(&b2,
|
||||
&((struct pfr_astats *)p)->pfras_a))
|
||||
err(1, "duplicate buffer");
|
||||
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
flags |= PFR_FLAG_FEEDBACK;
|
||||
RVTEST(pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size,
|
||||
&ndel, flags));
|
||||
xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size);
|
||||
if (opts & PF_OPT_VERBOSE)
|
||||
PFRB_FOREACH(a, &b2)
|
||||
if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
|
||||
print_addrx(a, NULL,
|
||||
opts & PF_OPT_USEDNS);
|
||||
} else if (!strcmp(command, "show")) {
|
||||
b.pfrb_type = (opts & PF_OPT_VERBOSE) ?
|
||||
PFRB_ASTATS : PFRB_ADDRS;
|
||||
@ -291,7 +326,7 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command,
|
||||
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))
|
||||
if ((opts & PF_OPT_VERBOSE) && !(opts & PF_OPT_VERBOSE2))
|
||||
PFRB_FOREACH(a, &b)
|
||||
if (a->pfra_fback == PFR_FB_MATCH)
|
||||
print_addrx(a, NULL,
|
||||
@ -539,17 +574,15 @@ int
|
||||
pfctl_show_ifaces(const char *filter, int opts)
|
||||
{
|
||||
struct pfr_buffer b;
|
||||
struct pfi_if *p;
|
||||
int i = 0, f = PFI_FLAG_GROUP|PFI_FLAG_INSTANCE;
|
||||
struct pfi_kif *p;
|
||||
int i = 0;
|
||||
|
||||
if (filter != NULL && *filter && !isdigit(filter[strlen(filter)-1]))
|
||||
f &= ~PFI_FLAG_INSTANCE;
|
||||
bzero(&b, sizeof(b));
|
||||
b.pfrb_type = PFRB_IFACES;
|
||||
for (;;) {
|
||||
pfr_buf_grow(&b, b.pfrb_size);
|
||||
b.pfrb_size = b.pfrb_msize;
|
||||
if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size, f)) {
|
||||
if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) {
|
||||
radix_perror();
|
||||
return (1);
|
||||
}
|
||||
@ -565,46 +598,30 @@ pfctl_show_ifaces(const char *filter, int opts)
|
||||
}
|
||||
|
||||
void
|
||||
print_iface(struct pfi_if *p, int opts)
|
||||
print_iface(struct pfi_kif *p, int opts)
|
||||
{
|
||||
time_t tzero = p->pfif_tzero;
|
||||
int flags = (opts & PF_OPT_VERBOSE) ? p->pfif_flags : 0;
|
||||
int first = 1;
|
||||
time_t tzero = p->pfik_tzero;
|
||||
int i, af, dir, act;
|
||||
|
||||
printf("%s", p->pfif_name);
|
||||
oprintf(flags, PFI_IFLAG_INSTANCE, "instance", &first, 0);
|
||||
oprintf(flags, PFI_IFLAG_GROUP, "group", &first, 0);
|
||||
oprintf(flags, PFI_IFLAG_CLONABLE, "clonable", &first, 0);
|
||||
oprintf(flags, PFI_IFLAG_DYNAMIC, "dynamic", &first, 0);
|
||||
oprintf(flags, PFI_IFLAG_ATTACHED, "attached", &first, 0);
|
||||
oprintf(flags, PFI_IFLAG_SKIP, "skipped", &first, 1);
|
||||
printf("%s", p->pfik_name);
|
||||
if (opts & PF_OPT_VERBOSE) {
|
||||
if (p->pfik_flags & PFI_IFLAG_SKIP)
|
||||
printf(" (skip)");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (!(opts & PF_OPT_VERBOSE2))
|
||||
return;
|
||||
printf("\tCleared: %s", ctime(&tzero));
|
||||
printf("\tReferences: [ States: %-18d Rules: %-18d ]\n",
|
||||
p->pfif_states, p->pfif_rules);
|
||||
p->pfik_states, p->pfik_rules);
|
||||
for (i = 0; i < 8; i++) {
|
||||
af = (i>>2) & 1;
|
||||
dir = (i>>1) &1;
|
||||
act = i & 1;
|
||||
printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
|
||||
istats_text[af][dir][act],
|
||||
(unsigned long long)p->pfif_packets[af][dir][act],
|
||||
(unsigned long long)p->pfif_bytes[af][dir][act]);
|
||||
(unsigned long long)p->pfik_packets[af][dir][act],
|
||||
(unsigned long long)p->pfik_bytes[af][dir][act]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
oprintf(int flags, int flag, const char *s, int *first, int last)
|
||||
{
|
||||
if (flags & flag) {
|
||||
printf(*first ? "\t(%s" : ", %s", s);
|
||||
*first = 0;
|
||||
}
|
||||
if (last && !*first)
|
||||
printf(")");
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: pflogd.8,v 1.25 2005/01/02 18:15:02 jmc Exp $
|
||||
.\" $OpenBSD: pflogd.8,v 1.32 2006/12/08 10:26:38 joel Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2001 Can Erkin Acar. All rights reserved.
|
||||
.\"
|
||||
@ -35,14 +35,17 @@
|
||||
.Op Fl Dx
|
||||
.Op Fl d Ar delay
|
||||
.Op Fl f Ar filename
|
||||
.Op Fl i Ar interface
|
||||
.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
|
||||
to a
|
||||
.Xr pflog 4
|
||||
interface, normally
|
||||
.Pa pflog0 ,
|
||||
and writes the packets to a logfile (normally
|
||||
.Pa /var/log/pflog )
|
||||
in
|
||||
@ -81,7 +84,9 @@ temporarily uses the old snaplen to keep the log file consistent.
|
||||
tries to preserve the integrity of the log file against I/O errors.
|
||||
Furthermore, integrity of an existing log file is verified before
|
||||
appending.
|
||||
If there is an invalid log file or an I/O error, logging is suspended until a
|
||||
If there is an invalid log file or an I/O error, the log file is moved
|
||||
out of the way and a new one is created.
|
||||
If a new file cannot be created, logging is suspended until a
|
||||
.Dv SIGHUP
|
||||
or a
|
||||
.Dv SIGALRM
|
||||
@ -101,11 +106,19 @@ If not specified, the default is 60 seconds.
|
||||
Log output filename.
|
||||
Default is
|
||||
.Pa /var/log/pflog .
|
||||
.It Fl i Ar interface
|
||||
Specifies the
|
||||
.Xr pflog 4
|
||||
interface to use.
|
||||
By default,
|
||||
.Nm
|
||||
will use
|
||||
.Ar pflog0 .
|
||||
.It Fl s Ar snaplen
|
||||
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
|
||||
bytes of data from each packet rather than the default of 116.
|
||||
The default of 116 is adequate for IP, ICMP, TCP, and UDP headers but may
|
||||
truncate protocol information for other protocols.
|
||||
Other file parsers may desire a higher snaplen.
|
||||
.It Fl x
|
||||
@ -129,6 +142,13 @@ Log specific tcp packets to a different log file with a large snaplen
|
||||
# pflogd -s 1600 -f suspicious.log port 80 and host evilhost
|
||||
.Ed
|
||||
.Pp
|
||||
Log from another
|
||||
.Xr pflog 4
|
||||
interface, excluding specific packets:
|
||||
.Bd -literal -offset indent
|
||||
# pflogd -i pflog3 -f network3.log "not (tcp and port 23)"
|
||||
.Ed
|
||||
.Pp
|
||||
Display binary logs:
|
||||
.Bd -literal -offset indent
|
||||
# tcpdump -n -e -ttt -r /var/log/pflog
|
||||
@ -148,7 +168,7 @@ 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
|
||||
.Bl -tag -width "ruleset authpf " -compact
|
||||
.It ip
|
||||
Address family equals IPv4.
|
||||
.It ip6
|
||||
@ -157,12 +177,16 @@ Address family equals IPv6.
|
||||
Interface name equals "kue0".
|
||||
.It on kue0
|
||||
Interface name equals "kue0".
|
||||
.It ruleset authpf
|
||||
Ruleset name equals "authpf".
|
||||
.It rulenum 10
|
||||
Rule number equals 10.
|
||||
.It reason match
|
||||
Reason equals match.
|
||||
Also accepts "bad-offset", "fragment", "bad-timestamp", "short",
|
||||
"normalize" and "memory".
|
||||
"normalize", "memory", "congestion", "ip-option", "proto-cksum",
|
||||
"state-mismatch", "state-insert", "state-limit", "src-limit",
|
||||
and "synproxy".
|
||||
.It action pass
|
||||
Action equals pass.
|
||||
Also accepts "block".
|
||||
@ -190,4 +214,6 @@ The
|
||||
command appeared in
|
||||
.Ox 3.0 .
|
||||
.Sh AUTHORS
|
||||
Can Erkin Acar
|
||||
.Nm
|
||||
was written by
|
||||
.An Can Erkin Acar Aq canacar@openbsd.org .
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pflogd.c,v 1.33 2005/02/09 12:09:30 henning Exp $ */
|
||||
/* $OpenBSD: pflogd.c,v 1.37 2006/10/26 13:34:47 jmc Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Theo de Raadt
|
||||
@ -73,7 +73,7 @@ int flush_buffer(FILE *);
|
||||
int init_pcap(void);
|
||||
void logmsg(int, const char *, ...);
|
||||
void purge_buffer(void);
|
||||
int reset_dump(void);
|
||||
int reset_dump(int);
|
||||
int scan_dump(FILE *, off_t);
|
||||
int set_snaplen(int);
|
||||
void set_suspended(int);
|
||||
@ -82,6 +82,8 @@ void sig_close(int);
|
||||
void sig_hup(int);
|
||||
void usage(void);
|
||||
|
||||
static int try_reset_dump(int);
|
||||
|
||||
/* buffer must always be greater than snaplen */
|
||||
static int bufpkt = 0; /* number of packets in buffer */
|
||||
static int buflen = 0; /* allocated size of buffer */
|
||||
@ -100,8 +102,9 @@ set_suspended(int s)
|
||||
return;
|
||||
|
||||
suspended = s;
|
||||
setproctitle("[%s] -s %d -f %s",
|
||||
suspended ? "suspended" : "running", cur_snaplen, filename);
|
||||
setproctitle("[%s] -s %d -i %s -f %s",
|
||||
suspended ? "suspended" : "running",
|
||||
cur_snaplen, interface, filename);
|
||||
}
|
||||
|
||||
char *
|
||||
@ -147,8 +150,9 @@ logmsg(int pri, const char *message, ...)
|
||||
__dead void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename] ");
|
||||
fprintf(stderr, "[-s snaplen] [expression]\n");
|
||||
fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename]");
|
||||
fprintf(stderr, " [-i interface] [-s snaplen]\n");
|
||||
fprintf(stderr, " [expression]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -228,7 +232,25 @@ set_snaplen(int snap)
|
||||
}
|
||||
|
||||
int
|
||||
reset_dump(void)
|
||||
reset_dump(int nomove)
|
||||
{
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
ret = try_reset_dump(nomove);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* tries to (re)open log file, nomove flag is used with -x switch
|
||||
* returns 0: success, 1: retry (log moved), -1: error
|
||||
*/
|
||||
int
|
||||
try_reset_dump(int nomove)
|
||||
{
|
||||
struct pcap_file_header hdr;
|
||||
struct stat st;
|
||||
@ -250,26 +272,26 @@ reset_dump(void)
|
||||
*/
|
||||
fd = priv_open_log();
|
||||
if (fd < 0)
|
||||
return (1);
|
||||
return (-1);
|
||||
|
||||
fp = fdopen(fd, "a+");
|
||||
|
||||
if (fp == NULL) {
|
||||
close(fd);
|
||||
logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
|
||||
return (1);
|
||||
close(fd);
|
||||
return (-1);
|
||||
}
|
||||
if (fstat(fileno(fp), &st) == -1) {
|
||||
fclose(fp);
|
||||
logmsg(LOG_ERR, "Error: %s: %s", filename, strerror(errno));
|
||||
return (1);
|
||||
fclose(fp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* set FILE unbuffered, we do our own buffering */
|
||||
if (setvbuf(fp, NULL, _IONBF, 0)) {
|
||||
fclose(fp);
|
||||
logmsg(LOG_ERR, "Failed to set output buffers");
|
||||
return (1);
|
||||
fclose(fp);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#define TCPDUMP_MAGIC 0xa1b2c3d4
|
||||
@ -277,12 +299,10 @@ reset_dump(void)
|
||||
if (st.st_size == 0) {
|
||||
if (snaplen != cur_snaplen) {
|
||||
logmsg(LOG_NOTICE, "Using snaplen %d", snaplen);
|
||||
if (set_snaplen(snaplen)) {
|
||||
fclose(fp);
|
||||
if (set_snaplen(snaplen))
|
||||
logmsg(LOG_WARNING,
|
||||
"Failed, using old settings");
|
||||
}
|
||||
}
|
||||
hdr.magic = TCPDUMP_MAGIC;
|
||||
hdr.version_major = PCAP_VERSION_MAJOR;
|
||||
hdr.version_minor = PCAP_VERSION_MINOR;
|
||||
@ -293,11 +313,15 @@ reset_dump(void)
|
||||
|
||||
if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
|
||||
fclose(fp);
|
||||
return (1);
|
||||
return (-1);
|
||||
}
|
||||
} else if (scan_dump(fp, st.st_size)) {
|
||||
/* XXX move file and continue? */
|
||||
fclose(fp);
|
||||
if (nomove || priv_move_log()) {
|
||||
logmsg(LOG_ERR,
|
||||
"Invalid/incompatible log file, move it away");
|
||||
return (-1);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
@ -336,7 +360,6 @@ scan_dump(FILE *fp, off_t size)
|
||||
hdr.version_minor != PCAP_VERSION_MINOR ||
|
||||
hdr.linktype != hpcap->linktype ||
|
||||
hdr.snaplen > PFLOGD_MAXSNAPLEN) {
|
||||
logmsg(LOG_ERR, "Invalid/incompatible log file, move it away");
|
||||
return (1);
|
||||
}
|
||||
|
||||
@ -511,7 +534,7 @@ main(int argc, char **argv)
|
||||
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
while ((ch = getopt(argc, argv, "Dxd:s:f:")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "Dxd:f:i:s:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'D':
|
||||
Debug = 1;
|
||||
@ -524,6 +547,9 @@ main(int argc, char **argv)
|
||||
case 'f':
|
||||
filename = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
interface = optarg;
|
||||
break;
|
||||
case 's':
|
||||
snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN,
|
||||
&errstr);
|
||||
@ -596,7 +622,7 @@ main(int argc, char **argv)
|
||||
bufpkt = 0;
|
||||
}
|
||||
|
||||
if (reset_dump()) {
|
||||
if (reset_dump(Xflag) < 0) {
|
||||
if (Xflag)
|
||||
return (1);
|
||||
|
||||
@ -614,7 +640,7 @@ main(int argc, char **argv)
|
||||
if (gotsig_close)
|
||||
break;
|
||||
if (gotsig_hup) {
|
||||
if (reset_dump()) {
|
||||
if (reset_dump(0)) {
|
||||
logmsg(LOG_ERR,
|
||||
"Logging suspended: open error");
|
||||
set_suspended(1);
|
||||
@ -625,6 +651,8 @@ main(int argc, char **argv)
|
||||
if (gotsig_alrm) {
|
||||
if (dpcap)
|
||||
flush_buffer(dpcap);
|
||||
else
|
||||
gotsig_hup = 1;
|
||||
gotsig_alrm = 0;
|
||||
alarm(delay);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: pflogd.h,v 1.2 2004/01/15 20:15:14 canacar Exp $ */
|
||||
/* $OpenBSD: pflogd.h,v 1.3 2006/01/15 16:38:04 canacar Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003 Can Erkin Acar
|
||||
@ -37,6 +37,7 @@ void logmsg(int priority, const char *message, ...);
|
||||
int priv_init(void);
|
||||
int priv_set_snaplen(int snaplen);
|
||||
int priv_open_log(void);
|
||||
int priv_move_log(void);
|
||||
pcap_t *pcap_open_live_fd(int fd, int snaplen, char *ebuf);
|
||||
|
||||
void set_pcap_filter(void);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: privsep.c,v 1.13 2004/12/22 09:21:02 otto Exp $ */
|
||||
/* $OpenBSD: privsep.c,v 1.16 2006/10/25 20:55:04 moritz Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003 Can Erkin Acar
|
||||
@ -16,7 +16,6 @@
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
@ -28,6 +27,7 @@
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <pcap.h>
|
||||
#include <pcap-int.h>
|
||||
#include <pwd.h>
|
||||
@ -41,6 +41,7 @@
|
||||
|
||||
enum cmd_types {
|
||||
PRIV_SET_SNAPLEN, /* set the snaplength */
|
||||
PRIV_MOVE_LOG, /* move logfile away */
|
||||
PRIV_OPEN_LOG /* open logfile for appending */
|
||||
};
|
||||
|
||||
@ -55,10 +56,8 @@ static int may_read(int, void *, size_t);
|
||||
static void must_read(int, void *, size_t);
|
||||
static void must_write(int, void *, size_t);
|
||||
static int set_snaplen(int snap);
|
||||
static int move_log(const char *name);
|
||||
|
||||
/* bpf filter expression common to parent and child */
|
||||
extern char *filter;
|
||||
extern char *errbuf;
|
||||
extern char *filename;
|
||||
extern pcap_t *hpcap;
|
||||
|
||||
@ -96,16 +95,12 @@ priv_init(void)
|
||||
err(1, "unable to chdir");
|
||||
|
||||
gidset[0] = pw->pw_gid;
|
||||
if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
|
||||
err(1, "setresgid() failed");
|
||||
if (setgroups(1, gidset) == -1)
|
||||
err(1, "setgroups() failed");
|
||||
if (setegid(pw->pw_gid) == -1)
|
||||
err(1, "setegid() failed");
|
||||
if (setgid(pw->pw_gid) == -1)
|
||||
err(1, "setgid() failed");
|
||||
if (seteuid(pw->pw_uid) == -1)
|
||||
err(1, "seteuid() failed");
|
||||
if (setuid(pw->pw_uid) == -1)
|
||||
err(1, "setuid() failed");
|
||||
if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
|
||||
err(1, "setresuid() failed");
|
||||
close(socks[0]);
|
||||
priv_fd = socks[1];
|
||||
return 0;
|
||||
@ -159,6 +154,13 @@ priv_init(void)
|
||||
close(fd);
|
||||
break;
|
||||
|
||||
case PRIV_MOVE_LOG:
|
||||
logmsg(LOG_DEBUG,
|
||||
"[priv]: msg PRIV_MOVE_LOG received");
|
||||
ret = move_log(filename);
|
||||
must_write(socks[0], &ret, sizeof(int));
|
||||
break;
|
||||
|
||||
default:
|
||||
logmsg(LOG_ERR, "[priv]: unknown command %d", cmd);
|
||||
_exit(1);
|
||||
@ -182,6 +184,47 @@ set_snaplen(int snap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
move_log(const char *name)
|
||||
{
|
||||
char ren[PATH_MAX];
|
||||
int len;
|
||||
|
||||
for (;;) {
|
||||
int fd;
|
||||
|
||||
len = snprintf(ren, sizeof(ren), "%s.bad.%08x",
|
||||
name, arc4random());
|
||||
if (len >= sizeof(ren)) {
|
||||
logmsg(LOG_ERR, "[priv] new name too long");
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* lock destinanion */
|
||||
fd = open(ren, O_CREAT|O_EXCL, 0);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
/* if file exists, try another name */
|
||||
if (errno != EEXIST && errno != EINTR) {
|
||||
logmsg(LOG_ERR, "[priv] failed to create new name: %s",
|
||||
strerror(errno));
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (rename(name, ren)) {
|
||||
logmsg(LOG_ERR, "[priv] failed to rename %s to %s: %s",
|
||||
name, ren, strerror(errno));
|
||||
return (1);
|
||||
}
|
||||
|
||||
logmsg(LOG_NOTICE,
|
||||
"[priv]: log file %s moved to %s", name, ren);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* send the snaplength to privileged process
|
||||
@ -223,6 +266,21 @@ priv_open_log(void)
|
||||
|
||||
return (fd);
|
||||
}
|
||||
/* Move-away and reopen log-file */
|
||||
int
|
||||
priv_move_log(void)
|
||||
{
|
||||
int cmd, ret;
|
||||
|
||||
if (priv_fd < 0)
|
||||
errx(1, "%s: called from privileged portion\n", __func__);
|
||||
|
||||
cmd = PRIV_MOVE_LOG;
|
||||
must_write(priv_fd, &cmd, sizeof(int));
|
||||
must_read(priv_fd, &ret, sizeof(int));
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* If priv parent gets a TERM or HUP, pass it through to child instead */
|
||||
static void
|
||||
|
397
contrib/pf/tftp-proxy/filter.c
Normal file
397
contrib/pf/tftp-proxy/filter.c
Normal file
@ -0,0 +1,397 @@
|
||||
/* $OpenBSD: filter.c,v 1.1 2005/12/28 19:07:07 jcs Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
|
||||
*
|
||||
* 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 <syslog.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/pfvar.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "filter.h"
|
||||
|
||||
/* From netinet/in.h, but only _KERNEL_ gets them. */
|
||||
#define satosin(sa) ((struct sockaddr_in *)(sa))
|
||||
#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
|
||||
|
||||
enum { TRANS_FILTER = 0, TRANS_NAT, TRANS_RDR, TRANS_SIZE };
|
||||
|
||||
int prepare_rule(u_int32_t, int, struct sockaddr *, struct sockaddr *,
|
||||
u_int16_t, u_int8_t);
|
||||
int server_lookup4(struct sockaddr_in *, struct sockaddr_in *,
|
||||
struct sockaddr_in *, u_int8_t);
|
||||
int server_lookup6(struct sockaddr_in6 *, struct sockaddr_in6 *,
|
||||
struct sockaddr_in6 *, u_int8_t);
|
||||
|
||||
static struct pfioc_pooladdr pfp;
|
||||
static struct pfioc_rule pfr;
|
||||
static struct pfioc_trans pft;
|
||||
static struct pfioc_trans_e pfte[TRANS_SIZE];
|
||||
static int dev, rule_log;
|
||||
static char *qname;
|
||||
|
||||
int
|
||||
add_filter(u_int32_t id, u_int8_t dir, struct sockaddr *src,
|
||||
struct sockaddr *dst, u_int16_t d_port, u_int8_t proto)
|
||||
{
|
||||
if (!src || !dst || !d_port || !proto) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (prepare_rule(id, PF_RULESET_FILTER, src, dst, d_port, proto) == -1)
|
||||
return (-1);
|
||||
|
||||
pfr.rule.direction = dir;
|
||||
if (ioctl(dev, DIOCADDRULE, &pfr) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
add_nat(u_int32_t id, struct sockaddr *src, struct sockaddr *dst,
|
||||
u_int16_t d_port, struct sockaddr *nat, u_int16_t nat_range_low,
|
||||
u_int16_t nat_range_high, u_int8_t proto)
|
||||
{
|
||||
if (!src || !dst || !d_port || !nat || !nat_range_low || !proto ||
|
||||
(src->sa_family != nat->sa_family)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (prepare_rule(id, PF_RULESET_NAT, src, dst, d_port, proto) == -1)
|
||||
return (-1);
|
||||
|
||||
if (nat->sa_family == AF_INET) {
|
||||
memcpy(&pfp.addr.addr.v.a.addr.v4,
|
||||
&satosin(nat)->sin_addr.s_addr, 4);
|
||||
memset(&pfp.addr.addr.v.a.mask.addr8, 255, 4);
|
||||
} else {
|
||||
memcpy(&pfp.addr.addr.v.a.addr.v6,
|
||||
&satosin6(nat)->sin6_addr.s6_addr, 16);
|
||||
memset(&pfp.addr.addr.v.a.mask.addr8, 255, 16);
|
||||
}
|
||||
if (ioctl(dev, DIOCADDADDR, &pfp) == -1)
|
||||
return (-1);
|
||||
|
||||
pfr.rule.rpool.proxy_port[0] = nat_range_low;
|
||||
pfr.rule.rpool.proxy_port[1] = nat_range_high;
|
||||
if (ioctl(dev, DIOCADDRULE, &pfr) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
add_rdr(u_int32_t id, struct sockaddr *src, struct sockaddr *dst,
|
||||
u_int16_t d_port, struct sockaddr *rdr, u_int16_t rdr_port, u_int8_t proto)
|
||||
{
|
||||
if (!src || !dst || !d_port || !rdr || !rdr_port || !proto ||
|
||||
(src->sa_family != rdr->sa_family)) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (prepare_rule(id, PF_RULESET_RDR, src, dst, d_port, proto) == -1)
|
||||
return (-1);
|
||||
|
||||
if (rdr->sa_family == AF_INET) {
|
||||
memcpy(&pfp.addr.addr.v.a.addr.v4,
|
||||
&satosin(rdr)->sin_addr.s_addr, 4);
|
||||
memset(&pfp.addr.addr.v.a.mask.addr8, 255, 4);
|
||||
} else {
|
||||
memcpy(&pfp.addr.addr.v.a.addr.v6,
|
||||
&satosin6(rdr)->sin6_addr.s6_addr, 16);
|
||||
memset(&pfp.addr.addr.v.a.mask.addr8, 255, 16);
|
||||
}
|
||||
if (ioctl(dev, DIOCADDADDR, &pfp) == -1)
|
||||
return (-1);
|
||||
|
||||
pfr.rule.rpool.proxy_port[0] = rdr_port;
|
||||
if (ioctl(dev, DIOCADDRULE, &pfr) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
do_commit(void)
|
||||
{
|
||||
if (ioctl(dev, DIOCXCOMMIT, &pft) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
do_rollback(void)
|
||||
{
|
||||
if (ioctl(dev, DIOCXROLLBACK, &pft) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
init_filter(char *opt_qname, int opt_verbose)
|
||||
{
|
||||
struct pf_status status;
|
||||
|
||||
qname = opt_qname;
|
||||
|
||||
if (opt_verbose == 1)
|
||||
rule_log = PF_LOG;
|
||||
else if (opt_verbose == 2)
|
||||
rule_log = PF_LOG_ALL;
|
||||
|
||||
dev = open("/dev/pf", O_RDWR);
|
||||
if (dev == -1) {
|
||||
syslog(LOG_ERR, "can't open /dev/pf");
|
||||
exit(1);
|
||||
}
|
||||
if (ioctl(dev, DIOCGETSTATUS, &status) == -1) {
|
||||
syslog(LOG_ERR, "DIOCGETSTATUS");
|
||||
exit(1);
|
||||
}
|
||||
if (!status.running) {
|
||||
syslog(LOG_ERR, "pf is disabled");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
prepare_commit(u_int32_t id)
|
||||
{
|
||||
char an[PF_ANCHOR_NAME_SIZE];
|
||||
int i;
|
||||
|
||||
memset(&pft, 0, sizeof pft);
|
||||
pft.size = TRANS_SIZE;
|
||||
pft.esize = sizeof pfte[0];
|
||||
pft.array = pfte;
|
||||
|
||||
snprintf(an, PF_ANCHOR_NAME_SIZE, "%s/%d.%d", FTP_PROXY_ANCHOR,
|
||||
getpid(), id);
|
||||
for (i = 0; i < TRANS_SIZE; i++) {
|
||||
memset(&pfte[i], 0, sizeof pfte[0]);
|
||||
strlcpy(pfte[i].anchor, an, PF_ANCHOR_NAME_SIZE);
|
||||
switch (i) {
|
||||
case TRANS_FILTER:
|
||||
pfte[i].rs_num = PF_RULESET_FILTER;
|
||||
break;
|
||||
case TRANS_NAT:
|
||||
pfte[i].rs_num = PF_RULESET_NAT;
|
||||
break;
|
||||
case TRANS_RDR:
|
||||
pfte[i].rs_num = PF_RULESET_RDR;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (ioctl(dev, DIOCXBEGIN, &pft) == -1)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
prepare_rule(u_int32_t id, int rs_num, struct sockaddr *src,
|
||||
struct sockaddr *dst, u_int16_t d_port, u_int8_t proto)
|
||||
{
|
||||
char an[PF_ANCHOR_NAME_SIZE];
|
||||
|
||||
if ((src->sa_family != AF_INET && src->sa_family != AF_INET6) ||
|
||||
(src->sa_family != dst->sa_family)) {
|
||||
errno = EPROTONOSUPPORT;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
memset(&pfp, 0, sizeof pfp);
|
||||
memset(&pfr, 0, sizeof pfr);
|
||||
snprintf(an, PF_ANCHOR_NAME_SIZE, "%s/%d.%d", FTP_PROXY_ANCHOR,
|
||||
getpid(), id);
|
||||
strlcpy(pfp.anchor, an, PF_ANCHOR_NAME_SIZE);
|
||||
strlcpy(pfr.anchor, an, PF_ANCHOR_NAME_SIZE);
|
||||
|
||||
switch (rs_num) {
|
||||
case PF_RULESET_FILTER:
|
||||
pfr.ticket = pfte[TRANS_FILTER].ticket;
|
||||
break;
|
||||
case PF_RULESET_NAT:
|
||||
pfr.ticket = pfte[TRANS_NAT].ticket;
|
||||
break;
|
||||
case PF_RULESET_RDR:
|
||||
pfr.ticket = pfte[TRANS_RDR].ticket;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (ioctl(dev, DIOCBEGINADDRS, &pfp) == -1)
|
||||
return (-1);
|
||||
pfr.pool_ticket = pfp.ticket;
|
||||
|
||||
/* Generic for all rule types. */
|
||||
pfr.rule.af = src->sa_family;
|
||||
pfr.rule.proto = proto;
|
||||
pfr.rule.src.addr.type = PF_ADDR_ADDRMASK;
|
||||
pfr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
|
||||
if (src->sa_family == AF_INET) {
|
||||
memcpy(&pfr.rule.src.addr.v.a.addr.v4,
|
||||
&satosin(src)->sin_addr.s_addr, 4);
|
||||
memset(&pfr.rule.src.addr.v.a.mask.addr8, 255, 4);
|
||||
memcpy(&pfr.rule.dst.addr.v.a.addr.v4,
|
||||
&satosin(dst)->sin_addr.s_addr, 4);
|
||||
memset(&pfr.rule.dst.addr.v.a.mask.addr8, 255, 4);
|
||||
} else {
|
||||
memcpy(&pfr.rule.src.addr.v.a.addr.v6,
|
||||
&satosin6(src)->sin6_addr.s6_addr, 16);
|
||||
memset(&pfr.rule.src.addr.v.a.mask.addr8, 255, 16);
|
||||
memcpy(&pfr.rule.dst.addr.v.a.addr.v6,
|
||||
&satosin6(dst)->sin6_addr.s6_addr, 16);
|
||||
memset(&pfr.rule.dst.addr.v.a.mask.addr8, 255, 16);
|
||||
}
|
||||
pfr.rule.dst.port_op = PF_OP_EQ;
|
||||
pfr.rule.dst.port[0] = htons(d_port);
|
||||
|
||||
switch (rs_num) {
|
||||
case PF_RULESET_FILTER:
|
||||
/*
|
||||
* pass quick [log] inet[6] proto tcp \
|
||||
* from $src to $dst port = $d_port flags S/SAFR keep state
|
||||
* (max 1) [queue qname]
|
||||
*/
|
||||
pfr.rule.action = PF_PASS;
|
||||
pfr.rule.quick = 1;
|
||||
pfr.rule.log = rule_log;
|
||||
pfr.rule.keep_state = 1;
|
||||
pfr.rule.flags = (proto == IPPROTO_TCP ? TH_SYN : NULL);
|
||||
pfr.rule.flagset = (proto == IPPROTO_TCP ?
|
||||
(TH_SYN|TH_ACK|TH_FIN|TH_RST) : NULL);
|
||||
pfr.rule.max_states = 1;
|
||||
if (qname != NULL)
|
||||
strlcpy(pfr.rule.qname, qname, sizeof pfr.rule.qname);
|
||||
break;
|
||||
case PF_RULESET_NAT:
|
||||
/*
|
||||
* nat inet[6] proto tcp from $src to $dst port $d_port -> $nat
|
||||
*/
|
||||
pfr.rule.action = PF_NAT;
|
||||
break;
|
||||
case PF_RULESET_RDR:
|
||||
/*
|
||||
* rdr inet[6] proto tcp from $src to $dst port $d_port -> $rdr
|
||||
*/
|
||||
pfr.rule.action = PF_RDR;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
server_lookup(struct sockaddr *client, struct sockaddr *proxy,
|
||||
struct sockaddr *server, u_int8_t proto)
|
||||
{
|
||||
if (client->sa_family == AF_INET)
|
||||
return (server_lookup4(satosin(client), satosin(proxy),
|
||||
satosin(server), proto));
|
||||
|
||||
if (client->sa_family == AF_INET6)
|
||||
return (server_lookup6(satosin6(client), satosin6(proxy),
|
||||
satosin6(server), proto));
|
||||
|
||||
errno = EPROTONOSUPPORT;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
server_lookup4(struct sockaddr_in *client, struct sockaddr_in *proxy,
|
||||
struct sockaddr_in *server, u_int8_t proto)
|
||||
{
|
||||
struct pfioc_natlook pnl;
|
||||
|
||||
memset(&pnl, 0, sizeof pnl);
|
||||
pnl.direction = PF_OUT;
|
||||
pnl.af = AF_INET;
|
||||
pnl.proto = proto;
|
||||
memcpy(&pnl.saddr.v4, &client->sin_addr.s_addr, sizeof pnl.saddr.v4);
|
||||
memcpy(&pnl.daddr.v4, &proxy->sin_addr.s_addr, sizeof pnl.daddr.v4);
|
||||
pnl.sport = client->sin_port;
|
||||
pnl.dport = proxy->sin_port;
|
||||
|
||||
if (ioctl(dev, DIOCNATLOOK, &pnl) == -1)
|
||||
return (-1);
|
||||
|
||||
memset(server, 0, sizeof(struct sockaddr_in));
|
||||
server->sin_len = sizeof(struct sockaddr_in);
|
||||
server->sin_family = AF_INET;
|
||||
memcpy(&server->sin_addr.s_addr, &pnl.rdaddr.v4,
|
||||
sizeof server->sin_addr.s_addr);
|
||||
server->sin_port = pnl.rdport;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
server_lookup6(struct sockaddr_in6 *client, struct sockaddr_in6 *proxy,
|
||||
struct sockaddr_in6 *server, u_int8_t proto)
|
||||
{
|
||||
struct pfioc_natlook pnl;
|
||||
|
||||
memset(&pnl, 0, sizeof pnl);
|
||||
pnl.direction = PF_OUT;
|
||||
pnl.af = AF_INET6;
|
||||
pnl.proto = proto;
|
||||
memcpy(&pnl.saddr.v6, &client->sin6_addr.s6_addr, sizeof pnl.saddr.v6);
|
||||
memcpy(&pnl.daddr.v6, &proxy->sin6_addr.s6_addr, sizeof pnl.daddr.v6);
|
||||
pnl.sport = client->sin6_port;
|
||||
pnl.dport = proxy->sin6_port;
|
||||
|
||||
if (ioctl(dev, DIOCNATLOOK, &pnl) == -1)
|
||||
return (-1);
|
||||
|
||||
memset(server, 0, sizeof(struct sockaddr_in6));
|
||||
server->sin6_len = sizeof(struct sockaddr_in6);
|
||||
server->sin6_family = AF_INET6;
|
||||
memcpy(&server->sin6_addr.s6_addr, &pnl.rdaddr.v6,
|
||||
sizeof server->sin6_addr);
|
||||
server->sin6_port = pnl.rdport;
|
||||
|
||||
return (0);
|
||||
}
|
32
contrib/pf/tftp-proxy/filter.h
Normal file
32
contrib/pf/tftp-proxy/filter.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* $OpenBSD: filter.h,v 1.1 2005/12/28 19:07:07 jcs Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define FTP_PROXY_ANCHOR "tftp-proxy"
|
||||
|
||||
int add_filter(u_int32_t, u_int8_t, struct sockaddr *, struct sockaddr *,
|
||||
u_int16_t, u_int8_t);
|
||||
int add_nat(u_int32_t, struct sockaddr *, struct sockaddr *, u_int16_t,
|
||||
struct sockaddr *, u_int16_t, u_int16_t, u_int8_t);
|
||||
int add_rdr(u_int32_t, struct sockaddr *, struct sockaddr *, u_int16_t,
|
||||
struct sockaddr *, u_int16_t, u_int8_t);
|
||||
int do_commit(void);
|
||||
int do_rollback(void);
|
||||
void init_filter(char *, int);
|
||||
int prepare_commit(u_int32_t);
|
||||
int server_lookup(struct sockaddr *, struct sockaddr *, struct sockaddr *,
|
||||
u_int8_t);
|
140
contrib/pf/tftp-proxy/tftp-proxy.8
Normal file
140
contrib/pf/tftp-proxy/tftp-proxy.8
Normal file
@ -0,0 +1,140 @@
|
||||
.\" $OpenBSD: tftp-proxy.8,v 1.1 2005/12/28 19:07:07 jcs Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2005 joshua stein <jcs@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.
|
||||
.\" 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 28, 2005
|
||||
.Dt TFTP-PROXY 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm tftp-proxy
|
||||
.Nd Internet Trivial File Transfer Protocol proxy
|
||||
.Sh SYNOPSIS
|
||||
.Nm tftp-proxy
|
||||
.Op Fl v
|
||||
.Op Fl w Ar transwait
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a proxy for the Internet Trivial File Transfer Protocol invoked by
|
||||
the
|
||||
.Xr inetd 8
|
||||
internet server.
|
||||
TFTP connections should be redirected to the proxy using the
|
||||
.Xr pf 4
|
||||
.Ar rdr
|
||||
command, after which the proxy connects to the server on behalf of
|
||||
the client.
|
||||
.Pp
|
||||
The proxy establishes a
|
||||
.Xr pf 4
|
||||
.Ar rdr
|
||||
rule using the
|
||||
.Ar anchor
|
||||
facility to rewrite packets between the client and the server.
|
||||
Once the rule is established,
|
||||
.Nm
|
||||
forwards the initial request from the client to the server to begin the
|
||||
transfer.
|
||||
After
|
||||
.Ar transwait
|
||||
seconds, the
|
||||
.Xr pf 4
|
||||
NAT state is assumed to have been established and the
|
||||
.Ar rdr
|
||||
rule is deleted and the program exits.
|
||||
Once the transfer between the client and the server is completed, the
|
||||
NAT state will naturally expire.
|
||||
.Pp
|
||||
Assuming the TFTP command request is from $client to $server, the
|
||||
proxy connected to the server using the $proxy source address, and
|
||||
$port is negotiated,
|
||||
.Nm
|
||||
adds the following rule to the anchor:
|
||||
.Bd -literal -offset indent
|
||||
rdr proto udp from $server to $proxy port $port -\*(Gt $client
|
||||
.Ed
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl v
|
||||
Log the connection and request information to
|
||||
.Xr syslogd 8 .
|
||||
.It Fl w Ar transwait
|
||||
Number of seconds to wait for the data transmission to begin before
|
||||
removing the
|
||||
.Xr pf 4
|
||||
.Ar rdr
|
||||
rule.
|
||||
The default is 2 seconds.
|
||||
.El
|
||||
.Sh CONFIGURATION
|
||||
To make use of the proxy,
|
||||
.Xr pf.conf 5
|
||||
needs the following rules.
|
||||
The anchors are mandatory.
|
||||
Adjust the rules as needed for your configuration.
|
||||
.Pp
|
||||
In the NAT section:
|
||||
.Bd -literal -offset indent
|
||||
nat on $ext_if from $int_if -\*(Gt ($ext_if:0)
|
||||
|
||||
no nat on $ext_if to port tftp
|
||||
|
||||
rdr-anchor "tftp-proxy/*"
|
||||
rdr on $int_if proto udp from $lan to any port tftp -\*(Gt \e
|
||||
127.0.0.1 port 6969
|
||||
.Ed
|
||||
.Pp
|
||||
In the filter section, an anchor must be added to hold the pass rules:
|
||||
.Bd -literal -offset indent
|
||||
anchor "tftp-proxy/*"
|
||||
.Ed
|
||||
.Pp
|
||||
.Xr inetd 8
|
||||
must be configured to spawn the proxy on the port that packets are
|
||||
being forwarded to by
|
||||
.Xr pf 4 .
|
||||
An example
|
||||
.Xr inetd.conf 5
|
||||
entry follows:
|
||||
.Bd -literal -offset indent
|
||||
127.0.0.1:6969 dgram udp wait root \e
|
||||
/usr/libexec/tftp-proxy tftp-proxy
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr tftp 1 ,
|
||||
.Xr pf 4 ,
|
||||
.Xr pf.conf 5 ,
|
||||
.Xr ftp-proxy 8 ,
|
||||
.Xr inetd 8 ,
|
||||
.Xr syslogd 8 ,
|
||||
.Xr tftpd 8
|
||||
.Sh CAVEATS
|
||||
.Nm
|
||||
chroots to
|
||||
.Pa /var/empty
|
||||
and changes to user
|
||||
.Dq proxy
|
||||
to drop privileges.
|
393
contrib/pf/tftp-proxy/tftp-proxy.c
Normal file
393
contrib/pf/tftp-proxy/tftp-proxy.c
Normal file
@ -0,0 +1,393 @@
|
||||
/* $OpenBSD: tftp-proxy.c,v 1.2 2006/12/20 03:33:38 joel Exp $
|
||||
*
|
||||
* Copyright (c) 2005 DLS Internet Services
|
||||
* Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <arpa/tftp.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/pfvar.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "filter.h"
|
||||
|
||||
#define CHROOT_DIR "/var/empty"
|
||||
#define NOPRIV_USER "proxy"
|
||||
|
||||
#define PF_NAT_PROXY_PORT_LOW 50001
|
||||
#define PF_NAT_PROXY_PORT_HIGH 65535
|
||||
|
||||
#define DEFTRANSWAIT 2
|
||||
#define NTOP_BUFS 4
|
||||
#define PKTSIZE SEGSIZE+4
|
||||
|
||||
const char *opcode(int);
|
||||
const char *sock_ntop(struct sockaddr *);
|
||||
u_int16_t pick_proxy_port(void);
|
||||
static void usage(void);
|
||||
|
||||
extern char *__progname;
|
||||
char ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN];
|
||||
int verbose = 0;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int c, fd = 0, on = 1, out_fd = 0, peer, reqsize = 0;
|
||||
int transwait = DEFTRANSWAIT;
|
||||
char *p;
|
||||
struct tftphdr *tp;
|
||||
struct passwd *pw;
|
||||
|
||||
char cbuf[CMSG_SPACE(sizeof(struct sockaddr_storage))];
|
||||
char req[PKTSIZE];
|
||||
struct cmsghdr *cmsg;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
|
||||
struct sockaddr_storage from, proxy, server, proxy_to_server, s_in;
|
||||
struct sockaddr_in sock_out;
|
||||
socklen_t j;
|
||||
in_port_t bindport;
|
||||
|
||||
openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
|
||||
|
||||
while ((c = getopt(argc, argv, "vw:")) != -1)
|
||||
switch (c) {
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'w':
|
||||
transwait = strtoll(optarg, &p, 10);
|
||||
if (transwait < 1) {
|
||||
syslog(LOG_ERR, "invalid -w value");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
|
||||
/* open /dev/pf */
|
||||
init_filter(NULL, verbose);
|
||||
|
||||
tzset();
|
||||
|
||||
pw = getpwnam(NOPRIV_USER);
|
||||
if (!pw) {
|
||||
syslog(LOG_ERR, "no such user %s: %m", NOPRIV_USER);
|
||||
exit(1);
|
||||
}
|
||||
if (chroot(CHROOT_DIR) || chdir("/")) {
|
||||
syslog(LOG_ERR, "chroot %s: %m", CHROOT_DIR);
|
||||
exit(1);
|
||||
}
|
||||
if (setgroups(1, &pw->pw_gid) ||
|
||||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
|
||||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) {
|
||||
syslog(LOG_ERR, "can't revoke privs: %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* non-blocking io */
|
||||
if (ioctl(fd, FIONBIO, &on) < 0) {
|
||||
syslog(LOG_ERR, "ioctl(FIONBIO): %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)) == -1) {
|
||||
syslog(LOG_ERR, "setsockopt(IP_RECVDSTADDR): %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
j = sizeof(s_in);
|
||||
if (getsockname(fd, (struct sockaddr *)&s_in, &j) == -1) {
|
||||
syslog(LOG_ERR, "getsockname: %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bindport = ((struct sockaddr_in *)&s_in)->sin_port;
|
||||
|
||||
/* req will be pushed back out at the end, unchanged */
|
||||
j = sizeof(from);
|
||||
if ((reqsize = recvfrom(fd, req, sizeof(req), MSG_PEEK,
|
||||
(struct sockaddr *)&from, &j)) < 0) {
|
||||
syslog(LOG_ERR, "recvfrom: %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bzero(&msg, sizeof(msg));
|
||||
iov.iov_base = req;
|
||||
iov.iov_len = sizeof(req);
|
||||
msg.msg_name = &from;
|
||||
msg.msg_namelen = sizeof(from);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = cbuf;
|
||||
msg.msg_controllen = CMSG_LEN(sizeof(struct sockaddr_storage));
|
||||
|
||||
if (recvmsg(fd, &msg, 0) < 0) {
|
||||
syslog(LOG_ERR, "recvmsg: %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
close(1);
|
||||
|
||||
peer = socket(from.ss_family, SOCK_DGRAM, 0);
|
||||
if (peer < 0) {
|
||||
syslog(LOG_ERR, "socket: %m");
|
||||
exit(1);
|
||||
}
|
||||
memset(&s_in, 0, sizeof(s_in));
|
||||
s_in.ss_family = from.ss_family;
|
||||
s_in.ss_len = from.ss_len;
|
||||
|
||||
/* get local address if possible */
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == IPPROTO_IP &&
|
||||
cmsg->cmsg_type == IP_RECVDSTADDR) {
|
||||
memcpy(&((struct sockaddr_in *)&s_in)->sin_addr,
|
||||
CMSG_DATA(cmsg), sizeof(struct in_addr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bind(peer, (struct sockaddr *)&s_in, s_in.ss_len) < 0) {
|
||||
syslog(LOG_ERR, "bind: %m");
|
||||
exit(1);
|
||||
}
|
||||
if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
|
||||
syslog(LOG_ERR, "connect: %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
tp = (struct tftphdr *)req;
|
||||
if (!(ntohs(tp->th_opcode) == RRQ || ntohs(tp->th_opcode) == WRQ)) {
|
||||
/* not a tftp request, bail */
|
||||
if (verbose) {
|
||||
syslog(LOG_WARNING, "not a valid tftp request");
|
||||
exit(1);
|
||||
} else
|
||||
/* exit 0 so inetd doesn't log anything */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
j = sizeof(struct sockaddr_storage);
|
||||
if (getsockname(fd, (struct sockaddr *)&proxy, &j) == -1) {
|
||||
syslog(LOG_ERR, "getsockname: %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
((struct sockaddr_in *)&proxy)->sin_port = bindport;
|
||||
|
||||
/* find the un-rdr'd server and port the client wanted */
|
||||
if (server_lookup((struct sockaddr *)&from,
|
||||
(struct sockaddr *)&proxy, (struct sockaddr *)&server,
|
||||
IPPROTO_UDP) != 0) {
|
||||
syslog(LOG_ERR, "pf connection lookup failed (no rdr?)");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* establish a new outbound connection to the remote server */
|
||||
if ((out_fd = socket(((struct sockaddr *)&from)->sa_family,
|
||||
SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
||||
syslog(LOG_ERR, "couldn't create new socket");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bzero((char *)&sock_out, sizeof(sock_out));
|
||||
sock_out.sin_family = from.ss_family;
|
||||
sock_out.sin_port = htons(pick_proxy_port());
|
||||
if (bind(out_fd, (struct sockaddr *)&sock_out, sizeof(sock_out)) < 0) {
|
||||
syslog(LOG_ERR, "couldn't bind to new socket: %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (connect(out_fd, (struct sockaddr *)&server,
|
||||
((struct sockaddr *)&server)->sa_len) < 0 && errno != EINPROGRESS) {
|
||||
syslog(LOG_ERR, "couldn't connect to remote server: %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
j = sizeof(struct sockaddr_storage);
|
||||
if ((getsockname(out_fd, (struct sockaddr *)&proxy_to_server,
|
||||
&j)) < 0) {
|
||||
syslog(LOG_ERR, "getsockname: %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
syslog(LOG_INFO, "%s:%d -> %s:%d/%s:%d -> %s:%d \"%s %s\"",
|
||||
sock_ntop((struct sockaddr *)&from),
|
||||
ntohs(((struct sockaddr_in *)&from)->sin_port),
|
||||
sock_ntop((struct sockaddr *)&proxy),
|
||||
ntohs(((struct sockaddr_in *)&proxy)->sin_port),
|
||||
sock_ntop((struct sockaddr *)&proxy_to_server),
|
||||
ntohs(((struct sockaddr_in *)&proxy_to_server)->sin_port),
|
||||
sock_ntop((struct sockaddr *)&server),
|
||||
ntohs(((struct sockaddr_in *)&server)->sin_port),
|
||||
opcode(ntohs(tp->th_opcode)),
|
||||
tp->th_stuff);
|
||||
|
||||
/* get ready to add rdr and pass rules */
|
||||
if (prepare_commit(1) == -1) {
|
||||
syslog(LOG_ERR, "couldn't prepare pf commit");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* rdr from server to us on our random port -> client on its port */
|
||||
if (add_rdr(1, (struct sockaddr *)&server,
|
||||
(struct sockaddr *)&proxy_to_server, ntohs(sock_out.sin_port),
|
||||
(struct sockaddr *)&from,
|
||||
ntohs(((struct sockaddr_in *)&from)->sin_port),
|
||||
IPPROTO_UDP) == -1) {
|
||||
syslog(LOG_ERR, "couldn't add rdr");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* explicitly allow the packets to return back to the client (which pf
|
||||
* will see post-rdr) */
|
||||
if (add_filter(1, PF_IN, (struct sockaddr *)&server,
|
||||
(struct sockaddr *)&from,
|
||||
ntohs(((struct sockaddr_in *)&from)->sin_port),
|
||||
IPPROTO_UDP) == -1) {
|
||||
syslog(LOG_ERR, "couldn't add pass in");
|
||||
exit(1);
|
||||
}
|
||||
if (add_filter(1, PF_OUT, (struct sockaddr *)&server,
|
||||
(struct sockaddr *)&from,
|
||||
ntohs(((struct sockaddr_in *)&from)->sin_port),
|
||||
IPPROTO_UDP) == -1) {
|
||||
syslog(LOG_ERR, "couldn't add pass out");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* and just in case, to pass out from us to the server */
|
||||
if (add_filter(1, PF_OUT, (struct sockaddr *)&proxy_to_server,
|
||||
(struct sockaddr *)&server,
|
||||
ntohs(((struct sockaddr_in *)&server)->sin_port),
|
||||
IPPROTO_UDP) == -1) {
|
||||
syslog(LOG_ERR, "couldn't add pass out");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (do_commit() == -1) {
|
||||
syslog(LOG_ERR, "couldn't commit pf rules");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* forward the initial tftp request and start the insanity */
|
||||
if (send(out_fd, tp, reqsize, 0) < 0) {
|
||||
syslog(LOG_ERR, "couldn't forward tftp packet: %m");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* allow the transfer to start to establish a state */
|
||||
sleep(transwait);
|
||||
|
||||
/* delete our rdr rule and clean up */
|
||||
prepare_commit(1);
|
||||
do_commit();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
const char *
|
||||
opcode(int code)
|
||||
{
|
||||
static char str[6];
|
||||
|
||||
switch (code) {
|
||||
case 1:
|
||||
(void)snprintf(str, sizeof(str), "RRQ");
|
||||
break;
|
||||
case 2:
|
||||
(void)snprintf(str, sizeof(str), "WRQ");
|
||||
break;
|
||||
default:
|
||||
(void)snprintf(str, sizeof(str), "(%d)", code);
|
||||
break;
|
||||
}
|
||||
|
||||
return (str);
|
||||
}
|
||||
|
||||
const char *
|
||||
sock_ntop(struct sockaddr *sa)
|
||||
{
|
||||
static int n = 0;
|
||||
|
||||
/* Cycle to next buffer. */
|
||||
n = (n + 1) % NTOP_BUFS;
|
||||
ntop_buf[n][0] = '\0';
|
||||
|
||||
if (sa->sa_family == AF_INET) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
|
||||
|
||||
return (inet_ntop(AF_INET, &sin->sin_addr, ntop_buf[n],
|
||||
sizeof ntop_buf[0]));
|
||||
}
|
||||
|
||||
if (sa->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
|
||||
|
||||
return (inet_ntop(AF_INET6, &sin6->sin6_addr, ntop_buf[n],
|
||||
sizeof ntop_buf[0]));
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
u_int16_t
|
||||
pick_proxy_port(void)
|
||||
{
|
||||
return (IPPORT_HIFIRSTAUTO + (arc4random() %
|
||||
(IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)));
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
syslog(LOG_ERR, "usage: %s [-v] [-w transwait]", __progname);
|
||||
exit(1);
|
||||
}
|
Loading…
Reference in New Issue
Block a user