1*082ebc44Swilfried /* $OpenBSD: pfctl_parser.c,v 1.11 2001/06/26 15:29:05 wilfried 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 33252d784aSderaadt #include <sys/types.h> 34252d784aSderaadt #include <sys/socket.h> 35252d784aSderaadt #include <net/if.h> 36252d784aSderaadt #include <netinet/in.h> 376329fa59Sderaadt #include <netinet/in_systm.h> 386329fa59Sderaadt #include <netinet/ip.h> 396329fa59Sderaadt #include <netinet/ip_icmp.h> 40252d784aSderaadt #include <net/pfvar.h> 41252d784aSderaadt 4214a9b182Skjell #include <stdio.h> 4314a9b182Skjell #include <stdlib.h> 4414a9b182Skjell #include <string.h> 4514a9b182Skjell #include <ctype.h> 4614a9b182Skjell #include <netdb.h> 476329fa59Sderaadt #include <stdarg.h> 486329fa59Sderaadt #include <errno.h> 4914a9b182Skjell 5014a9b182Skjell #include "pfctl_parser.h" 5114a9b182Skjell 5281a15e5dSderaadt void print_addr (u_int32_t); 536d5ce0fbSderaadt void print_host (struct pf_state_host *); 546d5ce0fbSderaadt void print_seq (struct pf_state_peer *); 5581a15e5dSderaadt void print_port (u_int8_t, u_int16_t, u_int16_t, char *); 5681a15e5dSderaadt void print_flags (u_int8_t); 5781a15e5dSderaadt char *next_word (char **); 5881a15e5dSderaadt u_int16_t next_number (char **); 5981a15e5dSderaadt u_int32_t next_addr (char **); 6081a15e5dSderaadt u_int8_t next_flags (char **); 6181a15e5dSderaadt u_int16_t rule_port (char *, u_int8_t); 6281a15e5dSderaadt u_int32_t rule_mask (u_int8_t); 6314a9b182Skjell 6481a15e5dSderaadt char *tcpflags = "FSRPAU"; 6514a9b182Skjell 66*082ebc44Swilfried struct icmptypeent { 67*082ebc44Swilfried char *name; 68*082ebc44Swilfried u_int8_t type; 69*082ebc44Swilfried }; 70*082ebc44Swilfried 71*082ebc44Swilfried struct icmpcodeent { 72*082ebc44Swilfried char *name; 73*082ebc44Swilfried u_int8_t type; 74*082ebc44Swilfried u_int8_t code; 75*082ebc44Swilfried }; 76*082ebc44Swilfried 77*082ebc44Swilfried struct icmptypeent icmp_type[] = { 78*082ebc44Swilfried { "echoreq", ICMP_ECHO }, 79*082ebc44Swilfried { "echorep", ICMP_ECHOREPLY }, 80*082ebc44Swilfried { "unreach", ICMP_UNREACH }, 81*082ebc44Swilfried { "squench", ICMP_SOURCEQUENCH }, 82*082ebc44Swilfried { "redir", ICMP_REDIRECT }, 83*082ebc44Swilfried { "althost", ICMP_ALTHOSTADDR }, 84*082ebc44Swilfried { "routeradv", ICMP_ROUTERADVERT }, 85*082ebc44Swilfried { "routersol", ICMP_ROUTERSOLICIT }, 86*082ebc44Swilfried { "timex", ICMP_TIMXCEED }, 87*082ebc44Swilfried { "paramprob", ICMP_PARAMPROB }, 88*082ebc44Swilfried { "timereq", ICMP_TSTAMP }, 89*082ebc44Swilfried { "timerep", ICMP_TSTAMPREPLY }, 90*082ebc44Swilfried { "inforeq", ICMP_IREQ }, 91*082ebc44Swilfried { "inforep", ICMP_IREQREPLY }, 92*082ebc44Swilfried { "maskreq", ICMP_MASKREQ }, 93*082ebc44Swilfried { "maskrep", ICMP_MASKREPLY } 94*082ebc44Swilfried }; 95*082ebc44Swilfried 96*082ebc44Swilfried struct icmpcodeent icmp_code[] = { 97*082ebc44Swilfried { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET }, 98*082ebc44Swilfried { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST }, 99*082ebc44Swilfried { "proto-unr", ICMP_UNREACH, ICMP_UNREACH_PROTOCOL }, 100*082ebc44Swilfried { "port-unr", ICMP_UNREACH, ICMP_UNREACH_PORT }, 101*082ebc44Swilfried { "needfrag", ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG }, 102*082ebc44Swilfried { "srcfail", ICMP_UNREACH, ICMP_UNREACH_SRCFAIL }, 103*082ebc44Swilfried { "net-unk", ICMP_UNREACH, ICMP_UNREACH_NET_UNKNOWN }, 104*082ebc44Swilfried { "host-unk", ICMP_UNREACH, ICMP_UNREACH_HOST_UNKNOWN }, 105*082ebc44Swilfried { "isolate", ICMP_UNREACH, ICMP_UNREACH_ISOLATED }, 106*082ebc44Swilfried { "net-prohib", ICMP_UNREACH, ICMP_UNREACH_NET_PROHIB }, 107*082ebc44Swilfried { "host-prohib", ICMP_UNREACH, ICMP_UNREACH_HOST_PROHIB }, 108*082ebc44Swilfried { "net-tos", ICMP_UNREACH, ICMP_UNREACH_TOSNET }, 109*082ebc44Swilfried { "host-tos", ICMP_UNREACH, ICMP_UNREACH_TOSHOST }, 110*082ebc44Swilfried { "filter-prohib", ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB }, 111*082ebc44Swilfried { "host-preced", ICMP_UNREACH, ICMP_UNREACH_HOST_PRECEDENCE }, 112*082ebc44Swilfried { "cutoff-preced", ICMP_UNREACH, ICMP_UNREACH_PRECEDENCE_CUTOFF }, 113*082ebc44Swilfried { "redir-net", ICMP_REDIRECT, ICMP_REDIRECT_NET }, 114*082ebc44Swilfried { "redir-host", ICMP_REDIRECT, ICMP_REDIRECT_HOST }, 115*082ebc44Swilfried { "redir-tos-net", ICMP_REDIRECT, ICMP_REDIRECT_TOSNET }, 116*082ebc44Swilfried { "redir-tos-host", ICMP_REDIRECT, ICMP_REDIRECT_TOSHOST }, 117*082ebc44Swilfried { "transit", ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS }, 118*082ebc44Swilfried { "reassemb", ICMP_TIMXCEED, ICMP_TIMXCEED_REASS }, 119*082ebc44Swilfried { "badhead", ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR }, 120*082ebc44Swilfried { "optmiss", ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT }, 121*082ebc44Swilfried { "badlen", ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH } 122*082ebc44Swilfried }; 123*082ebc44Swilfried 1246329fa59Sderaadt int 1256329fa59Sderaadt error(int n, char *fmt, ...) 1266329fa59Sderaadt { 1276329fa59Sderaadt extern char *__progname; 1286329fa59Sderaadt va_list ap; 1296329fa59Sderaadt 1306329fa59Sderaadt va_start(ap, fmt); 1316329fa59Sderaadt fprintf(stderr, "%s: line %d ", __progname, n); 1326329fa59Sderaadt vfprintf(stderr, fmt, ap); 1336329fa59Sderaadt va_end(ap); 1346329fa59Sderaadt return (0); 1356329fa59Sderaadt } 1366329fa59Sderaadt 137*082ebc44Swilfried struct icmptypeent * 138*082ebc44Swilfried geticmptypebynumber(u_int8_t type) 139*082ebc44Swilfried { 140*082ebc44Swilfried int i; 141*082ebc44Swilfried 142*082ebc44Swilfried for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) { 143*082ebc44Swilfried if(type == icmp_type[i].type) 144*082ebc44Swilfried return (&icmp_type[i]); 145*082ebc44Swilfried } 146*082ebc44Swilfried return (0); 147*082ebc44Swilfried } 148*082ebc44Swilfried 149*082ebc44Swilfried struct icmptypeent * 150*082ebc44Swilfried geticmptypebyname(char *w) 151*082ebc44Swilfried { 152*082ebc44Swilfried int i; 153*082ebc44Swilfried 154*082ebc44Swilfried for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) { 155*082ebc44Swilfried if(!strcmp(w, icmp_type[i].name)) 156*082ebc44Swilfried return (&icmp_type[i]); 157*082ebc44Swilfried } 158*082ebc44Swilfried return (0); 159*082ebc44Swilfried } 160*082ebc44Swilfried 161*082ebc44Swilfried struct icmpcodeent * 162*082ebc44Swilfried geticmpcodebynumber(u_int8_t type, u_int8_t code) 163*082ebc44Swilfried { 164*082ebc44Swilfried int i; 165*082ebc44Swilfried 166*082ebc44Swilfried for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) { 167*082ebc44Swilfried if (type == icmp_code[i].type && code == icmp_code[i].code) 168*082ebc44Swilfried return (&icmp_code[i]); 169*082ebc44Swilfried } 170*082ebc44Swilfried return (0); 171*082ebc44Swilfried } 172*082ebc44Swilfried 173*082ebc44Swilfried struct icmpcodeent * 174*082ebc44Swilfried geticmpcodebyname(u_long type, char *w) 175*082ebc44Swilfried { 176*082ebc44Swilfried int i; 177*082ebc44Swilfried 178*082ebc44Swilfried for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) { 179*082ebc44Swilfried if (type == icmp_code[i].type && !strcmp(w, icmp_code[i].name)) 180*082ebc44Swilfried return (&icmp_code[i]); 181*082ebc44Swilfried } 182*082ebc44Swilfried return (0); 183*082ebc44Swilfried } 184*082ebc44Swilfried 18581a15e5dSderaadt void 18614a9b182Skjell print_addr(u_int32_t a) 18714a9b182Skjell { 18814a9b182Skjell a = ntohl(a); 18914a9b182Skjell printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255); 19014a9b182Skjell } 19114a9b182Skjell 19281a15e5dSderaadt void 1936d5ce0fbSderaadt print_host(struct pf_state_host *h) 19414a9b182Skjell { 19514a9b182Skjell u_int32_t a = ntohl(h->addr); 19614a9b182Skjell u_int16_t p = ntohs(h->port); 19781a15e5dSderaadt 19814a9b182Skjell printf("%u.%u.%u.%u:%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255, p); 19914a9b182Skjell } 20014a9b182Skjell 20181a15e5dSderaadt void 2026d5ce0fbSderaadt print_seq(struct pf_state_peer *p) 20314a9b182Skjell { 20414a9b182Skjell printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo); 20514a9b182Skjell } 20614a9b182Skjell 20781a15e5dSderaadt void 20814a9b182Skjell print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto) 20914a9b182Skjell { 21014a9b182Skjell struct servent *s = getservbyport(p1, proto); 21181a15e5dSderaadt 21214a9b182Skjell p1 = ntohs(p1); 21314a9b182Skjell p2 = ntohs(p2); 21414a9b182Skjell printf("port "); 21514a9b182Skjell if (op == 1) 21614a9b182Skjell printf("%u >< %u ", p1, p2); 21714a9b182Skjell else if (op == 2) { 21814a9b182Skjell if (s != NULL) 21914a9b182Skjell printf("= %s ", s->s_name); 22014a9b182Skjell else 22114a9b182Skjell printf("= %u ", p1); 22281a15e5dSderaadt } else if (op == 3) { 22314a9b182Skjell if (s != NULL) 22414a9b182Skjell printf("!= %s ", s->s_name); 22514a9b182Skjell else 22614a9b182Skjell printf("!= %u ", p1); 22781a15e5dSderaadt } else if (op == 4) 22814a9b182Skjell printf("< %u ", p1); 22914a9b182Skjell else if (op == 5) 23014a9b182Skjell printf("<= %u ", p1); 23114a9b182Skjell else if (op == 6) 23214a9b182Skjell printf("> %u ", p1); 23314a9b182Skjell else 23414a9b182Skjell printf(">= %u ", p1); 23514a9b182Skjell } 23614a9b182Skjell 23781a15e5dSderaadt void 23814a9b182Skjell print_flags(u_int8_t f) 23914a9b182Skjell { 24014a9b182Skjell int i; 24181a15e5dSderaadt 24214a9b182Skjell for (i = 0; i < 6; ++i) 24314a9b182Skjell if (f & (1 << i)) 24414a9b182Skjell printf("%c", tcpflags[i]); 24514a9b182Skjell } 24614a9b182Skjell 24714a9b182Skjell void 24881a15e5dSderaadt print_nat(struct pf_nat *n) 24914a9b182Skjell { 25014a9b182Skjell printf("nat %s ", n->ifname); 25114a9b182Skjell if (n->not) 25214a9b182Skjell printf("! "); 25314a9b182Skjell print_addr(n->saddr); 25414a9b182Skjell if (n->smask != 0xFFFFFFFF) { 25514a9b182Skjell printf("/"); 25614a9b182Skjell print_addr(n->smask); 25714a9b182Skjell } 25814a9b182Skjell printf(" -> "); 25914a9b182Skjell print_addr(n->daddr); 26014a9b182Skjell switch (n->proto) { 26114a9b182Skjell case IPPROTO_TCP: 26214a9b182Skjell printf(" proto tcp"); 26314a9b182Skjell break; 26414a9b182Skjell case IPPROTO_UDP: 26514a9b182Skjell printf(" proto udp"); 26614a9b182Skjell break; 26714a9b182Skjell case IPPROTO_ICMP: 26814a9b182Skjell printf(" proto icmp"); 26914a9b182Skjell break; 27014a9b182Skjell } 27114a9b182Skjell printf("\n"); 27214a9b182Skjell } 27314a9b182Skjell 27414a9b182Skjell void 27581a15e5dSderaadt print_rdr(struct pf_rdr *r) 27614a9b182Skjell { 27714a9b182Skjell printf("rdr %s ", r->ifname); 27814a9b182Skjell if (r->not) 27914a9b182Skjell printf("! "); 28014a9b182Skjell print_addr(r->daddr); 28114a9b182Skjell if (r->dmask != 0xFFFFFFFF) { 28214a9b182Skjell printf("/"); 28314a9b182Skjell print_addr(r->dmask); 28414a9b182Skjell } 28514a9b182Skjell printf(" port %u -> ", ntohs(r->dport)); 28614a9b182Skjell print_addr(r->raddr); 28714a9b182Skjell printf(" port %u", ntohs(r->rport)); 28814a9b182Skjell switch (r->proto) { 28914a9b182Skjell case IPPROTO_TCP: 29014a9b182Skjell printf(" proto tcp"); 29114a9b182Skjell break; 29214a9b182Skjell case IPPROTO_UDP: 29314a9b182Skjell printf(" proto udp"); 29414a9b182Skjell break; 29514a9b182Skjell } 29614a9b182Skjell printf("\n"); 29714a9b182Skjell } 29814a9b182Skjell 29914a9b182Skjell void 30081a15e5dSderaadt print_status(struct pf_status *s) 30114a9b182Skjell { 30214a9b182Skjell time_t t = time(NULL); 30381a15e5dSderaadt 30414a9b182Skjell printf("%u %u %u", t, s->since, s->running); 30514a9b182Skjell if (s->running) { 30614a9b182Skjell printf(" %u %u", s->bytes[0], s->bytes[1]); 30714a9b182Skjell printf(" %u %u", s->packets[0][0], s->packets[0][1]); 30814a9b182Skjell printf(" %u %u", s->packets[1][0], s->packets[1][1]); 30914a9b182Skjell printf(" %u %u %u %u", s->states, s->state_inserts, 31014a9b182Skjell s->state_removals, s->state_searches); 31114a9b182Skjell } 31214a9b182Skjell printf("\n"); 31314a9b182Skjell } 31414a9b182Skjell 31514a9b182Skjell void 31681a15e5dSderaadt print_state(struct pf_state *s) 31714a9b182Skjell { 3186d5ce0fbSderaadt struct pf_state_peer *src, *dst; 31914a9b182Skjell u_int8_t hrs, min, sec; 320252d784aSderaadt 32114a9b182Skjell if (s->direction == PF_OUT) { 32214a9b182Skjell src = &s->src; 32314a9b182Skjell dst = &s->dst; 32414a9b182Skjell } else { 32514a9b182Skjell src = &s->dst; 32614a9b182Skjell dst = &s->src; 32714a9b182Skjell } 32814a9b182Skjell switch (s->proto) { 32914a9b182Skjell case IPPROTO_TCP: 33014a9b182Skjell printf("TCP "); 33114a9b182Skjell break; 33214a9b182Skjell case IPPROTO_UDP: 33314a9b182Skjell printf("UDP "); 33414a9b182Skjell break; 33514a9b182Skjell case IPPROTO_ICMP: 33614a9b182Skjell printf("ICMP "); 33714a9b182Skjell break; 33814a9b182Skjell default: 33914a9b182Skjell printf("???? "); 34014a9b182Skjell break; 34114a9b182Skjell } 34214a9b182Skjell if ((s->lan.addr != s->gwy.addr) || (s->lan.port != s->gwy.port)) { 34314a9b182Skjell print_host(&s->lan); 34414a9b182Skjell if (s->direction == PF_OUT) 34514a9b182Skjell printf(" -> "); 34614a9b182Skjell else 34714a9b182Skjell printf(" <- "); 34814a9b182Skjell } 34914a9b182Skjell print_host(&s->gwy); 35014a9b182Skjell if (s->direction == PF_OUT) 35114a9b182Skjell printf(" -> "); 35214a9b182Skjell else 35314a9b182Skjell printf(" <- "); 35414a9b182Skjell print_host(&s->ext); 35514a9b182Skjell printf("\n"); 35614a9b182Skjell 35714a9b182Skjell printf("%u:%u ", src->state, dst->state); 35814a9b182Skjell if (s->proto == IPPROTO_TCP) { 35914a9b182Skjell print_seq(src); 36014a9b182Skjell printf(" "); 36114a9b182Skjell print_seq(dst); 36214a9b182Skjell printf("\n "); 36314a9b182Skjell } 36414a9b182Skjell 36514a9b182Skjell sec = s->creation % 60; 36614a9b182Skjell s->creation /= 60; 36714a9b182Skjell min = s->creation % 60; 36814a9b182Skjell s->creation /= 60; 36914a9b182Skjell hrs = s->creation; 37014a9b182Skjell printf("age %.2u:%.2u:%.2u", hrs, min, sec); 37114a9b182Skjell sec = s->expire % 60; 37214a9b182Skjell s->expire /= 60; 37314a9b182Skjell min = s->expire % 60; 37414a9b182Skjell s->expire /= 60; 37514a9b182Skjell hrs = s->expire; 37614a9b182Skjell printf(", expires in %.2u:%.2u:%.2u", hrs, min, sec); 37714a9b182Skjell printf(", %u pkts, %u bytes\n", s->packets, s->bytes); 37814a9b182Skjell printf("\n"); 37914a9b182Skjell } 38014a9b182Skjell 38114a9b182Skjell void 38281a15e5dSderaadt print_rule(struct pf_rule *r) 38314a9b182Skjell { 38414a9b182Skjell if (r->action == 0) 38514a9b182Skjell printf("pass "); 38614a9b182Skjell else 38714a9b182Skjell printf("block "); 38814a9b182Skjell if (r->action == 2) 38914a9b182Skjell printf("return-rst "); 39014a9b182Skjell if (r->direction == 0) 39114a9b182Skjell printf("in "); 39214a9b182Skjell else 39314a9b182Skjell printf("out "); 39414a9b182Skjell if (r->log) 39514a9b182Skjell printf("log "); 39614a9b182Skjell if (r->quick) 39714a9b182Skjell printf("quick "); 39814a9b182Skjell if (r->ifname[0]) 39914a9b182Skjell printf("on %s ", r->ifname); 40014a9b182Skjell if (r->proto) { 40114a9b182Skjell struct protoent *p = getprotobynumber(r->proto); 40214a9b182Skjell if (p != NULL) 40314a9b182Skjell printf("proto %s ", p->p_name); 40414a9b182Skjell else 40514a9b182Skjell printf("proto %u ", r->proto); 40614a9b182Skjell } 407ade2013bSwilfried if (!r->src.addr && !r->src.mask && !r->src.port_op && !r->dst.addr && ! r->dst.mask && !r->dst.port_op) 40814a9b182Skjell printf("all "); 40914a9b182Skjell else { 41014a9b182Skjell printf("from "); 411ade2013bSwilfried if (!r->src.addr && !r->src.mask) 41214a9b182Skjell printf("any "); 41314a9b182Skjell else { 41414a9b182Skjell if (r->src.not) 41514a9b182Skjell printf("! "); 41614a9b182Skjell print_addr(r->src.addr); 41714a9b182Skjell if (r->src.mask != 0xFFFFFFFF) { 41814a9b182Skjell printf("/"); 41914a9b182Skjell print_addr(r->src.mask); 42014a9b182Skjell } 42114a9b182Skjell printf(" "); 42214a9b182Skjell } 42314a9b182Skjell if (r->src.port_op) 42414a9b182Skjell print_port(r->src.port_op, r->src.port[0], 4255df8e51cSsmart r->src.port[1], 4265df8e51cSsmart r->proto == IPPROTO_TCP ? "tcp" : "udp"); 42714a9b182Skjell 42814a9b182Skjell printf("to "); 429ade2013bSwilfried if (!r->dst.addr && !r->dst.mask) 43014a9b182Skjell printf("any "); 43114a9b182Skjell else { 43214a9b182Skjell if (r->dst.not) 43314a9b182Skjell printf("! "); 43414a9b182Skjell print_addr(r->dst.addr); 43514a9b182Skjell if (r->dst.mask != 0xFFFFFFFF) { 43614a9b182Skjell printf("/"); 43714a9b182Skjell print_addr(r->dst.mask); 43814a9b182Skjell } 43914a9b182Skjell printf(" "); 44014a9b182Skjell } 44114a9b182Skjell if (r->dst.port_op) 44214a9b182Skjell print_port(r->dst.port_op, r->dst.port[0], 4435df8e51cSsmart r->dst.port[1], 4445df8e51cSsmart r->proto == IPPROTO_TCP ? "tcp" : "udp"); 44514a9b182Skjell } 44614a9b182Skjell if (r->flags || r->flagset) { 44714a9b182Skjell printf("flags "); 44814a9b182Skjell print_flags(r->flags); 44914a9b182Skjell printf("/"); 45014a9b182Skjell print_flags(r->flagset); 45114a9b182Skjell printf(" "); 45214a9b182Skjell } 453*082ebc44Swilfried if (r->type) { 454*082ebc44Swilfried struct icmptypeent *p; 455*082ebc44Swilfried 456*082ebc44Swilfried p = geticmptypebynumber(r->type-1); 457*082ebc44Swilfried if (p != NULL) 458*082ebc44Swilfried printf("icmp-type %s ", p->name); 459*082ebc44Swilfried else 46014a9b182Skjell printf("icmp-type %u ", r->type-1); 461*082ebc44Swilfried if (r->code) { 462*082ebc44Swilfried struct icmpcodeent *p; 463*082ebc44Swilfried 464*082ebc44Swilfried p = geticmpcodebynumber(r->type-1, r->code-1); 465*082ebc44Swilfried if (p != NULL) 466*082ebc44Swilfried printf("code %s ", p->name); 467*082ebc44Swilfried else 46814a9b182Skjell printf("code %u ", r->code-1); 469*082ebc44Swilfried } 470*082ebc44Swilfried } 47114a9b182Skjell if (r->keep_state) 47214a9b182Skjell printf("keep state "); 47314a9b182Skjell printf("\n"); 47414a9b182Skjell } 47514a9b182Skjell 47614a9b182Skjell char * 47714a9b182Skjell next_line(char **s) 47814a9b182Skjell { 47981a15e5dSderaadt char *l = *s; 48081a15e5dSderaadt 48114a9b182Skjell while (**s && (**s != '\n')) 48214a9b182Skjell (*s)++; 48314a9b182Skjell if (**s) { 48414a9b182Skjell **s = 0; 48514a9b182Skjell (*s)++; 48614a9b182Skjell } 487dbfb98deSprovos return (l); 48814a9b182Skjell } 48914a9b182Skjell 49081a15e5dSderaadt char * 49114a9b182Skjell next_word(char **s) 49214a9b182Skjell { 49314a9b182Skjell char *w; 49481a15e5dSderaadt 49514a9b182Skjell while ((**s == ' ') || (**s == '\t') || (**s == '\n')) 49614a9b182Skjell (*s)++; 49714a9b182Skjell w = *s; 49814a9b182Skjell while (**s && (**s != ' ') && (**s != '\t') && (**s != '\n')) 49914a9b182Skjell (*s)++; 50014a9b182Skjell if (**s) { 50114a9b182Skjell **s = 0; 50214a9b182Skjell (*s)++; 50314a9b182Skjell } 504dbfb98deSprovos return (w); 50514a9b182Skjell } 50614a9b182Skjell 50781a15e5dSderaadt u_int16_t 50814a9b182Skjell next_number(char **s) 50914a9b182Skjell { 51014a9b182Skjell u_int16_t n = 0; 51181a15e5dSderaadt 51214a9b182Skjell while (**s && !isdigit(**s)) 51314a9b182Skjell (*s)++; 51414a9b182Skjell while (**s && isdigit(**s)) { 51514a9b182Skjell n *= 10; 51614a9b182Skjell n += **s - '0'; 51714a9b182Skjell (*s)++; 51814a9b182Skjell } 519dbfb98deSprovos return (n); 52014a9b182Skjell } 52114a9b182Skjell 52281a15e5dSderaadt u_int32_t 52314a9b182Skjell next_addr(char **w) 52414a9b182Skjell { 52514a9b182Skjell u_int8_t a, b, c, d; 52614a9b182Skjell a = next_number(w); 52714a9b182Skjell b = next_number(w); 52814a9b182Skjell c = next_number(w); 52914a9b182Skjell d = next_number(w); 530dbfb98deSprovos return (htonl((a << 24) | (b << 16) | (c << 8) | d)); 53114a9b182Skjell } 53214a9b182Skjell 53381a15e5dSderaadt u_int8_t 53414a9b182Skjell next_flags(char **s) 53514a9b182Skjell { 53614a9b182Skjell u_int8_t f = 0; 53714a9b182Skjell char *p; 53881a15e5dSderaadt 53914a9b182Skjell while (**s && !strchr(tcpflags, **s)) 54014a9b182Skjell (*s)++; 54114a9b182Skjell while (**s && ((p = strchr(tcpflags, **s)) != NULL)) { 54214a9b182Skjell f |= 1 << (p-tcpflags); 54314a9b182Skjell (*s)++; 54414a9b182Skjell } 545dbfb98deSprovos return (f ? f : 63); 54614a9b182Skjell } 54714a9b182Skjell 54881a15e5dSderaadt u_int16_t 54914a9b182Skjell rule_port(char *w, u_int8_t p) 55014a9b182Skjell { 55114a9b182Skjell struct servent *s; 5526329fa59Sderaadt u_long ul; 5536329fa59Sderaadt char *ep; 55481a15e5dSderaadt 5556329fa59Sderaadt errno = 0; 5566329fa59Sderaadt ul = strtoul(w, &ep, 10); 5576329fa59Sderaadt if (*w == '\0' || *ep != '\0') { 5585df8e51cSsmart s = getservbyname(w, p == IPPROTO_TCP ? "tcp" : "udp"); 55914a9b182Skjell if (s == NULL) 560dbfb98deSprovos return (0); 561dbfb98deSprovos return (s->s_port); 56214a9b182Skjell } 5636329fa59Sderaadt if (errno == ERANGE && ul == ULONG_MAX) 5646329fa59Sderaadt return (0); 5656329fa59Sderaadt if (ul > USHRT_MAX) { 5666329fa59Sderaadt errno = ERANGE; 5676329fa59Sderaadt return (0); 5686329fa59Sderaadt } 5696329fa59Sderaadt return (htons(ul)); 5706329fa59Sderaadt } 57114a9b182Skjell 57281a15e5dSderaadt u_int32_t 57314a9b182Skjell rule_mask(u_int8_t b) 57414a9b182Skjell { 57514a9b182Skjell u_int32_t m = 0; 57614a9b182Skjell int i; 57781a15e5dSderaadt 57814a9b182Skjell for (i = 31; i > 31-b; --i) 57914a9b182Skjell m |= (1 << i); 580dbfb98deSprovos return (htonl(m)); 58114a9b182Skjell } 58214a9b182Skjell 58314a9b182Skjell int 58481a15e5dSderaadt parse_rule(int n, char *l, struct pf_rule *r) 58514a9b182Skjell { 58614a9b182Skjell char *w; 58781a15e5dSderaadt memset(r, 0, sizeof(struct pf_rule)); 58814a9b182Skjell w = next_word(&l); 58914a9b182Skjell 59014a9b182Skjell /* pass / block */ 59114a9b182Skjell if (!strcmp(w, "pass" )) 59214a9b182Skjell r->action = 0; 59314a9b182Skjell else if (!strcmp(w, "block")) 59414a9b182Skjell r->action = 1; 59514a9b182Skjell else { 5966329fa59Sderaadt error(n, "expected pass/block, got %s\n", w); 597dbfb98deSprovos return (0); 59814a9b182Skjell } 59914a9b182Skjell w = next_word(&l); 60014a9b182Skjell 60114a9b182Skjell /* return-rst */ 60214a9b182Skjell if ((r->action == 1) && !strcmp(w, "return-rst")) { 60314a9b182Skjell r->action = 2; 60414a9b182Skjell w = next_word(&l); 60514a9b182Skjell } 60614a9b182Skjell 60714a9b182Skjell /* in / out */ 60814a9b182Skjell if (!strcmp(w, "in" )) 60914a9b182Skjell r->direction = 0; 61014a9b182Skjell else if (!strcmp(w, "out")) 61114a9b182Skjell r->direction = 1; 61214a9b182Skjell else { 6136329fa59Sderaadt error(n, "expected in/out, got %s\n", w); 614dbfb98deSprovos return (0); 61514a9b182Skjell } 61614a9b182Skjell w = next_word(&l); 61714a9b182Skjell 61814a9b182Skjell /* log */ 61914a9b182Skjell if (!strcmp(w, "log")) { 62014a9b182Skjell r->log = 1; 62114a9b182Skjell w = next_word(&l); 62214a9b182Skjell } 62314a9b182Skjell 62414a9b182Skjell /* quick */ 62514a9b182Skjell if (!strcmp(w, "quick")) { 62614a9b182Skjell r->quick = 1; 62714a9b182Skjell w = next_word(&l); 62814a9b182Skjell } 62914a9b182Skjell 63014a9b182Skjell /* on <if> */ 63114a9b182Skjell if (!strcmp(w, "on")) { 63214a9b182Skjell w = next_word(&l); 63314a9b182Skjell strncpy(r->ifname, w, 16); 63414a9b182Skjell w = next_word(&l); 63514a9b182Skjell } 63614a9b182Skjell 63714a9b182Skjell /* proto tcp/udp/icmp */ 63814a9b182Skjell if (!strcmp(w, "proto")) { 63914a9b182Skjell struct protoent *p; 64014a9b182Skjell w = next_word(&l); 64114a9b182Skjell p = getprotobyname(w); 64214a9b182Skjell if (p == NULL) { 6436329fa59Sderaadt error(n, "unknown protocol %s\n", w); 644dbfb98deSprovos return (0); 64514a9b182Skjell } 64614a9b182Skjell r->proto = p->p_proto; 64714a9b182Skjell w = next_word(&l); 64814a9b182Skjell } 64914a9b182Skjell 65014a9b182Skjell /* all / from src to dst */ 65114a9b182Skjell if (!strcmp(w, "all" )) 65214a9b182Skjell w = next_word(&l); 65314a9b182Skjell else if (!strcmp(w, "from")) { 65414a9b182Skjell w = next_word(&l); 65514a9b182Skjell 65614a9b182Skjell /* source address */ 65714a9b182Skjell if (!strcmp(w, "any")) 65814a9b182Skjell w = next_word(&l); 65914a9b182Skjell else { 66014a9b182Skjell if (!strcmp(w, "!")) { 66114a9b182Skjell r->src.not = 1; 66214a9b182Skjell w = next_word(&l); 66314a9b182Skjell } 66414a9b182Skjell r->src.addr = next_addr(&w); 66514a9b182Skjell if (!*w) 66614a9b182Skjell r->src.mask = 0xFFFFFFFF; 66714a9b182Skjell else if (*w == '/') 66814a9b182Skjell r->src.mask = rule_mask(next_number(&w)); 66914a9b182Skjell else { 6706329fa59Sderaadt error(n, "expected /, got '%c'\n", *w); 671dbfb98deSprovos return (0); 67214a9b182Skjell } 67314a9b182Skjell w = next_word(&l); 67414a9b182Skjell } 67514a9b182Skjell 67614a9b182Skjell /* source port */ 6775df8e51cSsmart if (((r->proto == IPPROTO_TCP) || (r->proto == IPPROTO_UDP)) && 6785df8e51cSsmart !strcmp(w, "port")) { 67914a9b182Skjell w = next_word(&l); 68014a9b182Skjell if (!strcmp(w, "=" )) 68114a9b182Skjell r->src.port_op = 2; 68214a9b182Skjell else if (!strcmp(w, "!=")) 68314a9b182Skjell r->src.port_op = 3; 68414a9b182Skjell else if (!strcmp(w, "<" )) 68514a9b182Skjell r->src.port_op = 4; 68614a9b182Skjell else if (!strcmp(w, "<=")) 68714a9b182Skjell r->src.port_op = 5; 68814a9b182Skjell else if (!strcmp(w, ">" )) 68914a9b182Skjell r->src.port_op = 6; 69014a9b182Skjell else if (!strcmp(w, ">=")) 69114a9b182Skjell r->src.port_op = 7; 69214a9b182Skjell else 69314a9b182Skjell r->src.port_op = 1; 69414a9b182Skjell if (r->src.port_op != 1) 69514a9b182Skjell w = next_word(&l); 69614a9b182Skjell r->src.port[0] = rule_port(w, r->proto); 69714a9b182Skjell w = next_word(&l); 69814a9b182Skjell if (r->src.port_op == 1) { 69914a9b182Skjell if (strcmp(w, "<>") && strcmp(w, "><")) { 7006329fa59Sderaadt error(n, "expected <>/><, got %s\n", 7016329fa59Sderaadt w); 702dbfb98deSprovos return (0); 70314a9b182Skjell } 70414a9b182Skjell w = next_word(&l); 70514a9b182Skjell r->src.port[1] = rule_port(w, r->proto); 70614a9b182Skjell w = next_word(&l); 70714a9b182Skjell } 70814a9b182Skjell } 70914a9b182Skjell 71014a9b182Skjell /* destination address */ 71114a9b182Skjell if (strcmp(w, "to")) { 7126329fa59Sderaadt error(n, "expected to, got %s\n", w); 713dbfb98deSprovos return (0); 71414a9b182Skjell } 71514a9b182Skjell w = next_word(&l); 71614a9b182Skjell if (!strcmp(w, "any")) 71714a9b182Skjell w = next_word(&l); 71814a9b182Skjell else { 71914a9b182Skjell if (!strcmp(w, "!")) { 72014a9b182Skjell r->dst.not = 1; 72114a9b182Skjell w = next_word(&l); 72214a9b182Skjell } 72314a9b182Skjell r->dst.addr = next_addr(&w); 72414a9b182Skjell if (!*w) 72514a9b182Skjell r->dst.mask = 0xFFFFFFFF; 72614a9b182Skjell else if (*w == '/') 72714a9b182Skjell r->dst.mask = rule_mask(next_number(&w)); 72814a9b182Skjell else { 7296329fa59Sderaadt error(n, "expected /, got '%c'\n", *w); 730dbfb98deSprovos return (0); 73114a9b182Skjell } 73214a9b182Skjell w = next_word(&l); 73314a9b182Skjell } 73414a9b182Skjell 73514a9b182Skjell /* destination port */ 7365df8e51cSsmart if (((r->proto == IPPROTO_TCP) || (r->proto == IPPROTO_UDP)) && 7375df8e51cSsmart !strcmp(w, "port")) { 73814a9b182Skjell w = next_word(&l); 73914a9b182Skjell if (!strcmp(w, "=" )) 74014a9b182Skjell r->dst.port_op = 2; 74114a9b182Skjell else if (!strcmp(w, "!=")) 74214a9b182Skjell r->dst.port_op = 3; 74314a9b182Skjell else if (!strcmp(w, "<" )) 74414a9b182Skjell r->dst.port_op = 4; 74514a9b182Skjell else if (!strcmp(w, "<=")) 74614a9b182Skjell r->dst.port_op = 5; 74714a9b182Skjell else if (!strcmp(w, ">" )) 74814a9b182Skjell r->dst.port_op = 6; 74914a9b182Skjell else if (!strcmp(w, ">=")) 75014a9b182Skjell r->dst.port_op = 7; 75114a9b182Skjell else 75214a9b182Skjell r->dst.port_op = 1; 75314a9b182Skjell if (r->dst.port_op != 1) 75414a9b182Skjell w = next_word(&l); 75514a9b182Skjell r->dst.port[0] = rule_port(w, r->proto); 75614a9b182Skjell w = next_word(&l); 75714a9b182Skjell if (r->dst.port_op == 1) { 75814a9b182Skjell if (strcmp(w, "<>") && strcmp(w, "><")) { 7596329fa59Sderaadt error(n, "expected <>/><, got %s\n", 7606329fa59Sderaadt w); 761dbfb98deSprovos return (0); 76214a9b182Skjell } 76314a9b182Skjell w = next_word(&l); 76414a9b182Skjell r->dst.port[1] = rule_port(w, r->proto); 76514a9b182Skjell w = next_word(&l); 76614a9b182Skjell } 76714a9b182Skjell } 76814a9b182Skjell 7696329fa59Sderaadt } else { 7706329fa59Sderaadt error(n, "expected all/from, got %s\n", w); 771dbfb98deSprovos return (0); 77214a9b182Skjell } 77314a9b182Skjell 77414a9b182Skjell /* flags */ 77514a9b182Skjell if (!strcmp(w, "flags")) { 7765df8e51cSsmart if (r->proto != IPPROTO_TCP) { 7776329fa59Sderaadt error(n, "flags only valid for proto tcp\n"); 778dbfb98deSprovos return (0); 7796329fa59Sderaadt } else { 78014a9b182Skjell w = next_word(&l); 78114a9b182Skjell r->flags = next_flags(&w); 78214a9b182Skjell r->flagset = next_flags(&w); 78314a9b182Skjell w = next_word(&l); 78414a9b182Skjell } 78514a9b182Skjell } 78614a9b182Skjell 78714a9b182Skjell /* icmp type/code */ 78814a9b182Skjell if (!strcmp(w, "icmp-type")) { 7895df8e51cSsmart if (r->proto != IPPROTO_ICMP) { 7906329fa59Sderaadt error(n, "icmp-type only valid for proto icmp\n"); 7916329fa59Sderaadt return (0); 7926329fa59Sderaadt } else { 7936329fa59Sderaadt u_long ul; 7946329fa59Sderaadt char *ep; 7956329fa59Sderaadt 7966329fa59Sderaadt w = next_word(&l); 7976329fa59Sderaadt 7986329fa59Sderaadt errno = 0; 7996329fa59Sderaadt ul = strtoul(w, &ep, 10); 800*082ebc44Swilfried if (w[0] == '\0' || *ep != '\0') { 801*082ebc44Swilfried struct icmptypeent *p; 802*082ebc44Swilfried 803*082ebc44Swilfried p = geticmptypebyname(w); 804*082ebc44Swilfried if (p == NULL) { 805*082ebc44Swilfried error(n, "unknown icmp-type %s\n", w); 806*082ebc44Swilfried return (0); 807*082ebc44Swilfried } 808*082ebc44Swilfried ul = p->type; 809*082ebc44Swilfried } else if ((errno == ERANGE && ul == ULONG_MAX) || 8106329fa59Sderaadt ul > ICMP_MAXTYPE) { 8116329fa59Sderaadt error(n, "icmp-type type wrong\n"); 812dbfb98deSprovos return (0); 81314a9b182Skjell } 8146329fa59Sderaadt r->type = ul+1; 8156329fa59Sderaadt 81614a9b182Skjell w = next_word(&l); 81714a9b182Skjell if (!strcmp(w, "code")) { 81814a9b182Skjell w = next_word(&l); 8196329fa59Sderaadt 8206329fa59Sderaadt errno = 0; 8216329fa59Sderaadt ul = strtoul(w, &ep, 10); 822*082ebc44Swilfried if (w[0] == '\0' || *ep != '\0') { 823*082ebc44Swilfried struct icmpcodeent *p; 824*082ebc44Swilfried 825*082ebc44Swilfried p = geticmpcodebyname(r->type-1, w); 826*082ebc44Swilfried if (p == NULL) { 827*082ebc44Swilfried error(n, "unknown code %s\n", w); 828*082ebc44Swilfried return (0); 829*082ebc44Swilfried } 830*082ebc44Swilfried ul = p->code; 831*082ebc44Swilfried } else if ((errno == ERANGE && ul == ULONG_MAX) || 8326329fa59Sderaadt ul > 255) { 8336329fa59Sderaadt error(n, "icmp-type code wrong\n"); 8346329fa59Sderaadt return (0); 8356329fa59Sderaadt } 8366329fa59Sderaadt r->code = ul + 1; 837*082ebc44Swilfried 83814a9b182Skjell w = next_word(&l); 83914a9b182Skjell } 84014a9b182Skjell } 84114a9b182Skjell } 84214a9b182Skjell 84314a9b182Skjell /* keep */ 84414a9b182Skjell if (!strcmp(w, "keep")) { 84514a9b182Skjell w = next_word(&l); 84614a9b182Skjell if (!strcmp(w, "state")) { 84714a9b182Skjell w = next_word(&l); 84814a9b182Skjell r->keep_state = 1; 8496329fa59Sderaadt } else { 8506329fa59Sderaadt error(n, "expected state, got %s\n", w); 851dbfb98deSprovos return (0); 85214a9b182Skjell } 85314a9b182Skjell } 85414a9b182Skjell 85514a9b182Skjell /* no further options expected */ 85614a9b182Skjell while (*w) { 8576329fa59Sderaadt error(n, "unexpected %s\n", w); 85814a9b182Skjell w = next_word(&l); 85914a9b182Skjell } 86014a9b182Skjell 861dbfb98deSprovos return (1); 86214a9b182Skjell } 86314a9b182Skjell 86414a9b182Skjell int 86581a15e5dSderaadt parse_nat(int n, char *l, struct pf_nat *nat) 86614a9b182Skjell { 86714a9b182Skjell char *w; 86881a15e5dSderaadt 86981a15e5dSderaadt memset(nat, 0, sizeof(struct pf_nat)); 87014a9b182Skjell w = next_word(&l); 87114a9b182Skjell 87214a9b182Skjell /* nat */ 87314a9b182Skjell if (strcmp(w, "nat" )) { 8746329fa59Sderaadt error(n, "expected nat, got %s\n", w); 875dbfb98deSprovos return (0); 87614a9b182Skjell } 87714a9b182Skjell w = next_word(&l); 87814a9b182Skjell 87914a9b182Skjell /* if */ 88014a9b182Skjell strncpy(nat->ifname, w, 16); 88114a9b182Skjell w = next_word(&l); 88214a9b182Skjell 88314a9b182Skjell /* internal addr/mask */ 88414a9b182Skjell if (!strcmp(w, "!")) { 88514a9b182Skjell nat->not = 1; 88614a9b182Skjell w = next_word(&l); 88714a9b182Skjell } 88814a9b182Skjell nat->saddr = next_addr(&w); 88914a9b182Skjell if (!*w) 89014a9b182Skjell nat->smask = 0xFFFFFFFF; 89114a9b182Skjell else if (*w == '/') 89214a9b182Skjell nat->smask = rule_mask(next_number(&w)); 89314a9b182Skjell else { 8946329fa59Sderaadt error(n, "expected /, got '%c'\n", *w); 895dbfb98deSprovos return (0); 89614a9b182Skjell } 89714a9b182Skjell w = next_word(&l); 89814a9b182Skjell 89914a9b182Skjell /* -> */ 90014a9b182Skjell if (strcmp(w, "->")) { 9016329fa59Sderaadt error(n, "expected ->, got %s\n", w); 902dbfb98deSprovos return (0); 90314a9b182Skjell } 90414a9b182Skjell w = next_word(&l); 90514a9b182Skjell 90614a9b182Skjell /* external addr */ 90714a9b182Skjell nat->daddr = next_addr(&w); 90814a9b182Skjell w = next_word(&l); 90914a9b182Skjell 91014a9b182Skjell /* proto */ 91114a9b182Skjell if (!strcmp(w, "proto")) { 91214a9b182Skjell w = next_word(&l); 91314a9b182Skjell if (!strcmp(w, "tcp")) 91414a9b182Skjell nat->proto = IPPROTO_TCP; 91514a9b182Skjell else if (!strcmp(w, "udp")) 91614a9b182Skjell nat->proto = IPPROTO_UDP; 91714a9b182Skjell else if (!strcmp(w, "icmp")) 91814a9b182Skjell nat->proto = IPPROTO_ICMP; 91914a9b182Skjell else { 9206329fa59Sderaadt error(n, "expected tcp/udp/icmp, got %s\n", w); 921dbfb98deSprovos return (0); 92214a9b182Skjell } 92314a9b182Skjell w = next_word(&l); 92414a9b182Skjell } 92514a9b182Skjell 92614a9b182Skjell /* no further options expected */ 92714a9b182Skjell while (*w) { 9286329fa59Sderaadt error(n, "unexpected %s\n", w); 92914a9b182Skjell w = next_word(&l); 93014a9b182Skjell } 93114a9b182Skjell 932dbfb98deSprovos return (1); 93314a9b182Skjell } 93414a9b182Skjell 93514a9b182Skjell int 93681a15e5dSderaadt parse_rdr(int n, char *l, struct pf_rdr *rdr) 93714a9b182Skjell { 93814a9b182Skjell char *w; 93981a15e5dSderaadt 94081a15e5dSderaadt memset(rdr, 0, sizeof(struct pf_rdr)); 94114a9b182Skjell w = next_word(&l); 94214a9b182Skjell 94314a9b182Skjell /* rdr */ 94414a9b182Skjell if (strcmp(w, "rdr" )) { 9456329fa59Sderaadt error(n, "expected rdr, got %s\n", w); 946dbfb98deSprovos return (0); 94714a9b182Skjell } 94814a9b182Skjell w = next_word(&l); 94914a9b182Skjell 95014a9b182Skjell /* if */ 95114a9b182Skjell strncpy(rdr->ifname, w, 16); 95214a9b182Skjell w = next_word(&l); 95314a9b182Skjell 95414a9b182Skjell /* external addr/mask */ 95514a9b182Skjell if (!strcmp(w, "!")) { 95614a9b182Skjell rdr->not = 1; 95714a9b182Skjell w = next_word(&l); 95814a9b182Skjell } 95914a9b182Skjell rdr->daddr = next_addr(&w); 96014a9b182Skjell if (!*w) 96114a9b182Skjell rdr->dmask = 0xFFFFFFFF; 96214a9b182Skjell else if (*w == '/') 96314a9b182Skjell rdr->dmask = rule_mask(next_number(&w)); 96414a9b182Skjell else { 9656329fa59Sderaadt error(n, "expected /, got '%c'\n", *w); 966dbfb98deSprovos return (0); 96714a9b182Skjell } 96814a9b182Skjell w = next_word(&l); 96914a9b182Skjell 97014a9b182Skjell /* external port */ 97114a9b182Skjell if (strcmp(w, "port")) { 9726329fa59Sderaadt error(n, "expected port, got %s\n", w); 973dbfb98deSprovos return (0); 97414a9b182Skjell } 97514a9b182Skjell w = next_word(&l); 97614a9b182Skjell rdr->dport = htons(next_number(&w)); 97714a9b182Skjell w = next_word(&l); 97814a9b182Skjell 97914a9b182Skjell /* -> */ 98014a9b182Skjell if (strcmp(w, "->")) { 9816329fa59Sderaadt error(n, "expected ->, got %s\n", w); 982dbfb98deSprovos return (0); 98314a9b182Skjell } 98414a9b182Skjell w = next_word(&l); 98514a9b182Skjell 98614a9b182Skjell /* internal addr */ 98714a9b182Skjell rdr->raddr = next_addr(&w); 98814a9b182Skjell w = next_word(&l); 98914a9b182Skjell 99014a9b182Skjell /* internal port */ 99114a9b182Skjell if (strcmp(w, "port")) { 9926329fa59Sderaadt error(n, "expected port, got %s\n", w); 993dbfb98deSprovos return (0); 99414a9b182Skjell } 99514a9b182Skjell w = next_word(&l); 99614a9b182Skjell rdr->rport = htons(next_number(&w)); 99714a9b182Skjell w = next_word(&l); 99814a9b182Skjell 99914a9b182Skjell /* proto */ 100014a9b182Skjell if (!strcmp(w, "proto")) { 100114a9b182Skjell w = next_word(&l); 100214a9b182Skjell if (!strcmp(w, "tcp")) 100314a9b182Skjell rdr->proto = IPPROTO_TCP; 100414a9b182Skjell else if (!strcmp(w, "udp")) 100514a9b182Skjell rdr->proto = IPPROTO_UDP; 100614a9b182Skjell else { 10076329fa59Sderaadt error(n, "expected tcp/udp, got %s\n", w); 1008dbfb98deSprovos return (0); 100914a9b182Skjell } 101014a9b182Skjell w = next_word(&l); 101114a9b182Skjell } 101214a9b182Skjell 101314a9b182Skjell /* no further options expected */ 101414a9b182Skjell while (*w) { 10156329fa59Sderaadt error(n, "unexpected %s\n", w); 101614a9b182Skjell w = next_word(&l); 101714a9b182Skjell } 101814a9b182Skjell 1019dbfb98deSprovos return (1); 102014a9b182Skjell } 1021