1 /*- 2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 4 * Internet Initiative Japan, Inc (IIJ) 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 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <netinet/in.h> 33 #include <netdb.h> 34 #include <netinet/in_systm.h> 35 #include <netinet/ip.h> 36 #include <sys/socket.h> 37 #include <sys/un.h> 38 39 #include <stdarg.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <termios.h> 44 45 #include "layer.h" 46 #include "defs.h" 47 #include "command.h" 48 #include "mbuf.h" 49 #include "log.h" 50 #include "iplist.h" 51 #include "timer.h" 52 #include "throughput.h" 53 #include "lqr.h" 54 #include "hdlc.h" 55 #include "fsm.h" 56 #include "lcp.h" 57 #include "ccp.h" 58 #include "link.h" 59 #include "slcompress.h" 60 #include "ncpaddr.h" 61 #include "ipcp.h" 62 #include "filter.h" 63 #include "descriptor.h" 64 #include "prompt.h" 65 #include "mp.h" 66 #ifndef NORADIUS 67 #include "radius.h" 68 #endif 69 #include "ipv6cp.h" 70 #include "ncp.h" 71 #include "bundle.h" 72 73 static unsigned filter_Nam2Op(const char *); 74 75 static int 76 ParsePort(const char *service, const char *proto) 77 { 78 struct servent *servent; 79 char *cp; 80 int port; 81 82 servent = getservbyname(service, proto); 83 if (servent != NULL) 84 return ntohs(servent->s_port); 85 86 port = strtol(service, &cp, 0); 87 if (cp == service) { 88 log_Printf(LogWARN, "ParsePort: %s is not a port name or number.\n", 89 service); 90 return 0; 91 } 92 return port; 93 } 94 95 /* 96 * ICMP Syntax: src eq icmp_message_type 97 */ 98 static int 99 ParseIcmp(int argc, char const *const *argv, struct filterent *tgt) 100 { 101 int type; 102 char *cp; 103 104 switch (argc) { 105 case 0: 106 /* permit/deny all ICMP types */ 107 tgt->f_srcop = tgt->f_dstop = OP_NONE; 108 break; 109 110 case 3: 111 if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) { 112 type = strtol(argv[2], &cp, 0); 113 if (cp == argv[2]) { 114 log_Printf(LogWARN, "ParseIcmp: type is expected.\n"); 115 return 0; 116 } 117 tgt->f_srcop = OP_EQ; 118 tgt->f_srcport = type; 119 tgt->f_dstop = OP_NONE; 120 } 121 break; 122 123 default: 124 log_Printf(LogWARN, "ParseIcmp: bad icmp syntax.\n"); 125 return 0; 126 } 127 return 1; 128 } 129 130 /* 131 * UDP Syntax: [src op port] [dst op port] 132 */ 133 static int 134 ParseUdpOrTcp(int argc, char const *const *argv, const struct protoent *pe, 135 struct filterent *tgt) 136 { 137 tgt->f_srcop = tgt->f_dstop = OP_NONE; 138 tgt->f_estab = tgt->f_syn = tgt->f_finrst = 0; 139 140 if (argc >= 3 && !strcmp(*argv, "src")) { 141 tgt->f_srcop = filter_Nam2Op(argv[1]); 142 if (tgt->f_srcop == OP_NONE) { 143 log_Printf(LogWARN, "ParseUdpOrTcp: bad operator\n"); 144 return 0; 145 } 146 if (pe == NULL) 147 return 0; 148 tgt->f_srcport = ParsePort(argv[2], pe->p_name); 149 if (tgt->f_srcport == 0) 150 return 0; 151 argc -= 3; 152 argv += 3; 153 } 154 155 if (argc >= 3 && !strcmp(argv[0], "dst")) { 156 tgt->f_dstop = filter_Nam2Op(argv[1]); 157 if (tgt->f_dstop == OP_NONE) { 158 log_Printf(LogWARN, "ParseUdpOrTcp: bad operator\n"); 159 return 0; 160 } 161 if (pe == NULL) 162 return 0; 163 tgt->f_dstport = ParsePort(argv[2], pe->p_name); 164 if (tgt->f_dstport == 0) 165 return 0; 166 argc -= 3; 167 argv += 3; 168 } 169 170 if (pe && pe->p_proto == IPPROTO_TCP) { 171 for (; argc > 0; argc--, argv++) 172 if (!strcmp(*argv, "estab")) 173 tgt->f_estab = 1; 174 else if (!strcmp(*argv, "syn")) 175 tgt->f_syn = 1; 176 else if (!strcmp(*argv, "finrst")) 177 tgt->f_finrst = 1; 178 else 179 break; 180 } 181 182 if (argc > 0) { 183 log_Printf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv); 184 return 0; 185 } 186 187 return 1; 188 } 189 190 static int 191 ParseGeneric(int argc, struct filterent *tgt) 192 { 193 /* 194 * Filter currently is a catch-all. Requests are either permitted or 195 * dropped. 196 */ 197 if (argc != 0) { 198 log_Printf(LogWARN, "ParseGeneric: Too many parameters\n"); 199 return 0; 200 } else 201 tgt->f_srcop = tgt->f_dstop = OP_NONE; 202 203 return 1; 204 } 205 206 static unsigned 207 addrtype(const char *addr) 208 { 209 if (!strncasecmp(addr, "MYADDR", 6) && (addr[6] == '\0' || addr[6] == '/')) 210 return T_MYADDR; 211 if (!strncasecmp(addr, "MYADDR6", 7) && (addr[7] == '\0' || addr[7] == '/')) 212 return T_MYADDR6; 213 if (!strncasecmp(addr, "HISADDR", 7) && (addr[7] == '\0' || addr[7] == '/')) 214 return T_HISADDR; 215 if (!strncasecmp(addr, "HISADDR6", 8) && (addr[8] == '\0' || addr[8] == '/')) 216 return T_HISADDR6; 217 if (!strncasecmp(addr, "DNS0", 4) && (addr[4] == '\0' || addr[4] == '/')) 218 return T_DNS0; 219 if (!strncasecmp(addr, "DNS1", 4) && (addr[4] == '\0' || addr[4] == '/')) 220 return T_DNS1; 221 222 return T_ADDR; 223 } 224 225 static const char * 226 addrstr(struct ncprange *addr, unsigned type) 227 { 228 switch (type) { 229 case T_MYADDR: 230 return "MYADDR"; 231 case T_HISADDR: 232 return "HISADDR"; 233 case T_DNS0: 234 return "DNS0"; 235 case T_DNS1: 236 return "DNS1"; 237 } 238 return ncprange_ntoa(addr); 239 } 240 241 static int 242 filter_Parse(struct ncp *ncp, int argc, char const *const *argv, 243 struct filterent *ofp) 244 { 245 struct filterent fe; 246 struct protoent *pe; 247 char *wp; 248 int action, family, ruleno, val, width; 249 250 ruleno = strtol(*argv, &wp, 0); 251 if (*argv == wp || ruleno >= MAXFILTERS) { 252 log_Printf(LogWARN, "Parse: invalid filter number.\n"); 253 return 0; 254 } 255 if (ruleno < 0) { 256 for (ruleno = 0; ruleno < MAXFILTERS; ruleno++) { 257 ofp->f_action = A_NONE; 258 ofp++; 259 } 260 log_Printf(LogWARN, "Parse: filter cleared.\n"); 261 return 1; 262 } 263 ofp += ruleno; 264 265 if (--argc == 0) { 266 log_Printf(LogWARN, "Parse: missing action.\n"); 267 return 0; 268 } 269 argv++; 270 271 memset(&fe, '\0', sizeof fe); 272 273 val = strtol(*argv, &wp, 0); 274 if (!*wp && val >= 0 && val < MAXFILTERS) { 275 if (val <= ruleno) { 276 log_Printf(LogWARN, "Parse: Can only jump forward from rule %d\n", 277 ruleno); 278 return 0; 279 } 280 action = val; 281 } else if (!strcmp(*argv, "permit")) { 282 action = A_PERMIT; 283 } else if (!strcmp(*argv, "deny")) { 284 action = A_DENY; 285 } else if (!strcmp(*argv, "clear")) { 286 ofp->f_action = A_NONE; 287 return 1; 288 } else { 289 log_Printf(LogWARN, "Parse: %s: bad action\n", *argv); 290 return 0; 291 } 292 fe.f_action = action; 293 294 argc--; 295 argv++; 296 297 if (argc && argv[0][0] == '!' && !argv[0][1]) { 298 fe.f_invert = 1; 299 argc--; 300 argv++; 301 } 302 303 ncprange_init(&fe.f_src); 304 ncprange_init(&fe.f_dst); 305 306 if (argc == 0) 307 pe = NULL; 308 else if ((pe = getprotobyname(*argv)) == NULL && strcmp(*argv, "all") != 0) { 309 if (argc < 2) { 310 log_Printf(LogWARN, "Parse: Protocol or address pair expected\n"); 311 return 0; 312 } else if (strcasecmp(*argv, "any") == 0 || 313 ncprange_aton(&fe.f_src, ncp, *argv)) { 314 family = ncprange_family(&fe.f_src); 315 if (!ncprange_getwidth(&fe.f_src, &width)) 316 width = 0; 317 if (width == 0) 318 ncprange_init(&fe.f_src); 319 fe.f_srctype = addrtype(*argv); 320 argc--; 321 argv++; 322 323 if (strcasecmp(*argv, "any") == 0 || 324 ncprange_aton(&fe.f_dst, ncp, *argv)) { 325 if (ncprange_family(&fe.f_dst) != AF_UNSPEC && 326 ncprange_family(&fe.f_src) != AF_UNSPEC && 327 family != ncprange_family(&fe.f_dst)) { 328 log_Printf(LogWARN, "Parse: src and dst address families differ\n"); 329 return 0; 330 } 331 if (!ncprange_getwidth(&fe.f_dst, &width)) 332 width = 0; 333 if (width == 0) 334 ncprange_init(&fe.f_dst); 335 fe.f_dsttype = addrtype(*argv); 336 argc--; 337 argv++; 338 } else { 339 log_Printf(LogWARN, "Parse: Protocol or address pair expected\n"); 340 return 0; 341 } 342 343 if (argc) { 344 if ((pe = getprotobyname(*argv)) == NULL && strcmp(*argv, "all") != 0) { 345 log_Printf(LogWARN, "Parse: %s: Protocol expected\n", *argv); 346 return 0; 347 } else { 348 argc--; 349 argv++; 350 } 351 } 352 } else { 353 log_Printf(LogWARN, "Parse: Protocol or address pair expected\n"); 354 return 0; 355 } 356 } else { 357 argc--; 358 argv++; 359 } 360 361 if (argc >= 2 && strcmp(*argv, "timeout") == 0) { 362 fe.timeout = strtoul(argv[1], NULL, 10); 363 argc -= 2; 364 argv += 2; 365 } 366 367 val = 1; 368 fe.f_proto = (pe == NULL) ? 0 : pe->p_proto; 369 370 switch (fe.f_proto) { 371 case IPPROTO_TCP: 372 case IPPROTO_UDP: 373 case IPPROTO_IPIP: 374 #ifndef NOINET6 375 case IPPROTO_IPV6: 376 #endif 377 val = ParseUdpOrTcp(argc, argv, pe, &fe); 378 break; 379 case IPPROTO_ICMP: 380 #ifndef NOINET6 381 case IPPROTO_ICMPV6: 382 #endif 383 val = ParseIcmp(argc, argv, &fe); 384 break; 385 default: 386 val = ParseGeneric(argc, &fe); 387 break; 388 } 389 390 log_Printf(LogDEBUG, "Parse: Src: %s\n", ncprange_ntoa(&fe.f_src)); 391 log_Printf(LogDEBUG, "Parse: Dst: %s\n", ncprange_ntoa(&fe.f_dst)); 392 log_Printf(LogDEBUG, "Parse: Proto: %d\n", fe.f_proto); 393 394 log_Printf(LogDEBUG, "Parse: src: %s (%d)\n", 395 filter_Op2Nam(fe.f_srcop), fe.f_srcport); 396 log_Printf(LogDEBUG, "Parse: dst: %s (%d)\n", 397 filter_Op2Nam(fe.f_dstop), fe.f_dstport); 398 log_Printf(LogDEBUG, "Parse: estab: %u\n", fe.f_estab); 399 log_Printf(LogDEBUG, "Parse: syn: %u\n", fe.f_syn); 400 log_Printf(LogDEBUG, "Parse: finrst: %u\n", fe.f_finrst); 401 402 if (val) 403 *ofp = fe; 404 405 return val; 406 } 407 408 int 409 filter_Set(struct cmdargs const *arg) 410 { 411 struct filter *filter; 412 413 if (arg->argc < arg->argn+2) 414 return -1; 415 416 if (!strcmp(arg->argv[arg->argn], "in")) 417 filter = &arg->bundle->filter.in; 418 else if (!strcmp(arg->argv[arg->argn], "out")) 419 filter = &arg->bundle->filter.out; 420 else if (!strcmp(arg->argv[arg->argn], "dial")) 421 filter = &arg->bundle->filter.dial; 422 else if (!strcmp(arg->argv[arg->argn], "alive")) 423 filter = &arg->bundle->filter.alive; 424 else { 425 log_Printf(LogWARN, "filter_Set: %s: Invalid filter name.\n", 426 arg->argv[arg->argn]); 427 return -1; 428 } 429 430 filter_Parse(&arg->bundle->ncp, arg->argc - arg->argn - 1, 431 arg->argv + arg->argn + 1, filter->rule); 432 return 0; 433 } 434 435 const char * 436 filter_Action2Nam(unsigned act) 437 { 438 static const char * const actname[] = { " none ", "permit ", " deny " }; 439 static char buf[8]; 440 441 if (act < MAXFILTERS) { 442 snprintf(buf, sizeof buf, "%6d ", act); 443 return buf; 444 } else if (act >= A_NONE && act < A_NONE + sizeof(actname)/sizeof(char *)) 445 return actname[act - A_NONE]; 446 else 447 return "?????? "; 448 } 449 450 static void 451 doShowFilter(struct filterent *fp, struct prompt *prompt) 452 { 453 struct protoent *pe; 454 int n; 455 456 for (n = 0; n < MAXFILTERS; n++, fp++) { 457 if (fp->f_action != A_NONE) { 458 prompt_Printf(prompt, " %2d %s", n, filter_Action2Nam(fp->f_action)); 459 prompt_Printf(prompt, "%c ", fp->f_invert ? '!' : ' '); 460 461 if (ncprange_isset(&fp->f_src)) 462 prompt_Printf(prompt, "%s ", addrstr(&fp->f_src, fp->f_srctype)); 463 else 464 prompt_Printf(prompt, "any "); 465 466 if (ncprange_isset(&fp->f_dst)) 467 prompt_Printf(prompt, "%s ", addrstr(&fp->f_dst, fp->f_dsttype)); 468 else 469 prompt_Printf(prompt, "any "); 470 471 if (fp->f_proto) { 472 if ((pe = getprotobynumber(fp->f_proto)) == NULL) 473 prompt_Printf(prompt, "P:%d", fp->f_proto); 474 else 475 prompt_Printf(prompt, "%s", pe->p_name); 476 477 if (fp->f_srcop) 478 prompt_Printf(prompt, " src %s %d", filter_Op2Nam(fp->f_srcop), 479 fp->f_srcport); 480 if (fp->f_dstop) 481 prompt_Printf(prompt, " dst %s %d", filter_Op2Nam(fp->f_dstop), 482 fp->f_dstport); 483 if (fp->f_estab) 484 prompt_Printf(prompt, " estab"); 485 if (fp->f_syn) 486 prompt_Printf(prompt, " syn"); 487 if (fp->f_finrst) 488 prompt_Printf(prompt, " finrst"); 489 } else 490 prompt_Printf(prompt, "all"); 491 if (fp->timeout != 0) 492 prompt_Printf(prompt, " timeout %u", fp->timeout); 493 prompt_Printf(prompt, "\n"); 494 } 495 } 496 } 497 498 int 499 filter_Show(struct cmdargs const *arg) 500 { 501 if (arg->argc > arg->argn+1) 502 return -1; 503 504 if (arg->argc == arg->argn+1) { 505 struct filter *filter; 506 507 if (!strcmp(arg->argv[arg->argn], "in")) 508 filter = &arg->bundle->filter.in; 509 else if (!strcmp(arg->argv[arg->argn], "out")) 510 filter = &arg->bundle->filter.out; 511 else if (!strcmp(arg->argv[arg->argn], "dial")) 512 filter = &arg->bundle->filter.dial; 513 else if (!strcmp(arg->argv[arg->argn], "alive")) 514 filter = &arg->bundle->filter.alive; 515 else 516 return -1; 517 doShowFilter(filter->rule, arg->prompt); 518 } else { 519 struct filter *filter[4]; 520 int f; 521 522 filter[0] = &arg->bundle->filter.in; 523 filter[1] = &arg->bundle->filter.out; 524 filter[2] = &arg->bundle->filter.dial; 525 filter[3] = &arg->bundle->filter.alive; 526 for (f = 0; f < 4; f++) { 527 if (f) 528 prompt_Printf(arg->prompt, "\n"); 529 prompt_Printf(arg->prompt, "%s:\n", filter[f]->name); 530 doShowFilter(filter[f]->rule, arg->prompt); 531 } 532 } 533 534 return 0; 535 } 536 537 static const char * const opname[] = {"none", "eq", "gt", "lt"}; 538 539 const char * 540 filter_Op2Nam(unsigned op) 541 { 542 if (op >= sizeof opname / sizeof opname[0]) 543 return "unknown"; 544 return opname[op]; 545 546 } 547 548 static unsigned 549 filter_Nam2Op(const char *cp) 550 { 551 unsigned op; 552 553 for (op = sizeof opname / sizeof opname[0] - 1; op; op--) 554 if (!strcasecmp(cp, opname[op])) 555 break; 556 557 return op; 558 } 559 560 void 561 filter_AdjustAddr(struct filter *filter, struct ncpaddr *local, 562 struct ncpaddr *remote, struct in_addr *dns) 563 { 564 struct filterent *fp; 565 int n; 566 567 for (fp = filter->rule, n = 0; n < MAXFILTERS; fp++, n++) 568 if (fp->f_action != A_NONE) { 569 if (local) { 570 if (fp->f_srctype == T_MYADDR && ncpaddr_family(local) == AF_INET) 571 ncprange_sethost(&fp->f_src, local); 572 if (fp->f_dsttype == T_MYADDR && ncpaddr_family(local) == AF_INET) 573 ncprange_sethost(&fp->f_dst, local); 574 #ifndef NOINET6 575 if (fp->f_srctype == T_MYADDR6 && ncpaddr_family(local) == AF_INET6) 576 ncprange_sethost(&fp->f_src, local); 577 if (fp->f_dsttype == T_MYADDR6 && ncpaddr_family(local) == AF_INET6) 578 ncprange_sethost(&fp->f_dst, local); 579 #endif 580 } 581 if (remote) { 582 if (fp->f_srctype == T_HISADDR && ncpaddr_family(remote) == AF_INET) 583 ncprange_sethost(&fp->f_src, remote); 584 if (fp->f_dsttype == T_HISADDR && ncpaddr_family(remote) == AF_INET) 585 ncprange_sethost(&fp->f_dst, remote); 586 #ifndef NOINET6 587 if (fp->f_srctype == T_HISADDR6 && ncpaddr_family(remote) == AF_INET6) 588 ncprange_sethost(&fp->f_src, remote); 589 if (fp->f_dsttype == T_HISADDR6 && ncpaddr_family(remote) == AF_INET6) 590 ncprange_sethost(&fp->f_dst, remote); 591 #endif 592 } 593 if (dns) { 594 if (fp->f_srctype == T_DNS0) 595 ncprange_setip4host(&fp->f_src, dns[0]); 596 if (fp->f_dsttype == T_DNS0) 597 ncprange_setip4host(&fp->f_dst, dns[0]); 598 if (fp->f_srctype == T_DNS1) 599 ncprange_setip4host(&fp->f_src, dns[1]); 600 if (fp->f_dsttype == T_DNS1) 601 ncprange_setip4host(&fp->f_dst, dns[1]); 602 } 603 } 604 } 605