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