filter.c revision 75894
1/* 2 * PPP Filter command Interface 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $FreeBSD: head/usr.sbin/ppp/filter.c 75894 2001-04-24 02:13:34Z brian $ 21 * 22 * TODO: Should send ICMP error message when we discard packets. 23 */ 24 25#include <sys/param.h> 26#include <netinet/in.h> 27#include <arpa/inet.h> 28#include <netdb.h> 29#include <netinet/in_systm.h> 30#include <netinet/ip.h> 31#include <sys/un.h> 32 33#include <stdio.h> 34#include <stdlib.h> 35#include <strings.h> 36#include <termios.h> 37 38#include "layer.h" 39#include "defs.h" 40#include "command.h" 41#include "mbuf.h" 42#include "log.h" 43#include "iplist.h" 44#include "timer.h" 45#include "throughput.h" 46#include "lqr.h" 47#include "hdlc.h" 48#include "fsm.h" 49#include "lcp.h" 50#include "ccp.h" 51#include "link.h" 52#include "slcompress.h" 53#include "ipcp.h" 54#include "filter.h" 55#include "descriptor.h" 56#include "prompt.h" 57#include "mp.h" 58#ifndef NORADIUS 59#include "radius.h" 60#endif 61#include "bundle.h" 62 63static int filter_Nam2Proto(int, char const *const *); 64static int filter_Nam2Op(const char *); 65 66static const u_int32_t netmasks[33] = { 67 0x00000000, 68 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, 69 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000, 70 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000, 71 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, 72 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, 73 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, 74 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0, 75 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF, 76}; 77 78struct in_addr 79bits2mask(int bits) 80{ 81 struct in_addr result; 82 83 result.s_addr = htonl(netmasks[bits]); 84 return result; 85} 86 87int 88ParseAddr(struct ipcp *ipcp, const char *data, 89 struct in_addr *paddr, struct in_addr *pmask, int *pwidth) 90{ 91 int bits, len; 92 char *wp; 93 const char *cp; 94 95 if (pmask) 96 pmask->s_addr = INADDR_BROADCAST; /* Assume 255.255.255.255 as default */ 97 98 cp = pmask || pwidth ? strchr(data, '/') : NULL; 99 len = cp ? cp - data : strlen(data); 100 101 if (ipcp && strncasecmp(data, "HISADDR", len) == 0) 102 *paddr = ipcp->peer_ip; 103 else if (ipcp && strncasecmp(data, "MYADDR", len) == 0) 104 *paddr = ipcp->my_ip; 105 else if (ipcp && strncasecmp(data, "DNS0", len) == 0) 106 *paddr = ipcp->ns.dns[0]; 107 else if (ipcp && strncasecmp(data, "DNS1", len) == 0) 108 *paddr = ipcp->ns.dns[1]; 109 else { 110 char *s; 111 112 s = (char *)alloca(len + 1); 113 strncpy(s, data, len); 114 s[len] = '\0'; 115 *paddr = GetIpAddr(s); 116 if (paddr->s_addr == INADDR_NONE) { 117 log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", s); 118 return 0; 119 } 120 } 121 if (cp && *++cp) { 122 bits = strtol(cp, &wp, 0); 123 if (cp == wp || bits < 0 || bits > 32) { 124 log_Printf(LogWARN, "ParseAddr: bad mask width.\n"); 125 return 0; 126 } 127 } else if (paddr->s_addr == INADDR_ANY) 128 /* An IP of 0.0.0.0 without a width is anything */ 129 bits = 0; 130 else 131 /* If a valid IP is given without a width, assume 32 bits */ 132 bits = 32; 133 134 if (pwidth) 135 *pwidth = bits; 136 137 if (pmask) { 138 if (paddr->s_addr == INADDR_ANY) 139 pmask->s_addr = INADDR_ANY; 140 else 141 *pmask = bits2mask(bits); 142 } 143 144 return 1; 145} 146 147static int 148ParsePort(const char *service, int proto) 149{ 150 const char *protocol_name; 151 char *cp; 152 struct servent *servent; 153 int port; 154 155 switch (proto) { 156 case P_IPIP: 157 protocol_name = "ipip"; 158 break; 159 case P_UDP: 160 protocol_name = "udp"; 161 break; 162 case P_TCP: 163 protocol_name = "tcp"; 164 break; 165 default: 166 protocol_name = 0; 167 } 168 169 servent = getservbyname(service, protocol_name); 170 if (servent != 0) 171 return ntohs(servent->s_port); 172 173 port = strtol(service, &cp, 0); 174 if (cp == service) { 175 log_Printf(LogWARN, "ParsePort: %s is not a port name or number.\n", 176 service); 177 return 0; 178 } 179 return port; 180} 181 182/* 183 * ICMP Syntax: src eq icmp_message_type 184 */ 185static int 186ParseIcmp(int argc, char const *const *argv, struct filterent *tgt) 187{ 188 int type; 189 char *cp; 190 191 switch (argc) { 192 case 0: 193 /* permit/deny all ICMP types */ 194 tgt->f_srcop = OP_NONE; 195 break; 196 197 case 3: 198 if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) { 199 type = strtol(argv[2], &cp, 0); 200 if (cp == argv[2]) { 201 log_Printf(LogWARN, "ParseIcmp: type is expected.\n"); 202 return 0; 203 } 204 tgt->f_srcop = OP_EQ; 205 tgt->f_srcport = type; 206 } 207 break; 208 209 default: 210 log_Printf(LogWARN, "ParseIcmp: bad icmp syntax.\n"); 211 return 0; 212 } 213 return 1; 214} 215 216/* 217 * UDP Syntax: [src op port] [dst op port] 218 */ 219static int 220ParseUdpOrTcp(int argc, char const *const *argv, int proto, 221 struct filterent *tgt) 222{ 223 tgt->f_srcop = tgt->f_dstop = OP_NONE; 224 tgt->f_estab = tgt->f_syn = tgt->f_finrst = 0; 225 226 if (argc >= 3 && !strcmp(*argv, "src")) { 227 tgt->f_srcop = filter_Nam2Op(argv[1]); 228 if (tgt->f_srcop == OP_NONE) { 229 log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n"); 230 return 0; 231 } 232 tgt->f_srcport = ParsePort(argv[2], proto); 233 if (tgt->f_srcport == 0) 234 return 0; 235 argc -= 3; 236 argv += 3; 237 } 238 239 if (argc >= 3 && !strcmp(argv[0], "dst")) { 240 tgt->f_dstop = filter_Nam2Op(argv[1]); 241 if (tgt->f_dstop == OP_NONE) { 242 log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n"); 243 return 0; 244 } 245 tgt->f_dstport = ParsePort(argv[2], proto); 246 if (tgt->f_dstport == 0) 247 return 0; 248 argc -= 3; 249 argv += 3; 250 } 251 252 if (proto == P_TCP) { 253 for (; argc > 0; argc--, argv++) 254 if (!strcmp(*argv, "estab")) 255 tgt->f_estab = 1; 256 else if (!strcmp(*argv, "syn")) 257 tgt->f_syn = 1; 258 else if (!strcmp(*argv, "finrst")) 259 tgt->f_finrst = 1; 260 else 261 break; 262 } 263 264 if (argc > 0) { 265 log_Printf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv); 266 return 0; 267 } 268 269 return 1; 270} 271 272static int 273ParseIgmp(int argc, char const * const *argv, struct filterent *tgt) 274{ 275 /* 276 * Filter currently is a catch-all. Requests are either permitted or 277 * dropped. 278 */ 279 if (argc != 0) { 280 log_Printf(LogWARN, "ParseIgmp: Too many parameters\n"); 281 return 0; 282 } else 283 tgt->f_srcop = OP_NONE; 284 285 return 1; 286} 287 288#ifdef P_GRE 289static int 290ParseGRE(int argc, char const * const *argv, struct filterent *tgt) 291{ 292 /* 293 * Filter currently is a catch-all. Requests are either permitted or 294 * dropped. 295 */ 296 if (argc != 0) { 297 log_Printf(LogWARN, "ParseGRE: Too many parameters\n"); 298 return 0; 299 } else 300 tgt->f_srcop = OP_NONE; 301 302 return 1; 303} 304#endif 305 306#ifdef P_OSPF 307static int 308ParseOspf(int argc, char const * const *argv, struct filterent *tgt) 309{ 310 /* 311 * Filter currently is a catch-all. Requests are either permitted or 312 * dropped. 313 */ 314 if (argc != 0) { 315 log_Printf(LogWARN, "ParseOspf: Too many parameters\n"); 316 return 0; 317 } else 318 tgt->f_srcop = OP_NONE; 319 320 return 1; 321} 322#endif 323 324static unsigned 325addrtype(const char *addr) 326{ 327 if (!strncasecmp(addr, "MYADDR", 6) && (addr[6] == '\0' || addr[6] == '/')) 328 return T_MYADDR; 329 if (!strncasecmp(addr, "HISADDR", 7) && (addr[7] == '\0' || addr[7] == '/')) 330 return T_HISADDR; 331 if (!strncasecmp(addr, "DNS0", 4) && (addr[4] == '\0' || addr[4] == '/')) 332 return T_DNS0; 333 if (!strncasecmp(addr, "DNS1", 4) && (addr[4] == '\0' || addr[4] == '/')) 334 return T_DNS1; 335 336 return T_ADDR; 337} 338 339static const char * 340addrstr(struct in_addr addr, unsigned type) 341{ 342 switch (type) { 343 case T_MYADDR: 344 return "MYADDR"; 345 case T_HISADDR: 346 return "HISADDR"; 347 case T_DNS0: 348 return "DNS0"; 349 case T_DNS1: 350 return "DNS1"; 351 } 352 return inet_ntoa(addr); 353} 354 355static const char * 356maskstr(int bits) 357{ 358 static char str[4]; 359 360 if (bits == 32) 361 *str = '\0'; 362 else 363 snprintf(str, sizeof str, "/%d", bits); 364 365 return str; 366} 367 368static int 369Parse(struct ipcp *ipcp, int argc, char const *const *argv, 370 struct filterent *ofp) 371{ 372 int action, proto; 373 int val, ruleno; 374 char *wp; 375 struct filterent filterdata; 376 377 ruleno = strtol(*argv, &wp, 0); 378 if (*argv == wp || ruleno >= MAXFILTERS) { 379 log_Printf(LogWARN, "Parse: invalid filter number.\n"); 380 return 0; 381 } 382 if (ruleno < 0) { 383 for (ruleno = 0; ruleno < MAXFILTERS; ruleno++) { 384 ofp->f_action = A_NONE; 385 ofp++; 386 } 387 log_Printf(LogWARN, "Parse: filter cleared.\n"); 388 return 1; 389 } 390 ofp += ruleno; 391 392 if (--argc == 0) { 393 log_Printf(LogWARN, "Parse: missing action.\n"); 394 return 0; 395 } 396 argv++; 397 398 proto = P_NONE; 399 memset(&filterdata, '\0', sizeof filterdata); 400 401 val = strtol(*argv, &wp, 0); 402 if (!*wp && val >= 0 && val < MAXFILTERS) { 403 if (val <= ruleno) { 404 log_Printf(LogWARN, "Parse: Can only jump forward from rule %d\n", 405 ruleno); 406 return 0; 407 } 408 action = val; 409 } else if (!strcmp(*argv, "permit")) { 410 action = A_PERMIT; 411 } else if (!strcmp(*argv, "deny")) { 412 action = A_DENY; 413 } else if (!strcmp(*argv, "clear")) { 414 ofp->f_action = A_NONE; 415 return 1; 416 } else { 417 log_Printf(LogWARN, "Parse: bad action: %s\n", *argv); 418 return 0; 419 } 420 filterdata.f_action = action; 421 422 argc--; 423 argv++; 424 425 if (argc && argv[0][0] == '!' && !argv[0][1]) { 426 filterdata.f_invert = 1; 427 argc--; 428 argv++; 429 } 430 431 proto = filter_Nam2Proto(argc, argv); 432 if (proto == P_NONE) { 433 if (!argc) 434 log_Printf(LogWARN, "Parse: address/mask is expected.\n"); 435 else if (ParseAddr(ipcp, *argv, &filterdata.f_src.ipaddr, 436 &filterdata.f_src.mask, &filterdata.f_src.width)) { 437 filterdata.f_srctype = addrtype(*argv); 438 argc--; 439 argv++; 440 proto = filter_Nam2Proto(argc, argv); 441 if (!argc) 442 log_Printf(LogWARN, "Parse: address/mask is expected.\n"); 443 else if (proto == P_NONE) { 444 if (ParseAddr(ipcp, *argv, &filterdata.f_dst.ipaddr, 445 &filterdata.f_dst.mask, &filterdata.f_dst.width)) { 446 filterdata.f_dsttype = addrtype(*argv); 447 argc--; 448 argv++; 449 } else 450 filterdata.f_dsttype = T_ADDR; 451 if (argc) { 452 proto = filter_Nam2Proto(argc, argv); 453 if (proto == P_NONE) { 454 log_Printf(LogWARN, "Parse: %s: Invalid protocol\n", *argv); 455 return 0; 456 } else { 457 argc--; 458 argv++; 459 } 460 } 461 } else { 462 argc--; 463 argv++; 464 } 465 } else { 466 log_Printf(LogWARN, "Parse: Address/protocol expected.\n"); 467 return 0; 468 } 469 } else { 470 argc--; 471 argv++; 472 } 473 474 if (argc >= 2 && strcmp(argv[argc - 2], "timeout") == 0) { 475 filterdata.timeout = strtoul(argv[argc - 1], NULL, 10); 476 argc -= 2; 477 } 478 479 val = 1; 480 filterdata.f_proto = proto; 481 482 switch (proto) { 483 case P_TCP: 484 val = ParseUdpOrTcp(argc, argv, P_TCP, &filterdata); 485 break; 486 case P_UDP: 487 val = ParseUdpOrTcp(argc, argv, P_UDP, &filterdata); 488 break; 489 case P_IPIP: 490 val = ParseUdpOrTcp(argc, argv, P_IPIP, &filterdata); 491 break; 492 case P_ICMP: 493 val = ParseIcmp(argc, argv, &filterdata); 494 break; 495 case P_IGMP: 496 val = ParseIgmp(argc, argv, &filterdata); 497 break; 498#ifdef P_OSPF 499 case P_OSPF: 500 val = ParseOspf(argc, argv, &filterdata); 501 break; 502#endif 503#ifdef P_GRE 504 case P_GRE: 505 val = ParseGRE(argc, argv, &filterdata); 506 break; 507#endif 508 } 509 510 log_Printf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(filterdata.f_src.ipaddr)); 511 log_Printf(LogDEBUG, "Parse: Src mask: %s\n", 512 inet_ntoa(filterdata.f_src.mask)); 513 log_Printf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(filterdata.f_dst.ipaddr)); 514 log_Printf(LogDEBUG, "Parse: Dst mask: %s\n", 515 inet_ntoa(filterdata.f_dst.mask)); 516 log_Printf(LogDEBUG, "Parse: Proto = %d\n", proto); 517 518 log_Printf(LogDEBUG, "Parse: src: %s (%d)\n", 519 filter_Op2Nam(filterdata.f_srcop), filterdata.f_srcport); 520 log_Printf(LogDEBUG, "Parse: dst: %s (%d)\n", 521 filter_Op2Nam(filterdata.f_dstop), filterdata.f_dstport); 522 log_Printf(LogDEBUG, "Parse: estab: %u\n", filterdata.f_estab); 523 log_Printf(LogDEBUG, "Parse: syn: %u\n", filterdata.f_syn); 524 log_Printf(LogDEBUG, "Parse: finrst: %u\n", filterdata.f_finrst); 525 526 if (val) 527 *ofp = filterdata; 528 529 return val; 530} 531 532int 533filter_Set(struct cmdargs const *arg) 534{ 535 struct filter *filter; 536 537 if (arg->argc < arg->argn+2) 538 return -1; 539 540 if (!strcmp(arg->argv[arg->argn], "in")) 541 filter = &arg->bundle->filter.in; 542 else if (!strcmp(arg->argv[arg->argn], "out")) 543 filter = &arg->bundle->filter.out; 544 else if (!strcmp(arg->argv[arg->argn], "dial")) 545 filter = &arg->bundle->filter.dial; 546 else if (!strcmp(arg->argv[arg->argn], "alive")) 547 filter = &arg->bundle->filter.alive; 548 else { 549 log_Printf(LogWARN, "filter_Set: %s: Invalid filter name.\n", 550 arg->argv[arg->argn]); 551 return -1; 552 } 553 554 Parse(&arg->bundle->ncp.ipcp, arg->argc - arg->argn - 1, 555 arg->argv + arg->argn + 1, filter->rule); 556 return 0; 557} 558 559const char * 560filter_Action2Nam(int act) 561{ 562 static const char * const actname[] = { " none ", "permit ", " deny " }; 563 static char buf[8]; 564 565 if (act >= 0 && act < MAXFILTERS) { 566 snprintf(buf, sizeof buf, "%6d ", act); 567 return buf; 568 } else if (act >= A_NONE && act < A_NONE + sizeof(actname)/sizeof(char *)) 569 return actname[act - A_NONE]; 570 else 571 return "?????? "; 572} 573 574static void 575doShowFilter(struct filterent *fp, struct prompt *prompt) 576{ 577 int n; 578 579 for (n = 0; n < MAXFILTERS; n++, fp++) { 580 if (fp->f_action != A_NONE) { 581 prompt_Printf(prompt, " %2d %s", n, filter_Action2Nam(fp->f_action)); 582 prompt_Printf(prompt, "%c ", fp->f_invert ? '!' : ' '); 583 prompt_Printf(prompt, "%s%s ", addrstr(fp->f_src.ipaddr, fp->f_srctype), 584 maskstr(fp->f_src.width)); 585 prompt_Printf(prompt, "%s%s ", addrstr(fp->f_dst.ipaddr, fp->f_dsttype), 586 maskstr(fp->f_dst.width)); 587 if (fp->f_proto) { 588 prompt_Printf(prompt, "%s", filter_Proto2Nam(fp->f_proto)); 589 590 if (fp->f_srcop) 591 prompt_Printf(prompt, " src %s %d", filter_Op2Nam(fp->f_srcop), 592 fp->f_srcport); 593 if (fp->f_dstop) 594 prompt_Printf(prompt, " dst %s %d", filter_Op2Nam(fp->f_dstop), 595 fp->f_dstport); 596 if (fp->f_estab) 597 prompt_Printf(prompt, " estab"); 598 if (fp->f_syn) 599 prompt_Printf(prompt, " syn"); 600 if (fp->f_finrst) 601 prompt_Printf(prompt, " finrst"); 602 } 603 if (fp->timeout != 0) 604 prompt_Printf(prompt, " timeout %u", fp->timeout); 605 prompt_Printf(prompt, "\n"); 606 } 607 } 608} 609 610int 611filter_Show(struct cmdargs const *arg) 612{ 613 if (arg->argc > arg->argn+1) 614 return -1; 615 616 if (arg->argc == arg->argn+1) { 617 struct filter *filter; 618 619 if (!strcmp(arg->argv[arg->argn], "in")) 620 filter = &arg->bundle->filter.in; 621 else if (!strcmp(arg->argv[arg->argn], "out")) 622 filter = &arg->bundle->filter.out; 623 else if (!strcmp(arg->argv[arg->argn], "dial")) 624 filter = &arg->bundle->filter.dial; 625 else if (!strcmp(arg->argv[arg->argn], "alive")) 626 filter = &arg->bundle->filter.alive; 627 else 628 return -1; 629 doShowFilter(filter->rule, arg->prompt); 630 } else { 631 struct filter *filter[4]; 632 int f; 633 634 filter[0] = &arg->bundle->filter.in; 635 filter[1] = &arg->bundle->filter.out; 636 filter[2] = &arg->bundle->filter.dial; 637 filter[3] = &arg->bundle->filter.alive; 638 for (f = 0; f < 4; f++) { 639 if (f) 640 prompt_Printf(arg->prompt, "\n"); 641 prompt_Printf(arg->prompt, "%s:\n", filter[f]->name); 642 doShowFilter(filter[f]->rule, arg->prompt); 643 } 644 } 645 646 return 0; 647} 648 649static const char * const protoname[] = { 650 "none", "tcp", "udp", "icmp", "ospf", "igmp", "gre", "ipip" 651}; 652 653const char * 654filter_Proto2Nam(int proto) 655{ 656 if (proto >= sizeof protoname / sizeof protoname[0]) 657 return "unknown"; 658 return protoname[proto]; 659} 660 661static int 662filter_Nam2Proto(int argc, char const *const *argv) 663{ 664 int proto; 665 666 if (argc == 0) 667 proto = 0; 668 else 669 for (proto = sizeof protoname / sizeof protoname[0] - 1; proto; proto--) 670 if (!strcasecmp(*argv, protoname[proto])) 671 break; 672 673 return proto; 674} 675 676static const char * const opname[] = {"none", "eq", "gt", "lt"}; 677 678const char * 679filter_Op2Nam(int op) 680{ 681 if (op >= sizeof opname / sizeof opname[0]) 682 return "unknown"; 683 return opname[op]; 684 685} 686 687static int 688filter_Nam2Op(const char *cp) 689{ 690 int op; 691 692 for (op = sizeof opname / sizeof opname[0] - 1; op; op--) 693 if (!strcasecmp(cp, opname[op])) 694 break; 695 696 return op; 697} 698 699void 700filter_AdjustAddr(struct filter *filter, struct in_addr *my_ip, 701 struct in_addr *peer_ip, struct in_addr dns[2]) 702{ 703 struct filterent *fp; 704 int n; 705 706 for (fp = filter->rule, n = 0; n < MAXFILTERS; fp++, n++) 707 if (fp->f_action != A_NONE) { 708 if (my_ip) { 709 if (fp->f_srctype == T_MYADDR) 710 fp->f_src.ipaddr = *my_ip; 711 if (fp->f_dsttype == T_MYADDR) 712 fp->f_dst.ipaddr = *my_ip; 713 } 714 if (peer_ip) { 715 if (fp->f_srctype == T_HISADDR) 716 fp->f_src.ipaddr = *peer_ip; 717 if (fp->f_dsttype == T_HISADDR) 718 fp->f_dst.ipaddr = *peer_ip; 719 } 720 if (dns) { 721 if (fp->f_srctype == T_DNS0) 722 fp->f_src.ipaddr = dns[0]; 723 if (fp->f_dsttype == T_DNS0) 724 fp->f_dst.ipaddr = dns[0]; 725 if (fp->f_srctype == T_DNS1) 726 fp->f_src.ipaddr = dns[1]; 727 if (fp->f_dsttype == T_DNS1) 728 fp->f_dst.ipaddr = dns[1]; 729 } 730 } 731} 732