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