From 89a3159080a774bd9de50eaf1861a1f0c1657a9f Mon Sep 17 00:00:00 2001 From: Max Laier Date: Wed, 10 Dec 2008 21:08:42 +0000 Subject: [PATCH] Import OPENBSD_4_4_BASE and libevent 1.3e --- authpf/authpf.8 | 6 +- ftp-proxy/filter.c | 4 +- ftp-proxy/ftp-proxy.c | 21 +- libevent/buffer.c | 22 +- libevent/event-internal.h | 5 + libevent/event.c | 174 ++++++++----- libevent/event.h | 41 ++-- libevent/evsignal.h | 13 +- libevent/kqueue.c | 32 ++- libevent/poll.c | 29 ++- libevent/select.c | 25 +- libevent/signal.c | 85 ++++--- man/pf.conf.5 | 61 ++++- man/pfsync.4 | 6 +- pfctl/parse.y | 505 +++++++++++++++++++++++--------------- pfctl/pf_print_state.c | 110 +++++---- pfctl/pfctl.8 | 71 ++++-- pfctl/pfctl.c | 132 +++++++--- pfctl/pfctl.h | 4 +- pfctl/pfctl_altq.c | 3 +- pfctl/pfctl_optimize.c | 6 +- pfctl/pfctl_parser.c | 30 ++- pfctl/pfctl_table.c | 13 +- pflogd/privsep_fdpass.c | 20 +- tftp-proxy/tftp-proxy.c | 16 +- 25 files changed, 922 insertions(+), 512 deletions(-) diff --git a/authpf/authpf.8 b/authpf/authpf.8 index be1f0c46fde8..6b6afa4616c3 100644 --- a/authpf/authpf.8 +++ b/authpf/authpf.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: authpf.8,v 1.45 2008/02/14 01:49:17 mcbride Exp $ +.\" $OpenBSD: authpf.8,v 1.46 2008/03/18 23:03:14 merdely Exp $ .\" .\" Copyright (c) 1998-2007 Bob Beck (beck@openbsd.org>. All rights reserved. .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: May 31 2007 $ +.Dd $Mdocdate: February 14 2008 $ .Dt AUTHPF 8 .Os .Sh NAME @@ -56,7 +56,7 @@ in this case the client's IP address is not provided to the packet filter via the .Ar client_ip macro or the -.Ar authpf users +.Ar authpf_users table. Additionally, states associated with the client IP address are not purged when the session is ended. diff --git a/ftp-proxy/filter.c b/ftp-proxy/filter.c index d99dfcbd6b17..80625a6fd9c8 100644 --- a/ftp-proxy/filter.c +++ b/ftp-proxy/filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: filter.c,v 1.7 2008/02/26 18:52:53 henning Exp $ */ +/* $OpenBSD: filter.c,v 1.8 2008/06/13 07:25:26 claudio Exp $ */ /* * Copyright (c) 2004, 2005 Camiel Dobbelaar, @@ -173,7 +173,7 @@ init_filter(char *opt_qname, char *opt_tagname, int opt_verbose) dev = open("/dev/pf", O_RDWR); if (dev == -1) - err(1, "/dev/pf"); + err(1, "open /dev/pf"); if (ioctl(dev, DIOCGETSTATUS, &status) == -1) err(1, "DIOCGETSTATUS"); if (!status.running) diff --git a/ftp-proxy/ftp-proxy.c b/ftp-proxy/ftp-proxy.c index 1a3bdf55fbd2..131991a4bb8e 100644 --- a/ftp-proxy/ftp-proxy.c +++ b/ftp-proxy/ftp-proxy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ftp-proxy.c,v 1.16 2008/02/26 18:52:53 henning Exp $ */ +/* $OpenBSD: ftp-proxy.c,v 1.19 2008/06/13 07:25:26 claudio Exp $ */ /* * Copyright (c) 2004, 2005 Camiel Dobbelaar, @@ -91,7 +91,7 @@ int client_parse_cmd(struct session *s); void client_read(struct bufferevent *, void *); int drop_privs(void); void end_session(struct session *); -int exit_daemon(void); +void exit_daemon(void); int getline(char *, size_t *); void handle_connection(const int, short, void *); void handle_signal(int, short, void *); @@ -282,6 +282,12 @@ end_session(struct session *s) logmsg(LOG_INFO, "#%d ending session", s->id); + /* Flush output buffers. */ + if (s->client_bufev && s->client_fd != -1) + evbuffer_write(s->client_bufev->output, s->client_fd); + if (s->server_bufev && s->server_fd != -1) + evbuffer_write(s->server_bufev->output, s->server_fd); + if (s->client_fd != -1) close(s->client_fd); if (s->server_fd != -1) @@ -309,7 +315,7 @@ end_session(struct session *s) session_count--; } -int +void exit_daemon(void) { struct session *s, *next; @@ -323,9 +329,6 @@ exit_daemon(void) closelog(); exit(0); - - /* NOTREACHED */ - return (-1); } int @@ -519,7 +522,7 @@ handle_signal(int sig, short event, void *arg) * Signal handler rules don't apply, libevent decouples for us. */ - logmsg(LOG_ERR, "%s exiting on signal %d", __progname, sig); + logmsg(LOG_ERR, "exiting on signal %d", sig); exit_daemon(); } @@ -834,8 +837,8 @@ u_int16_t pick_proxy_port(void) { /* Random should be good enough for avoiding port collisions. */ - return (IPPORT_HIFIRSTAUTO + (arc4random() % - (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO))); + return (IPPORT_HIFIRSTAUTO + + arc4random_uniform(IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)); } void diff --git a/libevent/buffer.c b/libevent/buffer.c index 77efd0cfa3e2..0327eb549383 100644 --- a/libevent/buffer.c +++ b/libevent/buffer.c @@ -44,6 +44,7 @@ #include #endif +#include #include #include #include @@ -106,7 +107,7 @@ evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf) /* * 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 + * of data that we transfered from inbuf to outbuf */ if (inbuf->off != oldoff && inbuf->cb != NULL) (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg); @@ -134,9 +135,13 @@ evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap) int sz; va_list aq; + /* make sure that at least some space is available */ + evbuffer_expand(buf, 64); for (;;) { + size_t used = buf->misalign + buf->off; buffer = (char *)buf->buffer + buf->off; - space = buf->totallen - buf->misalign - buf->off; + assert(buf->totallen >= used); + space = buf->totallen - used; #ifndef va_copy #define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list)) @@ -152,7 +157,7 @@ evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap) va_end(aq); - if (sz == -1) + if (sz < 0) return (-1); if (sz < space) { buf->off += sz; @@ -244,7 +249,7 @@ evbuffer_readline(struct evbuffer *buffer) /* Adds data to an event buffer */ -static inline void +static void evbuffer_align(struct evbuffer *buf) { memmove(buf->orig_buffer, buf->buffer, buf->off); @@ -431,13 +436,12 @@ evbuffer_write(struct evbuffer *buffer, int fd) 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 *search = buffer->buffer, *end = search + buffer->off; u_char *p; - while ((p = memchr(search, *what, remain)) != NULL) { - remain = buffer->off - (size_t)(search - buffer->buffer); - if (remain < len) + while (search < end && + (p = memchr(search, *what, end - search)) != NULL) { + if (p + len > end) break; if (memcmp(p, what, len) == 0) return (p); diff --git a/libevent/event-internal.h b/libevent/event-internal.h index becb6691d52a..7fd4b6c690f3 100644 --- a/libevent/event-internal.h +++ b/libevent/event-internal.h @@ -31,6 +31,8 @@ extern "C" { #endif +#include "evsignal.h" + struct event_base { const struct eventop *evsel; void *evbase; @@ -43,6 +45,9 @@ struct event_base { struct event_list **activequeues; int nactivequeues; + /* signal handling info */ + struct evsignal_info sig; + struct event_list eventqueue; struct timeval event_tv; diff --git a/libevent/event.c b/libevent/event.c index f6d2b1cc42ca..15bf14cf3b48 100644 --- a/libevent/event.c +++ b/libevent/event.c @@ -51,6 +51,7 @@ #include #include #include +#include #include "event.h" #include "event-internal.h" @@ -111,9 +112,9 @@ const struct eventop *eventops[] = { }; /* Global state */ -struct event_list signalqueue; - struct event_base *current_base = NULL; +extern struct event_base *evsignal_base; +static int use_monotonic; /* Handle signals - This is a deprecated interface */ int (*event_sigcb)(void); /* Signal callback when gotsig is set */ @@ -126,7 +127,7 @@ 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 int timeout_next(struct event_base *, struct timeval **); static void timeout_process(struct event_base *); static void timeout_correct(struct event_base *, struct timeval *); @@ -144,25 +145,34 @@ compare(struct event *a, struct event *b) return (0); } +static void +detect_monotonic(void) +{ +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + use_monotonic = 1; +#endif +} + static int gettime(struct timeval *tp) { -#ifdef HAVE_CLOCK_GETTIME +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) 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); + if (use_monotonic) { + if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) + return (-1); + + tp->tv_sec = ts.tv_sec; + tp->tv_usec = ts.tv_nsec / 1000; + return (0); + } #endif - return (0); + return (gettimeofday(tp, NULL)); } RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare); @@ -174,36 +184,42 @@ void * event_init(void) { int i; + struct event_base *base; - if ((current_base = calloc(1, sizeof(struct event_base))) == NULL) + if ((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(); + detect_monotonic(); + gettime(&base->event_tv); + + RB_INIT(&base->timetree); + TAILQ_INIT(&base->eventqueue); + TAILQ_INIT(&base->sig.signalqueue); + base->sig.ev_signal_pair[0] = -1; + base->sig.ev_signal_pair[1] = -1; + + base->evbase = NULL; + for (i = 0; eventops[i] && !base->evbase; i++) { + base->evsel = eventops[i]; + + base->evbase = base->evsel->init(base); } - if (current_base->evbase == NULL) + if (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); + base->evsel->name); /* allocate a single active event queue */ - event_base_priority_init(current_base, 1); + event_base_priority_init(base, 1); - return (current_base); + current_base = base; + return (base); } void @@ -217,7 +233,8 @@ event_base_free(struct event_base *base) current_base = NULL; assert(base); - assert(TAILQ_EMPTY(&base->eventqueue)); + if (base->evsel->dealloc != NULL) + base->evsel->dealloc(base, base->evbase); for (i=0; i < base->nactivequeues; ++i) assert(TAILQ_EMPTY(base->activequeues[i])); @@ -227,8 +244,7 @@ event_base_free(struct event_base *base) free(base->activequeues[i]); free(base->activequeues); - if (base->evsel->dealloc != NULL) - base->evsel->dealloc(base->evbase); + assert(TAILQ_EMPTY(&base->eventqueue)); free(base); } @@ -343,7 +359,6 @@ event_loopexit_cb(int fd, short what, void *arg) } /* not thread safe */ - int event_loopexit(struct timeval *tv) { @@ -354,7 +369,7 @@ event_loopexit(struct timeval *tv) int event_base_loopexit(struct event_base *event_base, struct timeval *tv) { - return (event_once(-1, EV_TIMEOUT, event_loopexit_cb, + return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb, event_base, tv)); } @@ -372,8 +387,13 @@ event_base_loop(struct event_base *base, int flags) const struct eventop *evsel = base->evsel; void *evbase = base->evbase; struct timeval tv; + struct timeval *tv_p; int res, done; +#ifndef WIN32 + if(!TAILQ_EMPTY(&base->sig.signalqueue)) + evsignal_base = base; +#endif done = 0; while (!done) { /* Calculate the initial events that we are waiting for */ @@ -398,21 +418,18 @@ event_base_loop(struct event_base *base, int flags) } } - /* 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; + timeout_correct(base, &tv); - if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) - timeout_next(base, &tv); - else + tv_p = &tv; + if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) { + timeout_next(base, &tv_p); + } else { + /* + * if we have active events, we just poll new events + * without waiting. + */ timerclear(&tv); + } /* If we have no events, we just exit */ if (!event_haveevents(base)) { @@ -420,7 +437,8 @@ event_base_loop(struct event_base *base, int flags) return (1); } - res = evsel->dispatch(base, evbase, &tv); + res = evsel->dispatch(base, evbase, tv_p); + if (res == -1) return (-1); @@ -459,11 +477,18 @@ event_once_cb(int fd, short events, void *arg) free(eonce); } -/* Schedules an event once */ - +/* not threadsafe, event scheduled once. */ int event_once(int fd, short events, void (*callback)(int, short, void *), void *arg, struct timeval *tv) +{ + return event_base_once(current_base, fd, events, callback, arg, tv); +} + +/* Schedules an event once */ +int +event_base_once(struct event_base *base, int fd, short events, + void (*callback)(int, short, void *), void *arg, struct timeval *tv) { struct event_once *eonce; struct timeval etv; @@ -496,7 +521,9 @@ event_once(int fd, short events, return (-1); } - res = event_add(&eonce->ev, tv); + res = event_base_set(base, &eonce->ev); + if (res == 0) + res = event_add(&eonce->ev, tv); if (res != 0) { free(eonce); return (res); @@ -516,12 +543,14 @@ event_set(struct event *ev, int fd, short events, ev->ev_arg = arg; ev->ev_fd = fd; ev->ev_events = events; + ev->ev_res = 0; 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; + if(current_base) + ev->ev_pri = current_base->nactivequeues/2; } int @@ -710,16 +739,16 @@ event_active(struct event *ev, int res, short ncalls) event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE); } -int -timeout_next(struct event_base *base, struct timeval *tv) +static int +timeout_next(struct event_base *base, struct timeval **tv_p) { - struct timeval dflt = TIMEOUT_DEFAULT; - struct timeval now; struct event *ev; + struct timeval *tv = *tv_p; if ((ev = RB_MIN(event_tree, &base->timetree)) == NULL) { - *tv = dflt; + /* if no time-based events are active wait for I/O */ + *tv_p = NULL; return (0); } @@ -740,17 +769,38 @@ timeout_next(struct event_base *base, struct timeval *tv) return (0); } +/* + * Determines if the time is running backwards by comparing the current + * time against the last time we checked. Not needed when using clock + * monotonic. + */ + static void -timeout_correct(struct event_base *base, struct timeval *off) +timeout_correct(struct event_base *base, struct timeval *tv) { struct event *ev; + struct timeval off; + + if (use_monotonic) + return; + + /* Check if time is running backwards */ + gettime(tv); + if (timercmp(tv, &base->event_tv, >=)) { + base->event_tv = *tv; + return; + } + + event_debug(("%s: time is running backwards, corrected", + __func__)); + timersub(&base->event_tv, tv, &off); /* * 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); + timersub(&ev->ev_timeout, &off, &ev->ev_timeout); } void @@ -801,7 +851,7 @@ event_queue_remove(struct event_base *base, struct event *ev, int queue) ev, ev_active_next); break; case EVLIST_SIGNAL: - TAILQ_REMOVE(&signalqueue, ev, ev_signal_next); + TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next); break; case EVLIST_TIMEOUT: RB_REMOVE(event_tree, &base->timetree, ev); @@ -843,7 +893,7 @@ event_queue_insert(struct event_base *base, struct event *ev, int queue) ev,ev_active_next); break; case EVLIST_SIGNAL: - TAILQ_INSERT_TAIL(&signalqueue, ev, ev_signal_next); + TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next); break; case EVLIST_TIMEOUT: { struct event *tmp = RB_INSERT(event_tree, &base->timetree, ev); diff --git a/libevent/event.h b/libevent/event.h index 3f2032dd068e..4c39939cc501 100644 --- a/libevent/event.h +++ b/libevent/event.h @@ -31,6 +31,8 @@ extern "C" { #endif +#include +#include #include #ifdef WIN32 @@ -131,16 +133,14 @@ TAILQ_HEAD (evkeyvalq, evkeyval); struct eventop { char *name; - void *(*init)(void); + void *(*init)(struct event_base *); 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 *); + void (*dealloc)(struct event_base *, void *); }; -#define TIMEOUT_DEFAULT {5, 0} - void *event_init(void); int event_dispatch(void); int event_base_dispatch(struct event_base *); @@ -184,6 +184,7 @@ int event_base_loopexit(struct event_base *, struct timeval *); 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_base_once(struct event_base *, int, short, void (*)(int, short, void *), void *, struct timeval *); int event_add(struct event *, struct timeval *); int event_del(struct event *); @@ -299,39 +300,37 @@ void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_ void evtag_init(void); -void evtag_marshal(struct evbuffer *evbuf, u_int8_t tag, const void *data, - u_int32_t len); +void evtag_marshal(struct evbuffer *evbuf, uint8_t tag, const void *data, + uint32_t len); -void encode_int(struct evbuffer *evbuf, u_int32_t number); +void encode_int(struct evbuffer *evbuf, uint32_t number); -void evtag_marshal_int(struct evbuffer *evbuf, u_int8_t tag, - u_int32_t integer); +void evtag_marshal_int(struct evbuffer *evbuf, uint8_t tag, uint32_t integer); -void evtag_marshal_string(struct evbuffer *buf, u_int8_t tag, +void evtag_marshal_string(struct evbuffer *buf, uint8_t tag, const char *string); -void evtag_marshal_timeval(struct evbuffer *evbuf, u_int8_t tag, +void evtag_marshal_timeval(struct evbuffer *evbuf, uint8_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_unmarshal(struct evbuffer *src, uint8_t *ptag, struct evbuffer *dst); +int evtag_peek(struct evbuffer *evbuf, uint8_t *ptag); +int evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength); +int evtag_payload_length(struct evbuffer *evbuf, uint32_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_int(struct evbuffer *evbuf, uint8_t need_tag, + uint32_t *pinteger); -int evtag_unmarshal_fixed(struct evbuffer *src, u_int8_t need_tag, void *data, +int evtag_unmarshal_fixed(struct evbuffer *src, uint8_t need_tag, void *data, size_t len); -int evtag_unmarshal_string(struct evbuffer *evbuf, u_int8_t need_tag, +int evtag_unmarshal_string(struct evbuffer *evbuf, uint8_t need_tag, char **pstring); -int evtag_unmarshal_timeval(struct evbuffer *evbuf, u_int8_t need_tag, +int evtag_unmarshal_timeval(struct evbuffer *evbuf, uint8_t need_tag, struct timeval *ptv); #ifdef __cplusplus diff --git a/libevent/evsignal.h b/libevent/evsignal.h index 5b92bd6e55fb..7efbcabec896 100644 --- a/libevent/evsignal.h +++ b/libevent/evsignal.h @@ -27,9 +27,18 @@ #ifndef _EVSIGNAL_H_ #define _EVSIGNAL_H_ -void evsignal_init(void); -void evsignal_process(void); +struct evsignal_info { + struct event_list signalqueue; + struct event ev_signal; + int ev_signal_pair[2]; + int ev_signal_added; + volatile sig_atomic_t evsignal_caught; + sig_atomic_t evsigcaught[NSIG]; +}; +void evsignal_init(struct event_base *); +void evsignal_process(struct event_base *); int evsignal_add(struct event *); int evsignal_del(struct event *); +void evsignal_dealloc(struct event_base *); #endif /* _EVSIGNAL_H_ */ diff --git a/libevent/kqueue.c b/libevent/kqueue.c index 08369c6dd51d..059d94a0b4d5 100644 --- a/libevent/kqueue.c +++ b/libevent/kqueue.c @@ -48,10 +48,13 @@ #include #endif -#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) -#define INTPTR(x) (intptr_t)x +/* Some platforms apparently define the udata field of struct kevent as + * ntptr_t, whereas others define it as void*. There doesn't seem to be an + * easy way to tell them apart via autoconf, so we need to use OS macros. */ +#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__) +#define PTR_TO_UDATA(x) ((intptr_t)(x)) #else -#define INTPTR(x) x +#define PTR_TO_UDATA(x) (x) #endif #include "event.h" @@ -69,13 +72,13 @@ struct kqop { int kq; }; -void *kq_init (void); +void *kq_init (struct event_base *); 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 *); +void kq_dealloc (struct event_base *, void *); const struct eventop kqops = { "kqueue", @@ -88,7 +91,7 @@ const struct eventop kqops = { }; void * -kq_init(void) +kq_init(struct event_base *base) { int kq; struct kqop *kqueueop; @@ -212,13 +215,16 @@ kq_dispatch(struct event_base *base, void *arg, struct timeval *tv) struct kevent *changes = kqop->changes; struct kevent *events = kqop->events; struct event *ev; - struct timespec ts; + struct timespec ts, *ts_p = NULL; int i, res; - TIMEVAL_TO_TIMESPEC(tv, &ts); + if (tv != NULL) { + TIMEVAL_TO_TIMESPEC(tv, &ts); + ts_p = &ts; + } res = kevent(kqop->kq, changes, kqop->nchanges, - events, kqop->nevents, &ts); + events, kqop->nevents, ts_p); kqop->nchanges = 0; if (res == -1) { if (errno != EINTR) { @@ -294,7 +300,7 @@ kq_add(void *arg, struct event *ev) kev.flags = EV_ADD; if (!(ev->ev_events & EV_PERSIST)) kev.flags |= EV_ONESHOT; - kev.udata = INTPTR(ev); + kev.udata = PTR_TO_UDATA(ev); if (kq_insert(kqop, &kev) == -1) return (-1); @@ -317,7 +323,7 @@ kq_add(void *arg, struct event *ev) kev.flags = EV_ADD; if (!(ev->ev_events & EV_PERSIST)) kev.flags |= EV_ONESHOT; - kev.udata = INTPTR(ev); + kev.udata = PTR_TO_UDATA(ev); if (kq_insert(kqop, &kev) == -1) return (-1); @@ -332,7 +338,7 @@ kq_add(void *arg, struct event *ev) kev.flags = EV_ADD; if (!(ev->ev_events & EV_PERSIST)) kev.flags |= EV_ONESHOT; - kev.udata = INTPTR(ev); + kev.udata = PTR_TO_UDATA(ev); if (kq_insert(kqop, &kev) == -1) return (-1); @@ -398,7 +404,7 @@ kq_del(void *arg, struct event *ev) } void -kq_dealloc(void *arg) +kq_dealloc(struct event_base *base, void *arg) { struct kqop *kqop = arg; diff --git a/libevent/poll.c b/libevent/poll.c index 14ca8453739b..123d36a56023 100644 --- a/libevent/poll.c +++ b/libevent/poll.c @@ -54,8 +54,6 @@ #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_* */ @@ -68,12 +66,12 @@ struct pollop { * "no entry." */ }; -void *poll_init (void); +void *poll_init (struct event_base *); 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 *); +void poll_dealloc (struct event_base *, void *); const struct eventop pollops = { "poll", @@ -86,7 +84,7 @@ const struct eventop pollops = { }; void * -poll_init(void) +poll_init(struct event_base *base) { struct pollop *pollop; @@ -97,7 +95,7 @@ poll_init(void) if (!(pollop = calloc(1, sizeof(struct pollop)))) return (NULL); - evsignal_init(); + evsignal_init(base); return (pollop); } @@ -150,13 +148,16 @@ poll_check_ok(struct pollop *pop) int poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) { - int res, i, sec, nfds; + int res, i, msec = -1, nfds; struct pollop *pop = arg; poll_check_ok(pop); - sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; + + if (tv != NULL) + msec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; + nfds = pop->nfds; - res = poll(pop->event_set, nfds, sec); + res = poll(pop->event_set, nfds, msec); if (res == -1) { if (errno != EINTR) { @@ -164,10 +165,11 @@ poll_dispatch(struct event_base *base, void *arg, struct timeval *tv) return (-1); } - evsignal_process(); + evsignal_process(base); return (0); - } else if (evsignal_caught) - evsignal_process(); + } else if (base->sig.evsignal_caught) { + evsignal_process(base); + } event_debug(("%s: poll reports %d", __func__, res)); @@ -370,10 +372,11 @@ poll_del(void *arg, struct event *ev) } void -poll_dealloc(void *arg) +poll_dealloc(struct event_base *base, void *arg) { struct pollop *pop = arg; + evsignal_dealloc(base); if (pop->event_set) free(pop->event_set); if (pop->event_r_back) diff --git a/libevent/select.c b/libevent/select.c index 6ce81a232bbe..d645f1a37030 100644 --- a/libevent/select.c +++ b/libevent/select.c @@ -36,6 +36,9 @@ #else #include #endif +#ifdef HAVE_SYS_SELECT_H +#include +#endif #include #include #include @@ -57,8 +60,6 @@ #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; @@ -70,12 +71,12 @@ struct selectop { struct event **event_w_by_fd; }; -void *select_init (void); +void *select_init (struct event_base *); 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 *); +void select_dealloc (struct event_base *, void *); const struct eventop selectops = { "select", @@ -90,7 +91,7 @@ const struct eventop selectops = { static int select_resize(struct selectop *sop, int fdsz); void * -select_init(void) +select_init(struct event_base *base) { struct selectop *sop; @@ -103,7 +104,7 @@ select_init(void) select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask)); - evsignal_init(); + evsignal_init(base); return (sop); } @@ -113,7 +114,7 @@ static void check_selectop(struct selectop *sop) { int i; - for (i=0;i<=sop->event_fds;++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); @@ -174,10 +175,11 @@ select_dispatch(struct event_base *base, void *arg, struct timeval *tv) return (-1); } - evsignal_process(); + evsignal_process(base); return (0); - } else if (evsignal_caught) - evsignal_process(); + } else if (base->sig.evsignal_caught) { + evsignal_process(base); + } event_debug(("%s: select reports %d", __func__, res)); @@ -348,10 +350,11 @@ select_del(void *arg, struct event *ev) } void -select_dealloc(void *arg) +select_dealloc(struct event_base *base, void *arg) { struct selectop *sop = arg; + evsignal_dealloc(base); if (sop->event_readset_in) free(sop->event_readset_in); if (sop->event_writeset_in) diff --git a/libevent/signal.c b/libevent/signal.c index 71bcffcba5b3..6c0953d9e121 100644 --- a/libevent/signal.c +++ b/libevent/signal.c @@ -31,6 +31,7 @@ #endif #include +#include #ifdef HAVE_SYS_TIME_H #include #else @@ -47,19 +48,14 @@ #ifdef HAVE_FCNTL_H #include #endif +#include #include "event.h" +#include "event-internal.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; +struct event_base *evsignal_base = NULL; static void evsignal_handler(int sig); @@ -87,24 +83,27 @@ evsignal_cb(int fd, short what, void *arg) #endif void -evsignal_init(void) +evsignal_init(struct event_base *base) { /* * 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) + if (socketpair(AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) event_err(1, "%s: socketpair", __func__); - FD_CLOSEONEXEC(ev_signal_pair[0]); - FD_CLOSEONEXEC(ev_signal_pair[1]); + FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]); + FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]); + base->sig.evsignal_caught = 0; + memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG); - fcntl(ev_signal_pair[0], F_SETFL, O_NONBLOCK); + fcntl(base->sig.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; + event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1], EV_READ, + evsignal_cb, &base->sig.ev_signal); + base->sig.ev_signal.ev_base = base; + base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL; } int @@ -112,6 +111,7 @@ evsignal_add(struct event *ev) { int evsignal; struct sigaction sa; + struct event_base *base = ev->ev_base; if (ev->ev_events & (EV_READ|EV_WRITE)) event_errx(1, "%s: EV_SIGNAL incompatible use", __func__); @@ -121,29 +121,23 @@ evsignal_add(struct event *ev) sa.sa_handler = evsignal_handler; sigfillset(&sa.sa_mask); sa.sa_flags |= SA_RESTART; + /* catch signals if they happen quickly */ + evsignal_base = base; if (sigaction(evsignal, &sa, NULL) == -1) return (-1); - if (!ev_signal_added) { - ev_signal_added = 1; - event_add(&ev_signal, NULL); + if (!base->sig.ev_signal_added) { + base->sig.ev_signal_added = 1; + event_add(&base->sig.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)); } @@ -152,29 +146,50 @@ evsignal_handler(int sig) { int save_errno = errno; - evsigcaught[sig]++; - evsignal_caught = 1; + if(evsignal_base == NULL) { + event_warn( + "%s: received signal %s, but have no base configured", + __func__, sig); + return; + } + + evsignal_base->sig.evsigcaught[sig]++; + evsignal_base->sig.evsignal_caught = 1; /* Wake up our notification mechanism */ - write(ev_signal_pair[0], "a", 1); + write(evsignal_base->sig.ev_signal_pair[0], "a", 1); errno = save_errno; } void -evsignal_process(void) +evsignal_process(struct event_base *base) { struct event *ev; sig_atomic_t ncalls; - evsignal_caught = 0; - TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) { - ncalls = evsigcaught[EVENT_SIGNAL(ev)]; + base->sig.evsignal_caught = 0; + TAILQ_FOREACH(ev, &base->sig.signalqueue, ev_signal_next) { + ncalls = base->sig.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; + base->sig.evsigcaught[EVENT_SIGNAL(ev)] = 0; } } } +void +evsignal_dealloc(struct event_base *base) +{ + if(base->sig.ev_signal_added) { + event_del(&base->sig.ev_signal); + base->sig.ev_signal_added = 0; + } + assert(TAILQ_EMPTY(&base->sig.signalqueue)); + + close(base->sig.ev_signal_pair[0]); + base->sig.ev_signal_pair[0] = -1; + close(base->sig.ev_signal_pair[1]); + base->sig.ev_signal_pair[1] = -1; +} diff --git a/man/pf.conf.5 b/man/pf.conf.5 index 7624dc074050..5e49a3c24930 100644 --- a/man/pf.conf.5 +++ b/man/pf.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pf.conf.5,v 1.393 2008/02/11 07:46:32 jmc Exp $ +.\" $OpenBSD: pf.conf.5,v 1.402 2008/06/11 07:21:00 jmc Exp $ .\" .\" Copyright (c) 2002, Daniel Hartmeier .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: Febuary 1 2008 $ +.Dd $Mdocdate: June 10 2008 $ .Dt PF.CONF 5 .Os .Sh NAME @@ -164,7 +164,7 @@ A table initialized with the empty list, will be cleared on load. .El .Pp -Tables may be defined with the following two attributes: +Tables may be defined with the following attributes: .Bl -tag -width persist .It Ar persist The @@ -183,6 +183,11 @@ can be used to add or remove addresses from the table at any time, even when running with .Xr securelevel 7 = 2. +.It Ar counters +The +.Ar counters +flag enables per-address packet and byte counters which can be displayed with +.Xr pfctl 8 . .El .Pp For example, @@ -629,6 +634,19 @@ modifier to ensure unique IP identifiers. Enforces a minimum TTL for matching IP packets. .It Ar max-mss Aq Ar number Enforces a maximum MSS for matching TCP packets. +.It Xo Ar set-tos Aq Ar string +.No \*(Ba Aq Ar number +.Xc +Enforces a +.Em TOS +for matching IP packets. +.Em TOS +may be +given as one of +.Ar lowdelay , +.Ar throughput , +.Ar reliability , +or as either hex or decimal. .It Ar random-id Replaces the IP identification field with random values to compensate for predictable values generated by many hosts. @@ -1808,7 +1826,8 @@ or rules in addition to filter rules. Tags take the same macros as labels (see above). .It Ar tagged Aq Ar string -Used with filter or translation rules to specify that packets must already +Used with filter, translation or scrub rules +to specify that packets must already be tagged with the given tag in order to match the rule. Inverse tag matching can also be done by specifying the @@ -1819,6 +1838,22 @@ keyword. .It Ar rtable Aq Ar number Used to select an alternate routing table for the routing lookup. Only effective before the route lookup happened, i.e. when filtering inbound. +.It Xo Ar divert-to Aq Ar host +.Ar port Aq Ar port +.Xc +Used to redirect packets to a local socket bound to +.Ar host +and +.Ar port . +The packets will not be modified, so +.Xr getsockname 2 +on the socket will return the original destination address of the packet. +.It Ar divert-reply +Used to receive replies for sockets that are bound to addresses +which are not local to the machine. +See +.Xr setsockopt 2 +for information on how to bind these sockets. .It Ar probability Aq Ar number A probability attribute can be attached to a rule, with a value set between 0 and 1, bounds not included. @@ -2056,6 +2091,13 @@ Changes the timeout values used for states created by this rule. For a list of all valid timeout names, see .Sx OPTIONS above. +.It Ar sloppy +Uses a sloppy TCP connection tracker that does not check sequence +numbers at all, which makes insertion and ICMP teardown attacks way +easier. +This is intended to be used in situations where one does not see all +packets of a connection, e.g. in asymmetric routing situations. +Cannot be used with modulate or synproxy state. .El .Pp Multiple options can be specified, separated by commas: @@ -2793,10 +2835,10 @@ logopts = logopt [ "," logopts ] logopt = "all" | "user" | "to" interface-name filteropt-list = filteropt-list filteropt | filteropt -filteropt = user | group | flags | icmp-type | icmp6-type | tos | +filteropt = user | group | flags | icmp-type | icmp6-type | "tos" tos | ( "no" | "keep" | "modulate" | "synproxy" ) "state" [ "(" state-opts ")" ] | - "fragment" | "no-df" | "min-ttl" number | + "fragment" | "no-df" | "min-ttl" number | "set-tos" tos | "max-mss" number | "random-id" | "reassemble tcp" | fragmentation | "allow-opts" | "label" string | "tag" string | [ ! ] "tagged" string | @@ -2827,7 +2869,7 @@ antispoof-rule = "antispoof" [ "log" ] [ "quick" ] table-rule = "table" "\*(Lt" string "\*(Gt" [ tableopts-list ] tableopts-list = tableopts-list tableopts | tableopts -tableopts = "persist" | "const" | "file" string | +tableopts = "persist" | "const" | "counters" | "file" string | "{" [ tableaddr-list ] "}" tableaddr-list = tableaddr-list [ "," ] tableaddr-spec | tableaddr-spec tableaddr-spec = [ "!" ] tableaddr [ "/" mask-bits ] @@ -2917,11 +2959,11 @@ icmp-type-code = ( icmp-type-name | icmp-type-number ) [ "code" ( icmp-code-name | icmp-code-number ) ] icmp-list = icmp-type-code [ [ "," ] icmp-list ] -tos = "tos" ( "lowdelay" | "throughput" | "reliability" | +tos = ( "lowdelay" | "throughput" | "reliability" | [ "0x" ] number ) state-opts = state-opt [ [ "," ] state-opts ] -state-opt = ( "max" number | "no-sync" | timeout | +state-opt = ( "max" number | "no-sync" | timeout | sloppy | "source-track" [ ( "rule" | "global" ) ] | "max-src-nodes" number | "max-src-states" number | "max-src-conn" number | @@ -2962,6 +3004,7 @@ realtime-sc = "realtime" sc-spec upperlimit-sc = "upperlimit" sc-spec sc-spec = ( bandwidth-spec | "(" bandwidth-spec number bandwidth-spec ")" ) +include = "include" filename .Ed .Sh FILES .Bl -tag -width "/etc/protocols" -compact diff --git a/man/pfsync.4 b/man/pfsync.4 index 027d46014d10..d10131457ad8 100644 --- a/man/pfsync.4 +++ b/man/pfsync.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pfsync.4,v 1.26 2007/09/20 20:50:07 mpf Exp $ +.\" $OpenBSD: pfsync.4,v 1.27 2008/06/03 19:51:02 jmc Exp $ .\" .\" Copyright (c) 2002 Michael Shalayeff .\" Copyright (c) 2003-2004 Ryan McBride @@ -24,7 +24,7 @@ .\" (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 $Mdocdate: May 31 2007 $ +.Dd $Mdocdate: September 20 2007 $ .Dt PFSYNC 4 .Os .Sh NAME @@ -121,7 +121,7 @@ e.g.: It is important that the pfsync traffic be well secured as there is no authentication on the protocol and it would be trivial to spoof packets which create states, bypassing the pf ruleset. -Either run the pfsync protocol on a trusted network \- ideally a network +Either run the pfsync protocol on a trusted network \- ideally a network dedicated to pfsync messages such as a crossover cable between two firewalls, or specify a peer address and protect the traffic with .Xr ipsec 4 . diff --git a/pfctl/parse.y b/pfctl/parse.y index c41899631987..55c3a7553739 100644 --- a/pfctl/parse.y +++ b/pfctl/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.536 2008/02/01 06:58:45 mcbride Exp $ */ +/* $OpenBSD: parse.y,v 1.549 2008/07/03 16:09:34 deraadt Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -153,7 +153,7 @@ enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN, PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES, PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK, - PF_STATE_OPT_TIMEOUT }; + PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY }; enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; @@ -232,6 +232,10 @@ struct filter_opts { char *match_tag; u_int8_t match_tag_not; u_int rtableid; + struct { + struct node_host *addr; + u_int16_t port; + } divert; } filter_opts; struct antispoof_opts { @@ -244,12 +248,16 @@ struct scrub_opts { #define SOM_MINTTL 0x01 #define SOM_MAXMSS 0x02 #define SOM_FRAGCACHE 0x04 +#define SOM_SETTOS 0x08 int nodf; int minttl; int maxmss; + int settos; int fragcache; int randomid; int reassemble_tcp; + char *match_tag; + u_int8_t match_tag_not; u_int rtableid; } scrub_opts; @@ -410,6 +418,10 @@ typedef struct { int lineno; } YYSTYPE; +#define PPORT_RANGE 1 +#define PPORT_STAR 2 +int parseport(char *, struct range *r, int); + #define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) @@ -430,8 +442,9 @@ typedef struct { %token QUEUE PRIORITY QLIMIT RTABLE %token LOAD RULESET_OPTIMIZATION %token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE -%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH -%token TAGGED TAG IFBOUND FLOATING STATEPOLICY ROUTE +%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY +%token TAGGED TAG IFBOUND FLOATING STATEPOLICY ROUTE SETTOS +%token DIVERTTO DIVERTREPLY %token STRING %token NUMBER %token PORTBINARY @@ -443,7 +456,7 @@ typedef struct { %type sourcetrack flush unaryop statelock %type action nataction natpasslog scrubaction %type flags flag blockspec -%type port rport +%type portplain portstar portrange %type hashkey %type proto proto_list proto_item %type protoval @@ -453,7 +466,7 @@ typedef struct { %type reticmpspec reticmp6spec %type fromto %type ipportspec from to -%type ipspec xhost host dynaddr host_list +%type ipspec toipspec xhost host dynaddr host_list %type redir_host_list redirspec %type route_host route_host_list routespec %type os xos os_list @@ -462,7 +475,8 @@ typedef struct { %type gids gid_list gid_item %type route %type redirection redirpool -%type label string stringall tag anchorname +%type label stringall tag anchorname +%type string varstring numberstring %type keep %type state_opt_spec state_opt_list state_opt_item %type logquick quick log logopts logopt @@ -563,9 +577,9 @@ option : SET OPTIMIZATION STRING { } } | SET TIMEOUT timeout_spec - | SET TIMEOUT '{' timeout_list '}' + | SET TIMEOUT '{' optnl timeout_list '}' | SET LIMIT limit_spec - | SET LIMIT '{' limit_list '}' + | SET LIMIT '{' optnl limit_list '}' | SET LOGINTERFACE stringall { if (check_rulestate(PFCTL_STATE_OPTION)) { free($3); @@ -666,7 +680,7 @@ stringall : STRING { $$ = $1; } } ; -string : string STRING { +string : STRING string { if (asprintf(&$$, "%s %s", $1, $2) == -1) err(1, "string: asprintf"); free($1); @@ -675,7 +689,27 @@ string : string STRING { | STRING ; -varset : STRING '=' string { +varstring : numberstring varstring { + if (asprintf(&$$, "%s %s", $1, $2) == -1) + err(1, "string: asprintf"); + free($1); + free($2); + } + | numberstring + ; + +numberstring : NUMBER { + char *s; + if (asprintf(&s, "%lld", $1) == -1) { + yyerror("string: asprintf"); + YYERROR; + } + $$ = s; + } + | STRING + ; + +varset : STRING '=' varstring { if (pf->opts & PF_OPT_VERBOSE) printf("%s = \"%s\"\n", $1, $3); if (symset($1, $3, 0) == -1) @@ -683,33 +717,16 @@ varset : STRING '=' string { free($1); free($3); } - | STRING '=' NUMBER { - char *s; - if (asprintf(&s, "%lld", $3) == -1) { - yyerror("string: asprintf"); - YYERROR; - } - if (pf->opts & PF_OPT_VERBOSE) - printf("%s = \"%s\"\n", $1, s); - if (symset($1, s, 0) == -1) - err(1, "cannot store variable %s", $1); - free($1); - free(s); - } ; anchorname : STRING { $$ = $1; } | /* empty */ { $$ = NULL; } ; -optnl : optnl '\n' - | - ; - -pfa_anchorlist : pfrule optnl - | anchorrule optnl - | pfa_anchorlist pfrule optnl - | pfa_anchorlist anchorrule optnl +pfa_anchorlist : /* empty */ + | pfa_anchorlist '\n' + | pfa_anchorlist pfrule '\n' + | pfa_anchorlist anchorrule '\n' ; pfa_anchor : '{' @@ -1037,8 +1054,20 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts r.min_ttl = $8.minttl; if ($8.maxmss) r.max_mss = $8.maxmss; + if ($8.marker & SOM_SETTOS) { + r.rule_flag |= PFRULE_SET_TOS; + r.set_tos = $8.settos; + } if ($8.fragcache) r.rule_flag |= $8.fragcache; + if ($8.match_tag) + if (strlcpy(r.match_tagname, $8.match_tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = $8.match_tag_not; r.rtableid = $8.rtableid; expand_rule(&r, $4, NULL, $6, $7.src_os, @@ -1095,6 +1124,14 @@ scrub_opt : NODF { scrub_opts.marker |= SOM_MAXMSS; scrub_opts.maxmss = $2; } + | SETTOS tos { + if (scrub_opts.marker & SOM_SETTOS) { + yyerror("set-tos cannot be respecified"); + YYERROR; + } + scrub_opts.marker |= SOM_SETTOS; + scrub_opts.settos = $2; + } | fragcache { if (scrub_opts.marker & SOM_FRAGCACHE) { yyerror("fragcache cannot be respecified"); @@ -1131,6 +1168,10 @@ scrub_opt : NODF { } scrub_opts.rtableid = $2; } + | not TAGGED string { + scrub_opts.match_tag = $3; + scrub_opts.match_tag_not = $1; + } ; fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } @@ -1225,11 +1266,11 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { ; antispoof_ifspc : FOR antispoof_if { $$ = $2; } - | FOR '{' antispoof_iflst '}' { $$ = $3; } + | FOR '{' optnl antispoof_iflst '}' { $$ = $4; } ; -antispoof_iflst : antispoof_if { $$ = $1; } - | antispoof_iflst comma antispoof_if { +antispoof_iflst : antispoof_if optnl { $$ = $1; } + | antispoof_iflst comma antispoof_if optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -1333,6 +1374,8 @@ table_opt : STRING { table_opts.flags |= PFR_TFLAG_CONST; else if (!strcmp($1, "persist")) table_opts.flags |= PFR_TFLAG_PERSIST; + else if (!strcmp($1, "counters")) + table_opts.flags |= PFR_TFLAG_COUNTERS; else { yyerror("invalid table option '%s'", $1); free($1); @@ -1340,12 +1383,12 @@ table_opt : STRING { } free($1); } - | '{' '}' { table_opts.init_addr = 1; } - | '{' host_list '}' { + | '{' optnl '}' { table_opts.init_addr = 1; } + | '{' optnl host_list '}' { struct node_host *n; struct node_tinit *ti; - for (n = $2; n != NULL; n = n->next) { + for (n = $3; n != NULL; n = n->next) { switch (n->addr.type) { case PF_ADDR_ADDRMASK: continue; /* ok */ @@ -1376,7 +1419,7 @@ table_opt : STRING { } if (!(ti = calloc(1, sizeof(*ti)))) err(1, "table_opt: calloc"); - ti->host = $2; + ti->host = $3; SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, entries); table_opts.init_addr = 1; @@ -1750,11 +1793,11 @@ hfscopts_item : LINKSHARE bandwidth { qassign : /* empty */ { $$ = NULL; } | qassign_item { $$ = $1; } - | '{' qassign_list '}' { $$ = $2; } + | '{' optnl qassign_list '}' { $$ = $3; } ; -qassign_list : qassign_item { $$ = $1; } - | qassign_list comma qassign_item { +qassign_list : qassign_item optnl { $$ = $1; } + | qassign_list comma qassign_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2009,6 +2052,14 @@ pfrule : action dir logquick interface route af proto fromto statelock = 1; r.rule_flag |= o->data.statelock; break; + case PF_STATE_OPT_SLOPPY: + if (r.rule_flag & PFRULE_STATESLOPPY) { + yyerror("state sloppy option: " + "multiple definitions"); + YYERROR; + } + r.rule_flag |= PFRULE_STATESLOPPY; + break; case PF_STATE_OPT_TIMEOUT: if (o->data.timeout.number == PFTM_ADAPTIVE_START || @@ -2145,6 +2196,30 @@ pfrule : action dir logquick interface route af proto fromto } free($9.queues.pqname); } + if ((r.divert.port = $9.divert.port)) { + if (r.direction == PF_OUT) { + if ($9.divert.addr) { + yyerror("address specified " + "for outgoing divert"); + YYERROR; + } + bzero(&r.divert.addr, + sizeof(r.divert.addr)); + } else { + if (!$9.divert.addr) { + yyerror("no address specified " + "for incoming divert"); + YYERROR; + } + if ($9.divert.addr->af != r.af) { + yyerror("address family " + "mismatch for divert"); + YYERROR; + } + r.divert.addr = + $9.divert.addr->addr.v.a.addr; + } + } expand_rule(&r, $4, $5.host, $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, @@ -2198,13 +2273,13 @@ filter_opt : USER uids { filter_opts.marker |= FOM_ICMP; filter_opts.icmpspec = $1; } - | tos { + | TOS tos { if (filter_opts.marker & FOM_TOS) { yyerror("tos cannot be redefined"); YYERROR; } filter_opts.marker |= FOM_TOS; - filter_opts.tos = $1; + filter_opts.tos = $2; } | keep { if (filter_opts.marker & FOM_KEEP) { @@ -2261,6 +2336,23 @@ filter_opt : USER uids { } filter_opts.rtableid = $2; } + | DIVERTTO STRING PORT portplain { + if ((filter_opts.divert.addr = host($2)) == NULL) { + yyerror("could not parse divert address: %s", + $2); + free($2); + YYERROR; + } + free($2); + filter_opts.divert.port = $4.a; + if (!filter_opts.divert.port) { + yyerror("invalid divert port: %u", ntohs($4.a)); + YYERROR; + } + } + | DIVERTREPLY { + filter_opts.divert.port = 1; /* some random value */ + } ; probability : STRING { @@ -2383,7 +2475,7 @@ reticmp6spec : STRING { } ; -dir : /* empty */ { $$ = 0; } +dir : /* empty */ { $$ = PF_INOUT; } | IN { $$ = PF_IN; } | OUT { $$ = PF_OUT; } ; @@ -2441,11 +2533,11 @@ logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } interface : /* empty */ { $$ = NULL; } | ON if_item_not { $$ = $2; } - | ON '{' if_list '}' { $$ = $3; } + | ON '{' optnl if_list '}' { $$ = $4; } ; -if_list : if_item_not { $$ = $1; } - | if_list comma if_item_not { +if_list : if_item_not optnl { $$ = $1; } + | if_list comma if_item_not optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2484,13 +2576,13 @@ af : /* empty */ { $$ = 0; } | INET6 { $$ = AF_INET6; } ; -proto : /* empty */ { $$ = NULL; } - | PROTO proto_item { $$ = $2; } - | PROTO '{' proto_list '}' { $$ = $3; } +proto : /* empty */ { $$ = NULL; } + | PROTO proto_item { $$ = $2; } + | PROTO '{' optnl proto_list '}' { $$ = $4; } ; -proto_list : proto_item { $$ = $1; } - | proto_list comma proto_item { +proto_list : proto_item optnl { $$ = $1; } + | proto_list comma proto_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2550,7 +2642,7 @@ fromto : ALL { os : /* empty */ { $$ = NULL; } | OS xos { $$ = $2; } - | OS '{' os_list '}' { $$ = $3; } + | OS '{' optnl os_list '}' { $$ = $4; } ; xos : STRING { @@ -2562,8 +2654,8 @@ xos : STRING { } ; -os_list : xos { $$ = $1; } - | os_list comma xos { +os_list : xos optnl { $$ = $1; } + | os_list comma xos optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2605,13 +2697,21 @@ ipportspec : ipspec { } ; -ipspec : ANY { $$ = NULL; } - | xhost { $$ = $1; } - | '{' host_list '}' { $$ = $2; } +optnl : '\n' optnl + | ; -host_list : ipspec { $$ = $1; } - | host_list comma ipspec { +ipspec : ANY { $$ = NULL; } + | xhost { $$ = $1; } + | '{' optnl host_list '}' { $$ = $3; } + ; + +toipspec : TO ipspec { $$ = $2; } + | /* empty */ { $$ = NULL; } + ; + +host_list : ipspec optnl { $$ = $1; } + | host_list comma ipspec optnl { if ($3 == NULL) $$ = $1; else if ($1 == NULL) @@ -2843,18 +2943,18 @@ dynaddr : '(' STRING ')' { ; portspec : port_item { $$ = $1; } - | '{' port_list '}' { $$ = $2; } + | '{' optnl port_list '}' { $$ = $3; } ; -port_list : port_item { $$ = $1; } - | port_list comma port_item { +port_list : port_item optnl { $$ = $1; } + | port_list comma port_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; -port_item : port { +port_item : portrange { $$ = calloc(1, sizeof(struct node_port)); if ($$ == NULL) err(1, "port_item: calloc"); @@ -2867,7 +2967,7 @@ port_item : port { $$->next = NULL; $$->tail = $$; } - | unaryop port { + | unaryop portrange { if ($2.t) { yyerror("':' cannot be used with an other " "port operator"); @@ -2882,7 +2982,7 @@ port_item : port { $$->next = NULL; $$->tail = $$; } - | port PORTBINARY port { + | portrange PORTBINARY portrange { if ($1.t || $3.t) { yyerror("':' cannot be used with an other " "port operator"); @@ -2899,46 +2999,30 @@ port_item : port { } ; -port : STRING { - char *p = strchr($1, ':'); - - if (p == NULL) { - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = $$.t = 0; - } else { - int port[2]; - - *p++ = 0; - if ((port[0] = getservice($1)) == -1 || - (port[1] = getservice(p)) == -1) { - free($1); - YYERROR; - } - $$.a = port[0]; - $$.b = port[1]; - $$.t = PF_OP_RRG; +portplain : numberstring { + if (parseport($1, &$$, 0) == -1) { + free($1); + YYERROR; } free($1); } - | NUMBER { - if ($1 < 0 || $1 > 65535) { - yyerror("illegal port value %lu", $1); + ; + +portrange : numberstring { + if (parseport($1, &$$, PPORT_RANGE) == -1) { + free($1); YYERROR; } - $$.a = ntohs($1); - $$.b = $$.t = 0; + free($1); } ; uids : uid_item { $$ = $1; } - | '{' uid_list '}' { $$ = $2; } + | '{' optnl uid_list '}' { $$ = $3; } ; -uid_list : uid_item { $$ = $1; } - | uid_list comma uid_item { +uid_list : uid_item optnl { $$ = $1; } + | uid_list comma uid_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -3012,11 +3096,11 @@ uid : STRING { ; gids : gid_item { $$ = $1; } - | '{' gid_list '}' { $$ = $2; } + | '{' optnl gid_list '}' { $$ = $3; } ; -gid_list : gid_item { $$ = $1; } - | gid_list comma gid_item { +gid_list : gid_item optnl { $$ = $1; } + | gid_list comma gid_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -3107,22 +3191,22 @@ flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; } ; -icmpspec : ICMPTYPE icmp_item { $$ = $2; } - | ICMPTYPE '{' icmp_list '}' { $$ = $3; } - | ICMP6TYPE icmp6_item { $$ = $2; } - | ICMP6TYPE '{' icmp6_list '}' { $$ = $3; } +icmpspec : ICMPTYPE icmp_item { $$ = $2; } + | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; } + | ICMP6TYPE icmp6_item { $$ = $2; } + | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; } ; -icmp_list : icmp_item { $$ = $1; } - | icmp_list comma icmp_item { +icmp_list : icmp_item optnl { $$ = $1; } + | icmp_list comma icmp_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; -icmp6_list : icmp6_item { $$ = $1; } - | icmp6_list comma icmp6_item { +icmp6_list : icmp6_item optnl { $$ = $1; } + | icmp6_list comma icmp6_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -3260,28 +3344,28 @@ icmp6type : STRING { } ; -tos : TOS STRING { - if (!strcmp($2, "lowdelay")) +tos : STRING { + if (!strcmp($1, "lowdelay")) $$ = IPTOS_LOWDELAY; - else if (!strcmp($2, "throughput")) + else if (!strcmp($1, "throughput")) $$ = IPTOS_THROUGHPUT; - else if (!strcmp($2, "reliability")) + else if (!strcmp($1, "reliability")) $$ = IPTOS_RELIABILITY; - else if ($2[0] == '0' && $2[1] == 'x') - $$ = strtoul($2, NULL, 16); + else if ($1[0] == '0' && $1[1] == 'x') + $$ = strtoul($1, NULL, 16); else $$ = 0; /* flag bad argument */ if (!$$ || $$ > 255) { - yyerror("illegal tos value %s", $2); - free($2); + yyerror("illegal tos value %s", $1); + free($1); YYERROR; } - free($2); + free($1); } - | TOS NUMBER { - $$ = $2; + | NUMBER { + $$ = $1; if (!$$ || $$ > 255) { - yyerror("illegal tos value %s", $2); + yyerror("illegal tos value %s", $1); YYERROR; } } @@ -3448,6 +3532,14 @@ state_opt_item : MAXIMUM NUMBER { $$->next = NULL; $$->tail = $$; } + | SLOPPY { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_SLOPPY; + $$->next = NULL; + $$->tail = $$; + } | STRING NUMBER { int i; @@ -3487,9 +3579,11 @@ label : LABEL STRING { qname : QUEUE STRING { $$.qname = $2; + $$.pqname = NULL; } | QUEUE '(' STRING ')' { $$.qname = $3; + $$.pqname = NULL; } | QUEUE '(' STRING comma STRING ')' { $$.qname = $3; @@ -3501,52 +3595,21 @@ no : /* empty */ { $$ = 0; } | NO { $$ = 1; } ; -rport : STRING { - char *p = strchr($1, ':'); - - if (p == NULL) { - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = $$.t = 0; - } else if (!strcmp(p+1, "*")) { - *p = 0; - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = 0; - $$.t = 1; - } else { - *p++ = 0; - if (($$.a = getservice($1)) == -1 || - ($$.b = getservice(p)) == -1) { - free($1); - YYERROR; - } - if ($$.a == $$.b) - $$.b = 0; - $$.t = 0; - } - free($1); - } - | NUMBER { - if ($1 < 0 || $1 > 65535) { - yyerror("illegal port value %ld", $1); +portstar : numberstring { + if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) { + free($1); YYERROR; } - $$.a = ntohs($1); - $$.b = $$.t = 0; + free($1); } ; redirspec : host { $$ = $1; } - | '{' redir_host_list '}' { $$ = $2; } + | '{' optnl redir_host_list '}' { $$ = $3; } ; -redir_host_list : host { $$ = $1; } - | redir_host_list comma host { +redir_host_list : host optnl { $$ = $1; } + | redir_host_list comma host optnl { $1->tail->next = $3; $1->tail = $3->tail; $$ = $1; @@ -3561,7 +3624,7 @@ redirpool : /* empty */ { $$ = NULL; } $$->host = $2; $$->rport.a = $$->rport.b = $$->rport.t = 0; } - | ARROW redirspec PORT rport { + | ARROW redirspec PORT portstar { $$ = calloc(1, sizeof(struct redirection)); if ($$ == NULL) err(1, "redirection: calloc"); @@ -3687,7 +3750,7 @@ redirection : /* empty */ { $$ = NULL; } $$->host = $2; $$->rport.a = $$->rport.b = $$->rport.t = 0; } - | ARROW host PORT rport { + | ARROW host PORT portstar { $$ = calloc(1, sizeof(struct redirection)); if ($$ == NULL) err(1, "redirection: calloc"); @@ -3889,7 +3952,7 @@ natrule : nataction interface af proto fromto tag tagged rtable } ; -binatrule : no BINAT natpasslog interface af proto FROM host TO ipspec tag +binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag tagged rtable redirection { struct pf_rule binat; @@ -3897,7 +3960,7 @@ binatrule : no BINAT natpasslog interface af proto FROM host TO ipspec tag if (check_rulestate(PFCTL_STATE_NAT)) YYERROR; - if (disallow_urpf_failed($10, "\"urpf-failed\" is not " + if (disallow_urpf_failed($9, "\"urpf-failed\" is not " "permitted as a binat destination")) YYERROR; @@ -3917,11 +3980,11 @@ binatrule : no BINAT natpasslog interface af proto FROM host TO ipspec tag binat.af = $5; if (!binat.af && $8 != NULL && $8->af) binat.af = $8->af; - if (!binat.af && $10 != NULL && $10->af) - binat.af = $10->af; + if (!binat.af && $9 != NULL && $9->af) + binat.af = $9->af; - if (!binat.af && $14 != NULL && $14->host) - binat.af = $14->host->af; + if (!binat.af && $13 != NULL && $13->host) + binat.af = $13->host->af; if (!binat.af) { yyerror("address family (inet/inet6) " "undefined"); @@ -3935,22 +3998,22 @@ binatrule : no BINAT natpasslog interface af proto FROM host TO ipspec tag free($4); } - if ($11 != NULL) - if (strlcpy(binat.tagname, $11, + if ($10 != NULL) + if (strlcpy(binat.tagname, $10, PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { yyerror("tag too long, max %u chars", PF_TAG_NAME_SIZE - 1); YYERROR; } - if ($12.name) - if (strlcpy(binat.match_tagname, $12.name, + if ($11.name) + if (strlcpy(binat.match_tagname, $11.name, PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { yyerror("tag too long, max %u chars", PF_TAG_NAME_SIZE - 1); YYERROR; } - binat.match_tag_not = $12.neg; - binat.rtableid = $13; + binat.match_tag_not = $11.neg; + binat.rtableid = $12; if ($6 != NULL) { binat.proto = $6->proto; @@ -3964,12 +4027,12 @@ binatrule : no BINAT natpasslog interface af proto FROM host TO ipspec tag "interface (%s) as the source address of a binat " "rule")) YYERROR; - if ($14 != NULL && $14->host != NULL && disallow_table( - $14->host, "invalid use of table <%s> as the " + if ($13 != NULL && $13->host != NULL && disallow_table( + $13->host, "invalid use of table <%s> as the " "redirect address of a binat rule")) YYERROR; - if ($14 != NULL && $14->host != NULL && disallow_alias( - $14->host, "invalid use of interface (%s) as the " + if ($13 != NULL && $13->host != NULL && disallow_alias( + $13->host, "invalid use of interface (%s) as the " "redirect address of a binat rule")) YYERROR; @@ -3990,51 +4053,51 @@ binatrule : no BINAT natpasslog interface af proto FROM host TO ipspec tag sizeof(binat.src.addr)); free($8); } - if ($10 != NULL) { - if ($10->next) { + if ($9 != NULL) { + if ($9->next) { yyerror("multiple binat ip addresses"); YYERROR; } - if ($10->af != binat.af && $10->af) { + if ($9->af != binat.af && $9->af) { yyerror("binat ip versions must match"); YYERROR; } - if (check_netmask($10, binat.af)) + if (check_netmask($9, binat.af)) YYERROR; - memcpy(&binat.dst.addr, &$10->addr, + memcpy(&binat.dst.addr, &$9->addr, sizeof(binat.dst.addr)); - binat.dst.neg = $10->not; - free($10); + binat.dst.neg = $9->not; + free($9); } if (binat.action == PF_NOBINAT) { - if ($14 != NULL) { + if ($13 != NULL) { yyerror("'no binat' rule does not need" " '->'"); YYERROR; } } else { - if ($14 == NULL || $14->host == NULL) { + if ($13 == NULL || $13->host == NULL) { yyerror("'binat' rule requires" " '-> address'"); YYERROR; } - remove_invalid_hosts(&$14->host, &binat.af); - if (invalid_redirect($14->host, binat.af)) + remove_invalid_hosts(&$13->host, &binat.af); + if (invalid_redirect($13->host, binat.af)) YYERROR; - if ($14->host->next != NULL) { + if ($13->host->next != NULL) { yyerror("binat rule must redirect to " "a single address"); YYERROR; } - if (check_netmask($14->host, binat.af)) + if (check_netmask($13->host, binat.af)) YYERROR; if (!PF_AZERO(&binat.src.addr.v.a.mask, binat.af) && !PF_AEQ(&binat.src.addr.v.a.mask, - &$14->host->addr.v.a.mask, binat.af)) { + &$13->host->addr.v.a.mask, binat.af)) { yyerror("'binat' source mask and " "redirect mask must be the same"); YYERROR; @@ -4044,12 +4107,12 @@ binatrule : no BINAT natpasslog interface af proto FROM host TO ipspec tag pa = calloc(1, sizeof(struct pf_pooladdr)); if (pa == NULL) err(1, "binat: calloc"); - pa->addr = $14->host->addr; + pa->addr = $13->host->addr; pa->ifname[0] = 0; TAILQ_INSERT_TAIL(&binat.rpool.list, pa, entries); - free($14); + free($13); } pfctl_add_rule(pf, &binat, ""); @@ -4089,8 +4152,8 @@ route_host : STRING { } ; -route_host_list : route_host { $$ = $1; } - | route_host_list comma route_host { +route_host_list : route_host optnl { $$ = $1; } + | route_host_list comma route_host optnl { if ($1->af == 0) $1->af = $3->af; if ($1->af != $3->af) { @@ -4105,7 +4168,7 @@ route_host_list : route_host { $$ = $1; } ; routespec : route_host { $$ = $1; } - | '{' route_host_list '}' { $$ = $2; } + | '{' optnl route_host_list '}' { $$ = $3; } ; route : /* empty */ { @@ -4160,8 +4223,8 @@ timeout_spec : STRING NUMBER } ; -timeout_list : timeout_list comma timeout_spec - | timeout_spec +timeout_list : timeout_list comma timeout_spec optnl + | timeout_spec optnl ; limit_spec : STRING NUMBER @@ -4183,8 +4246,8 @@ limit_spec : STRING NUMBER } ; -limit_list : limit_list comma limit_spec - | limit_spec +limit_list : limit_list comma limit_spec optnl + | limit_spec optnl ; comma : ',' @@ -4343,6 +4406,13 @@ filter_consistent(struct pf_rule *r, int anchor_call) yyerror("keep state on block rules doesn't make sense"); problems++; } + if (r->rule_flag & PFRULE_STATESLOPPY && + (r->keep_state == PF_STATE_MODULATE || + r->keep_state == PF_STATE_SYNPROXY)) { + yyerror("sloppy state matching cannot be used with " + "synproxy state or modulate state"); + problems++; + } return (-problems); } @@ -5133,6 +5203,8 @@ lookup(char *s) { "code", CODE}, { "crop", FRAGCROP}, { "debug", DEBUG}, + { "divert-reply", DIVERTREPLY}, + { "divert-to", DIVERTTO}, { "drop", DROP}, { "drop-ovl", FRAGDROP}, { "dup-to", DUPTO}, @@ -5211,7 +5283,9 @@ lookup(char *s) { "ruleset-optimization", RULESET_OPTIMIZATION}, { "scrub", SCRUB}, { "set", SET}, + { "set-tos", SETTOS}, { "skip", SKIP}, + { "sloppy", SLOPPY}, { "source-hash", SOURCEHASH}, { "source-track", SOURCETRACK}, { "state", STATE}, @@ -5861,6 +5935,41 @@ parseicmpspec(char *w, sa_family_t af) return (icmptype << 8 | ulval); } +int +parseport(char *port, struct range *r, int extensions) +{ + char *p = strchr(port, ':'); + + if (p == NULL) { + if ((r->a = getservice(port)) == -1) + return (-1); + r->b = 0; + r->t = PF_OP_NONE; + return (0); + } + if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) { + *p = 0; + if ((r->a = getservice(port)) == -1) + return (-1); + r->b = 0; + r->t = PF_OP_IRG; + return (0); + } + if ((extensions & PPORT_RANGE)) { + *p++ = 0; + if ((r->a = getservice(port)) == -1 || + (r->b = getservice(p)) == -1) + return (-1); + if (r->a == r->b) { + r->b = 0; + r->t = PF_OP_NONE; + } else + r->t = PF_OP_RRG; + return (0); + } + return (-1); +} + int pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) { diff --git a/pfctl/pf_print_state.c b/pfctl/pf_print_state.c index 8489c38c73a0..e95f2b04a063 100644 --- a/pfctl/pf_print_state.c +++ b/pfctl/pf_print_state.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_print_state.c,v 1.46 2007/08/30 09:28:49 dhartmei Exp $ */ +/* $OpenBSD: pf_print_state.c,v 1.51 2008/06/29 08:42:15 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -165,17 +165,15 @@ print_name(struct pf_addr *addr, sa_family_t af) } void -print_host(struct pfsync_state_host *h, sa_family_t af, int opts) +print_host(struct pf_addr *addr, u_int16_t port, sa_family_t af, int opts) { - u_int16_t p = ntohs(h->port); - if (opts & PF_OPT_USEDNS) - print_name(&h->addr, af); + print_name(addr, af); else { struct pf_addr_wrap aw; memset(&aw, 0, sizeof(aw)); - aw.v.a.addr = h->addr; + aw.v.a.addr = *addr; if (af == AF_INET) aw.v.a.mask.addr32[0] = 0xffffffff; else { @@ -185,11 +183,11 @@ print_host(struct pfsync_state_host *h, sa_family_t af, int opts) print_addr(&aw, af, opts & PF_OPT_VERBOSE2); } - if (p) { + if (port) { if (af == AF_INET) - printf(":%u", p); + printf(":%u", ntohs(port)); else - printf("[%u]", p); + printf("[%u]", ntohs(port)); } } @@ -197,45 +195,60 @@ void print_seq(struct pfsync_state_peer *p) { if (p->seqdiff) - printf("[%u + %u](+%u)", p->seqlo, p->seqhi - p->seqlo, - p->seqdiff); + printf("[%u + %u](+%u)", ntohl(p->seqlo), + ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff)); else - printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo); + printf("[%u + %u]", ntohl(p->seqlo), + ntohl(p->seqhi) - ntohl(p->seqlo)); } void print_state(struct pfsync_state *s, int opts) { struct pfsync_state_peer *src, *dst; + struct pfsync_state_key *sk, *nk; struct protoent *p; int min, sec; if (s->direction == PF_OUT) { src = &s->src; dst = &s->dst; + sk = &s->key[PF_SK_STACK]; + nk = &s->key[PF_SK_WIRE]; + if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6) + sk->port[0] = nk->port[0]; } else { src = &s->dst; dst = &s->src; + sk = &s->key[PF_SK_WIRE]; + nk = &s->key[PF_SK_STACK]; + if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6) + sk->port[1] = nk->port[1]; } printf("%s ", s->ifname); if ((p = getprotobynumber(s->proto)) != NULL) printf("%s ", p->p_name); else printf("%u ", s->proto); - if (PF_ANEQ(&s->lan.addr, &s->gwy.addr, s->af) || - (s->lan.port != s->gwy.port)) { - print_host(&s->lan, s->af, opts); - if (s->direction == PF_OUT) - printf(" -> "); - else - printf(" <- "); + + print_host(&nk->addr[1], nk->port[1], s->af, opts); + if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) || + nk->port[1] != sk->port[1]) { + printf(" ("); + print_host(&sk->addr[1], sk->port[1], s->af, opts); + printf(")"); } - print_host(&s->gwy, s->af, opts); if (s->direction == PF_OUT) printf(" -> "); else printf(" <- "); - print_host(&s->ext, s->af, opts); + print_host(&nk->addr[0], nk->port[0], s->af, opts); + if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) || + nk->port[0] != sk->port[0]) { + printf(" ("); + print_host(&sk->addr[0], sk->port[0], s->af, opts); + printf(")"); + } printf(" "); if (s->proto == IPPROTO_TCP) { @@ -281,25 +294,37 @@ print_state(struct pfsync_state *s, int opts) } if (opts & PF_OPT_VERBOSE) { - sec = s->creation % 60; - s->creation /= 60; - min = s->creation % 60; - s->creation /= 60; - printf(" age %.2u:%.2u:%.2u", s->creation, min, sec); - sec = s->expire % 60; - s->expire /= 60; + u_int64_t packets[2]; + u_int64_t bytes[2]; + u_int32_t creation = ntohl(s->creation); + u_int32_t expire = ntohl(s->expire); + + sec = creation % 60; + creation /= 60; + min = creation % 60; + creation /= 60; + printf(" age %.2u:%.2u:%.2u", creation, min, sec); + sec = expire % 60; + expire /= 60; min = s->expire % 60; - s->expire /= 60; - printf(", expires in %.2u:%.2u:%.2u", s->expire, min, sec); + expire /= 60; + printf(", expires in %.2u:%.2u:%.2u", expire, min, sec); + + bcopy(s->packets[0], &packets[0], sizeof(u_int64_t)); + bcopy(s->packets[1], &packets[1], sizeof(u_int64_t)); + bcopy(s->bytes[0], &bytes[0], sizeof(u_int64_t)); + bcopy(s->bytes[1], &bytes[1], sizeof(u_int64_t)); printf(", %llu:%llu pkts, %llu:%llu bytes", - pf_state_counter_from_pfsync(s->packets[0]), - pf_state_counter_from_pfsync(s->packets[1]), - pf_state_counter_from_pfsync(s->bytes[0]), - pf_state_counter_from_pfsync(s->bytes[1])); - if (s->anchor != -1) - printf(", anchor %u", s->anchor); - if (s->rule != -1) - printf(", rule %u", s->rule); + betoh64(packets[0]), + betoh64(packets[1]), + betoh64(bytes[0]), + betoh64(bytes[1])); + if (ntohl(s->anchor) != -1) + printf(", anchor %u", ntohl(s->anchor)); + if (ntohl(s->rule) != -1) + printf(", rule %u", ntohl(s->rule)); + if (s->state_flags & PFSTATE_SLOPPY) + printf(", sloppy"); if (s->sync_flags & PFSYNC_FLAG_SRCNODE) printf(", source-track"); if (s->sync_flags & PFSYNC_FLAG_NATSRCNODE) @@ -307,9 +332,12 @@ print_state(struct pfsync_state *s, int opts) printf("\n"); } if (opts & PF_OPT_VERBOSE2) { - printf(" id: %016llx creatorid: %08x%s\n", - pf_state_counter_from_pfsync(s->id), ntohl(s->creatorid), - ((s->sync_flags & PFSTATE_NOSYNC) ? " (no-sync)" : "")); + u_int64_t id; + + bcopy(&s->id, &id, sizeof(u_int64_t)); + printf(" id: %016llx creatorid: %08x", + betoh64(id), ntohl(s->creatorid)); + printf("\n"); } } diff --git a/pfctl/pfctl.8 b/pfctl/pfctl.8 index 4dfbc407aaea..9ce34ce41125 100644 --- a/pfctl/pfctl.8 +++ b/pfctl/pfctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pfctl.8,v 1.133 2007/07/01 11:38:51 henning Exp $ +.\" $OpenBSD: pfctl.8,v 1.139 2008/06/11 07:23:36 jmc Exp $ .\" .\" Copyright (c) 2001 Kjell Wooding. All rights reserved. .\" @@ -24,12 +24,12 @@ .\" (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 $Mdocdate: May 31 2007 $ +.Dd $Mdocdate: June 10 2008 $ .Dt PFCTL 8 .Os .Sh NAME .Nm pfctl -.Nd "control the packet filter (PF) and network address translation (NAT) device" +.Nd control the packet filter (PF) device .Sh SYNOPSIS .Nm pfctl .Bk -words @@ -41,7 +41,10 @@ .Op Fl f Ar file .Op Fl i Ar interface .Op Fl K Ar host | network -.Op Fl k Ar host | network +.Xo +.Oo Fl k +.Ar host | network | label | id +.Oc Xc .Op Fl o Ar level .Op Fl p Ar device .Op Fl s Ar modifier @@ -249,22 +252,28 @@ 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 +.It Xo +.Fl k +.Ar host | network | label | id +.Xc +Kill all of the state entries matching the specified +.Ar host , +.Ar network , +.Ar label , or -.Ar network . +.Ar id . +.Pp +For example, to kill all of the state entries originating from +.Dq host : +.Pp +.Dl # pfctl -k host +.Pp 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 host/network to the second. -For example, to kill all of the state entries originating from -.Dq host : -.Pp -.Dl # pfctl -k host -.Pp To kill all of the state entries from .Dq host1 to @@ -281,6 +290,32 @@ To kill all states with the target .Dq host2 : .Pp .Dl # pfctl -k 0.0.0.0/0 -k host2 +.Pp +It is also possible to kill states by rule label or state ID. +In this mode the first +.Fl k +argument is used to specify the type +of the second argument. +The following command would kill all states that have been created +from rules carrying the label +.Dq foobar : +.Pp +.Dl # pfctl -k label -k foobar +.Pp +To kill one specific state by its unique state ID +(as shown by pfctl -s state -vv), +use the +.Ar id +modifier and as a second argument the state ID and optional creator ID. +To kill a state with ID 4823e84500000003 use: +.Pp +.Dl # pfctl -k id -k 4823e84500000003 +.Pp +To kill a state with ID 4823e84500000018 created from a backup +firewall with hostid 00000002 use: +.Pp +.Dl # pfctl -k id -k 4823e84500000018/2 +.Pp .It Fl m Merge in explicitly given options without resetting those which are omitted. @@ -375,7 +410,7 @@ When used together with source tracking statistics are also shown. .It Fl s Cm labels Show per-rule statistics (label, evaluations, packets total, bytes total, -packets in, bytes in, packets out, bytes out) of +packets in, bytes in, packets out, bytes out, state creations) of filter rules with labels, useful for accounting. .It Fl s Cm timeouts Show the current global timeouts. @@ -486,7 +521,7 @@ attributes. The address/network has been cleared (statistics). .El .Pp -Each table maintains a set of counters that can be retrieved using the +Each table can maintain a set of counters that can be retrieved using the .Fl v flag of .Nm . @@ -497,7 +532,7 @@ FTP server. The following commands configure the firewall and send 10 pings to the FTP server: .Bd -literal -offset indent -# printf "table { ftp.openbsd.org }\en \e +# printf "table counters { ftp.openbsd.org }\en \e pass out to \en" | pfctl -f- # ping -qc10 ftp.openbsd.org .Ed @@ -531,7 +566,7 @@ the number of rules which reference the table, and the global packet statistics for the whole table: .Bd -literal -offset indent # pfctl -vvsTables ---a-r- test +--a-r-C test Addresses: 1 Cleared: Thu Feb 13 18:55:18 2003 References: [ Anchors: 0 Rules: 1 ] @@ -591,6 +626,8 @@ For tables which are referenced (used) by rules. .It h This flag is set when a table in the main ruleset is hidden by one or more tables of the same name from anchors attached below it. +.It C +This flag is set when per-address counters are enabled on the table. .El .It Fl t Ar table Specify the name of the table. diff --git a/pfctl/pfctl.c b/pfctl/pfctl.c index 3829f2cb413f..f01b6a92717f 100644 --- a/pfctl/pfctl.c +++ b/pfctl/pfctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.c,v 1.273 2008/02/13 19:55:12 kettenis Exp $ */ +/* $OpenBSD: pfctl.c,v 1.277 2008/07/24 10:52:43 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -68,7 +68,9 @@ int pfctl_clear_src_nodes(int, int); int pfctl_clear_states(int, const char *, int); void pfctl_addrprefix(char *, struct pf_addr *); int pfctl_kill_src_nodes(int, const char *, int); -int pfctl_kill_states(int, const char *, int); +int pfctl_net_kill_states(int, const char *, int); +int pfctl_label_kill_states(int, const char *, int); +int pfctl_id_kill_states(int, const char *, int); void pfctl_init_options(struct pfctl *); int pfctl_load_options(struct pfctl *); int pfctl_load_limit(struct pfctl *, unsigned int, unsigned int); @@ -229,7 +231,7 @@ usage(void) fprintf(stderr, "usage: %s [-AdeghmNnOqRrvz] ", __progname); fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n"); fprintf(stderr, "\t[-f file] [-i interface] [-K host | network] "); - fprintf(stderr, "[-k host | network]\n"); + fprintf(stderr, "[-k host | network | label | id]\n"); fprintf(stderr, "\t[-o level] [-p device] [-s modifier]\n"); fprintf(stderr, "\t[-t table -T command [address ...]] [-x level]\n"); exit(1); @@ -376,7 +378,7 @@ pfctl_clear_states(int dev, const char *iface, int opts) if (ioctl(dev, DIOCCLRSTATES, &psk)) err(1, "DIOCCLRSTATES"); if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "%d states cleared\n", psk.psk_af); + fprintf(stderr, "%d states cleared\n", psk.psk_killed); return (0); } @@ -515,17 +517,13 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts) if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) err(1, "DIOCKILLSRCNODES"); - killed += psnk.psnk_af; - /* fixup psnk.psnk_af */ - psnk.psnk_af = resp[1]->ai_family; + killed += psnk.psnk_killed; } freeaddrinfo(res[1]); } else { if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) err(1, "DIOCKILLSRCNODES"); - killed += psnk.psnk_af; - /* fixup psnk.psnk_af */ - psnk.psnk_af = res[0]->ai_family; + killed += psnk.psnk_killed; } } @@ -538,7 +536,7 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts) } int -pfctl_kill_states(int dev, const char *iface, int opts) +pfctl_net_kill_states(int dev, const char *iface, int opts) { struct pfioc_state_kill psk; struct addrinfo *res[2], *resp[2]; @@ -625,17 +623,13 @@ pfctl_kill_states(int dev, const char *iface, int opts) if (ioctl(dev, DIOCKILLSTATES, &psk)) err(1, "DIOCKILLSTATES"); - killed += psk.psk_af; - /* fixup psk.psk_af */ - psk.psk_af = resp[1]->ai_family; + killed += psk.psk_killed; } freeaddrinfo(res[1]); } else { if (ioctl(dev, DIOCKILLSTATES, &psk)) err(1, "DIOCKILLSTATES"); - killed += psk.psk_af; - /* fixup psk.psk_af */ - psk.psk_af = res[0]->ai_family; + killed += psk.psk_killed; } } @@ -647,6 +641,68 @@ pfctl_kill_states(int dev, const char *iface, int opts) return (0); } +int +pfctl_label_kill_states(int dev, const char *iface, int opts) +{ + struct pfioc_state_kill psk; + + if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { + warnx("no label specified"); + usage(); + } + memset(&psk, 0, sizeof(psk)); + if (iface != NULL && strlcpy(psk.psk_ifname, iface, + sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) + errx(1, "invalid interface: %s", iface); + + if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >= + sizeof(psk.psk_label)) + errx(1, "label too long: %s", state_kill[1]); + + if (ioctl(dev, DIOCKILLSTATES, &psk)) + err(1, "DIOCKILLSTATES"); + + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "killed %d states\n", psk.psk_killed); + + return (0); +} + +int +pfctl_id_kill_states(int dev, const char *iface, int opts) +{ + struct pfioc_state_kill psk; + + if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { + warnx("no id specified"); + usage(); + } + + memset(&psk, 0, sizeof(psk)); + if ((sscanf(state_kill[1], "%llx/%x", + &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2) + HTONL(psk.psk_pfcmp.creatorid); + else if ((sscanf(state_kill[1], "%llx", &psk.psk_pfcmp.id)) == 1) { + psk.psk_pfcmp.creatorid = 0; + } else { + warnx("wrong id format specified"); + usage(); + } + if (psk.psk_pfcmp.id == 0) { + warnx("cannot kill id 0"); + usage(); + } + + psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id); + if (ioctl(dev, DIOCKILLSTATES, &psk)) + err(1, "DIOCKILLSTATES"); + + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "killed %d states\n", psk.psk_killed); + + return (0); +} + int pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr, u_int32_t ticket, int r_action, char *anchorname) @@ -734,10 +790,12 @@ pfctl_print_rule_counters(struct pf_rule *rule, int opts) (unsigned long long)(rule->packets[0] + rule->packets[1]), (unsigned long long)(rule->bytes[0] + - rule->bytes[1]), rule->states); + rule->bytes[1]), rule->states_cur); if (!(opts & PF_OPT_DEBUG)) - printf(" [ Inserted: uid %u pid %u ]\n", - (unsigned)rule->cuid, (unsigned)rule->cpid); + printf(" [ Inserted: uid %u pid %u " + "State Creations: %-6u]\n", + (unsigned)rule->cuid, (unsigned)rule->cpid, + rule->states_tot); } } @@ -804,19 +862,6 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, switch (format) { case PFCTL_SHOW_LABELS: - if (pr.rule.label[0]) { - printf("%s ", pr.rule.label); - printf("%llu %llu %llu %llu %llu %llu %llu\n", - (unsigned long long)pr.rule.evaluations, - (unsigned long long)(pr.rule.packets[0] + - pr.rule.packets[1]), - (unsigned long long)(pr.rule.bytes[0] + - pr.rule.bytes[1]), - (unsigned long long)pr.rule.packets[0], - (unsigned long long)pr.rule.bytes[0], - (unsigned long long)pr.rule.packets[1], - (unsigned long long)pr.rule.bytes[1]); - } break; case PFCTL_SHOW_RULES: if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) @@ -850,8 +895,9 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, switch (format) { case PFCTL_SHOW_LABELS: if (pr.rule.label[0]) { - printf("%s ", pr.rule.label); - printf("%llu %llu %llu %llu %llu %llu %llu\n", + printf("%s %llu %llu %llu %llu" + " %llu %llu %llu %llu\n", + pr.rule.label, (unsigned long long)pr.rule.evaluations, (unsigned long long)(pr.rule.packets[0] + pr.rule.packets[1]), @@ -860,7 +906,8 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, (unsigned long long)pr.rule.packets[0], (unsigned long long)pr.rule.bytes[0], (unsigned long long)pr.rule.packets[1], - (unsigned long long)pr.rule.bytes[1]); + (unsigned long long)pr.rule.bytes[1], + (unsigned long long)pr.rule.states_tot); } break; case PFCTL_SHOW_RULES: @@ -1526,7 +1573,8 @@ pfctl_init_options(struct pfctl *pf) mib[0] = CTL_HW; mib[1] = HW_PHYSMEM64; size = sizeof(mem); - (void) sysctl(mib, 2, &mem, &size, NULL, 0); + if (sysctl(mib, 2, &mem, &size, NULL, 0) == -1) + err(1, "sysctl"); if (mem <= 100*1024*1024) pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT_SMALL; @@ -2256,8 +2304,14 @@ main(int argc, char *argv[]) break; } } - if (state_killers) - pfctl_kill_states(dev, ifaceopt, opts); + if (state_killers) { + if (!strcmp(state_kill[0], "label")) + pfctl_label_kill_states(dev, ifaceopt, opts); + else if (!strcmp(state_kill[0], "id")) + pfctl_id_kill_states(dev, ifaceopt, opts); + else + pfctl_net_kill_states(dev, ifaceopt, opts); + } if (src_node_killers) pfctl_kill_src_nodes(dev, ifaceopt, opts); diff --git a/pfctl/pfctl.h b/pfctl/pfctl.h index 7b7156e735d8..f9db55072dd9 100644 --- a/pfctl/pfctl.h +++ b/pfctl/pfctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.h,v 1.42 2007/12/05 12:01:47 chl Exp $ */ +/* $OpenBSD: pfctl.h,v 1.43 2008/05/29 01:00:53 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -109,7 +109,7 @@ struct pf_altq *pfaltq_lookup(const char *); char *rate2str(double); void print_addr(struct pf_addr_wrap *, sa_family_t, int); -void print_host(struct pfsync_state_host *, sa_family_t, int); +void print_host(struct pf_addr *, u_int16_t p, sa_family_t, int); void print_seq(struct pfsync_state_peer *); void print_state(struct pfsync_state *, int); int unmask(struct pf_addr *, sa_family_t); diff --git a/pfctl/pfctl_altq.c b/pfctl/pfctl_altq.c index d1a46609ccbb..0a174e5f46b6 100644 --- a/pfctl/pfctl_altq.c +++ b/pfctl/pfctl_altq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */ +/* $OpenBSD: pfctl_altq.c,v 1.94 2008/07/25 17:43:44 martynas Exp $ */ /* * Copyright (c) 2002 @@ -875,7 +875,6 @@ print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) /* * admission control using generalized service curve */ -#define INFINITY HUGE_VAL /* positive infinity defined in */ /* add a new service curve to a generalized service curve */ static void diff --git a/pfctl/pfctl_optimize.c b/pfctl/pfctl_optimize.c index 8a80232cc5bb..bbed611d2fe4 100644 --- a/pfctl/pfctl_optimize.c +++ b/pfctl/pfctl_optimize.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_optimize.c,v 1.16 2008/01/26 13:16:36 mcbride Exp $ */ +/* $OpenBSD: pfctl_optimize.c,v 1.18 2008/05/07 06:23:30 markus Exp $ */ /* * Copyright (c) 2004 Mike Frantzen @@ -182,7 +182,8 @@ struct pf_rule_field { PF_RULE_FIELD(packets, DC), PF_RULE_FIELD(bytes, DC), PF_RULE_FIELD(kif, DC), - PF_RULE_FIELD(states, DC), + PF_RULE_FIELD(states_cur, DC), + PF_RULE_FIELD(states_tot, DC), PF_RULE_FIELD(src_nodes, DC), PF_RULE_FIELD(nr, DC), PF_RULE_FIELD(entries, DC), @@ -198,6 +199,7 @@ struct pf_rule_field { PF_RULE_FIELD(natpass, NEVER), PF_RULE_FIELD(max_mss, NEVER), PF_RULE_FIELD(min_ttl, NEVER), + PF_RULE_FIELD(set_tos, NEVER), }; diff --git a/pfctl/pfctl_parser.c b/pfctl/pfctl_parser.c index e88306b30f4b..7368dbe7d3c4 100644 --- a/pfctl/pfctl_parser.c +++ b/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.235 2007/10/15 02:16:35 deraadt Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.240 2008/06/10 20:55:02 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -860,6 +860,8 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) opts = 1; if (r->rule_flag & PFRULE_IFBOUND) opts = 1; + if (r->rule_flag & PFRULE_STATESLOPPY) + opts = 1; for (i = 0; !opts && i < PFTM_MAX; ++i) if (r->timeout[i]) opts = 1; @@ -926,6 +928,12 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) printf("if-bound"); opts = 0; } + if (r->rule_flag & PFRULE_STATESLOPPY) { + if (!opts) + printf(", "); + printf("sloppy"); + opts = 0; + } for (i = 0; i < PFTM_MAX; ++i) if (r->timeout[i]) { int j; @@ -953,6 +961,8 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) printf(" min-ttl %d", r->min_ttl); if (r->max_mss) printf(" max-mss %d", r->max_mss); + if (r->rule_flag & PFRULE_SET_TOS) + printf(" set-tos 0x%2.2x", r->set_tos); if (r->allow_opts) printf(" allow-opts"); if (r->action == PF_SCRUB) { @@ -981,6 +991,22 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose) } if (r->rtableid != -1) printf(" rtable %u", r->rtableid); + if (r->divert.port) { + if (PF_AZERO(&r->divert.addr, r->af)) { + printf(" divert-reply"); + } else { + /* XXX cut&paste from print_addr */ + char buf[48]; + + printf(" divert-to "); + if (inet_ntop(r->af, &r->divert.addr, buf, + sizeof(buf)) == NULL) + printf("?"); + else + printf("%s", buf); + printf(" port %u", ntohs(r->divert.port)); + } + } if (!anchor_call[0] && (r->action == PF_NAT || r->action == PF_BINAT || r->action == PF_RDR)) { printf(" -> "); @@ -1001,6 +1027,8 @@ print_tabledef(const char *name, int flags, int addrs, printf(" const"); if (flags & PFR_TFLAG_PERSIST) printf(" persist"); + if (flags & PFR_TFLAG_COUNTERS) + printf(" counters"); SIMPLEQ_FOREACH(ti, nodes, entries) { if (ti->file) { printf(" file \"%s\"", ti->file); diff --git a/pfctl/pfctl_table.c b/pfctl/pfctl_table.c index bee578626505..fa4ae6a6e188 100644 --- a/pfctl/pfctl_table.c +++ b/pfctl/pfctl_table.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_table.c,v 1.66 2007/03/01 17:20:54 deraadt Exp $ */ +/* $OpenBSD: pfctl_table.c,v 1.68 2008/06/21 10:34:08 mcbride Exp $ */ /* * Copyright (c) 2002 Cedric Berger @@ -272,12 +272,14 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command, if (b.pfrb_size <= b.pfrb_msize) break; } - PFRB_FOREACH(p, &b) + PFRB_FOREACH(p, &b) { + ((struct pfr_astats *)p)->pfras_a.pfra_fback = 0; 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; @@ -364,13 +366,14 @@ print_table(struct pfr_table *ta, int verbose, int debug) if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE)) return; if (verbose) { - printf("%c%c%c%c%c%c\t%s", + printf("%c%c%c%c%c%c%c\t%s", (ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-', (ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-', (ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-', (ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-', (ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-', (ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-', + (ta->pfrt_flags & PFR_TFLAG_COUNTERS) ? 'C' : '-', ta->pfrt_name); if (ta->pfrt_anchor[0]) printf("\t%s", ta->pfrt_anchor); @@ -425,7 +428,7 @@ void print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns) { char ch, buf[256] = "{error}"; - char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y' }; + char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' }; unsigned int fback, hostnet; fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback; @@ -474,6 +477,8 @@ print_astats(struct pfr_astats *as, int dns) print_addrx(&as->pfras_a, NULL, dns); printf("\tCleared: %s", ctime(&time)); + if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT) + return; for (dir = 0; dir < PFR_DIR_MAX; dir++) for (op = 0; op < PFR_OP_ADDR_MAX; op++) printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", diff --git a/pflogd/privsep_fdpass.c b/pflogd/privsep_fdpass.c index 50afdfc28595..0e6c3c4c1e80 100644 --- a/pflogd/privsep_fdpass.c +++ b/pflogd/privsep_fdpass.c @@ -1,4 +1,4 @@ -/* $OpenBSD: privsep_fdpass.c,v 1.2 2004/08/13 02:51:48 djm Exp $ */ +/* $OpenBSD: privsep_fdpass.c,v 1.5 2008/03/24 16:11:08 deraadt Exp $ */ /* * Copyright 2001 Niels Provos @@ -50,7 +50,10 @@ void send_fd(int sock, int fd) { struct msghdr msg; - char tmp[CMSG_SPACE(sizeof(int))]; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; struct cmsghdr *cmsg; struct iovec vec; int result = 0; @@ -59,8 +62,8 @@ send_fd(int sock, int fd) memset(&msg, 0, sizeof(msg)); if (fd >= 0) { - msg.msg_control = (caddr_t)tmp; - msg.msg_controllen = CMSG_LEN(sizeof(int)); + msg.msg_control = (caddr_t)&cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; @@ -86,7 +89,10 @@ int receive_fd(int sock) { struct msghdr msg; - char tmp[CMSG_SPACE(sizeof(int))]; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; struct cmsghdr *cmsg; struct iovec vec; ssize_t n; @@ -98,8 +104,8 @@ receive_fd(int sock) vec.iov_len = sizeof(int); msg.msg_iov = &vec; msg.msg_iovlen = 1; - msg.msg_control = tmp; - msg.msg_controllen = sizeof(tmp); + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); if ((n = recvmsg(sock, &msg, 0)) == -1) warn("%s: recvmsg", __func__); diff --git a/tftp-proxy/tftp-proxy.c b/tftp-proxy/tftp-proxy.c index 18d3323e9117..d2d2875717a6 100644 --- a/tftp-proxy/tftp-proxy.c +++ b/tftp-proxy/tftp-proxy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tftp-proxy.c,v 1.2 2006/12/20 03:33:38 joel Exp $ +/* $OpenBSD: tftp-proxy.c,v 1.6 2008/04/13 00:22:17 djm Exp $ * * Copyright (c) 2005 DLS Internet Services * Copyright (c) 2004, 2005 Camiel Dobbelaar, @@ -75,8 +75,10 @@ main(int argc, char *argv[]) char *p; struct tftphdr *tp; struct passwd *pw; - - char cbuf[CMSG_SPACE(sizeof(struct sockaddr_storage))]; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))]; + } cmsgbuf; char req[PKTSIZE]; struct cmsghdr *cmsg; struct msghdr msg; @@ -161,8 +163,8 @@ main(int argc, char *argv[]) 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)); + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); if (recvmsg(fd, &msg, 0) < 0) { syslog(LOG_ERR, "recvmsg: %m"); @@ -381,8 +383,8 @@ sock_ntop(struct sockaddr *sa) u_int16_t pick_proxy_port(void) { - return (IPPORT_HIFIRSTAUTO + (arc4random() % - (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO))); + return (IPPORT_HIFIRSTAUTO + + arc4random_uniform(IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)); } static void