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