1 /* $OpenBSD: pfctl_parser.c,v 1.44 2001/08/23 04:10:51 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Daniel Hartmeier 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33 #include <sys/types.h> 34 #include <sys/socket.h> 35 #include <net/if.h> 36 #include <netinet/in.h> 37 #include <netinet/in_systm.h> 38 #include <netinet/ip.h> 39 #include <netinet/ip_icmp.h> 40 #define TCPSTATES 41 #include <netinet/tcp_fsm.h> 42 #include <net/pfvar.h> 43 #include <arpa/inet.h> 44 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <ctype.h> 49 #include <netdb.h> 50 #include <stdarg.h> 51 #include <errno.h> 52 #include <err.h> 53 54 #include "pfctl_parser.h" 55 56 void print_addr (u_int32_t); 57 void print_host (struct pf_state_host *); 58 void print_seq (struct pf_state_peer *); 59 void print_port (u_int8_t, u_int16_t, u_int16_t, char *); 60 void print_flags (u_int8_t); 61 62 char *tcpflags = "FSRPAU"; 63 64 struct icmptypeent icmp_type[] = { 65 { "echoreq", ICMP_ECHO }, 66 { "echorep", ICMP_ECHOREPLY }, 67 { "unreach", ICMP_UNREACH }, 68 { "squench", ICMP_SOURCEQUENCH }, 69 { "redir", ICMP_REDIRECT }, 70 { "althost", ICMP_ALTHOSTADDR }, 71 { "routeradv", ICMP_ROUTERADVERT }, 72 { "routersol", ICMP_ROUTERSOLICIT }, 73 { "timex", ICMP_TIMXCEED }, 74 { "paramprob", ICMP_PARAMPROB }, 75 { "timereq", ICMP_TSTAMP }, 76 { "timerep", ICMP_TSTAMPREPLY }, 77 { "inforeq", ICMP_IREQ }, 78 { "inforep", ICMP_IREQREPLY }, 79 { "maskreq", ICMP_MASKREQ }, 80 { "maskrep", ICMP_MASKREPLY }, 81 { "trace", ICMP_TRACEROUTE }, 82 { "dataconv", ICMP_DATACONVERR }, 83 { "mobredir", ICMP_MOBILE_REDIRECT }, 84 { "ipv6-where", ICMP_IPV6_WHEREAREYOU }, 85 { "ipv6-here", ICMP_IPV6_IAMHERE }, 86 { "mobregreq", ICMP_MOBILE_REGREQUEST }, 87 { "mobregrep", ICMP_MOBILE_REGREPLY }, 88 { "skip", ICMP_SKIP }, 89 { "photuris", ICMP_PHOTURIS } 90 91 }; 92 93 struct icmpcodeent icmp_code[] = { 94 { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET }, 95 { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST }, 96 { "proto-unr", ICMP_UNREACH, ICMP_UNREACH_PROTOCOL }, 97 { "port-unr", ICMP_UNREACH, ICMP_UNREACH_PORT }, 98 { "needfrag", ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG }, 99 { "srcfail", ICMP_UNREACH, ICMP_UNREACH_SRCFAIL }, 100 { "net-unk", ICMP_UNREACH, ICMP_UNREACH_NET_UNKNOWN }, 101 { "host-unk", ICMP_UNREACH, ICMP_UNREACH_HOST_UNKNOWN }, 102 { "isolate", ICMP_UNREACH, ICMP_UNREACH_ISOLATED }, 103 { "net-prohib", ICMP_UNREACH, ICMP_UNREACH_NET_PROHIB }, 104 { "host-prohib", ICMP_UNREACH, ICMP_UNREACH_HOST_PROHIB }, 105 { "net-tos", ICMP_UNREACH, ICMP_UNREACH_TOSNET }, 106 { "host-tos", ICMP_UNREACH, ICMP_UNREACH_TOSHOST }, 107 { "filter-prohib", ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB }, 108 { "host-preced", ICMP_UNREACH, ICMP_UNREACH_HOST_PRECEDENCE }, 109 { "cutoff-preced", ICMP_UNREACH, ICMP_UNREACH_PRECEDENCE_CUTOFF }, 110 { "redir-net", ICMP_REDIRECT, ICMP_REDIRECT_NET }, 111 { "redir-host", ICMP_REDIRECT, ICMP_REDIRECT_HOST }, 112 { "redir-tos-net", ICMP_REDIRECT, ICMP_REDIRECT_TOSNET }, 113 { "redir-tos-host", ICMP_REDIRECT, ICMP_REDIRECT_TOSHOST }, 114 { "normal-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL }, 115 { "common-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON }, 116 { "transit", ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS }, 117 { "reassemb", ICMP_TIMXCEED, ICMP_TIMXCEED_REASS }, 118 { "badhead", ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR }, 119 { "optmiss", ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT }, 120 { "badlen", ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH }, 121 { "unknown-ind", ICMP_PHOTURIS, ICMP_PHOTURIS_UNKNOWN_INDEX }, 122 { "auth-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_AUTH_FAILED }, 123 { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED } 124 }; 125 126 struct icmptypeent * 127 geticmptypebynumber(u_int8_t type) 128 { 129 unsigned i; 130 131 for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) { 132 if(type == icmp_type[i].type) 133 return (&icmp_type[i]); 134 } 135 return (0); 136 } 137 138 struct icmptypeent * 139 geticmptypebyname(char *w) 140 { 141 unsigned i; 142 143 for(i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); i++) { 144 if(!strcmp(w, icmp_type[i].name)) 145 return (&icmp_type[i]); 146 } 147 return (0); 148 } 149 150 struct icmpcodeent * 151 geticmpcodebynumber(u_int8_t type, u_int8_t code) 152 { 153 unsigned i; 154 155 for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) { 156 if (type == icmp_code[i].type && code == icmp_code[i].code) 157 return (&icmp_code[i]); 158 } 159 return (0); 160 } 161 162 struct icmpcodeent * 163 geticmpcodebyname(u_long type, char *w) 164 { 165 unsigned i; 166 167 for(i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); i++) { 168 if (type == icmp_code[i].type && !strcmp(w, icmp_code[i].name)) 169 return (&icmp_code[i]); 170 } 171 return (0); 172 } 173 174 void 175 print_addr(u_int32_t a) 176 { 177 a = ntohl(a); 178 printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255); 179 } 180 181 void 182 print_host(struct pf_state_host *h) 183 { 184 u_int32_t a = ntohl(h->addr); 185 u_int16_t p = ntohs(h->port); 186 187 printf("%u.%u.%u.%u:%u", (a>>24)&255, (a>>16)&255, (a>>8)&255, a&255, p); 188 } 189 190 void 191 print_seq(struct pf_state_peer *p) 192 { 193 printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo); 194 } 195 196 void 197 print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto) 198 { 199 struct servent *s = getservbyport(p1, proto); 200 201 p1 = ntohs(p1); 202 p2 = ntohs(p2); 203 printf("port "); 204 if (op == PF_OP_IRG) 205 printf("%u >< %u ", p1, p2); 206 else if (op == PF_OP_XRG) 207 printf("%u <> %u ", p1, p2); 208 else if (op == PF_OP_EQ) { 209 if (s != NULL) 210 printf("= %s ", s->s_name); 211 else 212 printf("= %u ", p1); 213 } else if (op == PF_OP_NE) { 214 if (s != NULL) 215 printf("!= %s ", s->s_name); 216 else 217 printf("!= %u ", p1); 218 } else if (op == PF_OP_LT) 219 printf("< %u ", p1); 220 else if (op == PF_OP_LE) 221 printf("<= %u ", p1); 222 else if (op == PF_OP_GT) 223 printf("> %u ", p1); 224 else if (op == PF_OP_GE) 225 printf(">= %u ", p1); 226 } 227 228 void 229 print_flags(u_int8_t f) 230 { 231 int i; 232 233 for (i = 0; i < 6; ++i) 234 if (f & (1 << i)) 235 printf("%c", tcpflags[i]); 236 } 237 238 void 239 print_nat(struct pf_nat *n) 240 { 241 printf("@nat "); 242 if (n->ifname[0]) { 243 printf("on "); 244 if (n->ifnot) 245 printf("! "); 246 printf("%s ", n->ifname); 247 } 248 printf("from "); 249 if (n->saddr || n->smask) { 250 if (n->snot) 251 printf("! "); 252 print_addr(n->saddr); 253 if (n->smask != 0xFFFFFFFF) { 254 printf("/"); 255 print_addr(n->smask); 256 } 257 printf(" "); 258 } else 259 printf("any "); 260 printf("to "); 261 if (n->daddr || n->dmask) { 262 if (n->dnot) 263 printf("! "); 264 print_addr(n->daddr); 265 if (n->dmask != 0xFFFFFFFF) { 266 printf("/"); 267 print_addr(n->dmask); 268 } 269 printf(" "); 270 } else 271 printf("any "); 272 printf("-> "); 273 print_addr(n->raddr); 274 printf(" "); 275 switch (n->proto) { 276 case IPPROTO_TCP: 277 printf("proto tcp"); 278 break; 279 case IPPROTO_UDP: 280 printf("proto udp"); 281 break; 282 case IPPROTO_ICMP: 283 printf("proto icmp"); 284 break; 285 } 286 printf("\n"); 287 } 288 289 void 290 print_rdr(struct pf_rdr *r) 291 { 292 printf("@rdr "); 293 if (r->ifname[0]) { 294 printf("on "); 295 if (r->ifnot) 296 printf("! "); 297 printf("%s ", r->ifname); 298 } 299 switch (r->proto) { 300 case IPPROTO_TCP: 301 printf("proto tcp "); 302 break; 303 case IPPROTO_UDP: 304 printf("proto udp "); 305 break; 306 } 307 printf("from "); 308 if (r->saddr || r->smask) { 309 if (r->snot) 310 printf("! "); 311 print_addr(r->saddr); 312 if (r->smask != 0xFFFFFFFF) { 313 printf("/"); 314 print_addr(r->smask); 315 } 316 printf(" "); 317 } else 318 printf("any "); 319 printf("to "); 320 if (r->daddr || r->dmask) { 321 if (r->dnot) 322 printf("! "); 323 print_addr(r->daddr); 324 if (r->dmask != 0xFFFFFFFF) { 325 printf("/"); 326 print_addr(r->dmask); 327 } 328 printf(" "); 329 } else 330 printf("any "); 331 printf("port %u", ntohs(r->dport)); 332 if (r->opts & PF_DPORT_RANGE) 333 printf(":%u", ntohs(r->dport2)); 334 printf(" -> "); 335 print_addr(r->raddr); 336 printf(" "); 337 printf("port %u", ntohs(r->rport)); 338 if (r->opts & PF_RPORT_RANGE) 339 printf(":*"); 340 printf("\n"); 341 } 342 343 char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES; 344 char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; 345 346 void 347 print_status(struct pf_status *s) 348 { 349 350 time_t t = time(NULL); 351 int i; 352 353 printf("Status: %s Time: %u Since: %u Debug: ", 354 s->running ? "Enabled" : "Disabled", 355 t, s->since); 356 switch (s->debug) { 357 case 0: 358 printf("None"); 359 break; 360 case 1: 361 printf("Urgent"); 362 break; 363 case 2: 364 printf("Misc"); 365 break; 366 } 367 printf("\nBytes In: %-10llu Bytes Out: %-10llu\n", 368 s->bcounters[PF_IN], s->bcounters[PF_OUT]); 369 printf("Inbound Packets: Passed: %-10llu Dropped: %-10llu\n", 370 s->pcounters[PF_IN][PF_PASS], 371 s->pcounters[PF_IN][PF_DROP]); 372 printf("Outbound Packets: Passed: %-10llu Dropped: %-10llu\n", 373 s->pcounters[PF_OUT][PF_PASS], 374 s->pcounters[PF_OUT][PF_DROP]); 375 printf("States: %u\n", s->states); 376 printf("pf Counters\n"); 377 for (i = 0; i < FCNT_MAX; i++) 378 printf("%-25s %-8lld\n", pf_fcounters[i], 379 s->fcounters[i]); 380 printf("Counters\n"); 381 for (i = 0; i < PFRES_MAX; i++) 382 printf("%-25s %-8lld\n", pf_reasons[i], 383 s->counters[i]); 384 } 385 386 void 387 print_state(struct pf_state *s) 388 { 389 struct pf_state_peer *src, *dst; 390 u_int8_t hrs, min, sec; 391 392 if (s->direction == PF_OUT) { 393 src = &s->src; 394 dst = &s->dst; 395 } else { 396 src = &s->dst; 397 dst = &s->src; 398 } 399 switch (s->proto) { 400 case IPPROTO_TCP: 401 printf("TCP "); 402 break; 403 case IPPROTO_UDP: 404 printf("UDP "); 405 break; 406 case IPPROTO_ICMP: 407 printf("ICMP "); 408 break; 409 default: 410 printf("???? "); 411 break; 412 } 413 if ((s->lan.addr != s->gwy.addr) || (s->lan.port != s->gwy.port)) { 414 print_host(&s->lan); 415 if (s->direction == PF_OUT) 416 printf(" -> "); 417 else 418 printf(" <- "); 419 } 420 print_host(&s->gwy); 421 if (s->direction == PF_OUT) 422 printf(" -> "); 423 else 424 printf(" <- "); 425 print_host(&s->ext); 426 printf("\n"); 427 428 if (s->proto == IPPROTO_TCP) { 429 printf(" %s:%s ", tcpstates[src->state], 430 tcpstates[dst->state]); 431 print_seq(src); 432 printf(" "); 433 print_seq(dst); 434 printf("\n"); 435 } else { 436 printf(" %u:%u ", src->state, dst->state); 437 } 438 439 sec = s->creation % 60; 440 s->creation /= 60; 441 min = s->creation % 60; 442 s->creation /= 60; 443 hrs = s->creation; 444 printf(" age %.2u:%.2u:%.2u", hrs, min, sec); 445 sec = s->expire % 60; 446 s->expire /= 60; 447 min = s->expire % 60; 448 s->expire /= 60; 449 hrs = s->expire; 450 printf(", expires in %.2u:%.2u:%.2u", hrs, min, sec); 451 printf(", %u pkts, %u bytes\n", s->packets, s->bytes); 452 } 453 454 void 455 print_rule(struct pf_rule *r) 456 { 457 printf("@%d ", r->nr + 1); 458 if (r->action == PF_PASS) 459 printf("pass "); 460 else if (r->action == PF_DROP) { 461 printf("block "); 462 if (r->rule_flag & PFRULE_RETURNRST) 463 printf("return-rst "); 464 else if (r->return_icmp) { 465 struct icmpcodeent *ic; 466 467 printf("return-icmp"); 468 ic = geticmpcodebynumber(r->return_icmp >> 8, 469 r->return_icmp & 255); 470 if ((ic == NULL) || (ic->type != ICMP_UNREACH)) 471 printf("(%u,%u) ", r->return_icmp >> 8, 472 r->return_icmp & 255); 473 else if (ic->code != ICMP_UNREACH_PORT) 474 printf("(%s) ", ic->name); 475 else 476 printf(" "); 477 } 478 } else 479 printf("scrub "); 480 if (r->direction == 0) 481 printf("in "); 482 else 483 printf("out "); 484 if (r->log == 1) 485 printf("log "); 486 else if (r->log == 2) 487 printf("log-all "); 488 if (r->quick) 489 printf("quick "); 490 if (r->ifname[0]) 491 printf("on %s ", r->ifname); 492 if (r->proto) { 493 struct protoent *p = getprotobynumber(r->proto); 494 if (p != NULL) 495 printf("proto %s ", p->p_name); 496 else 497 printf("proto %u ", r->proto); 498 } 499 if (!r->src.addr && !r->src.mask && !r->src.port_op && !r->dst.addr && ! r->dst.mask && !r->dst.port_op) 500 printf("all "); 501 else { 502 printf("from "); 503 if (!r->src.addr && !r->src.mask) 504 printf("any "); 505 else { 506 if (r->src.not) 507 printf("! "); 508 print_addr(r->src.addr); 509 if (r->src.mask != 0xFFFFFFFF) { 510 printf("/"); 511 print_addr(r->src.mask); 512 } 513 printf(" "); 514 } 515 if (r->src.port_op) 516 print_port(r->src.port_op, r->src.port[0], 517 r->src.port[1], 518 r->proto == IPPROTO_TCP ? "tcp" : "udp"); 519 520 printf("to "); 521 if (!r->dst.addr && !r->dst.mask) 522 printf("any "); 523 else { 524 if (r->dst.not) 525 printf("! "); 526 print_addr(r->dst.addr); 527 if (r->dst.mask != 0xFFFFFFFF) { 528 printf("/"); 529 print_addr(r->dst.mask); 530 } 531 printf(" "); 532 } 533 if (r->dst.port_op) 534 print_port(r->dst.port_op, r->dst.port[0], 535 r->dst.port[1], 536 r->proto == IPPROTO_TCP ? "tcp" : "udp"); 537 } 538 if (r->flags || r->flagset) { 539 printf("flags "); 540 print_flags(r->flags); 541 printf("/"); 542 print_flags(r->flagset); 543 printf(" "); 544 } 545 if (r->type) { 546 struct icmptypeent *p; 547 548 p = geticmptypebynumber(r->type-1); 549 if (p != NULL) 550 printf("icmp-type %s ", p->name); 551 else 552 printf("icmp-type %u ", r->type-1); 553 if (r->code) { 554 struct icmpcodeent *p; 555 556 p = geticmpcodebynumber(r->type-1, r->code-1); 557 if (p != NULL) 558 printf("code %s ", p->name); 559 else 560 printf("code %u ", r->code-1); 561 } 562 } 563 if (r->keep_state) 564 printf("keep state "); 565 if (r->rule_flag & PFRULE_NODF) 566 printf("no-df "); 567 if (r->min_ttl) 568 printf("min-ttl %d ", r->min_ttl); 569 570 printf("\n"); 571 } 572 573 int 574 parse_flags(char *s) 575 { 576 char *p, *q; 577 u_int8_t f = 0; 578 579 for (p = s; *p; p++) { 580 if ((q = strchr(tcpflags, *p)) == NULL) 581 return -1; 582 else 583 f |= 1 << (q - tcpflags); 584 } 585 return (f ? f : 63); 586 } 587