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.24 1998/06/15 19:06:07 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 (strncasecmp(*argv, "HISADDR", len) == 0) 94 *paddr = ipcp->peer_ip; 95 else if (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 pmask->s_addr = htonl(netmasks[bits]); 126 127 return (1); 128 } 129 130 static int 131 ParsePort(const char *service, int proto) 132 { 133 const char *protocol_name; 134 char *cp; 135 struct servent *servent; 136 int port; 137 138 switch (proto) { 139 case P_UDP: 140 protocol_name = "udp"; 141 break; 142 case P_TCP: 143 protocol_name = "tcp"; 144 break; 145 default: 146 protocol_name = 0; 147 } 148 149 servent = getservbyname(service, protocol_name); 150 if (servent != 0) 151 return (ntohs(servent->s_port)); 152 153 port = strtol(service, &cp, 0); 154 if (cp == service) { 155 log_Printf(LogWARN, "ParsePort: %s is not a port name or number.\n", 156 service); 157 return (0); 158 } 159 return (port); 160 } 161 162 /* 163 * ICMP Syntax: src eq icmp_message_type 164 */ 165 static int 166 ParseIcmp(int argc, char const *const *argv, struct filterent *tgt) 167 { 168 int type; 169 char *cp; 170 171 switch (argc) { 172 case 0: 173 /* permit/deny all ICMP types */ 174 tgt->opt.srcop = OP_NONE; 175 break; 176 177 case 3: 178 if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) { 179 type = strtol(argv[2], &cp, 0); 180 if (cp == argv[2]) { 181 log_Printf(LogWARN, "ParseIcmp: type is expected.\n"); 182 return (0); 183 } 184 tgt->opt.srcop = OP_EQ; 185 tgt->opt.srcport = type; 186 } 187 break; 188 189 default: 190 log_Printf(LogWARN, "ParseIcmp: bad icmp syntax.\n"); 191 return (0); 192 } 193 return (1); 194 } 195 196 /* 197 * UDP Syntax: [src op port] [dst op port] 198 */ 199 static int 200 ParseUdpOrTcp(int argc, char const *const *argv, int proto, 201 struct filterent *tgt) 202 { 203 tgt->opt.srcop = tgt->opt.dstop = OP_NONE; 204 tgt->opt.estab = tgt->opt.syn = tgt->opt.finrst = 0; 205 206 if (argc >= 3 && !strcmp(*argv, "src")) { 207 tgt->opt.srcop = filter_Nam2Op(argv[1]); 208 if (tgt->opt.srcop == OP_NONE) { 209 log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n"); 210 return (0); 211 } 212 tgt->opt.srcport = ParsePort(argv[2], proto); 213 if (tgt->opt.srcport == 0) 214 return (0); 215 argc -= 3; 216 argv += 3; 217 } 218 219 if (argc >= 3 && !strcmp(argv[0], "dst")) { 220 tgt->opt.dstop = filter_Nam2Op(argv[1]); 221 if (tgt->opt.dstop == OP_NONE) { 222 log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n"); 223 return (0); 224 } 225 tgt->opt.dstport = ParsePort(argv[2], proto); 226 if (tgt->opt.dstport == 0) 227 return (0); 228 argc -= 3; 229 argv += 3; 230 } 231 232 if (proto == P_TCP) { 233 for (; argc > 0; argc--, argv++) 234 if (!strcmp(*argv, "estab")) 235 tgt->opt.estab = 1; 236 else if (!strcmp(*argv, "syn")) 237 tgt->opt.syn = 1; 238 else if (!strcmp(*argv, "finrst")) 239 tgt->opt.finrst = 1; 240 else 241 break; 242 } 243 244 if (argc > 0) { 245 log_Printf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv); 246 return 0; 247 } 248 249 return 1; 250 } 251 252 static int 253 Parse(struct ipcp *ipcp, int argc, char const *const *argv, 254 struct filterent *ofp) 255 { 256 int action, proto; 257 int val; 258 char *wp; 259 struct filterent filterdata; 260 261 val = strtol(*argv, &wp, 0); 262 if (*argv == wp || val > MAXFILTERS) { 263 log_Printf(LogWARN, "Parse: invalid filter number.\n"); 264 return (0); 265 } 266 if (val < 0) { 267 for (val = 0; val < MAXFILTERS; val++) { 268 ofp->action = A_NONE; 269 ofp++; 270 } 271 log_Printf(LogWARN, "Parse: filter cleared.\n"); 272 return (1); 273 } 274 ofp += val; 275 276 if (--argc == 0) { 277 log_Printf(LogWARN, "Parse: missing action.\n"); 278 return (0); 279 } 280 argv++; 281 282 proto = P_NONE; 283 memset(&filterdata, '\0', sizeof filterdata); 284 285 if (!strcmp(*argv, "permit")) { 286 action = A_PERMIT; 287 } else if (!strcmp(*argv, "deny")) { 288 action = A_DENY; 289 } else if (!strcmp(*argv, "clear")) { 290 ofp->action = A_NONE; 291 return (1); 292 } else { 293 log_Printf(LogWARN, "Parse: bad action: %s\n", *argv); 294 return (0); 295 } 296 filterdata.action = action; 297 298 argc--; 299 argv++; 300 301 if (filterdata.action == A_DENY) { 302 if (!strcmp(*argv, "host")) { 303 filterdata.action |= A_UHOST; 304 argc--; 305 argv++; 306 } else if (!strcmp(*argv, "port")) { 307 filterdata.action |= A_UPORT; 308 argc--; 309 argv++; 310 } 311 } 312 proto = filter_Nam2Proto(argc, argv); 313 if (proto == P_NONE) { 314 if (ParseAddr(ipcp, argc, argv, &filterdata.saddr, &filterdata.smask, 315 &filterdata.swidth)) { 316 argc--; 317 argv++; 318 proto = filter_Nam2Proto(argc, argv); 319 if (proto == P_NONE) { 320 if (ParseAddr(ipcp, argc, argv, &filterdata.daddr, &filterdata.dmask, 321 &filterdata.dwidth)) { 322 argc--; 323 argv++; 324 } 325 proto = filter_Nam2Proto(argc, argv); 326 if (proto != P_NONE) { 327 argc--; 328 argv++; 329 } 330 } else { 331 argc--; 332 argv++; 333 } 334 } else { 335 log_Printf(LogWARN, "Parse: Address/protocol expected.\n"); 336 return (0); 337 } 338 } else { 339 argc--; 340 argv++; 341 } 342 343 val = 1; 344 filterdata.proto = proto; 345 346 switch (proto) { 347 case P_TCP: 348 val = ParseUdpOrTcp(argc, argv, P_TCP, &filterdata); 349 break; 350 case P_UDP: 351 val = ParseUdpOrTcp(argc, argv, P_UDP, &filterdata); 352 break; 353 case P_ICMP: 354 val = ParseIcmp(argc, argv, &filterdata); 355 break; 356 } 357 358 log_Printf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(filterdata.saddr)); 359 log_Printf(LogDEBUG, "Parse: Src mask: %s\n", inet_ntoa(filterdata.smask)); 360 log_Printf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(filterdata.daddr)); 361 log_Printf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(filterdata.dmask)); 362 log_Printf(LogDEBUG, "Parse: Proto = %d\n", proto); 363 364 log_Printf(LogDEBUG, "Parse: src: %s (%d)\n", 365 filter_Op2Nam(filterdata.opt.srcop), filterdata.opt.srcport); 366 log_Printf(LogDEBUG, "Parse: dst: %s (%d)\n", 367 filter_Op2Nam(filterdata.opt.dstop), filterdata.opt.dstport); 368 log_Printf(LogDEBUG, "Parse: estab: %u\n", filterdata.opt.estab); 369 log_Printf(LogDEBUG, "Parse: syn: %u\n", filterdata.opt.syn); 370 log_Printf(LogDEBUG, "Parse: finrst: %u\n", filterdata.opt.finrst); 371 372 if (val) 373 *ofp = filterdata; 374 return (val); 375 } 376 377 int 378 filter_Set(struct cmdargs const *arg) 379 { 380 struct filter *filter; 381 382 if (arg->argc < arg->argn+2) 383 return -1; 384 385 if (!strcmp(arg->argv[arg->argn], "in")) 386 filter = &arg->bundle->filter.in; 387 else if (!strcmp(arg->argv[arg->argn], "out")) 388 filter = &arg->bundle->filter.out; 389 else if (!strcmp(arg->argv[arg->argn], "dial")) 390 filter = &arg->bundle->filter.dial; 391 else if (!strcmp(arg->argv[arg->argn], "alive")) 392 filter = &arg->bundle->filter.alive; 393 else { 394 log_Printf(LogWARN, "filter_Set: %s: Invalid filter name.\n", 395 arg->argv[arg->argn]); 396 return -1; 397 } 398 399 Parse(&arg->bundle->ncp.ipcp, arg->argc - arg->argn - 1, 400 arg->argv + arg->argn + 1, filter->rule); 401 return 0; 402 } 403 404 const char * 405 filter_Action2Nam(int act) 406 { 407 static const char *actname[] = { "none ", "permit ", "deny " }; 408 return actname[act & (A_PERMIT|A_DENY)]; 409 } 410 411 static void 412 doShowFilter(struct filterent *fp, struct prompt *prompt) 413 { 414 int n; 415 416 for (n = 0; n < MAXFILTERS; n++, fp++) { 417 if (fp->action != A_NONE) { 418 prompt_Printf(prompt, " %2d %s", n, filter_Action2Nam(fp->action)); 419 if (fp->action & A_UHOST) 420 prompt_Printf(prompt, "host "); 421 else if (fp->action & A_UPORT) 422 prompt_Printf(prompt, "port "); 423 else 424 prompt_Printf(prompt, " "); 425 prompt_Printf(prompt, "%s/%d ", inet_ntoa(fp->saddr), fp->swidth); 426 prompt_Printf(prompt, "%s/%d ", inet_ntoa(fp->daddr), fp->dwidth); 427 if (fp->proto) { 428 prompt_Printf(prompt, "%s", filter_Proto2Nam(fp->proto)); 429 430 if (fp->opt.srcop) 431 prompt_Printf(prompt, " src %s %d", filter_Op2Nam(fp->opt.srcop), 432 fp->opt.srcport); 433 if (fp->opt.dstop) 434 prompt_Printf(prompt, " dst %s %d", filter_Op2Nam(fp->opt.dstop), 435 fp->opt.dstport); 436 if (fp->opt.estab) 437 prompt_Printf(prompt, " estab"); 438 if (fp->opt.syn) 439 prompt_Printf(prompt, " syn"); 440 if (fp->opt.finrst) 441 prompt_Printf(prompt, " finrst"); 442 } 443 prompt_Printf(prompt, "\n"); 444 } 445 } 446 } 447 448 int 449 filter_Show(struct cmdargs const *arg) 450 { 451 if (arg->argc > arg->argn+1) 452 return -1; 453 454 if (arg->argc == arg->argn+1) { 455 struct filter *filter; 456 457 if (!strcmp(arg->argv[arg->argn], "in")) 458 filter = &arg->bundle->filter.in; 459 else if (!strcmp(arg->argv[arg->argn], "out")) 460 filter = &arg->bundle->filter.out; 461 else if (!strcmp(arg->argv[arg->argn], "dial")) 462 filter = &arg->bundle->filter.dial; 463 else if (!strcmp(arg->argv[arg->argn], "alive")) 464 filter = &arg->bundle->filter.alive; 465 else 466 return -1; 467 doShowFilter(filter->rule, arg->prompt); 468 } else { 469 struct filter *filter[4]; 470 int f; 471 472 filter[0] = &arg->bundle->filter.in; 473 filter[1] = &arg->bundle->filter.out; 474 filter[2] = &arg->bundle->filter.dial; 475 filter[3] = &arg->bundle->filter.alive; 476 for (f = 0; f < 4; f++) { 477 if (f) 478 prompt_Printf(arg->prompt, "\n"); 479 prompt_Printf(arg->prompt, "%s:\n", filter[f]->name); 480 doShowFilter(filter[f]->rule, arg->prompt); 481 } 482 } 483 484 return 0; 485 } 486 487 static const char *protoname[] = { "none", "tcp", "udp", "icmp" }; 488 489 const char * 490 filter_Proto2Nam(int proto) 491 { 492 if (proto >= sizeof protoname / sizeof protoname[0]) 493 return "unknown"; 494 return protoname[proto]; 495 } 496 497 static int 498 filter_Nam2Proto(int argc, char const *const *argv) 499 { 500 int proto; 501 502 if (argc == 0) 503 proto = 0; 504 else 505 for (proto = sizeof protoname / sizeof protoname[0] - 1; proto; proto--) 506 if (!strcasecmp(*argv, protoname[proto])) 507 break; 508 509 return proto; 510 } 511 512 static const char *opname[] = {"none", "eq", "gt", "unknown", "lt"}; 513 514 const char * 515 filter_Op2Nam(int op) 516 { 517 if (op >= sizeof opname / sizeof opname[0]) 518 return "unknown"; 519 return opname[op]; 520 521 } 522 523 static int 524 filter_Nam2Op(const char *cp) 525 { 526 int op; 527 528 for (op = sizeof opname / sizeof opname[0] - 1; op; op--) 529 if (!strcasecmp(cp, opname[op])) 530 break; 531 532 return op; 533 } 534