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 * $Id: filter.c,v 1.25 1998/06/27 12:03:48 brian Exp $ 21 * 22 * TODO: Shoud send ICMP error message when we discard packets. 23 */ 24 25 #include <sys/types.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 "defs.h" 39 #include "command.h" 40 #include "mbuf.h" 41 #include "log.h" 42 #include "iplist.h" 43 #include "timer.h" 44 #include "throughput.h" 45 #include "lqr.h" 46 #include "hdlc.h" 47 #include "fsm.h" 48 #include "lcp.h" 49 #include "ccp.h" 50 #include "link.h" 51 #include "slcompress.h" 52 #include "ipcp.h" 53 #include "filter.h" 54 #include "descriptor.h" 55 #include "prompt.h" 56 #include "mp.h" 57 #include "bundle.h" 58 59 static int filter_Nam2Proto(int, char const *const *); 60 static int filter_Nam2Op(const char *); 61 62 static const u_int32_t netmasks[33] = { 63 0x00000000, 64 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, 65 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000, 66 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000, 67 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, 68 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, 69 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, 70 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0, 71 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF, 72 }; 73 74 int 75 ParseAddr(struct ipcp *ipcp, int argc, char const *const *argv, 76 struct in_addr *paddr, struct in_addr *pmask, int *pwidth) 77 { 78 int bits, len; 79 char *wp; 80 const char *cp; 81 82 if (argc < 1) { 83 log_Printf(LogWARN, "ParseAddr: address/mask is expected.\n"); 84 return (0); 85 } 86 87 if (pmask) 88 pmask->s_addr = INADDR_BROADCAST; /* Assume 255.255.255.255 as default */ 89 90 cp = pmask || pwidth ? strchr(*argv, '/') : NULL; 91 len = cp ? cp - *argv : strlen(*argv); 92 93 if (ipcp && strncasecmp(*argv, "HISADDR", len) == 0) 94 *paddr = ipcp->peer_ip; 95 else if (ipcp && strncasecmp(*argv, "MYADDR", len) == 0) 96 *paddr = ipcp->my_ip; 97 else if (len > 15) 98 log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", *argv); 99 else { 100 char s[16]; 101 strncpy(s, *argv, len); 102 s[len] = '\0'; 103 if (inet_aton(s, paddr) == 0) { 104 log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", s); 105 return (0); 106 } 107 } 108 if (cp && *++cp) { 109 bits = strtol(cp, &wp, 0); 110 if (cp == wp || bits < 0 || bits > 32) { 111 log_Printf(LogWARN, "ParseAddr: bad mask width.\n"); 112 return (0); 113 } 114 } else if (paddr->s_addr == INADDR_ANY) 115 /* An IP of 0.0.0.0 without a width is anything */ 116 bits = 0; 117 else 118 /* If a valid IP is given without a width, assume 32 bits */ 119 bits = 32; 120 121 if (pwidth) 122 *pwidth = bits; 123 124 if (pmask) { 125 if (paddr->s_addr == INADDR_ANY) 126 pmask->s_addr = INADDR_ANY; 127 else 128 pmask->s_addr = htonl(netmasks[bits]); 129 } 130 131 return (1); 132 } 133 134 static int 135 ParsePort(const char *service, int proto) 136 { 137 const char *protocol_name; 138 char *cp; 139 struct servent *servent; 140 int port; 141 142 switch (proto) { 143 case P_UDP: 144 protocol_name = "udp"; 145 break; 146 case P_TCP: 147 protocol_name = "tcp"; 148 break; 149 default: 150 protocol_name = 0; 151 } 152 153 servent = getservbyname(service, protocol_name); 154 if (servent != 0) 155 return (ntohs(servent->s_port)); 156 157 port = strtol(service, &cp, 0); 158 if (cp == service) { 159 log_Printf(LogWARN, "ParsePort: %s is not a port name or number.\n", 160 service); 161 return (0); 162 } 163 return (port); 164 } 165 166 /* 167 * ICMP Syntax: src eq icmp_message_type 168 */ 169 static int 170 ParseIcmp(int argc, char const *const *argv, struct filterent *tgt) 171 { 172 int type; 173 char *cp; 174 175 switch (argc) { 176 case 0: 177 /* permit/deny all ICMP types */ 178 tgt->opt.srcop = OP_NONE; 179 break; 180 181 case 3: 182 if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) { 183 type = strtol(argv[2], &cp, 0); 184 if (cp == argv[2]) { 185 log_Printf(LogWARN, "ParseIcmp: type is expected.\n"); 186 return (0); 187 } 188 tgt->opt.srcop = OP_EQ; 189 tgt->opt.srcport = type; 190 } 191 break; 192 193 default: 194 log_Printf(LogWARN, "ParseIcmp: bad icmp syntax.\n"); 195 return (0); 196 } 197 return (1); 198 } 199 200 /* 201 * UDP Syntax: [src op port] [dst op port] 202 */ 203 static int 204 ParseUdpOrTcp(int argc, char const *const *argv, int proto, 205 struct filterent *tgt) 206 { 207 tgt->opt.srcop = tgt->opt.dstop = OP_NONE; 208 tgt->opt.estab = tgt->opt.syn = tgt->opt.finrst = 0; 209 210 if (argc >= 3 && !strcmp(*argv, "src")) { 211 tgt->opt.srcop = filter_Nam2Op(argv[1]); 212 if (tgt->opt.srcop == OP_NONE) { 213 log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n"); 214 return (0); 215 } 216 tgt->opt.srcport = ParsePort(argv[2], proto); 217 if (tgt->opt.srcport == 0) 218 return (0); 219 argc -= 3; 220 argv += 3; 221 } 222 223 if (argc >= 3 && !strcmp(argv[0], "dst")) { 224 tgt->opt.dstop = filter_Nam2Op(argv[1]); 225 if (tgt->opt.dstop == OP_NONE) { 226 log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n"); 227 return (0); 228 } 229 tgt->opt.dstport = ParsePort(argv[2], proto); 230 if (tgt->opt.dstport == 0) 231 return (0); 232 argc -= 3; 233 argv += 3; 234 } 235 236 if (proto == P_TCP) { 237 for (; argc > 0; argc--, argv++) 238 if (!strcmp(*argv, "estab")) 239 tgt->opt.estab = 1; 240 else if (!strcmp(*argv, "syn")) 241 tgt->opt.syn = 1; 242 else if (!strcmp(*argv, "finrst")) 243 tgt->opt.finrst = 1; 244 else 245 break; 246 } 247 248 if (argc > 0) { 249 log_Printf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv); 250 return 0; 251 } 252 253 return 1; 254 } 255 256 static int 257 Parse(struct ipcp *ipcp, int argc, char const *const *argv, 258 struct filterent *ofp) 259 { 260 int action, proto; 261 int val; 262 char *wp; 263 struct filterent filterdata; 264 265 val = strtol(*argv, &wp, 0); 266 if (*argv == wp || val > MAXFILTERS) { 267 log_Printf(LogWARN, "Parse: invalid filter number.\n"); 268 return (0); 269 } 270 if (val < 0) { 271 for (val = 0; val < MAXFILTERS; val++) { 272 ofp->action = A_NONE; 273 ofp++; 274 } 275 log_Printf(LogWARN, "Parse: filter cleared.\n"); 276 return (1); 277 } 278 ofp += val; 279 280 if (--argc == 0) { 281 log_Printf(LogWARN, "Parse: missing action.\n"); 282 return (0); 283 } 284 argv++; 285 286 proto = P_NONE; 287 memset(&filterdata, '\0', sizeof filterdata); 288 289 if (!strcmp(*argv, "permit")) { 290 action = A_PERMIT; 291 } else if (!strcmp(*argv, "deny")) { 292 action = A_DENY; 293 } else if (!strcmp(*argv, "clear")) { 294 ofp->action = A_NONE; 295 return (1); 296 } else { 297 log_Printf(LogWARN, "Parse: bad action: %s\n", *argv); 298 return (0); 299 } 300 filterdata.action = action; 301 302 argc--; 303 argv++; 304 305 if (filterdata.action == A_DENY) { 306 if (!strcmp(*argv, "host")) { 307 filterdata.action |= A_UHOST; 308 argc--; 309 argv++; 310 } else if (!strcmp(*argv, "port")) { 311 filterdata.action |= A_UPORT; 312 argc--; 313 argv++; 314 } 315 } 316 proto = filter_Nam2Proto(argc, argv); 317 if (proto == P_NONE) { 318 if (ParseAddr(ipcp, argc, argv, &filterdata.saddr, &filterdata.smask, 319 &filterdata.swidth)) { 320 argc--; 321 argv++; 322 proto = filter_Nam2Proto(argc, argv); 323 if (proto == P_NONE) { 324 if (ParseAddr(ipcp, argc, argv, &filterdata.daddr, &filterdata.dmask, 325 &filterdata.dwidth)) { 326 argc--; 327 argv++; 328 } 329 proto = filter_Nam2Proto(argc, argv); 330 if (proto != P_NONE) { 331 argc--; 332 argv++; 333 } 334 } else { 335 argc--; 336 argv++; 337 } 338 } else { 339 log_Printf(LogWARN, "Parse: Address/protocol expected.\n"); 340 return (0); 341 } 342 } else { 343 argc--; 344 argv++; 345 } 346 347 val = 1; 348 filterdata.proto = proto; 349 350 switch (proto) { 351 case P_TCP: 352 val = ParseUdpOrTcp(argc, argv, P_TCP, &filterdata); 353 break; 354 case P_UDP: 355 val = ParseUdpOrTcp(argc, argv, P_UDP, &filterdata); 356 break; 357 case P_ICMP: 358 val = ParseIcmp(argc, argv, &filterdata); 359 break; 360 } 361 362 log_Printf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(filterdata.saddr)); 363 log_Printf(LogDEBUG, "Parse: Src mask: %s\n", inet_ntoa(filterdata.smask)); 364 log_Printf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(filterdata.daddr)); 365 log_Printf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(filterdata.dmask)); 366 log_Printf(LogDEBUG, "Parse: Proto = %d\n", proto); 367 368 log_Printf(LogDEBUG, "Parse: src: %s (%d)\n", 369 filter_Op2Nam(filterdata.opt.srcop), filterdata.opt.srcport); 370 log_Printf(LogDEBUG, "Parse: dst: %s (%d)\n", 371 filter_Op2Nam(filterdata.opt.dstop), filterdata.opt.dstport); 372 log_Printf(LogDEBUG, "Parse: estab: %u\n", filterdata.opt.estab); 373 log_Printf(LogDEBUG, "Parse: syn: %u\n", filterdata.opt.syn); 374 log_Printf(LogDEBUG, "Parse: finrst: %u\n", filterdata.opt.finrst); 375 376 if (val) 377 *ofp = filterdata; 378 return (val); 379 } 380 381 int 382 filter_Set(struct cmdargs const *arg) 383 { 384 struct filter *filter; 385 386 if (arg->argc < arg->argn+2) 387 return -1; 388 389 if (!strcmp(arg->argv[arg->argn], "in")) 390 filter = &arg->bundle->filter.in; 391 else if (!strcmp(arg->argv[arg->argn], "out")) 392 filter = &arg->bundle->filter.out; 393 else if (!strcmp(arg->argv[arg->argn], "dial")) 394 filter = &arg->bundle->filter.dial; 395 else if (!strcmp(arg->argv[arg->argn], "alive")) 396 filter = &arg->bundle->filter.alive; 397 else { 398 log_Printf(LogWARN, "filter_Set: %s: Invalid filter name.\n", 399 arg->argv[arg->argn]); 400 return -1; 401 } 402 403 Parse(&arg->bundle->ncp.ipcp, arg->argc - arg->argn - 1, 404 arg->argv + arg->argn + 1, filter->rule); 405 return 0; 406 } 407 408 const char * 409 filter_Action2Nam(int act) 410 { 411 static const char *actname[] = { "none ", "permit ", "deny " }; 412 return actname[act & (A_PERMIT|A_DENY)]; 413 } 414 415 static void 416 doShowFilter(struct filterent *fp, struct prompt *prompt) 417 { 418 int n; 419 420 for (n = 0; n < MAXFILTERS; n++, fp++) { 421 if (fp->action != A_NONE) { 422 prompt_Printf(prompt, " %2d %s", n, filter_Action2Nam(fp->action)); 423 if (fp->action & A_UHOST) 424 prompt_Printf(prompt, "host "); 425 else if (fp->action & A_UPORT) 426 prompt_Printf(prompt, "port "); 427 else 428 prompt_Printf(prompt, " "); 429 prompt_Printf(prompt, "%s/%d ", inet_ntoa(fp->saddr), fp->swidth); 430 prompt_Printf(prompt, "%s/%d ", inet_ntoa(fp->daddr), fp->dwidth); 431 if (fp->proto) { 432 prompt_Printf(prompt, "%s", filter_Proto2Nam(fp->proto)); 433 434 if (fp->opt.srcop) 435 prompt_Printf(prompt, " src %s %d", filter_Op2Nam(fp->opt.srcop), 436 fp->opt.srcport); 437 if (fp->opt.dstop) 438 prompt_Printf(prompt, " dst %s %d", filter_Op2Nam(fp->opt.dstop), 439 fp->opt.dstport); 440 if (fp->opt.estab) 441 prompt_Printf(prompt, " estab"); 442 if (fp->opt.syn) 443 prompt_Printf(prompt, " syn"); 444 if (fp->opt.finrst) 445 prompt_Printf(prompt, " finrst"); 446 } 447 prompt_Printf(prompt, "\n"); 448 } 449 } 450 } 451 452 int 453 filter_Show(struct cmdargs const *arg) 454 { 455 if (arg->argc > arg->argn+1) 456 return -1; 457 458 if (arg->argc == arg->argn+1) { 459 struct filter *filter; 460 461 if (!strcmp(arg->argv[arg->argn], "in")) 462 filter = &arg->bundle->filter.in; 463 else if (!strcmp(arg->argv[arg->argn], "out")) 464 filter = &arg->bundle->filter.out; 465 else if (!strcmp(arg->argv[arg->argn], "dial")) 466 filter = &arg->bundle->filter.dial; 467 else if (!strcmp(arg->argv[arg->argn], "alive")) 468 filter = &arg->bundle->filter.alive; 469 else 470 return -1; 471 doShowFilter(filter->rule, arg->prompt); 472 } else { 473 struct filter *filter[4]; 474 int f; 475 476 filter[0] = &arg->bundle->filter.in; 477 filter[1] = &arg->bundle->filter.out; 478 filter[2] = &arg->bundle->filter.dial; 479 filter[3] = &arg->bundle->filter.alive; 480 for (f = 0; f < 4; f++) { 481 if (f) 482 prompt_Printf(arg->prompt, "\n"); 483 prompt_Printf(arg->prompt, "%s:\n", filter[f]->name); 484 doShowFilter(filter[f]->rule, arg->prompt); 485 } 486 } 487 488 return 0; 489 } 490 491 static const char *protoname[] = { "none", "tcp", "udp", "icmp" }; 492 493 const char * 494 filter_Proto2Nam(int proto) 495 { 496 if (proto >= sizeof protoname / sizeof protoname[0]) 497 return "unknown"; 498 return protoname[proto]; 499 } 500 501 static int 502 filter_Nam2Proto(int argc, char const *const *argv) 503 { 504 int proto; 505 506 if (argc == 0) 507 proto = 0; 508 else 509 for (proto = sizeof protoname / sizeof protoname[0] - 1; proto; proto--) 510 if (!strcasecmp(*argv, protoname[proto])) 511 break; 512 513 return proto; 514 } 515 516 static const char *opname[] = {"none", "eq", "gt", "unknown", "lt"}; 517 518 const char * 519 filter_Op2Nam(int op) 520 { 521 if (op >= sizeof opname / sizeof opname[0]) 522 return "unknown"; 523 return opname[op]; 524 525 } 526 527 static int 528 filter_Nam2Op(const char *cp) 529 { 530 int op; 531 532 for (op = sizeof opname / sizeof opname[0] - 1; op; op--) 533 if (!strcasecmp(cp, opname[op])) 534 break; 535 536 return op; 537 } 538