summaryrefslogtreecommitdiff
path: root/sbin/pfctl
diff options
context:
space:
mode:
authorKjell Wooding <kjell@cvs.openbsd.org>2001-06-24 21:04:21 +0000
committerKjell Wooding <kjell@cvs.openbsd.org>2001-06-24 21:04:21 +0000
commitbeb2ed44a9d221c847249602b2a461b4ebbe2517 (patch)
tree3d10b4627ec4bd95aa181ac6a166eda387975602 /sbin/pfctl
parenta8e7ede44bdc1df0f4533b916123f47ef374c6fe (diff)
Move and rename packet filter userland.
grr. CVS: making easy things difficult, and directory operations impossible.
Diffstat (limited to 'sbin/pfctl')
-rw-r--r--sbin/pfctl/Makefile8
-rw-r--r--sbin/pfctl/pfctl.c371
-rw-r--r--sbin/pfctl/pfctl_parser.c825
-rw-r--r--sbin/pfctl/pfctl_parser.h48
4 files changed, 1252 insertions, 0 deletions
diff --git a/sbin/pfctl/Makefile b/sbin/pfctl/Makefile
new file mode 100644
index 00000000000..44bc6f17bd4
--- /dev/null
+++ b/sbin/pfctl/Makefile
@@ -0,0 +1,8 @@
+#
+# $OpenBSD: Makefile,v 1.1 2001/06/24 21:04:15 kjell Exp $
+
+PROG = pfctl
+SRCS = pfctl.c pfctl_parser.c
+MAN=
+
+.include <bsd.prog.mk>
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
new file mode 100644
index 00000000000..ae98842d61e
--- /dev/null
+++ b/sbin/pfctl/pfctl.c
@@ -0,0 +1,371 @@
+/* $OpenBSD: pfctl.c,v 1.1 2001/06/24 21:04:15 kjell Exp $ */
+
+/*
+ * Copyright (c) 2001, Daniel Hartmeier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#include "pfctl_parser.h"
+
+static void printerror(char *);
+static void usage(char *);
+static char *load_file(char *, size_t *);
+int main(int, char *[]);
+
+static char *errormsg[] = {
+ "invalid operation", /* ERROR_INVALID_OP */
+ "packetfilter is running", /* ERROR_ALREADY_RUNNING */
+ "packetfilter not running", /* ERROR_NOT_RUNNING */
+ "invalid parameters", /* ERROR_INVALID_PARAMETERS */
+ "memory allocation failed" /* ERROR_MALLOC */
+};
+
+static void
+printerror(char *s)
+{
+ char *msg;
+ if ((errno >= 100) && (errno < MAX_ERROR_NUM))
+ msg = errormsg[errno-100];
+ else
+ msg = strerror(errno);
+ fprintf(stderr, "ERROR: %s: %s\n", s, msg);
+ return;
+}
+
+static void
+usage(char *argv0)
+{
+ char *n = rindex(argv0, '/');
+ if (n != NULL)
+ n++;
+ else
+ n = argv0;
+ fprintf(stderr, "Usage: %s command argument\n", n);
+ fprintf(stderr, "\tstart\t\t\tStart packet filter\n");
+ fprintf(stderr, "\tstop\t\t\tStop packet filter\n");
+ fprintf(stderr, "\tshow\trules\t\tShow filter rules\n");
+ fprintf(stderr, "\t\tnat\t\t NAT/RDR rules\n");
+ fprintf(stderr, "\t\tstates [proto]\t list of active states\n");
+ fprintf(stderr, "\t\tstatus\t\t status\n");
+ fprintf(stderr, "\tclear\trules\t\tClear filter rules\n");
+ fprintf(stderr, "\t\tnat\t\t NAT/RDR rules\n");
+ fprintf(stderr, "\t\tstates\t\t states\n");
+ fprintf(stderr, "\tparse\trules\t<file>\tCheck syntax of filter rules\n");
+ fprintf(stderr, "\t\tnat\t<file>\t NAT/RDR rules\n");
+ fprintf(stderr, "\tload\trules\t<file>\tLoad filter rules\n");
+ fprintf(stderr, "\t\tnat\t<file>\t NAT/RDR rules\n");
+ fprintf(stderr, "\tlog\t\t<if>\tSet interface to log\n");
+}
+
+static char *
+load_file(char *name, size_t *len)
+{
+ char *buf = 0;
+ FILE *file = fopen(name, "r");
+ *len = 0;
+ if (file == NULL) {
+ fprintf(stderr, "ERROR: couldn't open file %s (%s)\n",
+ name, strerror(errno));
+ return 0;
+ }
+ fseek(file, 0, SEEK_END);
+ *len = ftell(file);
+ fseek(file, 0, SEEK_SET);
+ buf = malloc(*len);
+ if (buf == NULL) {
+ fclose(file);
+ fprintf(stderr, "ERROR: malloc() failed\n");
+ return 0;
+ }
+ if (fread(buf, 1, *len, file) != *len) {
+ free(buf);
+ fclose(file);
+ fprintf(stderr, "ERROR: fread() failed\n");
+ return 0;
+ }
+ fclose(file);
+ return buf;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int dev;
+ struct ioctlbuffer *ub;
+ u_int16_t n = 0;
+ ub = malloc(sizeof(struct ioctlbuffer));
+ if (ub == NULL) {
+ printf("ERROR: malloc() failed\n");
+ return 1;
+ }
+ ub->size = 131072;
+ ub->buffer = malloc(ub->size);
+ if (ub->buffer == NULL) {
+ printf("ERROR: malloc() failed\n");
+ return 1;
+ }
+ memset(ub->buffer, 0, ub->size);
+ ub->entries = 0;
+ if (argc < 2) {
+ usage(argv[0]);
+ return 1;
+ }
+ dev = open("/dev/pf", O_RDWR);
+ if (dev < 0) {
+ printerror("open(/dev/pf)");
+ return 1;
+ }
+ if (!strcmp(argv[1], "start")) {
+ if (ioctl(dev, DIOCSTART))
+ printerror("DIOCSTART");
+ else
+ printf("packetfilter started\n");
+ }
+ else if (!strcmp(argv[1], "stop")) {
+ if (ioctl(dev, DIOCSTOP))
+ printerror("DIOCSTOP");
+ else
+ printf("packetfilter stopped\n");
+ }
+ else if (!strcmp(argv[1], "show")) {
+ if (argc < 3) {
+ close(dev);
+ usage(argv[0]);
+ return 1;
+ }
+ if (!strcmp(argv[2], "rules")) {
+ struct rule *rule = ub->buffer;
+ ub->entries = ub->size / sizeof(struct rule);
+ if (ioctl(dev, DIOCGETRULES, ub))
+ printerror("DIOCGETRULES");
+ for (n = 0; n < ub->entries; ++n) {
+ printf("@%u ", n + 1);
+ print_rule(rule + n);
+ }
+ }
+ else if (!strcmp(argv[2], "nat")) {
+ struct nat *nat = ub->buffer;
+ struct rdr *rdr = ub->buffer;
+ ub->entries = ub->size / sizeof(struct nat);
+ if (ioctl(dev, DIOCGETNAT, ub))
+ printerror("DIOCGETNAT");
+ for (n = 0; n < ub->entries; ++n)
+ print_nat(nat + n);
+ ub->entries = ub->size / sizeof(struct rdr);
+ if (ioctl(dev, DIOCGETRDR, ub))
+ printerror("DIOCGETRDR");
+ for (n = 0; n < ub->entries; ++n)
+ print_rdr(rdr + n);
+ }
+ else if (!strcmp(argv[2], "states")) {
+ u_int8_t proto = 0;
+ struct state *state = ub->buffer;
+ if (argc >= 4) {
+ if (!strcmp(argv[3], "tcp"))
+ proto = IPPROTO_TCP;
+ else if (!strcmp(argv[3], "udp"))
+ proto = IPPROTO_UDP;
+ else if (!strcmp(argv[3], "icmp"))
+ proto = IPPROTO_ICMP;
+ else {
+ close(dev);
+ usage(argv[0]);
+ return 1;
+ }
+ }
+ ub->entries = ub->size / sizeof(struct state);
+ if (ioctl(dev, DIOCGETSTATES, ub))
+ printerror("DIOCGETSTATES");
+ for (n = ub->entries; n > 0; --n)
+ if (!proto || (state[n - 1].proto == proto))
+ print_state(state + n - 1);
+ }
+ else if (!strcmp(argv[2], "status")) {
+ struct status *status = ub->buffer;
+ ub->entries = 1;
+ if (ioctl(dev, DIOCGETSTATUS, ub))
+ printerror("DIOCGETSTATUS");
+ print_status(status);
+ }
+ else {
+ close(dev);
+ usage(argv[0]);
+ return 1;
+ }
+ }
+ else if (!strcmp(argv[1], "clear")) {
+ if (argc < 3) {
+ close(dev);
+ usage(argv[0]);
+ return 1;
+ }
+ ub->entries = 0;
+ if (!strcmp(argv[2], "rules")) {
+ if (ioctl(dev, DIOCSETRULES, ub))
+ printerror("DIOCSETRULES");
+ else printf("rules cleared\n");
+ }
+ else if (!strcmp(argv[2], "nat")) {
+ if (ioctl(dev, DIOCSETNAT, ub))
+ printerror("DIOCSETNAT");
+ else if (ioctl(dev, DIOCSETRDR, ub))
+ printerror("DIOCSETRDR");
+ else printf("nat cleared\n");
+ }
+ else if (!strcmp(argv[2], "states")) {
+ if (ioctl(dev, DIOCCLRSTATES))
+ printerror("DIOCCLRSTATES");
+ else
+ printf("states cleared\n");
+ }
+ else {
+ close(dev);
+ usage(argv[0]);
+ return 1;
+ }
+ }
+ else if (!strcmp(argv[1], "log")) {
+ if (argc < 3) {
+ close(dev);
+ usage(argv[0]);
+ return 1;
+ }
+ strncpy(ub->buffer, argv[2], 16);
+ if (ioctl(dev, DIOCSETSTATUSIF, ub))
+ printerror("DIOCSETSTATUSIF");
+ else
+ printf("now logging %s\n", argv[2]);
+ }
+ else if (!strcmp(argv[1], "parse") || !strcmp(argv[1], "load")) {
+ int load = !strcmp(argv[1], "load");
+ char *buf, *s;
+ size_t len;
+ unsigned nr = 0;
+ if ((argc < 4) || (strcmp(argv[2], "nat") &&
+ strcmp(argv[2], "rules"))) {
+ close(dev);
+ usage(argv[0]);
+ return 1;
+ }
+ buf = load_file(argv[3], &len);
+ if (buf == NULL)
+ return 1;
+
+ if (!strcmp(argv[2], "rules")) {
+ struct rule *rule = ub->buffer;
+ n = 0;
+ nr = 0;
+ s = buf;
+ do {
+ char *line = next_line(&s);
+ nr++;
+ if (*line && (*line != '#'))
+ if (parse_rule(nr, line, rule + n))
+ n++;
+ } while (s < (buf + len));
+ ub->entries = n;
+ if (load) {
+ if (ioctl(dev, DIOCSETRULES, ub))
+ printerror("DIOCSETRULES");
+ else
+ printf("%u rules loaded\n",
+ ub->entries);
+ } else
+ for (n = 0; n < ub->entries; ++n)
+ print_rule(rule + n);
+ } else {
+ struct nat *nat = ub->buffer;
+ struct rdr *rdr = ub->buffer;
+ n = 0;
+ nr = 0;
+ s = buf;
+ do {
+ char *line = next_line(&s);
+ nr++;
+ if (*line && (*line == 'n'))
+ if (parse_nat(nr, line, nat + n))
+ n++;
+ } while (s < (buf + len));
+ ub->entries = n;
+ if (load) {
+ if (ioctl(dev, DIOCSETNAT, ub))
+ printerror("DIOCSETNAT");
+ else
+ printf("%u nat entries loaded\n",
+ ub->entries);
+ } else
+ for (n = 0; n < ub->entries; ++n)
+ print_nat(nat + n);
+ free(buf);
+ buf = load_file(argv[3], &len);
+ if (buf == NULL)
+ return 1;
+ n = 0;
+ nr = 0;
+ s = buf;
+ do {
+ char *line = next_line(&s);
+ nr++;
+ if (*line && (*line == 'r'))
+ if (parse_rdr(nr, line, rdr + n))
+ n++;
+ } while (s < (buf + len));
+ ub->entries = n;
+ if (load) {
+ if (ioctl(dev, DIOCSETRDR, ub))
+ printerror("DIOCSETRDR");
+ else
+ printf("%u rdr entries loaded\n",
+ ub->entries);
+ } else
+ for (n = 0; n < ub->entries; ++n)
+ print_rdr(rdr + n);
+ }
+
+ free(buf);
+ }
+ else {
+ close(dev);
+ usage(argv[0]);
+ return 1;
+ }
+ close(dev);
+ free(ub->buffer);
+ free(ub);
+ return 0;
+}
+
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
new file mode 100644
index 00000000000..3f859f5f40c
--- /dev/null
+++ b/sbin/pfctl/pfctl_parser.c
@@ -0,0 +1,825 @@
+/* $OpenBSD: pfctl_parser.c,v 1.1 2001/06/24 21:04:16 kjell Exp $ */
+
+/*
+ * Copyright (c) 2001, Daniel Hartmeier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include "pfctl_parser.h"
+
+static void print_addr (u_int32_t);
+static void print_host (struct host *);
+static void print_seq (struct peer *);
+static void print_port (u_int8_t, u_int16_t, u_int16_t, char *);
+static void print_flags (u_int8_t);
+static char *next_word (char **);
+static u_int16_t next_number (char **);
+static u_int32_t next_addr (char **);
+static u_int8_t next_flags (char **);
+static u_int16_t rule_port (char *, u_int8_t);
+static u_int32_t rule_mask (u_int8_t);
+
+static char *tcpflags = "FSRPAU";
+
+static void
+print_addr(u_int32_t a)
+{
+ a = ntohl(a);
+ printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255);
+}
+
+static void
+print_host(struct host *h)
+{
+ u_int32_t a = ntohl(h->addr);
+ u_int16_t p = ntohs(h->port);
+ printf("%u.%u.%u.%u:%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255, p);
+}
+
+static void
+print_seq(struct peer *p)
+{
+ printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo);
+}
+
+static void
+print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto)
+{
+ struct servent *s = getservbyport(p1, proto);
+ p1 = ntohs(p1);
+ p2 = ntohs(p2);
+ printf("port ");
+ if (op == 1)
+ printf("%u >< %u ", p1, p2);
+ else if (op == 2) {
+ if (s != NULL)
+ printf("= %s ", s->s_name);
+ else
+ printf("= %u ", p1);
+ }
+ else if (op == 3) {
+ if (s != NULL)
+ printf("!= %s ", s->s_name);
+ else
+ printf("!= %u ", p1);
+ }
+ else if (op == 4)
+ printf("< %u ", p1);
+ else if (op == 5)
+ printf("<= %u ", p1);
+ else if (op == 6)
+ printf("> %u ", p1);
+ else
+ printf(">= %u ", p1);
+}
+
+static void
+print_flags(u_int8_t f)
+{
+ int i;
+ for (i = 0; i < 6; ++i)
+ if (f & (1 << i))
+ printf("%c", tcpflags[i]);
+}
+
+void
+print_nat(struct nat *n)
+{
+ printf("nat %s ", n->ifname);
+ if (n->not)
+ printf("! ");
+ print_addr(n->saddr);
+ if (n->smask != 0xFFFFFFFF) {
+ printf("/");
+ print_addr(n->smask);
+ }
+ printf(" -> ");
+ print_addr(n->daddr);
+ switch (n->proto) {
+ case IPPROTO_TCP:
+ printf(" proto tcp");
+ break;
+ case IPPROTO_UDP:
+ printf(" proto udp");
+ break;
+ case IPPROTO_ICMP:
+ printf(" proto icmp");
+ break;
+ }
+ printf("\n");
+}
+
+void
+print_rdr(struct rdr *r)
+{
+ printf("rdr %s ", r->ifname);
+ if (r->not)
+ printf("! ");
+ print_addr(r->daddr);
+ if (r->dmask != 0xFFFFFFFF) {
+ printf("/");
+ print_addr(r->dmask);
+ }
+ printf(" port %u -> ", ntohs(r->dport));
+ print_addr(r->raddr);
+ printf(" port %u", ntohs(r->rport));
+ switch (r->proto) {
+ case IPPROTO_TCP:
+ printf(" proto tcp");
+ break;
+ case IPPROTO_UDP:
+ printf(" proto udp");
+ break;
+ }
+ printf("\n");
+}
+
+void
+print_status(struct status *s)
+{
+ time_t t = time(NULL);
+ printf("%u %u %u", t, s->since, s->running);
+ if (s->running) {
+ printf(" %u %u", s->bytes[0], s->bytes[1]);
+ printf(" %u %u", s->packets[0][0], s->packets[0][1]);
+ printf(" %u %u", s->packets[1][0], s->packets[1][1]);
+ printf(" %u %u %u %u", s->states, s->state_inserts,
+ s->state_removals, s->state_searches);
+ }
+ printf("\n");
+}
+
+void
+print_state(struct state *s)
+{
+ struct peer *src, *dst;
+ u_int8_t hrs, min, sec;
+ if (s->direction == PF_OUT) {
+ src = &s->src;
+ dst = &s->dst;
+ } else {
+ src = &s->dst;
+ dst = &s->src;
+ }
+ switch (s->proto) {
+ case IPPROTO_TCP:
+ printf("TCP ");
+ break;
+ case IPPROTO_UDP:
+ printf("UDP ");
+ break;
+ case IPPROTO_ICMP:
+ printf("ICMP ");
+ break;
+ default:
+ printf("???? ");
+ break;
+ }
+ if ((s->lan.addr != s->gwy.addr) || (s->lan.port != s->gwy.port)) {
+ print_host(&s->lan);
+ if (s->direction == PF_OUT)
+ printf(" -> ");
+ else
+ printf(" <- ");
+ }
+ print_host(&s->gwy);
+ if (s->direction == PF_OUT)
+ printf(" -> ");
+ else
+ printf(" <- ");
+ print_host(&s->ext);
+ printf("\n");
+
+ printf("%u:%u ", src->state, dst->state);
+ if (s->proto == IPPROTO_TCP) {
+ print_seq(src);
+ printf(" ");
+ print_seq(dst);
+ printf("\n ");
+ }
+
+ sec = s->creation % 60;
+ s->creation /= 60;
+ min = s->creation % 60;
+ s->creation /= 60;
+ hrs = s->creation;
+ printf("age %.2u:%.2u:%.2u", hrs, min, sec);
+ sec = s->expire % 60;
+ s->expire /= 60;
+ min = s->expire % 60;
+ s->expire /= 60;
+ hrs = s->expire;
+ printf(", expires in %.2u:%.2u:%.2u", hrs, min, sec);
+ printf(", %u pkts, %u bytes\n", s->packets, s->bytes);
+ printf("\n");
+}
+
+void
+print_rule(struct rule *r)
+{
+ if (r->action == 0)
+ printf("pass ");
+ else
+ printf("block ");
+ if (r->action == 2)
+ printf("return-rst ");
+ if (r->direction == 0)
+ printf("in ");
+ else
+ printf("out ");
+ if (r->log)
+ printf("log ");
+ if (r->quick)
+ printf("quick ");
+ if (r->ifname[0])
+ printf("on %s ", r->ifname);
+ if (r->proto) {
+ struct protoent *p = getprotobynumber(r->proto);
+ if (p != NULL)
+ printf("proto %s ", p->p_name);
+ else
+ printf("proto %u ", r->proto);
+ }
+ if (!r->src.addr && !r->src.port_op && !r->dst.addr && !r->dst.port_op)
+ printf("all ");
+ else {
+ printf("from ");
+ if (!r->src.addr)
+ printf("any ");
+ else {
+ if (r->src.not)
+ printf("! ");
+ print_addr(r->src.addr);
+ if (r->src.mask != 0xFFFFFFFF) {
+ printf("/");
+ print_addr(r->src.mask);
+ }
+ printf(" ");
+ }
+ if (r->src.port_op)
+ print_port(r->src.port_op, r->src.port[0],
+ r->src.port[1], r->proto == 6 ? "tcp" : "udp");
+
+ printf("to ");
+ if (!r->dst.addr)
+ printf("any ");
+ else {
+ if (r->dst.not)
+ printf("! ");
+ print_addr(r->dst.addr);
+ if (r->dst.mask != 0xFFFFFFFF) {
+ printf("/");
+ print_addr(r->dst.mask);
+ }
+ printf(" ");
+ }
+ if (r->dst.port_op)
+ print_port(r->dst.port_op, r->dst.port[0],
+ r->dst.port[1], r->proto == 6 ? "tcp" : "udp");
+ }
+ if (r->flags || r->flagset) {
+ printf("flags ");
+ print_flags(r->flags);
+ printf("/");
+ print_flags(r->flagset);
+ printf(" ");
+ }
+ if (r->type)
+ printf("icmp-type %u ", r->type-1);
+ if (r->code)
+ printf("code %u ", r->code-1);
+ if (r->keep_state)
+ printf("keep state ");
+ printf("\n");
+}
+
+char *
+next_line(char **s)
+{
+ char *l;
+ l = *s;
+ while (**s && (**s != '\n'))
+ (*s)++;
+ if (**s) {
+ **s = 0;
+ (*s)++;
+ }
+ return l;
+}
+
+static char *
+next_word(char **s)
+{
+ char *w;
+ while ((**s == ' ') || (**s == '\t') || (**s == '\n'))
+ (*s)++;
+ w = *s;
+ while (**s && (**s != ' ') && (**s != '\t') && (**s != '\n'))
+ (*s)++;
+ if (**s) {
+ **s = 0;
+ (*s)++;
+ }
+ return w;
+}
+
+static u_int16_t
+next_number(char **s)
+{
+ u_int16_t n = 0;
+ while (**s && !isdigit(**s))
+ (*s)++;
+ while (**s && isdigit(**s)) {
+ n *= 10;
+ n += **s - '0';
+ (*s)++;
+ }
+ return n;
+}
+
+static u_int32_t
+next_addr(char **w)
+{
+ u_int8_t a, b, c, d;
+ a = next_number(w);
+ b = next_number(w);
+ c = next_number(w);
+ d = next_number(w);
+ return htonl((a << 24) | (b << 16) | (c << 8) | d);
+}
+
+static u_int8_t
+next_flags(char **s)
+{
+ u_int8_t f = 0;
+ char *p;
+ while (**s && !strchr(tcpflags, **s))
+ (*s)++;
+ while (**s && ((p = strchr(tcpflags, **s)) != NULL)) {
+ f |= 1 << (p-tcpflags);
+ (*s)++;
+ }
+ return f ? f : 63;
+}
+
+static u_int16_t
+rule_port(char *w, u_int8_t p)
+{
+ struct servent *s;
+ if (isdigit(*w))
+ return htons(atoi(w));
+ s = getservbyname(w, p == 6 ? "tcp" : "udp");
+ if (s == NULL)
+ return 0;
+ return s->s_port;
+}
+
+static u_int32_t
+rule_mask(u_int8_t b)
+{
+ u_int32_t m = 0;
+ int i;
+ for (i = 31; i > 31-b; --i)
+ m |= (1 << i);
+ return htonl(m);
+}
+
+int
+parse_rule(int n, char *l, struct rule *r)
+{
+ char *w;
+ memset(r, 0, sizeof(struct rule));
+ w = next_word(&l);
+
+ /* pass / block */
+ if (!strcmp(w, "pass" ))
+ r->action = 0;
+ else if (!strcmp(w, "block"))
+ r->action = 1;
+ else {
+ fprintf(stderr, "error on line %i: expected pass/block, got %s\n",
+ n, w);
+ return 0;
+ }
+ w = next_word(&l);
+
+ /* return-rst */
+ if ((r->action == 1) && !strcmp(w, "return-rst")) {
+ r->action = 2;
+ w = next_word(&l);
+ }
+
+ /* in / out */
+ if (!strcmp(w, "in" ))
+ r->direction = 0;
+ else if (!strcmp(w, "out"))
+ r->direction = 1;
+ else {
+ fprintf(stderr, "error on line %i: expected in/out, got %s\n",
+ n, w);
+ return 0;
+ }
+ w = next_word(&l);
+
+ /* log */
+ if (!strcmp(w, "log")) {
+ r->log = 1;
+ w = next_word(&l);
+ }
+
+ /* quick */
+ if (!strcmp(w, "quick")) {
+ r->quick = 1;
+ w = next_word(&l);
+ }
+
+ /* on <if> */
+ if (!strcmp(w, "on")) {
+ w = next_word(&l);
+ strncpy(r->ifname, w, 16);
+ w = next_word(&l);
+ }
+
+ /* proto tcp/udp/icmp */
+ if (!strcmp(w, "proto")) {
+ struct protoent *p;
+ w = next_word(&l);
+ p = getprotobyname(w);
+ if (p == NULL) {
+ fprintf(stderr, "error on line %i: unknown protocol %s\n",
+ n, w);
+ return 0;
+ }
+ r->proto = p->p_proto;
+ w = next_word(&l);
+ }
+
+ /* all / from src to dst */
+ if (!strcmp(w, "all" ))
+ w = next_word(&l);
+ else if (!strcmp(w, "from")) {
+ w = next_word(&l);
+
+ /* source address */
+ if (!strcmp(w, "any"))
+ w = next_word(&l);
+ else {
+ if (!strcmp(w, "!")) {
+ r->src.not = 1;
+ w = next_word(&l);
+ }
+ r->src.addr = next_addr(&w);
+ if (!*w)
+ r->src.mask = 0xFFFFFFFF;
+ else if (*w == '/')
+ r->src.mask = rule_mask(next_number(&w));
+ else {
+ fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w);
+ return 0;
+ }
+ w = next_word(&l);
+ }
+
+ /* source port */
+ if (((r->proto == 6) || (r->proto == 17)) && !strcmp(w, "port")) {
+ w = next_word(&l);
+ if (!strcmp(w, "=" ))
+ r->src.port_op = 2;
+ else if (!strcmp(w, "!="))
+ r->src.port_op = 3;
+ else if (!strcmp(w, "<" ))
+ r->src.port_op = 4;
+ else if (!strcmp(w, "<="))
+ r->src.port_op = 5;
+ else if (!strcmp(w, ">" ))
+ r->src.port_op = 6;
+ else if (!strcmp(w, ">="))
+ r->src.port_op = 7;
+ else
+ r->src.port_op = 1;
+ if (r->src.port_op != 1)
+ w = next_word(&l);
+ r->src.port[0] = rule_port(w, r->proto);
+ w = next_word(&l);
+ if (r->src.port_op == 1) {
+ if (strcmp(w, "<>") && strcmp(w, "><")) {
+ fprintf(stderr, "error on line %i: expected <>/><, got %s\n", n, w);
+ return 0;
+ }
+ w = next_word(&l);
+ r->src.port[1] = rule_port(w, r->proto);
+ w = next_word(&l);
+ }
+ }
+
+ /* destination address */
+ if (strcmp(w, "to")) {
+ fprintf(stderr, "error on line %i: expected to, got %s\n",
+ n, w);
+ return 0;
+ }
+ w = next_word(&l);
+ if (!strcmp(w, "any"))
+ w = next_word(&l);
+ else {
+ if (!strcmp(w, "!")) {
+ r->dst.not = 1;
+ w = next_word(&l);
+ }
+ r->dst.addr = next_addr(&w);
+ if (!*w)
+ r->dst.mask = 0xFFFFFFFF;
+ else if (*w == '/')
+ r->dst.mask = rule_mask(next_number(&w));
+ else {
+ fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w);
+ return 0;
+ }
+ w = next_word(&l);
+ }
+
+ /* destination port */
+ if (((r->proto == 6) || (r->proto == 17)) && !strcmp(w, "port")) {
+ w = next_word(&l);
+ if (!strcmp(w, "=" ))
+ r->dst.port_op = 2;
+ else if (!strcmp(w, "!="))
+ r->dst.port_op = 3;
+ else if (!strcmp(w, "<" ))
+ r->dst.port_op = 4;
+ else if (!strcmp(w, "<="))
+ r->dst.port_op = 5;
+ else if (!strcmp(w, ">" ))
+ r->dst.port_op = 6;
+ else if (!strcmp(w, ">="))
+ r->dst.port_op = 7;
+ else
+ r->dst.port_op = 1;
+ if (r->dst.port_op != 1)
+ w = next_word(&l);
+ r->dst.port[0] = rule_port(w, r->proto);
+ w = next_word(&l);
+ if (r->dst.port_op == 1) {
+ if (strcmp(w, "<>") && strcmp(w, "><")) {
+ fprintf(stderr, "error on line %i: expected <>/><, got %s\n", n, w);
+ return 0;
+ }
+ w = next_word(&l);
+ r->dst.port[1] = rule_port(w, r->proto);
+ w = next_word(&l);
+ }
+ }
+
+ }
+ else {
+ fprintf(stderr, "error on line %i: expected all/from, got %s\n",
+ n, w);
+ return 0;
+ }
+
+ /* flags */
+ if (!strcmp(w, "flags")) {
+ if (r->proto != 6) {
+ fprintf(stderr, "error on line %i: flags only valid for proto tcp\n", n);
+ return 0;
+ }
+ else {
+ w = next_word(&l);
+ r->flags = next_flags(&w);
+ r->flagset = next_flags(&w);
+ w = next_word(&l);
+ }
+ }
+
+ /* icmp type/code */
+ if (!strcmp(w, "icmp-type")) {
+ if (r->proto != 1) {
+ fprintf(stderr, "error on line %i: icmp-type only valid for proto icmp\n", n);
+ return 0;
+ }
+ else {
+ w = next_word(&l);
+ r->type = atoi(w)+1;
+ w = next_word(&l);
+ if (!strcmp(w, "code")) {
+ w = next_word(&l);
+ r->code = atoi(w) + 1;
+ w = next_word(&l);
+ }
+ }
+ }
+
+ /* keep */
+ if (!strcmp(w, "keep")) {
+ w = next_word(&l);
+ if (!strcmp(w, "state")) {
+ w = next_word(&l);
+ r->keep_state = 1;
+ }
+ else {
+ fprintf(stderr, "error on line %i: expected state, got %s\n", n, w);
+ return 0;
+ }
+ }
+
+ /* no further options expected */
+ while (*w) {
+ fprintf(stderr, "error on line %i: unexpected %s\n", n, w);
+ w = next_word(&l);
+ }
+
+ return 1;
+}
+
+int
+parse_nat(int n, char *l, struct nat *nat)
+{
+ char *w;
+ memset(nat, 0, sizeof(struct nat));
+ w = next_word(&l);
+
+ /* nat */
+ if (strcmp(w, "nat" )) {
+ fprintf(stderr, "error on line %i: expected nat, got %s\n", n, w);
+ return 0;
+ }
+ w = next_word(&l);
+
+ /* if */
+ strncpy(nat->ifname, w, 16);
+ w = next_word(&l);
+
+ /* internal addr/mask */
+ if (!strcmp(w, "!")) {
+ nat->not = 1;
+ w = next_word(&l);
+ }
+ nat->saddr = next_addr(&w);
+ if (!*w)
+ nat->smask = 0xFFFFFFFF;
+ else if (*w == '/')
+ nat->smask = rule_mask(next_number(&w));
+ else {
+ fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w);
+ return 0;
+ }
+ w = next_word(&l);
+
+ /* -> */
+ if (strcmp(w, "->")) {
+ fprintf(stderr, "error on line %i: expected ->, got %s\n", n, w);
+ return 0;
+ }
+ w = next_word(&l);
+
+ /* external addr */
+ nat->daddr = next_addr(&w);
+ w = next_word(&l);
+
+ /* proto */
+ if (!strcmp(w, "proto")) {
+ w = next_word(&l);
+ if (!strcmp(w, "tcp"))
+ nat->proto = IPPROTO_TCP;
+ else if (!strcmp(w, "udp"))
+ nat->proto = IPPROTO_UDP;
+ else if (!strcmp(w, "icmp"))
+ nat->proto = IPPROTO_ICMP;
+ else {
+ fprintf(stderr,
+ "error on line %i: expected tcp/udp/icmp, got %s\n",
+ n, w);
+ return 0;
+ }
+ w = next_word(&l);
+ }
+
+ /* no further options expected */
+ while (*w) {
+ fprintf(stderr, "error on line %i: unexpected %s\n", n, w);
+ w = next_word(&l);
+ }
+
+ return 1;
+}
+
+int
+parse_rdr(int n, char *l, struct rdr *rdr)
+{
+ char *w;
+ memset(rdr, 0, sizeof(struct rdr));
+ w = next_word(&l);
+
+ /* rdr */
+ if (strcmp(w, "rdr" )) {
+ fprintf(stderr, "error on line %i: expected rdr, got %s\n", n, w);
+ return 0;
+ }
+ w = next_word(&l);
+
+ /* if */
+ strncpy(rdr->ifname, w, 16);
+ w = next_word(&l);
+
+ /* external addr/mask */
+ if (!strcmp(w, "!")) {
+ rdr->not = 1;
+ w = next_word(&l);
+ }
+ rdr->daddr = next_addr(&w);
+ if (!*w)
+ rdr->dmask = 0xFFFFFFFF;
+ else if (*w == '/')
+ rdr->dmask = rule_mask(next_number(&w));
+ else {
+ fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w);
+ return 0;
+ }
+ w = next_word(&l);
+
+ /* external port */
+ if (strcmp(w, "port")) {
+ fprintf(stderr, "error on line %i: expected port, got %s\n", n, w);
+ return 0;
+ }
+ w = next_word(&l);
+ rdr->dport = htons(next_number(&w));
+ w = next_word(&l);
+
+ /* -> */
+ if (strcmp(w, "->")) {
+ fprintf(stderr, "error on line %i: expected ->, got %s\n", n, w);
+ return 0;
+ }
+ w = next_word(&l);
+
+ /* internal addr */
+ rdr->raddr = next_addr(&w);
+ w = next_word(&l);
+
+ /* internal port */
+ if (strcmp(w, "port")) {
+ fprintf(stderr, "error on line %i: expected port, got %s\n", n, w);
+ return 0;
+ }
+ w = next_word(&l);
+ rdr->rport = htons(next_number(&w));
+ w = next_word(&l);
+
+ /* proto */
+ if (!strcmp(w, "proto")) {
+ w = next_word(&l);
+ if (!strcmp(w, "tcp"))
+ rdr->proto = IPPROTO_TCP;
+ else if (!strcmp(w, "udp"))
+ rdr->proto = IPPROTO_UDP;
+ else {
+ fprintf(stderr,
+ "error on line %i: expected tcp/udp, got %s\n",
+ n, w);
+ return 0;
+ }
+ w = next_word(&l);
+ }
+
+ /* no further options expected */
+ while (*w) {
+ fprintf(stderr, "error on line %i: unexpected %s\n", n, w);
+ w = next_word(&l);
+ }
+
+ return 1;
+}
+
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
new file mode 100644
index 00000000000..b1daad3ee8a
--- /dev/null
+++ b/sbin/pfctl/pfctl_parser.h
@@ -0,0 +1,48 @@
+/* $OpenBSD: pfctl_parser.h,v 1.1 2001/06/24 21:04:16 kjell Exp $ */
+
+/*
+ * Copyright (c) 2001, Daniel Hartmeier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * 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.
+ *
+ */
+
+#ifndef _PFM_PARSER_H_
+#define _PFM_PARSER_H_
+
+#include <net/pfvar.h>
+
+char *next_line (char **);
+int parse_rule (int, char *, struct rule *);
+int parse_nat (int, char *, struct nat *);
+int parse_rdr (int, char *, struct rdr *);
+void print_rule (struct rule *);
+void print_nat (struct nat *);
+void print_rdr (struct rdr *);
+void print_state (struct state *);
+void print_status (struct status *);
+
+#endif /* _PFM_PARSER_H_ */