diff options
author | Kjell Wooding <kjell@cvs.openbsd.org> | 2001-06-24 20:18:13 +0000 |
---|---|---|
committer | Kjell Wooding <kjell@cvs.openbsd.org> | 2001-06-24 20:18:13 +0000 |
commit | fe7bed690123dbfc3b6d51af528c5691fb044425 (patch) | |
tree | eb7760f7cd6c75acc49657cd693fdad369648b08 | |
parent | cce28f3f21812d1d97559f73acdbd81f05f4e8d2 (diff) |
Add userland for the new packet filter.
Code from dhartmei.
-rw-r--r-- | usr.sbin/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/pfm/Makefile | 8 | ||||
-rw-r--r-- | usr.sbin/pfm/pfm.c | 371 | ||||
-rw-r--r-- | usr.sbin/pfm/pfm_parser.c | 825 | ||||
-rw-r--r-- | usr.sbin/pfm/pfm_parser.h | 48 |
5 files changed, 1255 insertions, 3 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 36b3e490aae..447676fce0b 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.81 2001/06/04 22:18:19 deraadt Exp $ +# $OpenBSD: Makefile,v 1.82 2001/06/24 20:18:11 kjell Exp $ # not yet done: catman @@ -9,8 +9,8 @@ SUBDIR= ac accton adduser amd arp bootpd bootpgw bootpef bootptest \ edquota gspa httpd inetd iostat \ kgmon kvm_mkdb lpr \ mailwrapper mopd mtree named \ - netgroup_mkdb openssl pkg pkg_install portmap ppp pppd pppoe pstat \ - pwd_mkdb quot quotaon rarpd rbootd rdconfig rdate repquota rmt \ + netgroup_mkdb openssl pfm pkg pkg_install portmap ppp pppd pppoe \ + pstat pwd_mkdb quot quotaon rarpd rbootd rdconfig rdate repquota rmt \ rpc.bootparamd rpc.lockd rpc.pcnfsd rwhod \ sa sesd sliplogin slstats spppcontrol spray \ syslogd tcpdump timed tokenadm tokeninit traceroute trpt trsp \ diff --git a/usr.sbin/pfm/Makefile b/usr.sbin/pfm/Makefile new file mode 100644 index 00000000000..971939c08d1 --- /dev/null +++ b/usr.sbin/pfm/Makefile @@ -0,0 +1,8 @@ +# +# $OpenBSD: Makefile,v 1.1 2001/06/24 20:18:12 kjell Exp $ + +PROG = pfm +SRCS = pfm.c pfm_parser.c +MAN= + +.include <bsd.prog.mk> diff --git a/usr.sbin/pfm/pfm.c b/usr.sbin/pfm/pfm.c new file mode 100644 index 00000000000..17cac757d41 --- /dev/null +++ b/usr.sbin/pfm/pfm.c @@ -0,0 +1,371 @@ +/* $OpenBSD: pfm.c,v 1.1 2001/06/24 20:18:12 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 "pfm_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/usr.sbin/pfm/pfm_parser.c b/usr.sbin/pfm/pfm_parser.c new file mode 100644 index 00000000000..2ad20912a29 --- /dev/null +++ b/usr.sbin/pfm/pfm_parser.c @@ -0,0 +1,825 @@ +/* $OpenBSD: pfm_parser.c,v 1.1 2001/06/24 20:18:12 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 "pfm_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/usr.sbin/pfm/pfm_parser.h b/usr.sbin/pfm/pfm_parser.h new file mode 100644 index 00000000000..95be2c2898c --- /dev/null +++ b/usr.sbin/pfm/pfm_parser.h @@ -0,0 +1,48 @@ +/* $OpenBSD: pfm_parser.h,v 1.1 2001/06/24 20:18:12 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_ */ |