filter.c revision 47648
174465Srwatson/* 274465Srwatson * PPP Filter command Interface 374465Srwatson * 474465Srwatson * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 574465Srwatson * 674465Srwatson * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 774465Srwatson * 874465Srwatson * Redistribution and use in source and binary forms are permitted 974465Srwatson * provided that the above copyright notice and this paragraph are 1074465Srwatson * duplicated in all such forms and that any documentation, 1174465Srwatson * advertising materials, and other materials related to such 1274465Srwatson * distribution and use acknowledge that the software was developed 1374465Srwatson * by the Internet Initiative Japan. The name of the 1474465Srwatson * IIJ may not be used to endorse or promote products derived 1574465Srwatson * from this software without specific prior written permission. 1674465Srwatson * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1774465Srwatson * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1874465Srwatson * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1974465Srwatson * 2074465Srwatson * $Id: filter.c,v 1.28 1999/05/08 11:06:33 brian Exp $ 2174465Srwatson * 2274465Srwatson * TODO: Shoud send ICMP error message when we discard packets. 2374465Srwatson */ 2474465Srwatson 2574465Srwatson#include <sys/param.h> 2674465Srwatson#include <netinet/in.h> 2774465Srwatson#include <arpa/inet.h> 2874465Srwatson#include <netdb.h> 2974465Srwatson#include <netinet/in_systm.h> 3074465Srwatson#include <netinet/ip.h> 3174465Srwatson#include <sys/un.h> 3274465Srwatson 3374465Srwatson#include <stdio.h> 3474465Srwatson#include <stdlib.h> 3574465Srwatson#include <strings.h> 3674465Srwatson#include <termios.h> 3774465Srwatson 3874465Srwatson#include "layer.h" 3974465Srwatson#include "defs.h" 4074465Srwatson#include "command.h" 4174465Srwatson#include "mbuf.h" 4274465Srwatson#include "log.h" 4374465Srwatson#include "iplist.h" 4474465Srwatson#include "timer.h" 4574465Srwatson#include "throughput.h" 4674465Srwatson#include "lqr.h" 4774465Srwatson#include "hdlc.h" 4874465Srwatson#include "fsm.h" 4974465Srwatson#include "lcp.h" 5074465Srwatson#include "ccp.h" 5174465Srwatson#include "link.h" 5274465Srwatson#include "slcompress.h" 5374465Srwatson#include "ipcp.h" 5474465Srwatson#include "filter.h" 5574465Srwatson#include "descriptor.h" 5674465Srwatson#include "prompt.h" 5774465Srwatson#include "mp.h" 5874465Srwatson#ifndef NORADIUS 5974465Srwatson#include "radius.h" 6074465Srwatson#endif 6174465Srwatson#include "bundle.h" 6274465Srwatson 6374465Srwatsonstatic int filter_Nam2Proto(int, char const *const *); 6474465Srwatsonstatic int filter_Nam2Op(const char *); 6574465Srwatson 6674465Srwatsonstatic const u_int32_t netmasks[33] = { 6774465Srwatson 0x00000000, 6874465Srwatson 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, 6974465Srwatson 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000, 7074465Srwatson 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000, 7174465Srwatson 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, 7274465Srwatson 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, 7374465Srwatson 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, 7474465Srwatson 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0, 7574465Srwatson 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF, 7674465Srwatson}; 7774465Srwatson 7874465Srwatsonstruct in_addr 7974465Srwatsonbits2mask(int bits) 8074465Srwatson{ 8174465Srwatson struct in_addr result; 8274465Srwatson 8374465Srwatson result.s_addr = htonl(netmasks[bits]); 8474465Srwatson return result; 8574465Srwatson} 8674465Srwatson 8774465Srwatsonint 8874465SrwatsonParseAddr(struct ipcp *ipcp, const char *data, 8974465Srwatson struct in_addr *paddr, struct in_addr *pmask, int *pwidth) 9074465Srwatson{ 9174465Srwatson int bits, len; 9274465Srwatson char *wp; 9374465Srwatson const char *cp; 9474465Srwatson 9574465Srwatson if (pmask) 9674465Srwatson pmask->s_addr = INADDR_BROADCAST; /* Assume 255.255.255.255 as default */ 9774465Srwatson 9874465Srwatson cp = pmask || pwidth ? strchr(data, '/') : NULL; 9974465Srwatson len = cp ? cp - data : strlen(data); 10074465Srwatson 10174465Srwatson if (ipcp && strncasecmp(data, "HISADDR", len) == 0) 10274465Srwatson *paddr = ipcp->peer_ip; 10374465Srwatson else if (ipcp && strncasecmp(data, "MYADDR", len) == 0) 10474465Srwatson *paddr = ipcp->my_ip; 10574465Srwatson else if (len > 15) 10674465Srwatson log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", data); 10774465Srwatson else { 10874465Srwatson char s[16]; 10974465Srwatson strncpy(s, data, len); 11074465Srwatson s[len] = '\0'; 11174465Srwatson if (inet_aton(s, paddr) == 0) { 11274465Srwatson log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", s); 11374465Srwatson return (0); 11474465Srwatson } 11574465Srwatson } 11674465Srwatson if (cp && *++cp) { 11774465Srwatson bits = strtol(cp, &wp, 0); 11874465Srwatson if (cp == wp || bits < 0 || bits > 32) { 11974465Srwatson log_Printf(LogWARN, "ParseAddr: bad mask width.\n"); 12074465Srwatson return (0); 12174465Srwatson } 12274465Srwatson } else if (paddr->s_addr == INADDR_ANY) 12374465Srwatson /* An IP of 0.0.0.0 without a width is anything */ 12474465Srwatson bits = 0; 12574465Srwatson else 12674465Srwatson /* If a valid IP is given without a width, assume 32 bits */ 12774465Srwatson bits = 32; 12874465Srwatson 12974465Srwatson if (pwidth) 13074465Srwatson *pwidth = bits; 13174465Srwatson 13274465Srwatson if (pmask) { 13374465Srwatson if (paddr->s_addr == INADDR_ANY) 13474465Srwatson pmask->s_addr = INADDR_ANY; 13574465Srwatson else 13674465Srwatson *pmask = bits2mask(bits); 13774465Srwatson } 13874465Srwatson 13974465Srwatson return (1); 14074465Srwatson} 14174465Srwatson 14274465Srwatsonstatic int 14374465SrwatsonParsePort(const char *service, int proto) 14474465Srwatson{ 14574465Srwatson const char *protocol_name; 14674465Srwatson char *cp; 14774465Srwatson struct servent *servent; 14874465Srwatson int port; 14974465Srwatson 15074465Srwatson switch (proto) { 15174465Srwatson case P_UDP: 15274465Srwatson protocol_name = "udp"; 15374465Srwatson break; 15474465Srwatson case P_TCP: 15574465Srwatson protocol_name = "tcp"; 15674465Srwatson break; 15774465Srwatson default: 15874465Srwatson protocol_name = 0; 15974465Srwatson } 16074465Srwatson 16174465Srwatson servent = getservbyname(service, protocol_name); 16274465Srwatson if (servent != 0) 16374465Srwatson return (ntohs(servent->s_port)); 16474465Srwatson 16574465Srwatson port = strtol(service, &cp, 0); 16674465Srwatson if (cp == service) { 16774465Srwatson log_Printf(LogWARN, "ParsePort: %s is not a port name or number.\n", 16874465Srwatson service); 16974465Srwatson return (0); 17074465Srwatson } 17174465Srwatson return (port); 17274465Srwatson} 17374465Srwatson 17474465Srwatson/* 17574465Srwatson * ICMP Syntax: src eq icmp_message_type 17674465Srwatson */ 17774465Srwatsonstatic int 17874465SrwatsonParseIcmp(int argc, char const *const *argv, struct filterent *tgt) 17974465Srwatson{ 18074465Srwatson int type; 18174465Srwatson char *cp; 18274465Srwatson 18374465Srwatson switch (argc) { 18474465Srwatson case 0: 18574465Srwatson /* permit/deny all ICMP types */ 18674465Srwatson tgt->opt.srcop = OP_NONE; 18774465Srwatson break; 18874465Srwatson 18974465Srwatson case 3: 19074465Srwatson if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) { 19174465Srwatson type = strtol(argv[2], &cp, 0); 19274465Srwatson if (cp == argv[2]) { 19374465Srwatson log_Printf(LogWARN, "ParseIcmp: type is expected.\n"); 19474465Srwatson return (0); 19574465Srwatson } 19674465Srwatson tgt->opt.srcop = OP_EQ; 19774465Srwatson tgt->opt.srcport = type; 19874465Srwatson } 19974465Srwatson break; 20074465Srwatson 20174465Srwatson default: 20274465Srwatson log_Printf(LogWARN, "ParseIcmp: bad icmp syntax.\n"); 20374465Srwatson return (0); 20474465Srwatson } 20574465Srwatson return (1); 20674465Srwatson} 20774465Srwatson 20874465Srwatson/* 20974465Srwatson * UDP Syntax: [src op port] [dst op port] 21074465Srwatson */ 21174465Srwatsonstatic int 21274465SrwatsonParseUdpOrTcp(int argc, char const *const *argv, int proto, 21374465Srwatson struct filterent *tgt) 21474465Srwatson{ 21574465Srwatson tgt->opt.srcop = tgt->opt.dstop = OP_NONE; 21674465Srwatson tgt->opt.estab = tgt->opt.syn = tgt->opt.finrst = 0; 21774465Srwatson 21874465Srwatson if (argc >= 3 && !strcmp(*argv, "src")) { 21974465Srwatson tgt->opt.srcop = filter_Nam2Op(argv[1]); 22074465Srwatson if (tgt->opt.srcop == OP_NONE) { 22174465Srwatson log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n"); 22274465Srwatson return (0); 22374465Srwatson } 22474465Srwatson tgt->opt.srcport = ParsePort(argv[2], proto); 22574465Srwatson if (tgt->opt.srcport == 0) 22674465Srwatson return (0); 22774465Srwatson argc -= 3; 22874465Srwatson argv += 3; 22974465Srwatson } 23074465Srwatson 23174465Srwatson if (argc >= 3 && !strcmp(argv[0], "dst")) { 23274465Srwatson tgt->opt.dstop = filter_Nam2Op(argv[1]); 23374465Srwatson if (tgt->opt.dstop == OP_NONE) { 23474465Srwatson log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n"); 23574465Srwatson return (0); 23674465Srwatson } 23774465Srwatson tgt->opt.dstport = ParsePort(argv[2], proto); 23874465Srwatson if (tgt->opt.dstport == 0) 23974465Srwatson return (0); 24074465Srwatson argc -= 3; 24174465Srwatson argv += 3; 24274465Srwatson } 24374465Srwatson 24474465Srwatson if (proto == P_TCP) { 24574465Srwatson for (; argc > 0; argc--, argv++) 24674465Srwatson if (!strcmp(*argv, "estab")) 24774465Srwatson tgt->opt.estab = 1; 24874465Srwatson else if (!strcmp(*argv, "syn")) 24974465Srwatson tgt->opt.syn = 1; 25074465Srwatson else if (!strcmp(*argv, "finrst")) 25174465Srwatson tgt->opt.finrst = 1; 25274465Srwatson else 25374465Srwatson break; 25474465Srwatson } 255 256 if (argc > 0) { 257 log_Printf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv); 258 return 0; 259 } 260 261 return 1; 262} 263 264static unsigned 265addrtype(const char *addr) 266{ 267 if (!strncasecmp(addr, "MYADDR", 6) && (addr[6] == '\0' || addr[6] == '/')) 268 return T_MYADDR; 269 if (!strncasecmp(addr, "HISADDR", 7) && (addr[7] == '\0' || addr[7] == '/')) 270 return T_HISADDR; 271 272 return T_ADDR; 273} 274 275static const char * 276addrstr(struct in_addr addr, unsigned type) 277{ 278 switch (type) { 279 case T_MYADDR: 280 return "MYADDR"; 281 case T_HISADDR: 282 return "HISADDR"; 283 } 284 return inet_ntoa(addr); 285} 286 287static int 288Parse(struct ipcp *ipcp, int argc, char const *const *argv, 289 struct filterent *ofp) 290{ 291 int action, proto; 292 int val; 293 char *wp; 294 struct filterent filterdata; 295 296 val = strtol(*argv, &wp, 0); 297 if (*argv == wp || val > MAXFILTERS) { 298 log_Printf(LogWARN, "Parse: invalid filter number.\n"); 299 return (0); 300 } 301 if (val < 0) { 302 for (val = 0; val < MAXFILTERS; val++) { 303 ofp->action = A_NONE; 304 ofp++; 305 } 306 log_Printf(LogWARN, "Parse: filter cleared.\n"); 307 return (1); 308 } 309 ofp += val; 310 311 if (--argc == 0) { 312 log_Printf(LogWARN, "Parse: missing action.\n"); 313 return (0); 314 } 315 argv++; 316 317 proto = P_NONE; 318 memset(&filterdata, '\0', sizeof filterdata); 319 320 if (!strcmp(*argv, "permit")) { 321 action = A_PERMIT; 322 } else if (!strcmp(*argv, "deny")) { 323 action = A_DENY; 324 } else if (!strcmp(*argv, "clear")) { 325 ofp->action = A_NONE; 326 return (1); 327 } else { 328 log_Printf(LogWARN, "Parse: bad action: %s\n", *argv); 329 return (0); 330 } 331 filterdata.action = action; 332 333 argc--; 334 argv++; 335 336 if (argc && filterdata.action == A_DENY) { 337 if (!strcmp(*argv, "host")) { 338 filterdata.action |= A_UHOST; 339 argc--; 340 argv++; 341 } else if (!strcmp(*argv, "port")) { 342 filterdata.action |= A_UPORT; 343 argc--; 344 argv++; 345 } 346 } 347 348 proto = filter_Nam2Proto(argc, argv); 349 if (proto == P_NONE) { 350 if (!argc) 351 log_Printf(LogWARN, "Parse: address/mask is expected.\n"); 352 else if (ParseAddr(ipcp, *argv, &filterdata.src.ipaddr, 353 &filterdata.src.mask, &filterdata.src.width)) { 354 filterdata.srctype = addrtype(*argv); 355 argc--; 356 argv++; 357 proto = filter_Nam2Proto(argc, argv); 358 if (!argc) 359 log_Printf(LogWARN, "Parse: address/mask is expected.\n"); 360 else if (proto == P_NONE) { 361 if (ParseAddr(ipcp, *argv, &filterdata.dst.ipaddr, &filterdata.dst.mask, 362 &filterdata.dst.width)) { 363 filterdata.dsttype = addrtype(*argv); 364 argc--; 365 argv++; 366 } else 367 filterdata.dsttype = T_ADDR; 368 proto = filter_Nam2Proto(argc, argv); 369 if (argc && proto != P_NONE) { 370 argc--; 371 argv++; 372 } 373 } else { 374 argc--; 375 argv++; 376 } 377 } else { 378 log_Printf(LogWARN, "Parse: Address/protocol expected.\n"); 379 return (0); 380 } 381 } else { 382 argc--; 383 argv++; 384 } 385 386 val = 1; 387 filterdata.proto = proto; 388 389 switch (proto) { 390 case P_TCP: 391 val = ParseUdpOrTcp(argc, argv, P_TCP, &filterdata); 392 break; 393 case P_UDP: 394 val = ParseUdpOrTcp(argc, argv, P_UDP, &filterdata); 395 break; 396 case P_ICMP: 397 val = ParseIcmp(argc, argv, &filterdata); 398 break; 399 } 400 401 log_Printf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(filterdata.src.ipaddr)); 402 log_Printf(LogDEBUG, "Parse: Src mask: %s\n", inet_ntoa(filterdata.src.mask)); 403 log_Printf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(filterdata.dst.ipaddr)); 404 log_Printf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(filterdata.dst.mask)); 405 log_Printf(LogDEBUG, "Parse: Proto = %d\n", proto); 406 407 log_Printf(LogDEBUG, "Parse: src: %s (%d)\n", 408 filter_Op2Nam(filterdata.opt.srcop), filterdata.opt.srcport); 409 log_Printf(LogDEBUG, "Parse: dst: %s (%d)\n", 410 filter_Op2Nam(filterdata.opt.dstop), filterdata.opt.dstport); 411 log_Printf(LogDEBUG, "Parse: estab: %u\n", filterdata.opt.estab); 412 log_Printf(LogDEBUG, "Parse: syn: %u\n", filterdata.opt.syn); 413 log_Printf(LogDEBUG, "Parse: finrst: %u\n", filterdata.opt.finrst); 414 415 if (val) 416 *ofp = filterdata; 417 return (val); 418} 419 420int 421filter_Set(struct cmdargs const *arg) 422{ 423 struct filter *filter; 424 425 if (arg->argc < arg->argn+2) 426 return -1; 427 428 if (!strcmp(arg->argv[arg->argn], "in")) 429 filter = &arg->bundle->filter.in; 430 else if (!strcmp(arg->argv[arg->argn], "out")) 431 filter = &arg->bundle->filter.out; 432 else if (!strcmp(arg->argv[arg->argn], "dial")) 433 filter = &arg->bundle->filter.dial; 434 else if (!strcmp(arg->argv[arg->argn], "alive")) 435 filter = &arg->bundle->filter.alive; 436 else { 437 log_Printf(LogWARN, "filter_Set: %s: Invalid filter name.\n", 438 arg->argv[arg->argn]); 439 return -1; 440 } 441 442 Parse(&arg->bundle->ncp.ipcp, arg->argc - arg->argn - 1, 443 arg->argv + arg->argn + 1, filter->rule); 444 return 0; 445} 446 447const char * 448filter_Action2Nam(int act) 449{ 450 static const char *actname[] = { "none ", "permit ", "deny " }; 451 return actname[act & (A_PERMIT|A_DENY)]; 452} 453 454static void 455doShowFilter(struct filterent *fp, struct prompt *prompt) 456{ 457 int n; 458 459 for (n = 0; n < MAXFILTERS; n++, fp++) { 460 if (fp->action != A_NONE) { 461 prompt_Printf(prompt, " %2d %s", n, filter_Action2Nam(fp->action)); 462 if (fp->action & A_UHOST) 463 prompt_Printf(prompt, "host "); 464 else if (fp->action & A_UPORT) 465 prompt_Printf(prompt, "port "); 466 else 467 prompt_Printf(prompt, " "); 468 prompt_Printf(prompt, "%s/%d ", addrstr(fp->src.ipaddr, fp->srctype), 469 fp->src.width); 470 prompt_Printf(prompt, "%s/%d ", addrstr(fp->dst.ipaddr, fp->dsttype), 471 fp->dst.width); 472 if (fp->proto) { 473 prompt_Printf(prompt, "%s", filter_Proto2Nam(fp->proto)); 474 475 if (fp->opt.srcop) 476 prompt_Printf(prompt, " src %s %d", filter_Op2Nam(fp->opt.srcop), 477 fp->opt.srcport); 478 if (fp->opt.dstop) 479 prompt_Printf(prompt, " dst %s %d", filter_Op2Nam(fp->opt.dstop), 480 fp->opt.dstport); 481 if (fp->opt.estab) 482 prompt_Printf(prompt, " estab"); 483 if (fp->opt.syn) 484 prompt_Printf(prompt, " syn"); 485 if (fp->opt.finrst) 486 prompt_Printf(prompt, " finrst"); 487 } 488 prompt_Printf(prompt, "\n"); 489 } 490 } 491} 492 493int 494filter_Show(struct cmdargs const *arg) 495{ 496 if (arg->argc > arg->argn+1) 497 return -1; 498 499 if (arg->argc == arg->argn+1) { 500 struct filter *filter; 501 502 if (!strcmp(arg->argv[arg->argn], "in")) 503 filter = &arg->bundle->filter.in; 504 else if (!strcmp(arg->argv[arg->argn], "out")) 505 filter = &arg->bundle->filter.out; 506 else if (!strcmp(arg->argv[arg->argn], "dial")) 507 filter = &arg->bundle->filter.dial; 508 else if (!strcmp(arg->argv[arg->argn], "alive")) 509 filter = &arg->bundle->filter.alive; 510 else 511 return -1; 512 doShowFilter(filter->rule, arg->prompt); 513 } else { 514 struct filter *filter[4]; 515 int f; 516 517 filter[0] = &arg->bundle->filter.in; 518 filter[1] = &arg->bundle->filter.out; 519 filter[2] = &arg->bundle->filter.dial; 520 filter[3] = &arg->bundle->filter.alive; 521 for (f = 0; f < 4; f++) { 522 if (f) 523 prompt_Printf(arg->prompt, "\n"); 524 prompt_Printf(arg->prompt, "%s:\n", filter[f]->name); 525 doShowFilter(filter[f]->rule, arg->prompt); 526 } 527 } 528 529 return 0; 530} 531 532static const char *protoname[] = { "none", "tcp", "udp", "icmp" }; 533 534const char * 535filter_Proto2Nam(int proto) 536{ 537 if (proto >= sizeof protoname / sizeof protoname[0]) 538 return "unknown"; 539 return protoname[proto]; 540} 541 542static int 543filter_Nam2Proto(int argc, char const *const *argv) 544{ 545 int proto; 546 547 if (argc == 0) 548 proto = 0; 549 else 550 for (proto = sizeof protoname / sizeof protoname[0] - 1; proto; proto--) 551 if (!strcasecmp(*argv, protoname[proto])) 552 break; 553 554 return proto; 555} 556 557static const char *opname[] = {"none", "eq", "gt", "unknown", "lt"}; 558 559const char * 560filter_Op2Nam(int op) 561{ 562 if (op >= sizeof opname / sizeof opname[0]) 563 return "unknown"; 564 return opname[op]; 565 566} 567 568static int 569filter_Nam2Op(const char *cp) 570{ 571 int op; 572 573 for (op = sizeof opname / sizeof opname[0] - 1; op; op--) 574 if (!strcasecmp(cp, opname[op])) 575 break; 576 577 return op; 578} 579 580void 581filter_AdjustAddr(struct filter *filter, struct in_addr *my_ip, 582 struct in_addr *peer_ip) 583{ 584 struct filterent *fp; 585 int n; 586 587 for (fp = filter->rule, n = 0; n < MAXFILTERS; fp++, n++) 588 if (fp->action != A_NONE) { 589 if (my_ip) { 590 if (fp->srctype == T_MYADDR) 591 fp->src.ipaddr = *my_ip; 592 if (fp->dsttype == T_MYADDR) 593 fp->dst.ipaddr = *my_ip; 594 } 595 if (peer_ip) { 596 if (fp->srctype == T_HISADDR) 597 fp->src.ipaddr = *peer_ip; 598 if (fp->dsttype == T_HISADDR) 599 fp->dst.ipaddr = *peer_ip; 600 } 601 } 602} 603