summaryrefslogtreecommitdiff
path: root/sbin/pfctl/pfctl_parser.c
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2001-07-16 21:09:39 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2001-07-16 21:09:39 +0000
commit1defaba8181da172c09956573344866905b6214b (patch)
treeb9ae985615de9fa158424e408b68aa2de238ac60 /sbin/pfctl/pfctl_parser.c
parent277e157f9ed157245f3a3521f9ec960c5e2a59f7 (diff)
add a yacc parser for pf.conf and nat.conf, with help from mickey@,
plus: -n now turns off all operations, and just parses the conf files ok deraadt@
Diffstat (limited to 'sbin/pfctl/pfctl_parser.c')
-rw-r--r--sbin/pfctl/pfctl_parser.c788
1 files changed, 12 insertions, 776 deletions
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index ca69fff779c..d60cf229c45 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl_parser.c,v 1.34 2001/07/11 21:30:14 csapuntz Exp $ */
+/* $OpenBSD: pfctl_parser.c,v 1.35 2001/07/16 21:09:38 markus Exp $ */
/*
* Copyright (c) 2001, Daniel Hartmeier
@@ -47,6 +47,7 @@
#include <netdb.h>
#include <stdarg.h>
#include <errno.h>
+#include <err.h>
#include "pfctl_parser.h"
@@ -55,26 +56,9 @@ void print_host (struct pf_state_host *);
void print_seq (struct pf_state_peer *);
void print_port (u_int8_t, u_int16_t, u_int16_t, char *);
void print_flags (u_int8_t);
-char *next_word (char **);
-int next_addr (char **, u_int32_t *);
-u_int16_t next_number (char **);
-u_int8_t next_flags (char **);
-int rule_port (char *, u_int8_t, u_int16_t *);
-u_int32_t rule_mask (u_int8_t);
char *tcpflags = "FSRPAU";
-struct icmptypeent {
- char *name;
- u_int8_t type;
-};
-
-struct icmpcodeent {
- char *name;
- u_int8_t type;
- u_int8_t code;
-};
-
struct icmptypeent icmp_type[] = {
{ "echoreq", ICMP_ECHO },
{ "echorep", ICMP_ECHOREPLY },
@@ -137,19 +121,6 @@ struct icmpcodeent icmp_code[] = {
{ "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED }
};
-int
-error(int n, char *fmt, ...)
-{
- extern char *__progname;
- va_list ap;
-
- va_start(ap, fmt);
- fprintf(stderr, "%s: line %d ", __progname, n);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- return (0);
-}
-
struct icmptypeent *
geticmptypebynumber(u_int8_t type)
{
@@ -577,752 +548,17 @@ print_rule(struct pf_rule *r)
printf("\n");
}
-char *
-next_line(char **s)
-{
- char *l = *s;
-
- while (**s && (**s != '\n'))
- (*s)++;
- if (**s) {
- **s = 0;
- (*s)++;
- }
- return (l);
-}
-
-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);
-}
-
-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);
-}
-
-int
-next_addr(char **w, u_int32_t *a)
-{
- struct hostent *hp;
- char *slash;
-
- if ((slash = strchr(*w, '/')))
- *slash = '\0';
- if (inet_pton(AF_INET, *w, a) != 1) {
- if ((hp = gethostbyname(*w)) == NULL)
- return(0);
- memcpy(a, hp->h_addr, sizeof(*a));
- }
- if (slash) {
- *slash = '/';
- *w = slash;
- } else
- *w += strlen(*w);
- return(1);
-}
-
-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);
-}
-
-int
-rule_port(char *w, u_int8_t p, u_int16_t *result)
-{
- struct servent *s;
- u_long ul;
- char *ep;
-
- errno = 0;
- ul = strtoul(w, &ep, 10);
- if (*w == '\0' || *ep != '\0') {
- s = getservbyname(w, p == IPPROTO_TCP ? "tcp" : "udp");
- if (s == NULL)
- return (0);
-
- *result = s->s_port;
- return (1);
- }
- if (errno == ERANGE && ul == ULONG_MAX)
- return (0);
- if (ul > USHRT_MAX) {
- errno = ERANGE;
- return (0);
- }
-
- *result = htons(ul);
- return (1);
-}
-
-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 pf_rule *r)
-{
- char *w;
- memset(r, 0, sizeof(struct pf_rule));
- w = next_word(&l);
-
- /* pass / block */
- if (!strcmp(w, "pass" ))
- r->action = PF_PASS;
- else if (!strcmp(w, "block"))
- r->action = PF_DROP;
- else if (!strcmp(w, "scrub"))
- r->action = PF_SCRUB;
- else {
- error(n, "expected pass/block/scrub, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
-
- /* return-rst/return-icmp */
- if (r->action == PF_DROP) {
- if (!strcmp(w, "return-rst")) {
- r->return_rst = 1;
- w = next_word(&l);
- } else if (!strncmp(w, "return-icmp", 11)) {
- w += 11;
- if ((strlen(w) > 2) && (w[0] == '(') &&
- (w[strlen(w)-1] == ')')) {
- struct icmpcodeent *ic;
-
- w[strlen(w)-1] = 0;
- w++;
- ic = geticmpcodebyname(ICMP_UNREACH, w);
- if (ic == NULL) {
- error(n, "expected icmp code, got %s\n",
- w);
- return (0);
- }
- r->return_icmp = ic->type << 8;
- r->return_icmp |= ic->code;
- } else
- r->return_icmp = (ICMP_UNREACH << 8) |
- ICMP_UNREACH_PORT;
- w = next_word(&l);
- }
- }
-
- /* in / out */
- if (!strcmp(w, "in" ))
- r->direction = 0;
- else if (!strcmp(w, "out"))
- r->direction = 1;
- else {
- error(n, "expected in/out, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
-
- /* log */
- if (!strcmp(w, "log")) {
- r->log = 1;
- w = next_word(&l);
- } else if (!strcmp(w, "log-all")) {
- r->log = 2;
- w = next_word(&l);
- }
-
- /* quick */
- if (!strcmp(w, "quick")) {
- if (r->action == PF_SCRUB) {
- error(n, "quick does not apply to scrub\n");
- return (0);
- }
- 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) {
- int proto = atoi(w);
- if (proto > 0)
- p = getprotobynumber(proto);
- }
- if (p == NULL) {
- error(n, "unknown protocol %s\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);
- }
- if (!next_addr(&w, &r->src.addr)) {
- error(n, "unresolvable host %s\n", w);
- return (0);
- }
- if (!*w)
- r->src.mask = 0xFFFFFFFF;
- else if (*w == '/')
- r->src.mask = rule_mask(next_number(&w));
- else {
- error(n, "expected /, got '%c'\n", *w);
- return (0);
- }
- w = next_word(&l);
- }
-
- if (r->action == PF_SCRUB)
- goto skip_fromport;
-
- /* source port */
- if (((r->proto == IPPROTO_TCP) || (r->proto == IPPROTO_UDP)) &&
- !strcmp(w, "port")) {
- w = next_word(&l);
- if (!strcmp(w, "=" ))
- r->src.port_op = PF_OP_EQ;
- else if (!strcmp(w, "!="))
- r->src.port_op = PF_OP_NE;
- else if (!strcmp(w, "<" ))
- r->src.port_op = PF_OP_LT;
- else if (!strcmp(w, "<="))
- r->src.port_op = PF_OP_LE;
- else if (!strcmp(w, ">" ))
- r->src.port_op = PF_OP_GT;
- else if (!strcmp(w, ">="))
- r->src.port_op = PF_OP_GE;
- else
- r->src.port_op = PF_OP_GL;
- if (r->src.port_op != 1)
- w = next_word(&l);
- if (!rule_port(w, r->proto, &r->src.port[0])) {
- error(n, "invalid port '%s'\n", w);
- return (0);
- }
- w = next_word(&l);
- if (r->src.port_op == PF_OP_GL) {
- if (strcmp(w, "<>") && strcmp(w, "><")) {
- error(n, "expected <>/><, got %s\n",
- w);
- return (0);
- }
- w = next_word(&l);
- if (!rule_port(w, r->proto, &r->src.port[1])) {
- error(n, "invalid port '%s'\n", w);
- return (0);
- }
- w = next_word(&l);
- }
- }
-
- skip_fromport:
-
- /* destination address */
- if (strcmp(w, "to")) {
- error(n, "expected to, got %s\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);
- }
- if (!next_addr(&w, &r->dst.addr)) {
- error(n, "unresolvable host %s\n", w);
- return (0);
- }
- if (!*w)
- r->dst.mask = 0xFFFFFFFF;
- else if (*w == '/')
- r->dst.mask = rule_mask(next_number(&w));
- else {
- error(n, "expected /, got '%c'\n", *w);
- return (0);
- }
- w = next_word(&l);
- }
-
- if (r->action == PF_SCRUB)
- goto skip_toport;
-
- /* destination port */
- if (((r->proto == IPPROTO_TCP) || (r->proto == IPPROTO_UDP)) &&
- !strcmp(w, "port")) {
- w = next_word(&l);
- if (!strcmp(w, "=" ))
- r->dst.port_op = PF_OP_EQ;
- else if (!strcmp(w, "!="))
- r->dst.port_op = PF_OP_NE;
- else if (!strcmp(w, "<" ))
- r->dst.port_op = PF_OP_LT;
- else if (!strcmp(w, "<="))
- r->dst.port_op = PF_OP_LE;
- else if (!strcmp(w, ">" ))
- r->dst.port_op = PF_OP_GT;
- else if (!strcmp(w, ">="))
- r->dst.port_op = PF_OP_GE;
- else
- r->dst.port_op = PF_OP_GL;
- if (r->dst.port_op != PF_OP_GL)
- w = next_word(&l);
- if (!rule_port(w, r->proto, &r->dst.port[0])) {
- error(n, "invalid port '%s'\n", w);
- return (0);
- }
- w = next_word(&l);
- if (r->dst.port_op == PF_OP_GL) {
- if (strcmp(w, "<>") && strcmp(w, "><")) {
- error(n, "expected <>/><, got %s\n",
- w);
- return (0);
- }
- w = next_word(&l);
- if (!rule_port(w, r->proto, &r->dst.port[1])) {
- error(n, "invalid port '%s'\n", w);
- return (0);
- }
- w = next_word(&l);
- }
- }
- skip_toport:
-
- } else {
- error(n, "expected all/from, got %s\n", w);
- return (0);
- }
-
- /* flags */
- if (!strcmp(w, "flags")) {
- if (r->proto != IPPROTO_TCP || r->action == PF_SCRUB) {
- error(n, "flags only valid for proto tcp\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 != IPPROTO_ICMP || r->action == PF_SCRUB) {
- error(n, "icmp-type only valid for proto icmp\n");
- return (0);
- } else {
- u_long ul;
- char *ep;
-
- w = next_word(&l);
-
- errno = 0;
- ul = strtoul(w, &ep, 10);
- if (w[0] == '\0' || *ep != '\0') {
- struct icmptypeent *p;
-
- p = geticmptypebyname(w);
- if (p == NULL) {
- error(n, "unknown icmp-type %s\n", w);
- return (0);
- }
- ul = p->type;
- } else if ((errno == ERANGE && ul == ULONG_MAX) ||
- ul > ICMP_MAXTYPE) {
- error(n, "icmp-type type wrong\n");
- return (0);
- }
- r->type = ul+1;
-
- w = next_word(&l);
- if (!strcmp(w, "code")) {
- w = next_word(&l);
-
- errno = 0;
- ul = strtoul(w, &ep, 10);
- if (w[0] == '\0' || *ep != '\0') {
- struct icmpcodeent *p;
-
- p = geticmpcodebyname(r->type-1, w);
- if (p == NULL) {
- error(n, "unknown code %s\n", w);
- return (0);
- }
- ul = p->code;
- } else if ((errno == ERANGE && ul == ULONG_MAX) ||
- ul > 255) {
- error(n, "icmp-type code wrong\n");
- return (0);
- }
- r->code = ul + 1;
-
- w = next_word(&l);
- }
- }
- }
-
- /* keep */
- if (!strcmp(w, "keep") && r->action != PF_SCRUB) {
- w = next_word(&l);
- if (!strcmp(w, "state")) {
- w = next_word(&l);
- r->keep_state = 1;
- } else {
- error(n, "expected state, got %s\n", w);
- return (0);
- }
- }
-
- /* no further options expected */
- while (*w) {
- error(n, "unexpected %s\n", w);
- w = next_word(&l);
- }
-
- return (1);
-}
-
-int
-parse_nat(int n, char *l, struct pf_nat *nat)
-{
- char *w;
-
- memset(nat, 0, sizeof(struct pf_nat));
- w = next_word(&l);
-
- /* nat */
- if (strcmp(w, "nat" )) {
- error(n, "expected nat, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
-
- /* interface */
- if (!strcmp(w, "on")) {
- w = next_word(&l);
- if (!strcmp(w, "!")) {
- nat->ifnot = 1;
- w = next_word(&l);
- }
- strncpy(nat->ifname, w, 16);
- 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 {
- error(n, "expected tcp/udp/icmp, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
- }
-
- /* source addr/mask */
- if (strcmp(w, "from")) {
- error(n, "expected from, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
- if (!strcmp(w, "any"))
- w = next_word(&l);
- else {
- if (!strcmp(w, "!")) {
- nat->snot = 1;
- w = next_word(&l);
- }
- if (!next_addr(&w, &nat->saddr)) {
- error(n, "unresolvable host %s\n", w);
- return (0);
- }
- if (!*w)
- nat->smask = 0xFFFFFFFF;
- else if (*w == '/')
- nat->smask = rule_mask(next_number(&w));
- else {
- error(n, "expected /, get '%c'\n", *w);
- return (0);
- }
- w = next_word(&l);
- }
-
- /* destination addr/mask */
- if (strcmp(w, "to")) {
- error(n, "expected to, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
- if (!strcmp(w, "any"))
- w = next_word(&l);
- else {
- if (!strcmp(w, "!")) {
- nat->dnot = 1;
- w = next_word(&l);
- }
- if (!next_addr(&w, &nat->daddr)) {
- error(n, "unresolvable host %s\n", w);
- return (0);
- }
- if (!*w)
- nat->dmask = 0xFFFFFFFF;
- else if (*w == '/')
- nat->dmask = rule_mask(next_number(&w));
- else {
- error(n, "expected /, get '%c'\n", *w);
- return (0);
- }
- w = next_word(&l);
- }
-
- /* -> */
- if (strcmp(w, "->")) {
- error(n, "expected ->, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
-
- /* external addr */
- if (!next_addr(&w, &nat->raddr)) {
- error(n, "unresolvable host %s\n", w);
- return (0);
- }
- w = next_word(&l);
-
- /* no further options expected */
- while (*w) {
- error(n, "unexpected %s\n", w);
- w = next_word(&l);
- }
-
- return (1);
-}
-
int
-parse_rdr(int n, char *l, struct pf_rdr *rdr)
+parse_flags(char *s)
{
- char *w, *s;
-
- memset(rdr, 0, sizeof(struct pf_rdr));
- w = next_word(&l);
-
- /* rdr */
- if (strcmp(w, "rdr" )) {
- error(n, "expected rdr, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
-
- /* interface */
- if (!strcmp(w, "on")) {
- w = next_word(&l);
- if (!strcmp(w, "!")) {
- rdr->ifnot = 1;
- w = next_word(&l);
- }
- strncpy(rdr->ifname, w, 16);
- w = next_word(&l);
- }
+ char *p, *q;
+ u_int8_t f = 0;
- /* source addr/mask */
- if (strcmp(w, "from")) {
- error(n, "expected from, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
- if (!strcmp(w, "any"))
- w = next_word(&l);
- else {
- if (!strcmp(w, "!")) {
- rdr->snot = 1;
- w = next_word(&l);
- }
- if (!next_addr(&w, &rdr->saddr)) {
- error(n, "unresolvable host %s\n", w);
- return (0);
- }
- if (!*w)
- rdr->smask = 0xFFFFFFFF;
- else if (*w == '/')
- rdr->smask = rule_mask(next_number(&w));
- else {
- error(n, "expected /, get '%c'\n", *w);
- return (0);
- }
- w = next_word(&l);
- }
-
- /* proto (default is tcp) */
- 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 {
- error(n, "expected tcp/udp, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
- } else
- rdr->proto = IPPROTO_TCP;
-
- /* external addr/mask */
- if (strcmp(w, "to")) {
- error(n, "expected to, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
- if (!strcmp(w, "any"))
- w = next_word(&l);
- else {
- if (!strcmp(w, "!")) {
- rdr->dnot = 1;
- w = next_word(&l);
- }
- if (!next_addr(&w, &rdr->daddr)) {
- error(n, "unresolvable host %s\n", w);
- return (0);
- }
- if (!*w)
- rdr->dmask = 0xFFFFFFFF;
- else if (*w == '/')
- rdr->dmask = rule_mask(next_number(&w));
- else {
- error(n, "expected /, get '%c'\n", *w);
- return (0);
- }
- w = next_word(&l);
- }
-
- /* external port (range) */
- if (strcmp(w, "port")) {
- error(n, "expected port, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
- /* check for port range */
- if ((s = strchr(w, ':')) == NULL) {
- if (!rule_port(w, rdr->proto, &rdr->dport)) {
- error(n, "invalid destination port '%s'\n", w);
- return (0);
- }
- rdr->dport2 = rdr->dport;
- } else {
- *s++ = '\0';
- if (!rule_port(w, rdr->proto, &rdr->dport)) {
- error(n, "invalid destination port '%s'\n", w);
- return (0);
- }
- if (!rule_port(s, rdr->proto, &rdr->dport2)) {
- error(n, "invalid destination port '%s'\n", s);
- return (0);
- }
- rdr->opts |= PF_DPORT_RANGE;
- }
- w = next_word(&l);
-
- /* -> */
- if (strcmp(w, "->")) {
- error(n, "expected ->, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
-
- /* internal addr */
- if (!next_addr(&w, &rdr->raddr)) {
- error(n, "unresolvable host %s\n", w);
- return (0);
- }
- w = next_word(&l);
-
- /* internal port */
- if (strcmp(w, "port")) {
- error(n, "expected port, got %s\n", w);
- return (0);
- }
- w = next_word(&l);
- /* check if redirected port is a range */
- if ((s = strchr(w, ':')) != NULL) {
- rdr->opts |= PF_RPORT_RANGE;
- }
-
- if (!rule_port(w, rdr->proto, &rdr->rport)) {
- error(n, "invalid port '%s'\n", w);
- return (0);
- }
- w = next_word(&l);
-
- /* no further options expected */
- while (*w) {
- error(n, "unexpected %s\n", w);
- w = next_word(&l);
- }
-
- return (1);
+ for (p = s; *p; p++) {
+ if ((q = strchr(tcpflags, *p)) == NULL)
+ return -1;
+ else
+ f |= 1 << (q - tcpflags);
+ }
+ return (f ? f : 63);
}