1*252d784aSderaadt /* $OpenBSD: pfctl_parser.c,v 1.3 2001/06/24 23:16:36 deraadt Exp $ */ 214a9b182Skjell 314a9b182Skjell /* 414a9b182Skjell * Copyright (c) 2001, Daniel Hartmeier 514a9b182Skjell * All rights reserved. 614a9b182Skjell * 714a9b182Skjell * Redistribution and use in source and binary forms, with or without 814a9b182Skjell * modification, are permitted provided that the following conditions 914a9b182Skjell * are met: 1014a9b182Skjell * 1114a9b182Skjell * - Redistributions of source code must retain the above copyright 1214a9b182Skjell * notice, this list of conditions and the following disclaimer. 1314a9b182Skjell * - Redistributions in binary form must reproduce the above 1414a9b182Skjell * copyright notice, this list of conditions and the following 1514a9b182Skjell * disclaimer in the documentation and/or other materials provided 1614a9b182Skjell * with the distribution. 1714a9b182Skjell * 1814a9b182Skjell * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1914a9b182Skjell * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2014a9b182Skjell * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2114a9b182Skjell * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 225974bd37Sdhartmei * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2314a9b182Skjell * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2414a9b182Skjell * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2514a9b182Skjell * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 2614a9b182Skjell * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2714a9b182Skjell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 2814a9b182Skjell * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2914a9b182Skjell * POSSIBILITY OF SUCH DAMAGE. 3014a9b182Skjell * 3114a9b182Skjell */ 3214a9b182Skjell 33*252d784aSderaadt #include <sys/types.h> 34*252d784aSderaadt #include <sys/socket.h> 35*252d784aSderaadt #include <net/if.h> 36*252d784aSderaadt #include <netinet/in.h> 37*252d784aSderaadt #include <net/pfvar.h> 38*252d784aSderaadt 3914a9b182Skjell #include <stdio.h> 4014a9b182Skjell #include <stdlib.h> 4114a9b182Skjell #include <string.h> 4214a9b182Skjell #include <ctype.h> 4314a9b182Skjell #include <netdb.h> 4414a9b182Skjell 4514a9b182Skjell #include "pfctl_parser.h" 4614a9b182Skjell 4714a9b182Skjell static void print_addr (u_int32_t); 48*252d784aSderaadt static void print_host (struct state_host *); 49*252d784aSderaadt static void print_seq (struct state_peer *); 5014a9b182Skjell static void print_port (u_int8_t, u_int16_t, u_int16_t, char *); 5114a9b182Skjell static void print_flags (u_int8_t); 5214a9b182Skjell static char *next_word (char **); 5314a9b182Skjell static u_int16_t next_number (char **); 5414a9b182Skjell static u_int32_t next_addr (char **); 5514a9b182Skjell static u_int8_t next_flags (char **); 5614a9b182Skjell static u_int16_t rule_port (char *, u_int8_t); 5714a9b182Skjell static u_int32_t rule_mask (u_int8_t); 5814a9b182Skjell 5914a9b182Skjell static char *tcpflags = "FSRPAU"; 6014a9b182Skjell 6114a9b182Skjell static void 6214a9b182Skjell print_addr(u_int32_t a) 6314a9b182Skjell { 6414a9b182Skjell a = ntohl(a); 6514a9b182Skjell printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255); 6614a9b182Skjell } 6714a9b182Skjell 6814a9b182Skjell static void 69*252d784aSderaadt print_host(struct state_host *h) 7014a9b182Skjell { 7114a9b182Skjell u_int32_t a = ntohl(h->addr); 7214a9b182Skjell u_int16_t p = ntohs(h->port); 7314a9b182Skjell printf("%u.%u.%u.%u:%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255, p); 7414a9b182Skjell } 7514a9b182Skjell 7614a9b182Skjell static void 77*252d784aSderaadt print_seq(struct state_peer *p) 7814a9b182Skjell { 7914a9b182Skjell printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo); 8014a9b182Skjell } 8114a9b182Skjell 8214a9b182Skjell static void 8314a9b182Skjell print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto) 8414a9b182Skjell { 8514a9b182Skjell struct servent *s = getservbyport(p1, proto); 8614a9b182Skjell p1 = ntohs(p1); 8714a9b182Skjell p2 = ntohs(p2); 8814a9b182Skjell printf("port "); 8914a9b182Skjell if (op == 1) 9014a9b182Skjell printf("%u >< %u ", p1, p2); 9114a9b182Skjell else if (op == 2) { 9214a9b182Skjell if (s != NULL) 9314a9b182Skjell printf("= %s ", s->s_name); 9414a9b182Skjell else 9514a9b182Skjell printf("= %u ", p1); 9614a9b182Skjell } 9714a9b182Skjell else if (op == 3) { 9814a9b182Skjell if (s != NULL) 9914a9b182Skjell printf("!= %s ", s->s_name); 10014a9b182Skjell else 10114a9b182Skjell printf("!= %u ", p1); 10214a9b182Skjell } 10314a9b182Skjell else if (op == 4) 10414a9b182Skjell printf("< %u ", p1); 10514a9b182Skjell else if (op == 5) 10614a9b182Skjell printf("<= %u ", p1); 10714a9b182Skjell else if (op == 6) 10814a9b182Skjell printf("> %u ", p1); 10914a9b182Skjell else 11014a9b182Skjell printf(">= %u ", p1); 11114a9b182Skjell } 11214a9b182Skjell 11314a9b182Skjell static void 11414a9b182Skjell print_flags(u_int8_t f) 11514a9b182Skjell { 11614a9b182Skjell int i; 11714a9b182Skjell for (i = 0; i < 6; ++i) 11814a9b182Skjell if (f & (1 << i)) 11914a9b182Skjell printf("%c", tcpflags[i]); 12014a9b182Skjell } 12114a9b182Skjell 12214a9b182Skjell void 12314a9b182Skjell print_nat(struct nat *n) 12414a9b182Skjell { 12514a9b182Skjell printf("nat %s ", n->ifname); 12614a9b182Skjell if (n->not) 12714a9b182Skjell printf("! "); 12814a9b182Skjell print_addr(n->saddr); 12914a9b182Skjell if (n->smask != 0xFFFFFFFF) { 13014a9b182Skjell printf("/"); 13114a9b182Skjell print_addr(n->smask); 13214a9b182Skjell } 13314a9b182Skjell printf(" -> "); 13414a9b182Skjell print_addr(n->daddr); 13514a9b182Skjell switch (n->proto) { 13614a9b182Skjell case IPPROTO_TCP: 13714a9b182Skjell printf(" proto tcp"); 13814a9b182Skjell break; 13914a9b182Skjell case IPPROTO_UDP: 14014a9b182Skjell printf(" proto udp"); 14114a9b182Skjell break; 14214a9b182Skjell case IPPROTO_ICMP: 14314a9b182Skjell printf(" proto icmp"); 14414a9b182Skjell break; 14514a9b182Skjell } 14614a9b182Skjell printf("\n"); 14714a9b182Skjell } 14814a9b182Skjell 14914a9b182Skjell void 15014a9b182Skjell print_rdr(struct rdr *r) 15114a9b182Skjell { 15214a9b182Skjell printf("rdr %s ", r->ifname); 15314a9b182Skjell if (r->not) 15414a9b182Skjell printf("! "); 15514a9b182Skjell print_addr(r->daddr); 15614a9b182Skjell if (r->dmask != 0xFFFFFFFF) { 15714a9b182Skjell printf("/"); 15814a9b182Skjell print_addr(r->dmask); 15914a9b182Skjell } 16014a9b182Skjell printf(" port %u -> ", ntohs(r->dport)); 16114a9b182Skjell print_addr(r->raddr); 16214a9b182Skjell printf(" port %u", ntohs(r->rport)); 16314a9b182Skjell switch (r->proto) { 16414a9b182Skjell case IPPROTO_TCP: 16514a9b182Skjell printf(" proto tcp"); 16614a9b182Skjell break; 16714a9b182Skjell case IPPROTO_UDP: 16814a9b182Skjell printf(" proto udp"); 16914a9b182Skjell break; 17014a9b182Skjell } 17114a9b182Skjell printf("\n"); 17214a9b182Skjell } 17314a9b182Skjell 17414a9b182Skjell void 17514a9b182Skjell print_status(struct status *s) 17614a9b182Skjell { 17714a9b182Skjell time_t t = time(NULL); 17814a9b182Skjell printf("%u %u %u", t, s->since, s->running); 17914a9b182Skjell if (s->running) { 18014a9b182Skjell printf(" %u %u", s->bytes[0], s->bytes[1]); 18114a9b182Skjell printf(" %u %u", s->packets[0][0], s->packets[0][1]); 18214a9b182Skjell printf(" %u %u", s->packets[1][0], s->packets[1][1]); 18314a9b182Skjell printf(" %u %u %u %u", s->states, s->state_inserts, 18414a9b182Skjell s->state_removals, s->state_searches); 18514a9b182Skjell } 18614a9b182Skjell printf("\n"); 18714a9b182Skjell } 18814a9b182Skjell 18914a9b182Skjell void 19014a9b182Skjell print_state(struct state *s) 19114a9b182Skjell { 192*252d784aSderaadt struct state_peer *src, *dst; 19314a9b182Skjell u_int8_t hrs, min, sec; 194*252d784aSderaadt 19514a9b182Skjell if (s->direction == PF_OUT) { 19614a9b182Skjell src = &s->src; 19714a9b182Skjell dst = &s->dst; 19814a9b182Skjell } else { 19914a9b182Skjell src = &s->dst; 20014a9b182Skjell dst = &s->src; 20114a9b182Skjell } 20214a9b182Skjell switch (s->proto) { 20314a9b182Skjell case IPPROTO_TCP: 20414a9b182Skjell printf("TCP "); 20514a9b182Skjell break; 20614a9b182Skjell case IPPROTO_UDP: 20714a9b182Skjell printf("UDP "); 20814a9b182Skjell break; 20914a9b182Skjell case IPPROTO_ICMP: 21014a9b182Skjell printf("ICMP "); 21114a9b182Skjell break; 21214a9b182Skjell default: 21314a9b182Skjell printf("???? "); 21414a9b182Skjell break; 21514a9b182Skjell } 21614a9b182Skjell if ((s->lan.addr != s->gwy.addr) || (s->lan.port != s->gwy.port)) { 21714a9b182Skjell print_host(&s->lan); 21814a9b182Skjell if (s->direction == PF_OUT) 21914a9b182Skjell printf(" -> "); 22014a9b182Skjell else 22114a9b182Skjell printf(" <- "); 22214a9b182Skjell } 22314a9b182Skjell print_host(&s->gwy); 22414a9b182Skjell if (s->direction == PF_OUT) 22514a9b182Skjell printf(" -> "); 22614a9b182Skjell else 22714a9b182Skjell printf(" <- "); 22814a9b182Skjell print_host(&s->ext); 22914a9b182Skjell printf("\n"); 23014a9b182Skjell 23114a9b182Skjell printf("%u:%u ", src->state, dst->state); 23214a9b182Skjell if (s->proto == IPPROTO_TCP) { 23314a9b182Skjell print_seq(src); 23414a9b182Skjell printf(" "); 23514a9b182Skjell print_seq(dst); 23614a9b182Skjell printf("\n "); 23714a9b182Skjell } 23814a9b182Skjell 23914a9b182Skjell sec = s->creation % 60; 24014a9b182Skjell s->creation /= 60; 24114a9b182Skjell min = s->creation % 60; 24214a9b182Skjell s->creation /= 60; 24314a9b182Skjell hrs = s->creation; 24414a9b182Skjell printf("age %.2u:%.2u:%.2u", hrs, min, sec); 24514a9b182Skjell sec = s->expire % 60; 24614a9b182Skjell s->expire /= 60; 24714a9b182Skjell min = s->expire % 60; 24814a9b182Skjell s->expire /= 60; 24914a9b182Skjell hrs = s->expire; 25014a9b182Skjell printf(", expires in %.2u:%.2u:%.2u", hrs, min, sec); 25114a9b182Skjell printf(", %u pkts, %u bytes\n", s->packets, s->bytes); 25214a9b182Skjell printf("\n"); 25314a9b182Skjell } 25414a9b182Skjell 25514a9b182Skjell void 25614a9b182Skjell print_rule(struct rule *r) 25714a9b182Skjell { 25814a9b182Skjell if (r->action == 0) 25914a9b182Skjell printf("pass "); 26014a9b182Skjell else 26114a9b182Skjell printf("block "); 26214a9b182Skjell if (r->action == 2) 26314a9b182Skjell printf("return-rst "); 26414a9b182Skjell if (r->direction == 0) 26514a9b182Skjell printf("in "); 26614a9b182Skjell else 26714a9b182Skjell printf("out "); 26814a9b182Skjell if (r->log) 26914a9b182Skjell printf("log "); 27014a9b182Skjell if (r->quick) 27114a9b182Skjell printf("quick "); 27214a9b182Skjell if (r->ifname[0]) 27314a9b182Skjell printf("on %s ", r->ifname); 27414a9b182Skjell if (r->proto) { 27514a9b182Skjell struct protoent *p = getprotobynumber(r->proto); 27614a9b182Skjell if (p != NULL) 27714a9b182Skjell printf("proto %s ", p->p_name); 27814a9b182Skjell else 27914a9b182Skjell printf("proto %u ", r->proto); 28014a9b182Skjell } 28114a9b182Skjell if (!r->src.addr && !r->src.port_op && !r->dst.addr && !r->dst.port_op) 28214a9b182Skjell printf("all "); 28314a9b182Skjell else { 28414a9b182Skjell printf("from "); 28514a9b182Skjell if (!r->src.addr) 28614a9b182Skjell printf("any "); 28714a9b182Skjell else { 28814a9b182Skjell if (r->src.not) 28914a9b182Skjell printf("! "); 29014a9b182Skjell print_addr(r->src.addr); 29114a9b182Skjell if (r->src.mask != 0xFFFFFFFF) { 29214a9b182Skjell printf("/"); 29314a9b182Skjell print_addr(r->src.mask); 29414a9b182Skjell } 29514a9b182Skjell printf(" "); 29614a9b182Skjell } 29714a9b182Skjell if (r->src.port_op) 29814a9b182Skjell print_port(r->src.port_op, r->src.port[0], 29914a9b182Skjell r->src.port[1], r->proto == 6 ? "tcp" : "udp"); 30014a9b182Skjell 30114a9b182Skjell printf("to "); 30214a9b182Skjell if (!r->dst.addr) 30314a9b182Skjell printf("any "); 30414a9b182Skjell else { 30514a9b182Skjell if (r->dst.not) 30614a9b182Skjell printf("! "); 30714a9b182Skjell print_addr(r->dst.addr); 30814a9b182Skjell if (r->dst.mask != 0xFFFFFFFF) { 30914a9b182Skjell printf("/"); 31014a9b182Skjell print_addr(r->dst.mask); 31114a9b182Skjell } 31214a9b182Skjell printf(" "); 31314a9b182Skjell } 31414a9b182Skjell if (r->dst.port_op) 31514a9b182Skjell print_port(r->dst.port_op, r->dst.port[0], 31614a9b182Skjell r->dst.port[1], r->proto == 6 ? "tcp" : "udp"); 31714a9b182Skjell } 31814a9b182Skjell if (r->flags || r->flagset) { 31914a9b182Skjell printf("flags "); 32014a9b182Skjell print_flags(r->flags); 32114a9b182Skjell printf("/"); 32214a9b182Skjell print_flags(r->flagset); 32314a9b182Skjell printf(" "); 32414a9b182Skjell } 32514a9b182Skjell if (r->type) 32614a9b182Skjell printf("icmp-type %u ", r->type-1); 32714a9b182Skjell if (r->code) 32814a9b182Skjell printf("code %u ", r->code-1); 32914a9b182Skjell if (r->keep_state) 33014a9b182Skjell printf("keep state "); 33114a9b182Skjell printf("\n"); 33214a9b182Skjell } 33314a9b182Skjell 33414a9b182Skjell char * 33514a9b182Skjell next_line(char **s) 33614a9b182Skjell { 33714a9b182Skjell char *l; 33814a9b182Skjell l = *s; 33914a9b182Skjell while (**s && (**s != '\n')) 34014a9b182Skjell (*s)++; 34114a9b182Skjell if (**s) { 34214a9b182Skjell **s = 0; 34314a9b182Skjell (*s)++; 34414a9b182Skjell } 34514a9b182Skjell return l; 34614a9b182Skjell } 34714a9b182Skjell 34814a9b182Skjell static char * 34914a9b182Skjell next_word(char **s) 35014a9b182Skjell { 35114a9b182Skjell char *w; 35214a9b182Skjell while ((**s == ' ') || (**s == '\t') || (**s == '\n')) 35314a9b182Skjell (*s)++; 35414a9b182Skjell w = *s; 35514a9b182Skjell while (**s && (**s != ' ') && (**s != '\t') && (**s != '\n')) 35614a9b182Skjell (*s)++; 35714a9b182Skjell if (**s) { 35814a9b182Skjell **s = 0; 35914a9b182Skjell (*s)++; 36014a9b182Skjell } 36114a9b182Skjell return w; 36214a9b182Skjell } 36314a9b182Skjell 36414a9b182Skjell static u_int16_t 36514a9b182Skjell next_number(char **s) 36614a9b182Skjell { 36714a9b182Skjell u_int16_t n = 0; 36814a9b182Skjell while (**s && !isdigit(**s)) 36914a9b182Skjell (*s)++; 37014a9b182Skjell while (**s && isdigit(**s)) { 37114a9b182Skjell n *= 10; 37214a9b182Skjell n += **s - '0'; 37314a9b182Skjell (*s)++; 37414a9b182Skjell } 37514a9b182Skjell return n; 37614a9b182Skjell } 37714a9b182Skjell 37814a9b182Skjell static u_int32_t 37914a9b182Skjell next_addr(char **w) 38014a9b182Skjell { 38114a9b182Skjell u_int8_t a, b, c, d; 38214a9b182Skjell a = next_number(w); 38314a9b182Skjell b = next_number(w); 38414a9b182Skjell c = next_number(w); 38514a9b182Skjell d = next_number(w); 38614a9b182Skjell return htonl((a << 24) | (b << 16) | (c << 8) | d); 38714a9b182Skjell } 38814a9b182Skjell 38914a9b182Skjell static u_int8_t 39014a9b182Skjell next_flags(char **s) 39114a9b182Skjell { 39214a9b182Skjell u_int8_t f = 0; 39314a9b182Skjell char *p; 39414a9b182Skjell while (**s && !strchr(tcpflags, **s)) 39514a9b182Skjell (*s)++; 39614a9b182Skjell while (**s && ((p = strchr(tcpflags, **s)) != NULL)) { 39714a9b182Skjell f |= 1 << (p-tcpflags); 39814a9b182Skjell (*s)++; 39914a9b182Skjell } 40014a9b182Skjell return f ? f : 63; 40114a9b182Skjell } 40214a9b182Skjell 40314a9b182Skjell static u_int16_t 40414a9b182Skjell rule_port(char *w, u_int8_t p) 40514a9b182Skjell { 40614a9b182Skjell struct servent *s; 40714a9b182Skjell if (isdigit(*w)) 40814a9b182Skjell return htons(atoi(w)); 40914a9b182Skjell s = getservbyname(w, p == 6 ? "tcp" : "udp"); 41014a9b182Skjell if (s == NULL) 41114a9b182Skjell return 0; 41214a9b182Skjell return s->s_port; 41314a9b182Skjell } 41414a9b182Skjell 41514a9b182Skjell static u_int32_t 41614a9b182Skjell rule_mask(u_int8_t b) 41714a9b182Skjell { 41814a9b182Skjell u_int32_t m = 0; 41914a9b182Skjell int i; 42014a9b182Skjell for (i = 31; i > 31-b; --i) 42114a9b182Skjell m |= (1 << i); 42214a9b182Skjell return htonl(m); 42314a9b182Skjell } 42414a9b182Skjell 42514a9b182Skjell int 42614a9b182Skjell parse_rule(int n, char *l, struct rule *r) 42714a9b182Skjell { 42814a9b182Skjell char *w; 42914a9b182Skjell memset(r, 0, sizeof(struct rule)); 43014a9b182Skjell w = next_word(&l); 43114a9b182Skjell 43214a9b182Skjell /* pass / block */ 43314a9b182Skjell if (!strcmp(w, "pass" )) 43414a9b182Skjell r->action = 0; 43514a9b182Skjell else if (!strcmp(w, "block")) 43614a9b182Skjell r->action = 1; 43714a9b182Skjell else { 43814a9b182Skjell fprintf(stderr, "error on line %i: expected pass/block, got %s\n", 43914a9b182Skjell n, w); 44014a9b182Skjell return 0; 44114a9b182Skjell } 44214a9b182Skjell w = next_word(&l); 44314a9b182Skjell 44414a9b182Skjell /* return-rst */ 44514a9b182Skjell if ((r->action == 1) && !strcmp(w, "return-rst")) { 44614a9b182Skjell r->action = 2; 44714a9b182Skjell w = next_word(&l); 44814a9b182Skjell } 44914a9b182Skjell 45014a9b182Skjell /* in / out */ 45114a9b182Skjell if (!strcmp(w, "in" )) 45214a9b182Skjell r->direction = 0; 45314a9b182Skjell else if (!strcmp(w, "out")) 45414a9b182Skjell r->direction = 1; 45514a9b182Skjell else { 45614a9b182Skjell fprintf(stderr, "error on line %i: expected in/out, got %s\n", 45714a9b182Skjell n, w); 45814a9b182Skjell return 0; 45914a9b182Skjell } 46014a9b182Skjell w = next_word(&l); 46114a9b182Skjell 46214a9b182Skjell /* log */ 46314a9b182Skjell if (!strcmp(w, "log")) { 46414a9b182Skjell r->log = 1; 46514a9b182Skjell w = next_word(&l); 46614a9b182Skjell } 46714a9b182Skjell 46814a9b182Skjell /* quick */ 46914a9b182Skjell if (!strcmp(w, "quick")) { 47014a9b182Skjell r->quick = 1; 47114a9b182Skjell w = next_word(&l); 47214a9b182Skjell } 47314a9b182Skjell 47414a9b182Skjell /* on <if> */ 47514a9b182Skjell if (!strcmp(w, "on")) { 47614a9b182Skjell w = next_word(&l); 47714a9b182Skjell strncpy(r->ifname, w, 16); 47814a9b182Skjell w = next_word(&l); 47914a9b182Skjell } 48014a9b182Skjell 48114a9b182Skjell /* proto tcp/udp/icmp */ 48214a9b182Skjell if (!strcmp(w, "proto")) { 48314a9b182Skjell struct protoent *p; 48414a9b182Skjell w = next_word(&l); 48514a9b182Skjell p = getprotobyname(w); 48614a9b182Skjell if (p == NULL) { 48714a9b182Skjell fprintf(stderr, "error on line %i: unknown protocol %s\n", 48814a9b182Skjell n, w); 48914a9b182Skjell return 0; 49014a9b182Skjell } 49114a9b182Skjell r->proto = p->p_proto; 49214a9b182Skjell w = next_word(&l); 49314a9b182Skjell } 49414a9b182Skjell 49514a9b182Skjell /* all / from src to dst */ 49614a9b182Skjell if (!strcmp(w, "all" )) 49714a9b182Skjell w = next_word(&l); 49814a9b182Skjell else if (!strcmp(w, "from")) { 49914a9b182Skjell w = next_word(&l); 50014a9b182Skjell 50114a9b182Skjell /* source address */ 50214a9b182Skjell if (!strcmp(w, "any")) 50314a9b182Skjell w = next_word(&l); 50414a9b182Skjell else { 50514a9b182Skjell if (!strcmp(w, "!")) { 50614a9b182Skjell r->src.not = 1; 50714a9b182Skjell w = next_word(&l); 50814a9b182Skjell } 50914a9b182Skjell r->src.addr = next_addr(&w); 51014a9b182Skjell if (!*w) 51114a9b182Skjell r->src.mask = 0xFFFFFFFF; 51214a9b182Skjell else if (*w == '/') 51314a9b182Skjell r->src.mask = rule_mask(next_number(&w)); 51414a9b182Skjell else { 51514a9b182Skjell fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w); 51614a9b182Skjell return 0; 51714a9b182Skjell } 51814a9b182Skjell w = next_word(&l); 51914a9b182Skjell } 52014a9b182Skjell 52114a9b182Skjell /* source port */ 52214a9b182Skjell if (((r->proto == 6) || (r->proto == 17)) && !strcmp(w, "port")) { 52314a9b182Skjell w = next_word(&l); 52414a9b182Skjell if (!strcmp(w, "=" )) 52514a9b182Skjell r->src.port_op = 2; 52614a9b182Skjell else if (!strcmp(w, "!=")) 52714a9b182Skjell r->src.port_op = 3; 52814a9b182Skjell else if (!strcmp(w, "<" )) 52914a9b182Skjell r->src.port_op = 4; 53014a9b182Skjell else if (!strcmp(w, "<=")) 53114a9b182Skjell r->src.port_op = 5; 53214a9b182Skjell else if (!strcmp(w, ">" )) 53314a9b182Skjell r->src.port_op = 6; 53414a9b182Skjell else if (!strcmp(w, ">=")) 53514a9b182Skjell r->src.port_op = 7; 53614a9b182Skjell else 53714a9b182Skjell r->src.port_op = 1; 53814a9b182Skjell if (r->src.port_op != 1) 53914a9b182Skjell w = next_word(&l); 54014a9b182Skjell r->src.port[0] = rule_port(w, r->proto); 54114a9b182Skjell w = next_word(&l); 54214a9b182Skjell if (r->src.port_op == 1) { 54314a9b182Skjell if (strcmp(w, "<>") && strcmp(w, "><")) { 54414a9b182Skjell fprintf(stderr, "error on line %i: expected <>/><, got %s\n", n, w); 54514a9b182Skjell return 0; 54614a9b182Skjell } 54714a9b182Skjell w = next_word(&l); 54814a9b182Skjell r->src.port[1] = rule_port(w, r->proto); 54914a9b182Skjell w = next_word(&l); 55014a9b182Skjell } 55114a9b182Skjell } 55214a9b182Skjell 55314a9b182Skjell /* destination address */ 55414a9b182Skjell if (strcmp(w, "to")) { 55514a9b182Skjell fprintf(stderr, "error on line %i: expected to, got %s\n", 55614a9b182Skjell n, w); 55714a9b182Skjell return 0; 55814a9b182Skjell } 55914a9b182Skjell w = next_word(&l); 56014a9b182Skjell if (!strcmp(w, "any")) 56114a9b182Skjell w = next_word(&l); 56214a9b182Skjell else { 56314a9b182Skjell if (!strcmp(w, "!")) { 56414a9b182Skjell r->dst.not = 1; 56514a9b182Skjell w = next_word(&l); 56614a9b182Skjell } 56714a9b182Skjell r->dst.addr = next_addr(&w); 56814a9b182Skjell if (!*w) 56914a9b182Skjell r->dst.mask = 0xFFFFFFFF; 57014a9b182Skjell else if (*w == '/') 57114a9b182Skjell r->dst.mask = rule_mask(next_number(&w)); 57214a9b182Skjell else { 57314a9b182Skjell fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w); 57414a9b182Skjell return 0; 57514a9b182Skjell } 57614a9b182Skjell w = next_word(&l); 57714a9b182Skjell } 57814a9b182Skjell 57914a9b182Skjell /* destination port */ 58014a9b182Skjell if (((r->proto == 6) || (r->proto == 17)) && !strcmp(w, "port")) { 58114a9b182Skjell w = next_word(&l); 58214a9b182Skjell if (!strcmp(w, "=" )) 58314a9b182Skjell r->dst.port_op = 2; 58414a9b182Skjell else if (!strcmp(w, "!=")) 58514a9b182Skjell r->dst.port_op = 3; 58614a9b182Skjell else if (!strcmp(w, "<" )) 58714a9b182Skjell r->dst.port_op = 4; 58814a9b182Skjell else if (!strcmp(w, "<=")) 58914a9b182Skjell r->dst.port_op = 5; 59014a9b182Skjell else if (!strcmp(w, ">" )) 59114a9b182Skjell r->dst.port_op = 6; 59214a9b182Skjell else if (!strcmp(w, ">=")) 59314a9b182Skjell r->dst.port_op = 7; 59414a9b182Skjell else 59514a9b182Skjell r->dst.port_op = 1; 59614a9b182Skjell if (r->dst.port_op != 1) 59714a9b182Skjell w = next_word(&l); 59814a9b182Skjell r->dst.port[0] = rule_port(w, r->proto); 59914a9b182Skjell w = next_word(&l); 60014a9b182Skjell if (r->dst.port_op == 1) { 60114a9b182Skjell if (strcmp(w, "<>") && strcmp(w, "><")) { 60214a9b182Skjell fprintf(stderr, "error on line %i: expected <>/><, got %s\n", n, w); 60314a9b182Skjell return 0; 60414a9b182Skjell } 60514a9b182Skjell w = next_word(&l); 60614a9b182Skjell r->dst.port[1] = rule_port(w, r->proto); 60714a9b182Skjell w = next_word(&l); 60814a9b182Skjell } 60914a9b182Skjell } 61014a9b182Skjell 61114a9b182Skjell } 61214a9b182Skjell else { 61314a9b182Skjell fprintf(stderr, "error on line %i: expected all/from, got %s\n", 61414a9b182Skjell n, w); 61514a9b182Skjell return 0; 61614a9b182Skjell } 61714a9b182Skjell 61814a9b182Skjell /* flags */ 61914a9b182Skjell if (!strcmp(w, "flags")) { 62014a9b182Skjell if (r->proto != 6) { 62114a9b182Skjell fprintf(stderr, "error on line %i: flags only valid for proto tcp\n", n); 62214a9b182Skjell return 0; 62314a9b182Skjell } 62414a9b182Skjell else { 62514a9b182Skjell w = next_word(&l); 62614a9b182Skjell r->flags = next_flags(&w); 62714a9b182Skjell r->flagset = next_flags(&w); 62814a9b182Skjell w = next_word(&l); 62914a9b182Skjell } 63014a9b182Skjell } 63114a9b182Skjell 63214a9b182Skjell /* icmp type/code */ 63314a9b182Skjell if (!strcmp(w, "icmp-type")) { 63414a9b182Skjell if (r->proto != 1) { 63514a9b182Skjell fprintf(stderr, "error on line %i: icmp-type only valid for proto icmp\n", n); 63614a9b182Skjell return 0; 63714a9b182Skjell } 63814a9b182Skjell else { 63914a9b182Skjell w = next_word(&l); 64014a9b182Skjell r->type = atoi(w)+1; 64114a9b182Skjell w = next_word(&l); 64214a9b182Skjell if (!strcmp(w, "code")) { 64314a9b182Skjell w = next_word(&l); 64414a9b182Skjell r->code = atoi(w) + 1; 64514a9b182Skjell w = next_word(&l); 64614a9b182Skjell } 64714a9b182Skjell } 64814a9b182Skjell } 64914a9b182Skjell 65014a9b182Skjell /* keep */ 65114a9b182Skjell if (!strcmp(w, "keep")) { 65214a9b182Skjell w = next_word(&l); 65314a9b182Skjell if (!strcmp(w, "state")) { 65414a9b182Skjell w = next_word(&l); 65514a9b182Skjell r->keep_state = 1; 65614a9b182Skjell } 65714a9b182Skjell else { 65814a9b182Skjell fprintf(stderr, "error on line %i: expected state, got %s\n", n, w); 65914a9b182Skjell return 0; 66014a9b182Skjell } 66114a9b182Skjell } 66214a9b182Skjell 66314a9b182Skjell /* no further options expected */ 66414a9b182Skjell while (*w) { 66514a9b182Skjell fprintf(stderr, "error on line %i: unexpected %s\n", n, w); 66614a9b182Skjell w = next_word(&l); 66714a9b182Skjell } 66814a9b182Skjell 66914a9b182Skjell return 1; 67014a9b182Skjell } 67114a9b182Skjell 67214a9b182Skjell int 67314a9b182Skjell parse_nat(int n, char *l, struct nat *nat) 67414a9b182Skjell { 67514a9b182Skjell char *w; 67614a9b182Skjell memset(nat, 0, sizeof(struct nat)); 67714a9b182Skjell w = next_word(&l); 67814a9b182Skjell 67914a9b182Skjell /* nat */ 68014a9b182Skjell if (strcmp(w, "nat" )) { 68114a9b182Skjell fprintf(stderr, "error on line %i: expected nat, got %s\n", n, w); 68214a9b182Skjell return 0; 68314a9b182Skjell } 68414a9b182Skjell w = next_word(&l); 68514a9b182Skjell 68614a9b182Skjell /* if */ 68714a9b182Skjell strncpy(nat->ifname, w, 16); 68814a9b182Skjell w = next_word(&l); 68914a9b182Skjell 69014a9b182Skjell /* internal addr/mask */ 69114a9b182Skjell if (!strcmp(w, "!")) { 69214a9b182Skjell nat->not = 1; 69314a9b182Skjell w = next_word(&l); 69414a9b182Skjell } 69514a9b182Skjell nat->saddr = next_addr(&w); 69614a9b182Skjell if (!*w) 69714a9b182Skjell nat->smask = 0xFFFFFFFF; 69814a9b182Skjell else if (*w == '/') 69914a9b182Skjell nat->smask = rule_mask(next_number(&w)); 70014a9b182Skjell else { 70114a9b182Skjell fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w); 70214a9b182Skjell return 0; 70314a9b182Skjell } 70414a9b182Skjell w = next_word(&l); 70514a9b182Skjell 70614a9b182Skjell /* -> */ 70714a9b182Skjell if (strcmp(w, "->")) { 70814a9b182Skjell fprintf(stderr, "error on line %i: expected ->, got %s\n", n, w); 70914a9b182Skjell return 0; 71014a9b182Skjell } 71114a9b182Skjell w = next_word(&l); 71214a9b182Skjell 71314a9b182Skjell /* external addr */ 71414a9b182Skjell nat->daddr = next_addr(&w); 71514a9b182Skjell w = next_word(&l); 71614a9b182Skjell 71714a9b182Skjell /* proto */ 71814a9b182Skjell if (!strcmp(w, "proto")) { 71914a9b182Skjell w = next_word(&l); 72014a9b182Skjell if (!strcmp(w, "tcp")) 72114a9b182Skjell nat->proto = IPPROTO_TCP; 72214a9b182Skjell else if (!strcmp(w, "udp")) 72314a9b182Skjell nat->proto = IPPROTO_UDP; 72414a9b182Skjell else if (!strcmp(w, "icmp")) 72514a9b182Skjell nat->proto = IPPROTO_ICMP; 72614a9b182Skjell else { 72714a9b182Skjell fprintf(stderr, 72814a9b182Skjell "error on line %i: expected tcp/udp/icmp, got %s\n", 72914a9b182Skjell n, w); 73014a9b182Skjell return 0; 73114a9b182Skjell } 73214a9b182Skjell w = next_word(&l); 73314a9b182Skjell } 73414a9b182Skjell 73514a9b182Skjell /* no further options expected */ 73614a9b182Skjell while (*w) { 73714a9b182Skjell fprintf(stderr, "error on line %i: unexpected %s\n", n, w); 73814a9b182Skjell w = next_word(&l); 73914a9b182Skjell } 74014a9b182Skjell 74114a9b182Skjell return 1; 74214a9b182Skjell } 74314a9b182Skjell 74414a9b182Skjell int 74514a9b182Skjell parse_rdr(int n, char *l, struct rdr *rdr) 74614a9b182Skjell { 74714a9b182Skjell char *w; 74814a9b182Skjell memset(rdr, 0, sizeof(struct rdr)); 74914a9b182Skjell w = next_word(&l); 75014a9b182Skjell 75114a9b182Skjell /* rdr */ 75214a9b182Skjell if (strcmp(w, "rdr" )) { 75314a9b182Skjell fprintf(stderr, "error on line %i: expected rdr, got %s\n", n, w); 75414a9b182Skjell return 0; 75514a9b182Skjell } 75614a9b182Skjell w = next_word(&l); 75714a9b182Skjell 75814a9b182Skjell /* if */ 75914a9b182Skjell strncpy(rdr->ifname, w, 16); 76014a9b182Skjell w = next_word(&l); 76114a9b182Skjell 76214a9b182Skjell /* external addr/mask */ 76314a9b182Skjell if (!strcmp(w, "!")) { 76414a9b182Skjell rdr->not = 1; 76514a9b182Skjell w = next_word(&l); 76614a9b182Skjell } 76714a9b182Skjell rdr->daddr = next_addr(&w); 76814a9b182Skjell if (!*w) 76914a9b182Skjell rdr->dmask = 0xFFFFFFFF; 77014a9b182Skjell else if (*w == '/') 77114a9b182Skjell rdr->dmask = rule_mask(next_number(&w)); 77214a9b182Skjell else { 77314a9b182Skjell fprintf(stderr, "error on line %i: expected /, got '%c'\n", n, *w); 77414a9b182Skjell return 0; 77514a9b182Skjell } 77614a9b182Skjell w = next_word(&l); 77714a9b182Skjell 77814a9b182Skjell /* external port */ 77914a9b182Skjell if (strcmp(w, "port")) { 78014a9b182Skjell fprintf(stderr, "error on line %i: expected port, got %s\n", n, w); 78114a9b182Skjell return 0; 78214a9b182Skjell } 78314a9b182Skjell w = next_word(&l); 78414a9b182Skjell rdr->dport = htons(next_number(&w)); 78514a9b182Skjell w = next_word(&l); 78614a9b182Skjell 78714a9b182Skjell /* -> */ 78814a9b182Skjell if (strcmp(w, "->")) { 78914a9b182Skjell fprintf(stderr, "error on line %i: expected ->, got %s\n", n, w); 79014a9b182Skjell return 0; 79114a9b182Skjell } 79214a9b182Skjell w = next_word(&l); 79314a9b182Skjell 79414a9b182Skjell /* internal addr */ 79514a9b182Skjell rdr->raddr = next_addr(&w); 79614a9b182Skjell w = next_word(&l); 79714a9b182Skjell 79814a9b182Skjell /* internal port */ 79914a9b182Skjell if (strcmp(w, "port")) { 80014a9b182Skjell fprintf(stderr, "error on line %i: expected port, got %s\n", n, w); 80114a9b182Skjell return 0; 80214a9b182Skjell } 80314a9b182Skjell w = next_word(&l); 80414a9b182Skjell rdr->rport = htons(next_number(&w)); 80514a9b182Skjell w = next_word(&l); 80614a9b182Skjell 80714a9b182Skjell /* proto */ 80814a9b182Skjell if (!strcmp(w, "proto")) { 80914a9b182Skjell w = next_word(&l); 81014a9b182Skjell if (!strcmp(w, "tcp")) 81114a9b182Skjell rdr->proto = IPPROTO_TCP; 81214a9b182Skjell else if (!strcmp(w, "udp")) 81314a9b182Skjell rdr->proto = IPPROTO_UDP; 81414a9b182Skjell else { 81514a9b182Skjell fprintf(stderr, 81614a9b182Skjell "error on line %i: expected tcp/udp, got %s\n", 81714a9b182Skjell n, w); 81814a9b182Skjell return 0; 81914a9b182Skjell } 82014a9b182Skjell w = next_word(&l); 82114a9b182Skjell } 82214a9b182Skjell 82314a9b182Skjell /* no further options expected */ 82414a9b182Skjell while (*w) { 82514a9b182Skjell fprintf(stderr, "error on line %i: unexpected %s\n", n, w); 82614a9b182Skjell w = next_word(&l); 82714a9b182Skjell } 82814a9b182Skjell 82914a9b182Skjell return 1; 83014a9b182Skjell } 83114a9b182Skjell 832