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