1*d0aca2f2Shenning /* $OpenBSD: pfctl_parser.c,v 1.155 2003/05/14 00:56:38 henning Exp $ */ 214a9b182Skjell 314a9b182Skjell /* 4fd3c3a0cSderaadt * 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> 4030620b12Sfrantzen #include <netinet/icmp6.h> 41252d784aSderaadt #include <net/pfvar.h> 429f13c6caSmillert #include <arpa/inet.h> 43252d784aSderaadt 4414a9b182Skjell #include <stdio.h> 4514a9b182Skjell #include <stdlib.h> 4614a9b182Skjell #include <string.h> 4714a9b182Skjell #include <ctype.h> 4814a9b182Skjell #include <netdb.h> 496329fa59Sderaadt #include <stdarg.h> 506329fa59Sderaadt #include <errno.h> 51ff352a37Smarkus #include <err.h> 5294e9410bShenning #include <ifaddrs.h> 5314a9b182Skjell 5414a9b182Skjell #include "pfctl_parser.h" 55eb824e11Sderaadt #include "pfctl.h" 5614a9b182Skjell 575d9ac2dcSdhartmei void print_op (u_int8_t, const char *, const char *); 58132c30ccShenning void print_port (u_int8_t, u_int16_t, u_int16_t, const char *); 591173271aScedric void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned); 6081a15e5dSderaadt void print_flags (u_int8_t); 6115e76891Sdhartmei void print_fromto(struct pf_rule_addr *, struct pf_rule_addr *, 6244f5ed0aScedric u_int8_t, u_int8_t, int); 6314a9b182Skjell 64f2370d27Shenning struct node_host *host_if(const char *, int); 65383ebbbfShenning struct node_host *host_v4(const char *, int); 66f2370d27Shenning struct node_host *host_v6(const char *, int); 67f2370d27Shenning struct node_host *host_dns(const char *, int, int); 682a6c1abaShenning 69361e311cShenning const char *tcpflags = "FSRPAUEW"; 7014a9b182Skjell 717d27d81aSdhartmei static const struct icmptypeent icmp_type[] = { 72082ebc44Swilfried { "echoreq", ICMP_ECHO }, 73082ebc44Swilfried { "echorep", ICMP_ECHOREPLY }, 74082ebc44Swilfried { "unreach", ICMP_UNREACH }, 75082ebc44Swilfried { "squench", ICMP_SOURCEQUENCH }, 76082ebc44Swilfried { "redir", ICMP_REDIRECT }, 77082ebc44Swilfried { "althost", ICMP_ALTHOSTADDR }, 78082ebc44Swilfried { "routeradv", ICMP_ROUTERADVERT }, 79082ebc44Swilfried { "routersol", ICMP_ROUTERSOLICIT }, 80082ebc44Swilfried { "timex", ICMP_TIMXCEED }, 81082ebc44Swilfried { "paramprob", ICMP_PARAMPROB }, 82082ebc44Swilfried { "timereq", ICMP_TSTAMP }, 83082ebc44Swilfried { "timerep", ICMP_TSTAMPREPLY }, 84082ebc44Swilfried { "inforeq", ICMP_IREQ }, 85082ebc44Swilfried { "inforep", ICMP_IREQREPLY }, 86082ebc44Swilfried { "maskreq", ICMP_MASKREQ }, 8702cbcc9eSwilfried { "maskrep", ICMP_MASKREPLY }, 8802cbcc9eSwilfried { "trace", ICMP_TRACEROUTE }, 8902cbcc9eSwilfried { "dataconv", ICMP_DATACONVERR }, 9002cbcc9eSwilfried { "mobredir", ICMP_MOBILE_REDIRECT }, 9102cbcc9eSwilfried { "ipv6-where", ICMP_IPV6_WHEREAREYOU }, 9202cbcc9eSwilfried { "ipv6-here", ICMP_IPV6_IAMHERE }, 9302cbcc9eSwilfried { "mobregreq", ICMP_MOBILE_REGREQUEST }, 9402cbcc9eSwilfried { "mobregrep", ICMP_MOBILE_REGREPLY }, 9502cbcc9eSwilfried { "skip", ICMP_SKIP }, 9602cbcc9eSwilfried { "photuris", ICMP_PHOTURIS } 97082ebc44Swilfried }; 98082ebc44Swilfried 997d27d81aSdhartmei static const struct icmptypeent icmp6_type[] = { 10030620b12Sfrantzen { "unreach", ICMP6_DST_UNREACH }, 10130620b12Sfrantzen { "toobig", ICMP6_PACKET_TOO_BIG }, 10230620b12Sfrantzen { "timex", ICMP6_TIME_EXCEEDED }, 10330620b12Sfrantzen { "paramprob", ICMP6_PARAM_PROB }, 10430620b12Sfrantzen { "echoreq", ICMP6_ECHO_REQUEST }, 10530620b12Sfrantzen { "echorep", ICMP6_ECHO_REPLY }, 10630620b12Sfrantzen { "groupqry", ICMP6_MEMBERSHIP_QUERY }, 10730620b12Sfrantzen { "listqry", MLD6_LISTENER_QUERY }, 10830620b12Sfrantzen { "grouprep", ICMP6_MEMBERSHIP_REPORT }, 10930620b12Sfrantzen { "listenrep", MLD6_LISTENER_REPORT }, 11030620b12Sfrantzen { "groupterm", ICMP6_MEMBERSHIP_REDUCTION }, 11130620b12Sfrantzen { "listendone", MLD6_LISTENER_DONE }, 11230620b12Sfrantzen { "routersol", ND_ROUTER_SOLICIT }, 11330620b12Sfrantzen { "routeradv", ND_ROUTER_ADVERT }, 11430620b12Sfrantzen { "neighbrsol", ND_NEIGHBOR_SOLICIT }, 11530620b12Sfrantzen { "neighbradv", ND_NEIGHBOR_ADVERT }, 11630620b12Sfrantzen { "redir", ND_REDIRECT }, 11730620b12Sfrantzen { "routrrenum", ICMP6_ROUTER_RENUMBERING }, 11830620b12Sfrantzen { "wrureq", ICMP6_WRUREQUEST }, 11930620b12Sfrantzen { "wrurep", ICMP6_WRUREPLY }, 12030620b12Sfrantzen { "fqdnreq", ICMP6_FQDN_QUERY }, 12130620b12Sfrantzen { "fqdnrep", ICMP6_FQDN_REPLY }, 12230620b12Sfrantzen { "niqry", ICMP6_NI_QUERY }, 12330620b12Sfrantzen { "nirep", ICMP6_NI_REPLY }, 12430620b12Sfrantzen { "mtraceresp", MLD6_MTRACE_RESP }, 12530620b12Sfrantzen { "mtrace", MLD6_MTRACE } 12630620b12Sfrantzen }; 12730620b12Sfrantzen 1287d27d81aSdhartmei static const struct icmpcodeent icmp_code[] = { 129082ebc44Swilfried { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET }, 130082ebc44Swilfried { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST }, 131082ebc44Swilfried { "proto-unr", ICMP_UNREACH, ICMP_UNREACH_PROTOCOL }, 132082ebc44Swilfried { "port-unr", ICMP_UNREACH, ICMP_UNREACH_PORT }, 133082ebc44Swilfried { "needfrag", ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG }, 134082ebc44Swilfried { "srcfail", ICMP_UNREACH, ICMP_UNREACH_SRCFAIL }, 135082ebc44Swilfried { "net-unk", ICMP_UNREACH, ICMP_UNREACH_NET_UNKNOWN }, 136082ebc44Swilfried { "host-unk", ICMP_UNREACH, ICMP_UNREACH_HOST_UNKNOWN }, 137082ebc44Swilfried { "isolate", ICMP_UNREACH, ICMP_UNREACH_ISOLATED }, 138082ebc44Swilfried { "net-prohib", ICMP_UNREACH, ICMP_UNREACH_NET_PROHIB }, 139082ebc44Swilfried { "host-prohib", ICMP_UNREACH, ICMP_UNREACH_HOST_PROHIB }, 140082ebc44Swilfried { "net-tos", ICMP_UNREACH, ICMP_UNREACH_TOSNET }, 141082ebc44Swilfried { "host-tos", ICMP_UNREACH, ICMP_UNREACH_TOSHOST }, 142082ebc44Swilfried { "filter-prohib", ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB }, 143082ebc44Swilfried { "host-preced", ICMP_UNREACH, ICMP_UNREACH_HOST_PRECEDENCE }, 144082ebc44Swilfried { "cutoff-preced", ICMP_UNREACH, ICMP_UNREACH_PRECEDENCE_CUTOFF }, 145082ebc44Swilfried { "redir-net", ICMP_REDIRECT, ICMP_REDIRECT_NET }, 146082ebc44Swilfried { "redir-host", ICMP_REDIRECT, ICMP_REDIRECT_HOST }, 147082ebc44Swilfried { "redir-tos-net", ICMP_REDIRECT, ICMP_REDIRECT_TOSNET }, 148082ebc44Swilfried { "redir-tos-host", ICMP_REDIRECT, ICMP_REDIRECT_TOSHOST }, 14902cbcc9eSwilfried { "normal-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL }, 15002cbcc9eSwilfried { "common-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON }, 151082ebc44Swilfried { "transit", ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS }, 152082ebc44Swilfried { "reassemb", ICMP_TIMXCEED, ICMP_TIMXCEED_REASS }, 153082ebc44Swilfried { "badhead", ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR }, 154082ebc44Swilfried { "optmiss", ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT }, 15502cbcc9eSwilfried { "badlen", ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH }, 15602cbcc9eSwilfried { "unknown-ind", ICMP_PHOTURIS, ICMP_PHOTURIS_UNKNOWN_INDEX }, 15702cbcc9eSwilfried { "auth-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_AUTH_FAILED }, 15802cbcc9eSwilfried { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED } 159082ebc44Swilfried }; 160082ebc44Swilfried 1617d27d81aSdhartmei static const struct icmpcodeent icmp6_code[] = { 1621d32ee3bSdhartmei { "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN }, 1631d32ee3bSdhartmei { "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE }, 16430620b12Sfrantzen { "notnbr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR }, 16530620b12Sfrantzen { "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE }, 16630620b12Sfrantzen { "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR }, 16730620b12Sfrantzen { "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT }, 16830620b12Sfrantzen { "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT }, 16930620b12Sfrantzen { "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY }, 17030620b12Sfrantzen { "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER }, 17130620b12Sfrantzen { "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER }, 17230620b12Sfrantzen { "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK }, 17330620b12Sfrantzen { "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER } 17430620b12Sfrantzen }; 17530620b12Sfrantzen 176d593fb91Sdrahn const struct pf_timeout pf_timeouts[] = { 177d593fb91Sdrahn { "tcp.first", PFTM_TCP_FIRST_PACKET }, 178d593fb91Sdrahn { "tcp.opening", PFTM_TCP_OPENING }, 179d593fb91Sdrahn { "tcp.established", PFTM_TCP_ESTABLISHED }, 180d593fb91Sdrahn { "tcp.closing", PFTM_TCP_CLOSING }, 181d593fb91Sdrahn { "tcp.finwait", PFTM_TCP_FIN_WAIT }, 182d593fb91Sdrahn { "tcp.closed", PFTM_TCP_CLOSED }, 183d593fb91Sdrahn { "udp.first", PFTM_UDP_FIRST_PACKET }, 184d593fb91Sdrahn { "udp.single", PFTM_UDP_SINGLE }, 185d593fb91Sdrahn { "udp.multiple", PFTM_UDP_MULTIPLE }, 186d593fb91Sdrahn { "icmp.first", PFTM_ICMP_FIRST_PACKET }, 187d593fb91Sdrahn { "icmp.error", PFTM_ICMP_ERROR_REPLY }, 188d593fb91Sdrahn { "other.first", PFTM_OTHER_FIRST_PACKET }, 189d593fb91Sdrahn { "other.single", PFTM_OTHER_SINGLE }, 190d593fb91Sdrahn { "other.multiple", PFTM_OTHER_MULTIPLE }, 191d593fb91Sdrahn { "frag", PFTM_FRAG }, 192d593fb91Sdrahn { "interval", PFTM_INTERVAL }, 193a85e74a5Sdhartmei { "adaptive.start", PFTM_ADAPTIVE_START }, 194a85e74a5Sdhartmei { "adaptive.end", PFTM_ADAPTIVE_END }, 195d593fb91Sdrahn { NULL, 0 } 196d593fb91Sdrahn }; 197d593fb91Sdrahn 1987d27d81aSdhartmei const struct icmptypeent * 199bb9f691eSmcbride geticmptypebynumber(u_int8_t type, sa_family_t af) 200082ebc44Swilfried { 201ed99c291Sderaadt unsigned int i; 202082ebc44Swilfried 203d14c53d7Swilfried if (af != AF_INET6) { 204e4ebe044Shenning for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); 205e4ebe044Shenning i++) { 206082ebc44Swilfried if (type == icmp_type[i].type) 207082ebc44Swilfried return (&icmp_type[i]); 208082ebc44Swilfried } 20930620b12Sfrantzen } else { 21030620b12Sfrantzen for (i=0; i < (sizeof (icmp6_type) / 21130620b12Sfrantzen sizeof(icmp6_type[0])); i++) { 21230620b12Sfrantzen if (type == icmp6_type[i].type) 21330620b12Sfrantzen return (&icmp6_type[i]); 21430620b12Sfrantzen } 21530620b12Sfrantzen } 21630620b12Sfrantzen return (NULL); 217082ebc44Swilfried } 218082ebc44Swilfried 2197d27d81aSdhartmei const struct icmptypeent * 220bb9f691eSmcbride geticmptypebyname(char *w, sa_family_t af) 221082ebc44Swilfried { 222ed99c291Sderaadt unsigned int i; 223082ebc44Swilfried 224d14c53d7Swilfried if (af != AF_INET6) { 225e4ebe044Shenning for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); 226e4ebe044Shenning i++) { 227082ebc44Swilfried if (!strcmp(w, icmp_type[i].name)) 228082ebc44Swilfried return (&icmp_type[i]); 229082ebc44Swilfried } 23030620b12Sfrantzen } else { 23130620b12Sfrantzen for (i=0; i < (sizeof (icmp6_type) / 23230620b12Sfrantzen sizeof(icmp6_type[0])); i++) { 23330620b12Sfrantzen if (!strcmp(w, icmp6_type[i].name)) 23430620b12Sfrantzen return (&icmp6_type[i]); 23530620b12Sfrantzen } 23630620b12Sfrantzen } 23730620b12Sfrantzen return (NULL); 238082ebc44Swilfried } 239082ebc44Swilfried 2407d27d81aSdhartmei const struct icmpcodeent * 241bb9f691eSmcbride geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af) 242082ebc44Swilfried { 243ed99c291Sderaadt unsigned int i; 244082ebc44Swilfried 245d14c53d7Swilfried if (af != AF_INET6) { 246e4ebe044Shenning for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); 247e4ebe044Shenning i++) { 24830620b12Sfrantzen if (type == icmp_code[i].type && 24930620b12Sfrantzen code == icmp_code[i].code) 250082ebc44Swilfried return (&icmp_code[i]); 251082ebc44Swilfried } 25230620b12Sfrantzen } else { 25330620b12Sfrantzen for (i=0; i < (sizeof (icmp6_code) / 25430620b12Sfrantzen sizeof(icmp6_code[0])); i++) { 25530620b12Sfrantzen if (type == icmp6_code[i].type && 25630620b12Sfrantzen code == icmp6_code[i].code) 25730620b12Sfrantzen return (&icmp6_code[i]); 25830620b12Sfrantzen } 25930620b12Sfrantzen } 26030620b12Sfrantzen return (NULL); 261082ebc44Swilfried } 262082ebc44Swilfried 2637d27d81aSdhartmei const struct icmpcodeent * 264bb9f691eSmcbride geticmpcodebyname(u_long type, char *w, sa_family_t af) 265082ebc44Swilfried { 266ed99c291Sderaadt unsigned int i; 267082ebc44Swilfried 268d14c53d7Swilfried if (af != AF_INET6) { 269e4ebe044Shenning for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); 270e4ebe044Shenning i++) { 27130620b12Sfrantzen if (type == icmp_code[i].type && 27230620b12Sfrantzen !strcmp(w, icmp_code[i].name)) 273082ebc44Swilfried return (&icmp_code[i]); 274082ebc44Swilfried } 27530620b12Sfrantzen } else { 27630620b12Sfrantzen for (i=0; i < (sizeof (icmp6_code) / 27730620b12Sfrantzen sizeof(icmp6_code[0])); i++) { 27830620b12Sfrantzen if (type == icmp6_code[i].type && 27930620b12Sfrantzen !strcmp(w, icmp6_code[i].name)) 28030620b12Sfrantzen return (&icmp6_code[i]); 28130620b12Sfrantzen } 28230620b12Sfrantzen } 28330620b12Sfrantzen return (NULL); 28430620b12Sfrantzen } 28530620b12Sfrantzen 28681a15e5dSderaadt void 2875d9ac2dcSdhartmei print_op(u_int8_t op, const char *a1, const char *a2) 2885d9ac2dcSdhartmei { 2895d9ac2dcSdhartmei if (op == PF_OP_IRG) 2905d9ac2dcSdhartmei printf("%s >< %s ", a1, a2); 2915d9ac2dcSdhartmei else if (op == PF_OP_XRG) 2925d9ac2dcSdhartmei printf("%s <> %s ", a1, a2); 2931308506cShenning else if (op == PF_OP_EQ) 2945d9ac2dcSdhartmei printf("= %s ", a1); 2951308506cShenning else if (op == PF_OP_NE) 2965d9ac2dcSdhartmei printf("!= %s ", a1); 2971308506cShenning else if (op == PF_OP_LT) 2985d9ac2dcSdhartmei printf("< %s ", a1); 2995d9ac2dcSdhartmei else if (op == PF_OP_LE) 3005d9ac2dcSdhartmei printf("<= %s ", a1); 3015d9ac2dcSdhartmei else if (op == PF_OP_GT) 3025d9ac2dcSdhartmei printf("> %s ", a1); 3035d9ac2dcSdhartmei else if (op == PF_OP_GE) 3045d9ac2dcSdhartmei printf(">= %s ", a1); 3058da4e377Smcbride else if (op == PF_OP_RRG) 3068da4e377Smcbride printf("%s:%s ", a1, a2); 3075d9ac2dcSdhartmei } 3085d9ac2dcSdhartmei 3095d9ac2dcSdhartmei void 310132c30ccShenning print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto) 31114a9b182Skjell { 312e31d21c9Sdhartmei char a1[6], a2[6]; 313e4ebe044Shenning struct servent *s; 31481a15e5dSderaadt 315e4ebe044Shenning s = getservbyport(p1, proto); 31614a9b182Skjell p1 = ntohs(p1); 31714a9b182Skjell p2 = ntohs(p2); 3185d9ac2dcSdhartmei snprintf(a1, sizeof(a1), "%u", p1); 3195d9ac2dcSdhartmei snprintf(a2, sizeof(a2), "%u", p2); 32014a9b182Skjell printf("port "); 3215d9ac2dcSdhartmei if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE)) 3225d9ac2dcSdhartmei print_op(op, s->s_name, a2); 32314a9b182Skjell else 3245d9ac2dcSdhartmei print_op(op, a1, a2); 3255d9ac2dcSdhartmei } 3265d9ac2dcSdhartmei 3275d9ac2dcSdhartmei void 3281173271aScedric print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax) 3295d9ac2dcSdhartmei { 330d8fcd2dfSdhartmei char a1[11], a2[11]; 3315d9ac2dcSdhartmei 3325d9ac2dcSdhartmei snprintf(a1, sizeof(a1), "%u", u1); 3335d9ac2dcSdhartmei snprintf(a2, sizeof(a2), "%u", u2); 3345d9ac2dcSdhartmei printf("%s ", t); 3351173271aScedric if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE)) 336c16ab608Sdhartmei print_op(op, "unknown", a2); 337c16ab608Sdhartmei else 338c16ab608Sdhartmei print_op(op, a1, a2); 339c16ab608Sdhartmei } 340c16ab608Sdhartmei 341c16ab608Sdhartmei void 34214a9b182Skjell print_flags(u_int8_t f) 34314a9b182Skjell { 34414a9b182Skjell int i; 34581a15e5dSderaadt 346bc795af0Shugh for (i = 0; tcpflags[i]; ++i) 34714a9b182Skjell if (f & (1 << i)) 34814a9b182Skjell printf("%c", tcpflags[i]); 34914a9b182Skjell } 35014a9b182Skjell 35114a9b182Skjell void 35215e76891Sdhartmei print_fromto(struct pf_rule_addr *src, struct pf_rule_addr *dst, 35344f5ed0aScedric sa_family_t af, u_int8_t proto, int verbose) 35415e76891Sdhartmei { 3551173271aScedric if (src->addr.type == PF_ADDR_ADDRMASK && 3561173271aScedric dst->addr.type == PF_ADDR_ADDRMASK && 357bcf142a4Sdhartmei PF_AZERO(&src->addr.v.a.addr, AF_INET6) && 358bcf142a4Sdhartmei PF_AZERO(&src->addr.v.a.mask, AF_INET6) && 3591173271aScedric PF_AZERO(&dst->addr.v.a.addr, AF_INET6) && 3601173271aScedric PF_AZERO(&dst->addr.v.a.mask, AF_INET6) && 3611173271aScedric !src->not && !dst->not && 3621173271aScedric !src->port_op && !dst->port_op) 36315e76891Sdhartmei printf("all "); 36415e76891Sdhartmei else { 36515e76891Sdhartmei printf("from "); 36615e76891Sdhartmei if (src->not) 36715e76891Sdhartmei printf("! "); 36844f5ed0aScedric print_addr(&src->addr, af, verbose); 36915e76891Sdhartmei printf(" "); 37015e76891Sdhartmei if (src->port_op) 37115e76891Sdhartmei print_port(src->port_op, src->port[0], 37215e76891Sdhartmei src->port[1], 37315e76891Sdhartmei proto == IPPROTO_TCP ? "tcp" : "udp"); 37415e76891Sdhartmei 37515e76891Sdhartmei printf("to "); 37615e76891Sdhartmei if (dst->not) 37715e76891Sdhartmei printf("! "); 37844f5ed0aScedric print_addr(&dst->addr, af, verbose); 37915e76891Sdhartmei printf(" "); 38015e76891Sdhartmei if (dst->port_op) 38115e76891Sdhartmei print_port(dst->port_op, dst->port[0], 38215e76891Sdhartmei dst->port[1], 38315e76891Sdhartmei proto == IPPROTO_TCP ? "tcp" : "udp"); 38415e76891Sdhartmei } 38515e76891Sdhartmei } 38615e76891Sdhartmei 38715e76891Sdhartmei void 388e0c302d0Smcbride print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2, 389e0c302d0Smcbride sa_family_t af, int id) 3903a44df3cSmcbride { 3913a44df3cSmcbride struct pf_pooladdr *pooladdr; 3923a44df3cSmcbride 3936c917913Smcbride if ((TAILQ_FIRST(&pool->list) != NULL) && 3946c917913Smcbride TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) 3953a44df3cSmcbride printf("{ "); 3963a44df3cSmcbride TAILQ_FOREACH(pooladdr, &pool->list, entries){ 3973a44df3cSmcbride switch (id) { 398e8793aa9Smcbride case PF_NAT: 399e8793aa9Smcbride case PF_RDR: 400e8793aa9Smcbride case PF_BINAT: 40144f5ed0aScedric print_addr(&pooladdr->addr.addr, af, 0); 4023a44df3cSmcbride break; 403e8793aa9Smcbride case PF_PASS: 404bcf142a4Sdhartmei if (PF_AZERO(&pooladdr->addr.addr.v.a.addr, af)) 4053b9b234fSmcbride printf("%s", pooladdr->ifname); 406790504a6Sdhartmei else { 4073a44df3cSmcbride printf("(%s ", pooladdr->ifname); 40844f5ed0aScedric print_addr(&pooladdr->addr.addr, af, 0); 4093a44df3cSmcbride printf(")"); 4103b9b234fSmcbride } 4113a44df3cSmcbride break; 412e8793aa9Smcbride default: 413e8793aa9Smcbride break; 4143a44df3cSmcbride } 4153a44df3cSmcbride if (TAILQ_NEXT(pooladdr, entries) != NULL) 4163a44df3cSmcbride printf(", "); 4173a44df3cSmcbride else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) 4183a44df3cSmcbride printf(" }"); 4193a44df3cSmcbride } 420e0c302d0Smcbride switch (id) { 421e8793aa9Smcbride case PF_NAT: 422e0c302d0Smcbride if (p1 != PF_NAT_PROXY_PORT_LOW || 423e0c302d0Smcbride p2 != PF_NAT_PROXY_PORT_HIGH) { 424e0c302d0Smcbride if (p1 == p2) 425e0c302d0Smcbride printf(" port %u", p1); 426e0c302d0Smcbride else 427e0c302d0Smcbride printf(" port %u:%u", p1, p2); 428e0c302d0Smcbride } 429e0c302d0Smcbride break; 430e8793aa9Smcbride case PF_RDR: 431e0c302d0Smcbride if (p1) { 4328da4e377Smcbride printf(" port %u", p1); 4338da4e377Smcbride if (p2 && (p2 != p1)) 4348da4e377Smcbride printf(":%u", p2); 435e0c302d0Smcbride } 436e0c302d0Smcbride break; 437e0c302d0Smcbride default: 438e0c302d0Smcbride break; 439e0c302d0Smcbride } 440e0c302d0Smcbride switch (pool->opts & PF_POOL_TYPEMASK) { 441e0c302d0Smcbride case PF_POOL_NONE: 442e0c302d0Smcbride break; 443e0c302d0Smcbride case PF_POOL_BITMASK: 444e0c302d0Smcbride printf(" bitmask"); 445e0c302d0Smcbride break; 446e0c302d0Smcbride case PF_POOL_RANDOM: 447e0c302d0Smcbride printf(" random"); 448e0c302d0Smcbride break; 449e0c302d0Smcbride case PF_POOL_SRCHASH: 4500436fa02Smcbride printf(" source-hash 0x%08x%08x%08x%08x", 451e0c302d0Smcbride pool->key.key32[0], pool->key.key32[1], 452e0c302d0Smcbride pool->key.key32[2], pool->key.key32[3]); 453e0c302d0Smcbride break; 454e0c302d0Smcbride case PF_POOL_ROUNDROBIN: 455e0c302d0Smcbride printf(" round-robin"); 456e0c302d0Smcbride break; 457e0c302d0Smcbride } 458e0c302d0Smcbride if (pool->opts & PF_POOL_STATICPORT) 459e0c302d0Smcbride printf(" static-port"); 4603a44df3cSmcbride } 4613a44df3cSmcbride 462132c30ccShenning const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES; 463132c30ccShenning const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; 46499a73934Sderaadt 46514a9b182Skjell void 46681a15e5dSderaadt print_status(struct pf_status *s) 46714a9b182Skjell { 468e4ebe044Shenning char statline[80]; 469c474e331Shenning time_t runtime; 47099a73934Sderaadt int i; 47199a73934Sderaadt 472c474e331Shenning runtime = time(NULL) - s->since; 473c474e331Shenning 474d85e4ad6Sdhartmei if (s->running) { 475d85e4ad6Sdhartmei unsigned sec, min, hrs, day = runtime; 476d85e4ad6Sdhartmei 477d85e4ad6Sdhartmei sec = day % 60; 478d85e4ad6Sdhartmei day /= 60; 479d85e4ad6Sdhartmei min = day % 60; 480d85e4ad6Sdhartmei day /= 60; 481d85e4ad6Sdhartmei hrs = day % 24; 482d85e4ad6Sdhartmei day /= 24; 483c474e331Shenning snprintf(statline, sizeof(statline), 484d85e4ad6Sdhartmei "Status: Enabled for %u days %.2u:%.2u:%.2u", 485d85e4ad6Sdhartmei day, hrs, min, sec); 486d85e4ad6Sdhartmei } else 487c474e331Shenning snprintf(statline, sizeof(statline), "Status: Disabled"); 488c97b4ee1Shenning printf("%-44s", statline); 489ae58c8acSdhartmei switch (s->debug) { 490ae58c8acSdhartmei case 0: 491c97b4ee1Shenning printf("%15s\n\n", "Debug: None"); 492ae58c8acSdhartmei break; 493ae58c8acSdhartmei case 1: 494c97b4ee1Shenning printf("%15s\n\n", "Debug: Urgent"); 495ae58c8acSdhartmei break; 496ae58c8acSdhartmei case 2: 497c97b4ee1Shenning printf("%15s\n\n", "Debug: Misc"); 498ae58c8acSdhartmei break; 499ae58c8acSdhartmei } 500c474e331Shenning if (s->ifname[0] != 0) { 501c474e331Shenning printf("Interface Stats for %-16s %5s %16s\n", 502c474e331Shenning s->ifname, "IPv4", "IPv6"); 503c474e331Shenning printf(" %-25s %14llu %16llu\n", "Bytes In", 5047189e280Sdhartmei s->bcounters[0][0], s->bcounters[1][0]); 505c474e331Shenning printf(" %-25s %14llu %16llu\n", "Bytes Out", 5067189e280Sdhartmei s->bcounters[0][1], s->bcounters[1][1]); 507c474e331Shenning printf(" Packets In\n"); 508c474e331Shenning printf(" %-23s %14llu %16llu\n", "Passed", 5097189e280Sdhartmei s->pcounters[0][0][PF_PASS], 5107189e280Sdhartmei s->pcounters[1][0][PF_PASS]); 511c474e331Shenning printf(" %-23s %14llu %16llu\n", "Blocked", 5127189e280Sdhartmei s->pcounters[0][0][PF_DROP], 5137189e280Sdhartmei s->pcounters[1][0][PF_DROP]); 514c474e331Shenning printf(" Packets Out\n"); 515c474e331Shenning printf(" %-23s %14llu %16llu\n", "Passed", 5167189e280Sdhartmei s->pcounters[0][1][PF_PASS], 5177189e280Sdhartmei s->pcounters[1][1][PF_PASS]); 518c474e331Shenning printf(" %-23s %14llu %16llu\n\n", "Blocked", 5197189e280Sdhartmei s->pcounters[0][1][PF_DROP], 5207189e280Sdhartmei s->pcounters[1][1][PF_DROP]); 521c474e331Shenning } 522c474e331Shenning printf("%-27s %14s %16s\n", "State Table", "Total", "Rate"); 523c474e331Shenning printf(" %-25s %14u %14s\n", "current entries", s->states, ""); 524c474e331Shenning for (i = 0; i < FCNT_MAX; i++) { 525c474e331Shenning printf(" %-25s %14lld ", pf_fcounters[i], 52684976600Sderaadt s->fcounters[i]); 527c474e331Shenning if (runtime > 0) 528c474e331Shenning printf("%14.1f/s\n", 529c474e331Shenning (double)s->fcounters[i] / (double)runtime); 530c474e331Shenning else 531c474e331Shenning printf("%14s\n", ""); 532c474e331Shenning } 53399a73934Sderaadt printf("Counters\n"); 534c474e331Shenning for (i = 0; i < PFRES_MAX; i++) { 535c474e331Shenning printf(" %-25s %14lld ", pf_reasons[i], 53699a73934Sderaadt s->counters[i]); 537c474e331Shenning if (runtime > 0) 538c474e331Shenning printf("%14.1f/s\n", 539c474e331Shenning (double)s->counters[i] / (double)runtime); 540c474e331Shenning else 541c474e331Shenning printf("%14s\n", ""); 542c474e331Shenning } 54314a9b182Skjell } 54414a9b182Skjell 54514a9b182Skjell void 5461173271aScedric print_rule(struct pf_rule *r, int verbose) 54714a9b182Skjell { 5481173271aScedric static const char *actiontypes[] = { "pass", "block", "scrub", "nat", 5491173271aScedric "no nat", "binat", "no binat", "rdr", "no rdr" }; 5501173271aScedric static const char *anchortypes[] = { "anchor", "anchor", "anchor", 5511173271aScedric "nat-anchor", "nat-anchor", "binat-anchor", "binat-anchor", 5521173271aScedric "rdr-anchor", "rdr-anchor" }; 553cc5f0329Sdhartmei int i, opts; 554cc5f0329Sdhartmei 55574dc4fddShenning if (verbose) 55678baf774Sdhartmei printf("@%d ", r->nr); 5571173271aScedric if (r->action > PF_NORDR) 5581173271aScedric printf("action(%d) ", r->action); 5591173271aScedric else if (r->anchorname[0]) 5601173271aScedric printf("%s %s ", anchortypes[r->action], r->anchorname); 5611173271aScedric else 5621173271aScedric printf("%s ", actiontypes[r->action]); 5631173271aScedric if (r->action == PF_DROP) { 5648a87542aShenning if (r->rule_flag & PFRULE_RETURN) 5658a87542aShenning printf("return "); 5668a87542aShenning else if (r->rule_flag & PFRULE_RETURNRST) { 5671f77cc8aSpb if (!r->return_ttl) 56814a9b182Skjell printf("return-rst "); 5691f77cc8aSpb else 5701f77cc8aSpb printf("return-rst(ttl %d) ", r->return_ttl); 571328b2decShenning } else if (r->rule_flag & PFRULE_RETURNICMP) { 572328b2decShenning const struct icmpcodeent *ic, *ic6; 573b996d042Sdhartmei 574b996d042Sdhartmei ic = geticmpcodebynumber(r->return_icmp >> 8, 575328b2decShenning r->return_icmp & 255, AF_INET); 576328b2decShenning ic6 = geticmpcodebynumber(r->return_icmp6 >> 8, 577328b2decShenning r->return_icmp6 & 255, AF_INET6); 578d14c53d7Swilfried 579328b2decShenning switch(r->af) { 580328b2decShenning case AF_INET: 581328b2decShenning printf("return-icmp"); 582d14c53d7Swilfried if (ic == NULL) 583d14c53d7Swilfried printf("(%u) ", r->return_icmp & 255); 584b996d042Sdhartmei else 585328b2decShenning printf("(%s) ", ic->name); 586328b2decShenning break; 587328b2decShenning case AF_INET6: 588328b2decShenning printf("return-icmp6"); 589328b2decShenning if (ic6 == NULL) 590328b2decShenning printf("(%u) ", r->return_icmp6 & 255); 591328b2decShenning else 592328b2decShenning printf("(%s) ", ic6->name); 593328b2decShenning break; 594328b2decShenning default: 595328b2decShenning printf("return-icmp"); 596328b2decShenning if (ic == NULL) 597328b2decShenning printf("(%u, ", r->return_icmp & 255); 598328b2decShenning else 599328b2decShenning printf("(%s, ", ic->name); 600328b2decShenning if (ic6 == NULL) 601328b2decShenning printf("%u) ", r->return_icmp6 & 255); 602328b2decShenning else 603328b2decShenning printf("%s) ", ic6->name); 604328b2decShenning break; 605328b2decShenning } 606acf2444cShenning } else 607acf2444cShenning printf("drop "); 6081173271aScedric } 6097189e280Sdhartmei if (r->direction == PF_IN) 61014a9b182Skjell printf("in "); 6117189e280Sdhartmei else if (r->direction == PF_OUT) 61214a9b182Skjell printf("out "); 6137242ce7aSdhartmei if (r->log == 1) 61414a9b182Skjell printf("log "); 6157242ce7aSdhartmei else if (r->log == 2) 6167242ce7aSdhartmei printf("log-all "); 61714a9b182Skjell if (r->quick) 61814a9b182Skjell printf("quick "); 6197d0c9138Shenning if (r->ifname[0]) { 6207d0c9138Shenning if (r->ifnot) 6217d0c9138Shenning printf("on ! %s ", r->ifname); 6227d0c9138Shenning else 62314a9b182Skjell printf("on %s ", r->ifname); 6247d0c9138Shenning } 625cb3a4e31Sjasoni if (r->rt) { 626cb3a4e31Sjasoni if (r->rt == PF_ROUTETO) 627cb3a4e31Sjasoni printf("route-to "); 628fa1cdd09Sdhartmei else if (r->rt == PF_REPLYTO) 629fa1cdd09Sdhartmei printf("reply-to "); 630cb3a4e31Sjasoni else if (r->rt == PF_DUPTO) 631cb3a4e31Sjasoni printf("dup-to "); 632cb3a4e31Sjasoni else if (r->rt == PF_FASTROUTE) 633cb3a4e31Sjasoni printf("fastroute "); 634790504a6Sdhartmei if (r->rt != PF_FASTROUTE) { 635e8793aa9Smcbride print_pool(&r->rpool, 0, 0, r->af, PF_PASS); 636790504a6Sdhartmei printf(" "); 637790504a6Sdhartmei } 638cb3a4e31Sjasoni } 63930620b12Sfrantzen if (r->af) { 64030620b12Sfrantzen if (r->af == AF_INET) 64130620b12Sfrantzen printf("inet "); 64230620b12Sfrantzen else 64330620b12Sfrantzen printf("inet6 "); 64430620b12Sfrantzen } 64514a9b182Skjell if (r->proto) { 646e4ebe044Shenning struct protoent *p; 647ed99c291Sderaadt 648e4ebe044Shenning if ((p = getprotobynumber(r->proto)) != NULL) 64914a9b182Skjell printf("proto %s ", p->p_name); 65014a9b182Skjell else 65114a9b182Skjell printf("proto %u ", r->proto); 65214a9b182Skjell } 65344f5ed0aScedric print_fromto(&r->src, &r->dst, r->af, r->proto, verbose); 654c16ab608Sdhartmei if (r->uid.op) 6551173271aScedric print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user", 6561173271aScedric UID_MAX); 657c16ab608Sdhartmei if (r->gid.op) 6581173271aScedric print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group", 6591173271aScedric GID_MAX); 66014a9b182Skjell if (r->flags || r->flagset) { 66114a9b182Skjell printf("flags "); 66214a9b182Skjell print_flags(r->flags); 66314a9b182Skjell printf("/"); 66414a9b182Skjell print_flags(r->flagset); 66514a9b182Skjell printf(" "); 66614a9b182Skjell } 667082ebc44Swilfried if (r->type) { 668b49ca6bbShenning const struct icmptypeent *it; 669082ebc44Swilfried 670b49ca6bbShenning it = geticmptypebynumber(r->type-1, r->af); 671d14c53d7Swilfried if (r->af != AF_INET6) 672d14c53d7Swilfried printf("icmp-type"); 673082ebc44Swilfried else 674d0cb3502Smcbride printf("icmp6-type"); 675b49ca6bbShenning if (it != NULL) 676b49ca6bbShenning printf(" %s ", it->name); 677d14c53d7Swilfried else 678d14c53d7Swilfried printf(" %u ", r->type-1); 679082ebc44Swilfried if (r->code) { 680b49ca6bbShenning const struct icmpcodeent *ic; 681082ebc44Swilfried 682b49ca6bbShenning ic = geticmpcodebynumber(r->type-1, r->code-1, r->af); 683b49ca6bbShenning if (ic != NULL) 684b49ca6bbShenning printf("code %s ", ic->name); 685082ebc44Swilfried else 68614a9b182Skjell printf("code %u ", r->code-1); 687082ebc44Swilfried } 688082ebc44Swilfried } 689e4cbe364Sdhartmei if (r->tos) 690e4cbe364Sdhartmei printf("tos 0x%2.2x ", r->tos); 691b96c47abSfrantzen if (r->keep_state == PF_STATE_NORMAL) 69214a9b182Skjell printf("keep state "); 693b96c47abSfrantzen else if (r->keep_state == PF_STATE_MODULATE) 694b96c47abSfrantzen printf("modulate state "); 695cc5f0329Sdhartmei opts = 0; 696b3c86969Sdhartmei if (r->max_states) 697cc5f0329Sdhartmei opts = 1; 698cc5f0329Sdhartmei for (i = 0; !opts && i < PFTM_MAX; ++i) 699cc5f0329Sdhartmei if (r->timeout[i]) 700cc5f0329Sdhartmei opts = 1; 701cc5f0329Sdhartmei if (opts) { 702cc5f0329Sdhartmei printf("("); 703cc5f0329Sdhartmei if (r->max_states) { 704cc5f0329Sdhartmei printf("max %u", r->max_states); 705cc5f0329Sdhartmei opts = 0; 706cc5f0329Sdhartmei } 707cc5f0329Sdhartmei for (i = 0; i < PFTM_MAX; ++i) 708cc5f0329Sdhartmei if (r->timeout[i]) { 709cc5f0329Sdhartmei if (!opts) 710cc5f0329Sdhartmei printf(", "); 711cc5f0329Sdhartmei opts = 0; 712cc5f0329Sdhartmei printf("%s %u", pf_timeouts[i].name, 713cc5f0329Sdhartmei r->timeout[i]); 714cc5f0329Sdhartmei } 715cc5f0329Sdhartmei printf(") "); 716cc5f0329Sdhartmei } 7176673dee2Sdhartmei if (r->rule_flag & PFRULE_FRAGMENT) 7186673dee2Sdhartmei printf("fragment "); 71967d2a440Sprovos if (r->rule_flag & PFRULE_NODF) 72067d2a440Sprovos printf("no-df "); 721edbe3066Sdhartmei if (r->rule_flag & PFRULE_RANDOMID) 722edbe3066Sdhartmei printf("random-id "); 723e258bfd4Sprovos if (r->min_ttl) 72434c76dcbSprovos printf("min-ttl %d ", r->min_ttl); 725cfa91859Sjasoni if (r->max_mss) 726cfa91859Sjasoni printf("max-mss %d ", r->max_mss); 727f48d62b3Sdhartmei if (r->allow_opts) 728f48d62b3Sdhartmei printf("allow-opts "); 729b02af636Sfrantzen if (r->action == PF_SCRUB) { 730b02af636Sfrantzen if (r->rule_flag & PFRULE_FRAGDROP) 731b02af636Sfrantzen printf("fragment drop-ovl "); 732b02af636Sfrantzen else if (r->rule_flag & PFRULE_FRAGCROP) 733b02af636Sfrantzen printf("fragment crop "); 734b02af636Sfrantzen else 735b02af636Sfrantzen printf("fragment reassemble "); 736b02af636Sfrantzen } 737455ef0c1Sdhartmei if (r->label[0]) 738ff45dfa8Scamield printf("label \"%s\" ", r->label); 739f98324c6Shenning if (r->qname[0] && r->pqname[0]) 740f98324c6Shenning printf("queue(%s, %s) ", r->qname, r->pqname); 741f98324c6Shenning else if (r->qname[0]) 74278e1d2a6Shenning printf("queue %s ", r->qname); 7438aecb81aShenning if (r->tagname[0]) 7448aecb81aShenning printf("tag %s ", r->tagname); 7458aecb81aShenning if (r->match_tagname[0]) 7460a5f7f2fShenning printf("tagged %s ", r->match_tagname); 747*d0aca2f2Shenning if (!r->anchorname[0] && (r->action == PF_NAT || 748*d0aca2f2Shenning r->action == PF_BINAT || r->action == PF_RDR)) { 749*d0aca2f2Shenning printf("-> "); 750*d0aca2f2Shenning print_pool(&r->rpool, r->rpool.proxy_port[0], 751*d0aca2f2Shenning r->rpool.proxy_port[1], r->af, r->action); 752*d0aca2f2Shenning } 75314a9b182Skjell printf("\n"); 75414a9b182Skjell } 75514a9b182Skjell 7561f8f21bdSmillert int 757ff352a37Smarkus parse_flags(char *s) 75814a9b182Skjell { 759ff352a37Smarkus char *p, *q; 76014a9b182Skjell u_int8_t f = 0; 76181a15e5dSderaadt 762ff352a37Smarkus for (p = s; *p; p++) { 763ff352a37Smarkus if ((q = strchr(tcpflags, *p)) == NULL) 764ff352a37Smarkus return -1; 765ff352a37Smarkus else 766ff352a37Smarkus f |= 1 << (q - tcpflags); 76714a9b182Skjell } 768bc795af0Shugh return (f ? f : PF_TH_ALL); 76914a9b182Skjell } 77094e9410bShenning 77194e9410bShenning void 77294e9410bShenning set_ipmask(struct node_host *h, u_int8_t b) 77394e9410bShenning { 77494e9410bShenning struct pf_addr *m, *n; 77594e9410bShenning int i, j = 0; 77694e9410bShenning 77794e9410bShenning m = &h->addr.v.a.mask; 77894e9410bShenning 77994e9410bShenning for (i = 0; i < 4; i++) 78094e9410bShenning m->addr32[i] = 0; 78194e9410bShenning 78294e9410bShenning while (b >= 32) { 78394e9410bShenning m->addr32[j++] = 0xffffffff; 78494e9410bShenning b -= 32; 78594e9410bShenning } 78694e9410bShenning for (i = 31; i > 31-b; --i) 78794e9410bShenning m->addr32[j] |= (1 << i); 78894e9410bShenning if (b) 78994e9410bShenning m->addr32[j] = htonl(m->addr32[j]); 79094e9410bShenning 79194e9410bShenning /* Mask off bits of the address that will never be used. */ 79294e9410bShenning n = &h->addr.v.a.addr; 79394e9410bShenning for (i = 0; i < 4; i++) 79494e9410bShenning n->addr32[i] = n->addr32[i] & m->addr32[i]; 79594e9410bShenning } 79694e9410bShenning 79794e9410bShenning /* interface lookup routines */ 79894e9410bShenning 79994e9410bShenning struct node_host *iftab; 80094e9410bShenning 80194e9410bShenning void 80294e9410bShenning ifa_load(void) 80394e9410bShenning { 80494e9410bShenning struct ifaddrs *ifap, *ifa; 80594e9410bShenning struct node_host *n = NULL, *h = NULL; 80694e9410bShenning 80794e9410bShenning if (getifaddrs(&ifap) < 0) 80894e9410bShenning err(1, "getifaddrs"); 80994e9410bShenning 81094e9410bShenning for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 81194e9410bShenning if (!(ifa->ifa_addr->sa_family == AF_INET || 81294e9410bShenning ifa->ifa_addr->sa_family == AF_INET6 || 81394e9410bShenning ifa->ifa_addr->sa_family == AF_LINK)) 81494e9410bShenning continue; 81594e9410bShenning n = calloc(1, sizeof(struct node_host)); 81694e9410bShenning if (n == NULL) 81794e9410bShenning err(1, "address: calloc"); 81894e9410bShenning n->af = ifa->ifa_addr->sa_family; 81994e9410bShenning n->ifa_flags = ifa->ifa_flags; 82094e9410bShenning #ifdef __KAME__ 82194e9410bShenning if (n->af == AF_INET6 && 82294e9410bShenning IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) 82394e9410bShenning ifa->ifa_addr)->sin6_addr) && 82494e9410bShenning ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == 0) { 82594e9410bShenning struct sockaddr_in6 *sin6; 82694e9410bShenning 82794e9410bShenning sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 82894e9410bShenning sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 | 82994e9410bShenning sin6->sin6_addr.s6_addr[3]; 83094e9410bShenning sin6->sin6_addr.s6_addr[2] = 0; 83194e9410bShenning sin6->sin6_addr.s6_addr[3] = 0; 83294e9410bShenning } 83394e9410bShenning #endif 83494e9410bShenning n->ifindex = 0; 83594e9410bShenning if (n->af == AF_INET) { 83694e9410bShenning memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *) 83794e9410bShenning ifa->ifa_addr)->sin_addr.s_addr, 83894e9410bShenning sizeof(struct in_addr)); 83994e9410bShenning memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *) 84094e9410bShenning ifa->ifa_netmask)->sin_addr.s_addr, 84194e9410bShenning sizeof(struct in_addr)); 84294e9410bShenning if (ifa->ifa_broadaddr != NULL) 84394e9410bShenning memcpy(&n->bcast, &((struct sockaddr_in *) 84494e9410bShenning ifa->ifa_broadaddr)->sin_addr.s_addr, 84594e9410bShenning sizeof(struct in_addr)); 84694e9410bShenning } else if (n->af == AF_INET6) { 84794e9410bShenning memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *) 84894e9410bShenning ifa->ifa_addr)->sin6_addr.s6_addr, 84994e9410bShenning sizeof(struct in6_addr)); 85094e9410bShenning memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *) 85194e9410bShenning ifa->ifa_netmask)->sin6_addr.s6_addr, 85294e9410bShenning sizeof(struct in6_addr)); 85394e9410bShenning if (ifa->ifa_broadaddr != NULL) 85494e9410bShenning memcpy(&n->bcast, &((struct sockaddr_in6 *) 85594e9410bShenning ifa->ifa_broadaddr)->sin6_addr.s6_addr, 85694e9410bShenning sizeof(struct in6_addr)); 85794e9410bShenning n->ifindex = ((struct sockaddr_in6 *) 85894e9410bShenning ifa->ifa_addr)->sin6_scope_id; 85994e9410bShenning } 86094e9410bShenning if ((n->ifname = strdup(ifa->ifa_name)) == NULL) 86194e9410bShenning err(1, "ifa_load: strdup"); 86294e9410bShenning n->next = NULL; 86394e9410bShenning n->tail = n; 86494e9410bShenning if (h == NULL) 86594e9410bShenning h = n; 86694e9410bShenning else { 86794e9410bShenning h->tail->next = n; 86894e9410bShenning h->tail = n; 86994e9410bShenning } 87094e9410bShenning } 87194e9410bShenning iftab = h; 87294e9410bShenning freeifaddrs(ifap); 87394e9410bShenning } 87494e9410bShenning 87594e9410bShenning struct node_host * 8766cba701cShenning ifa_exists(const char *ifa_name) 87794e9410bShenning { 87894e9410bShenning struct node_host *n; 87994e9410bShenning 88094e9410bShenning if (iftab == NULL) 88194e9410bShenning ifa_load(); 88294e9410bShenning 88394e9410bShenning for (n = iftab; n; n = n->next) { 88494e9410bShenning if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) 88594e9410bShenning return (n); 88694e9410bShenning } 88794e9410bShenning return (NULL); 88894e9410bShenning } 88994e9410bShenning 89094e9410bShenning struct node_host * 8916cba701cShenning ifa_lookup(const char *ifa_name, enum pfctl_iflookup_mode mode) 89294e9410bShenning { 89394e9410bShenning struct node_host *p = NULL, *h = NULL, *n = NULL; 89494e9410bShenning int return_all = 0; 89594e9410bShenning 89694e9410bShenning if (!strncmp(ifa_name, "self", IFNAMSIZ)) 89794e9410bShenning return_all = 1; 89894e9410bShenning 89994e9410bShenning if (iftab == NULL) 90094e9410bShenning ifa_load(); 90194e9410bShenning 90294e9410bShenning for (p = iftab; p; p = p->next) { 90394e9410bShenning if (!((p->af == AF_INET || p->af == AF_INET6) && 90494e9410bShenning (!strncmp(p->ifname, ifa_name, IFNAMSIZ) || return_all))) 90594e9410bShenning continue; 90694e9410bShenning if (mode == PFCTL_IFLOOKUP_BCAST && p->af != AF_INET) 90794e9410bShenning continue; 90894e9410bShenning if (mode == PFCTL_IFLOOKUP_NET && p->ifindex > 0) 90994e9410bShenning continue; 91094e9410bShenning n = calloc(1, sizeof(struct node_host)); 91194e9410bShenning if (n == NULL) 91294e9410bShenning err(1, "address: calloc"); 91394e9410bShenning n->af = p->af; 91494e9410bShenning if (mode == PFCTL_IFLOOKUP_BCAST) 91594e9410bShenning memcpy(&n->addr.v.a.addr, &p->bcast, 91694e9410bShenning sizeof(struct pf_addr)); 91794e9410bShenning else 91894e9410bShenning memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr, 91994e9410bShenning sizeof(struct pf_addr)); 92094e9410bShenning if (mode == PFCTL_IFLOOKUP_NET) 92194e9410bShenning set_ipmask(n, unmask(&p->addr.v.a.mask, n->af)); 92294e9410bShenning else { 92394e9410bShenning if (n->af == AF_INET) { 92494e9410bShenning if (p->ifa_flags & IFF_LOOPBACK && 92594e9410bShenning p->ifa_flags & IFF_LINK1) 92694e9410bShenning memcpy(&n->addr.v.a.mask, 92794e9410bShenning &p->addr.v.a.mask, 92894e9410bShenning sizeof(struct pf_addr)); 92994e9410bShenning else 93094e9410bShenning set_ipmask(n, 32); 93194e9410bShenning } else 93294e9410bShenning set_ipmask(n, 128); 93394e9410bShenning } 93494e9410bShenning n->ifindex = p->ifindex; 93594e9410bShenning 93694e9410bShenning n->next = NULL; 93794e9410bShenning n->tail = n; 93894e9410bShenning if (h == NULL) 93994e9410bShenning h = n; 94094e9410bShenning else { 94194e9410bShenning h->tail->next = n; 94294e9410bShenning h->tail = n; 94394e9410bShenning } 94494e9410bShenning } 94594e9410bShenning if (h == NULL && mode == PFCTL_IFLOOKUP_HOST) { 94694e9410bShenning fprintf(stderr, "no IP address found for %s\n", ifa_name); 94794e9410bShenning } 94894e9410bShenning return (h); 94994e9410bShenning } 95094e9410bShenning 95194e9410bShenning struct node_host * 952f23861c1Shenning host(const char *s) 95394e9410bShenning { 9542a6c1abaShenning struct node_host *h = NULL; 955f23861c1Shenning int mask, v4mask, v6mask, cont = 1; 956f23861c1Shenning char *p, *q, *ps; 95794e9410bShenning 95894e9410bShenning if ((p = strrchr(s, '/')) != NULL) { 95994e9410bShenning mask = strtol(p+1, &q, 0); 96094e9410bShenning if (!q || *q) { 96194e9410bShenning fprintf(stderr, "invalid netmask\n"); 96294e9410bShenning return (NULL); 96394e9410bShenning } 964a81c851cShenning if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL) 96594e9410bShenning err(1, "host: malloc"); 96694e9410bShenning strlcpy(ps, s, strlen(s) - strlen(p) + 1); 96794e9410bShenning v4mask = v6mask = mask; 96894e9410bShenning } else { 969f23861c1Shenning if ((ps = strdup(s)) == NULL) 970f23861c1Shenning err(1, "host: strdup"); 97194e9410bShenning v4mask = 32; 97294e9410bShenning v6mask = 128; 973f23861c1Shenning mask = -1; 97494e9410bShenning } 97594e9410bShenning 9762a6c1abaShenning /* interface with this name exists? */ 9774a36d485Shenning if (cont && (h = host_if(ps, mask)) != NULL) 9782a6c1abaShenning cont = 0; 9792a6c1abaShenning 9802a6c1abaShenning /* IPv4 address? */ 981f23861c1Shenning if (cont && (h = host_v4(s, mask)) != NULL) 9822a6c1abaShenning cont = 0; 9832a6c1abaShenning 9842a6c1abaShenning /* IPv6 address? */ 9852a6c1abaShenning if (cont && (h = host_v6(ps, v6mask)) != NULL) 9862a6c1abaShenning cont = 0; 9872a6c1abaShenning 9882a6c1abaShenning /* dns lookup */ 9892a6c1abaShenning if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL) 9902a6c1abaShenning cont = 0; 9912a6c1abaShenning free(ps); 9922a6c1abaShenning 9932a6c1abaShenning if (h == NULL || cont == 1) { 9942a6c1abaShenning fprintf(stderr, "no IP address found for %s\n", s); 9952a6c1abaShenning return (NULL); 9962a6c1abaShenning } 9972a6c1abaShenning return (h); 9982a6c1abaShenning } 9992a6c1abaShenning 10002a6c1abaShenning struct node_host * 1001f2370d27Shenning host_if(const char *s, int mask) 10022a6c1abaShenning { 10032a6c1abaShenning struct node_host *n, *h = NULL; 10044a36d485Shenning char *p, *ps; 10054a36d485Shenning int mode = PFCTL_IFLOOKUP_HOST; 10062a6c1abaShenning 10074a36d485Shenning if ((p = strrchr(s, ':')) != NULL && 10084a36d485Shenning (!strcmp(p+1, "network") || !strcmp(p+1, "broadcast"))) { 10094a36d485Shenning if (!strcmp(p+1, "network")) 10104a36d485Shenning mode = PFCTL_IFLOOKUP_NET; 10114a36d485Shenning if (!strcmp(p+1, "broadcast")) 10124a36d485Shenning mode = PFCTL_IFLOOKUP_BCAST; 10134a36d485Shenning if (mask > -1) { 10144a36d485Shenning fprintf(stderr, "network or broadcast lookup, but " 10154a36d485Shenning "extra netmask given\n"); 10164a36d485Shenning return (NULL); 10174a36d485Shenning } 10184a36d485Shenning if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL) 10194a36d485Shenning err(1, "host: malloc"); 10204a36d485Shenning strlcpy(ps, s, strlen(s) - strlen(p) + 1); 10214a36d485Shenning } else 10224a36d485Shenning if ((ps = strdup(s)) == NULL) 10234a36d485Shenning err(1, "host_if: strdup"); 10244a36d485Shenning 10254a36d485Shenning if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) { 10262a6c1abaShenning /* interface with this name exists */ 10274a36d485Shenning h = ifa_lookup(ps, mode); 10282a6c1abaShenning for (n = h; n != NULL && mask > -1; n = n->next) 10292a6c1abaShenning set_ipmask(n, mask); 10302a6c1abaShenning } 10314a36d485Shenning 10324a36d485Shenning free(ps); 10332a6c1abaShenning return (h); 10342a6c1abaShenning } 10352a6c1abaShenning 10362a6c1abaShenning struct node_host * 1037383ebbbfShenning host_v4(const char *s, int mask) 10382a6c1abaShenning { 10392a6c1abaShenning struct node_host *h = NULL; 10402a6c1abaShenning struct in_addr ina; 10412a6c1abaShenning int bits; 10422a6c1abaShenning 104394e9410bShenning memset(&ina, 0, sizeof(struct in_addr)); 10443c58a40aScedric if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) > -1) { 104594e9410bShenning h = calloc(1, sizeof(struct node_host)); 104694e9410bShenning if (h == NULL) 104794e9410bShenning err(1, "address: calloc"); 104894e9410bShenning h->ifname = NULL; 104994e9410bShenning h->af = AF_INET; 105094e9410bShenning h->addr.v.a.addr.addr32[0] = ina.s_addr; 105194e9410bShenning set_ipmask(h, bits); 105294e9410bShenning h->next = NULL; 105394e9410bShenning h->tail = h; 105494e9410bShenning } 10552a6c1abaShenning 105694e9410bShenning return (h); 105794e9410bShenning } 10582a6c1abaShenning 10592a6c1abaShenning struct node_host * 1060f2370d27Shenning host_v6(const char *s, int mask) 10612a6c1abaShenning { 10622a6c1abaShenning struct addrinfo hints, *res; 10632a6c1abaShenning struct node_host *h = NULL; 106494e9410bShenning 106594e9410bShenning memset(&hints, 0, sizeof(hints)); 106694e9410bShenning hints.ai_family = AF_INET6; 106794e9410bShenning hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 106894e9410bShenning hints.ai_flags = AI_NUMERICHOST; 10692a6c1abaShenning if (getaddrinfo(s, "0", &hints, &res) == 0) { 10702a6c1abaShenning h = calloc(1, sizeof(struct node_host)); 10712a6c1abaShenning if (h == NULL) 107294e9410bShenning err(1, "address: calloc"); 10732a6c1abaShenning h->ifname = NULL; 10742a6c1abaShenning h->af = AF_INET6; 10752a6c1abaShenning memcpy(&h->addr.v.a.addr, 107694e9410bShenning &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, 10772a6c1abaShenning sizeof(h->addr.v.a.addr)); 10782a6c1abaShenning h->ifindex = 10792a6c1abaShenning ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 10802a6c1abaShenning set_ipmask(h, mask); 108194e9410bShenning freeaddrinfo(res); 10822a6c1abaShenning h->next = NULL; 10832a6c1abaShenning h->tail = h; 108494e9410bShenning } 108594e9410bShenning 10862a6c1abaShenning return (h); 10872a6c1abaShenning } 10882a6c1abaShenning 10892a6c1abaShenning struct node_host * 1090f2370d27Shenning host_dns(const char *s, int v4mask, int v6mask) 10912a6c1abaShenning { 10922a6c1abaShenning struct addrinfo hints, *res0, *res; 10932a6c1abaShenning struct node_host *n, *h = NULL; 10942a6c1abaShenning int error; 10952a6c1abaShenning 109694e9410bShenning memset(&hints, 0, sizeof(hints)); 109794e9410bShenning hints.ai_family = PF_UNSPEC; 109894e9410bShenning hints.ai_socktype = SOCK_STREAM; /* DUMMY */ 10992a6c1abaShenning error = getaddrinfo(s, NULL, &hints, &res0); 11002a6c1abaShenning if (error) 11012a6c1abaShenning return (h); 11022a6c1abaShenning 110394e9410bShenning for (res = res0; res; res = res->ai_next) { 110494e9410bShenning if (res->ai_family != AF_INET && 110594e9410bShenning res->ai_family != AF_INET6) 110694e9410bShenning continue; 110794e9410bShenning n = calloc(1, sizeof(struct node_host)); 110894e9410bShenning if (n == NULL) 11092a6c1abaShenning err(1, "host_dns: calloc"); 111094e9410bShenning n->ifname = NULL; 111194e9410bShenning n->af = res->ai_family; 111294e9410bShenning if (res->ai_family == AF_INET) { 111394e9410bShenning memcpy(&n->addr.v.a.addr, 11142a6c1abaShenning &((struct sockaddr_in *) 11152a6c1abaShenning res->ai_addr)->sin_addr.s_addr, 111694e9410bShenning sizeof(struct in_addr)); 111794e9410bShenning set_ipmask(n, v4mask); 111894e9410bShenning } else { 111994e9410bShenning memcpy(&n->addr.v.a.addr, 11202a6c1abaShenning &((struct sockaddr_in6 *) 11212a6c1abaShenning res->ai_addr)->sin6_addr.s6_addr, 112294e9410bShenning sizeof(struct in6_addr)); 112394e9410bShenning n->ifindex = 11242a6c1abaShenning ((struct sockaddr_in6 *) 11252a6c1abaShenning res->ai_addr)->sin6_scope_id; 112694e9410bShenning set_ipmask(n, v6mask); 112794e9410bShenning } 112894e9410bShenning n->next = NULL; 112994e9410bShenning n->tail = n; 113094e9410bShenning if (h == NULL) 113194e9410bShenning h = n; 113294e9410bShenning else { 113394e9410bShenning h->tail->next = n; 113494e9410bShenning h->tail = n; 113594e9410bShenning } 113694e9410bShenning } 113794e9410bShenning freeaddrinfo(res0); 113894e9410bShenning 113994e9410bShenning return (h); 114094e9410bShenning } 1141