diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2001-07-16 21:09:39 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2001-07-16 21:09:39 +0000 |
commit | 1defaba8181da172c09956573344866905b6214b (patch) | |
tree | b9ae985615de9fa158424e408b68aa2de238ac60 /sbin/pfctl/pfctl_parser.c | |
parent | 277e157f9ed157245f3a3521f9ec960c5e2a59f7 (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.c | 788 |
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); } |