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.4 1995/05/30 03:50:31 rgrimes 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 int port; 204 char *cp; 205 206 if (argc == 0) { 207 /* permit/deny all tcp traffic */ 208 filterdata.opt.srcop = filterdata.opt.dstop = A_NONE; 209 return(1); 210 } 211 if (argc < 3) { 212 #ifdef notdef 213 printf("bad udp syntax.\n"); 214 #endif 215 return(0); 216 } 217 if (argc >= 3 && STREQ(*argv, "src")) { 218 filterdata.opt.srcop = ParseOp(argv[1]); 219 if (filterdata.opt.srcop == OP_NONE) { 220 printf("bad operation\n"); 221 return(0); 222 } 223 filterdata.opt.srcport = ParsePort(argv[2], proto); 224 if (filterdata.opt.srcport == 0) 225 return(0); 226 argc -= 3; argv += 3; 227 if (argc == 0) 228 return(1); 229 } 230 if (argc >= 3 && STREQ(argv[0], "dst")) { 231 filterdata.opt.dstop = ParseOp(argv[1]); 232 if (filterdata.opt.dstop == OP_NONE) { 233 printf("bad operation\n"); 234 return(0); 235 } 236 filterdata.opt.dstport = ParsePort(argv[2], proto); 237 if (filterdata.opt.dstport == 0) 238 return(0); 239 argc -= 3; argv += 3; 240 if (argc == 0) 241 return(1); 242 } 243 if (argc == 1) { 244 if (STREQ(*argv, "estab")) { 245 filterdata.opt.estab = 1; 246 return(1); 247 } 248 printf("estab is expected: %s\n", *argv); 249 return(0); 250 } 251 if (argc > 0) 252 printf("bad %s src/dst port syntax: %s\n", *argv); 253 return(0); 254 } 255 256 char *opname[] = { "none", "eq", "gt", "lt" }; 257 258 static int 259 Parse(argc, argv, ofp) 260 int argc; 261 char **argv; 262 struct filterent *ofp; 263 { 264 int action, proto; 265 int val; 266 char *wp; 267 struct filterent *fp = &filterdata; 268 269 val = strtol(*argv, &wp, 0); 270 if (*argv == wp || val > MAXFILTERS) { 271 printf("invalid filter number.\n"); 272 return(0); 273 } 274 if (val < 0) { 275 for (val = 0; val < MAXFILTERS; val++) { 276 ofp->action = A_NONE; 277 ofp++; 278 } 279 printf("filter cleard.\n"); 280 return(1); 281 } 282 ofp += val; 283 284 if (--argc == 0) { 285 printf("missing action.\n"); 286 return(0); 287 } 288 argv++; 289 290 proto = P_NONE; 291 bzero(&filterdata, sizeof(filterdata)); 292 293 if (STREQ(*argv, "permit")) { 294 action = A_PERMIT; 295 } else if (STREQ(*argv, "deny")) { 296 action = A_DENY; 297 } else if (STREQ(*argv, "clear")) { 298 ofp->action = A_NONE; 299 return(1); 300 } else { 301 printf("bad action: %s\n", *argv); 302 return(0); 303 } 304 fp->action = action; 305 306 argc--; argv++; 307 308 if (ofp->action == A_DENY) { 309 if (STREQ(*argv, "host")) { 310 fp->action |= A_UHOST; 311 argc--; argv++; 312 } else if (STREQ(*argv, "port")) { 313 fp->action |= A_UPORT; 314 argc--; argv++; 315 } 316 } 317 318 proto = ParseProto(argc, argv); 319 if (proto == P_NONE) { 320 if (ParseAddr(argc, argv, &fp->saddr, &fp->smask, &fp->swidth)) { 321 argc--; argv++; 322 proto = ParseProto(argc, argv); 323 if (proto == P_NONE) { 324 if (ParseAddr(argc, argv, &fp->daddr, &fp->dmask, &fp->dwidth)) { 325 argc--; argv++; 326 } 327 proto = ParseProto(argc, argv); 328 if (proto) { 329 argc--; argv++; 330 } 331 } 332 } else { 333 printf("Address/protocol expected.\n"); 334 return(0); 335 } 336 } else { 337 argc--; argv++; 338 } 339 340 val = 1; 341 fp->proto = proto; 342 343 switch (proto) { 344 case P_TCP: 345 val = ParseUdpOrTcp(argc, argv, P_TCP); 346 break; 347 case P_UDP: 348 val = ParseUdpOrTcp(argc, argv, P_UDP); 349 break; 350 case P_ICMP: 351 val = ParseIcmp(argc, argv); 352 break; 353 } 354 355 #ifdef DEBUG 356 printf("src: %s/", inet_ntoa(fp->saddr)); 357 printf("%s ", inet_ntoa(fp->smask)); 358 printf("dst: %s/", inet_ntoa(fp->daddr)); 359 printf("%s proto = %d\n", inet_ntoa(fp->dmask), proto); 360 361 printf("src: %s (%d)\n", opname[fp->opt.srcop], fp->opt.srcport); 362 printf("dst: %s (%d)\n", opname[fp->opt.dstop], fp->opt.dstport); 363 printf("estab: %d\n", fp->opt.estab); 364 #endif 365 366 if (val) 367 *ofp = *fp; 368 return(val); 369 } 370 371 int 372 SetIfilter(list, argc, argv) 373 struct cmdtab *list; 374 int argc; 375 char **argv; 376 { 377 if (argc > 0) 378 (void) Parse(argc, argv, ifilters); 379 else 380 printf("syntax error.\n"); 381 382 return(1); 383 } 384 385 int 386 SetOfilter(list, argc, argv) 387 struct cmdtab *list; 388 int argc; 389 char **argv; 390 { 391 if (argc > 0) 392 (void) Parse(argc, argv, ofilters); 393 else 394 printf("syntax error.\n"); 395 return(1); 396 } 397 398 int 399 SetDfilter(list, argc, argv) 400 struct cmdtab *list; 401 int argc; 402 char **argv; 403 { 404 if (argc > 0) 405 (void) Parse(argc, argv, dfilters); 406 else 407 printf("syntax error.\n"); 408 return(1); 409 } 410 411 int 412 SetAfilter(list, argc, argv) 413 struct cmdtab *list; 414 int argc; 415 char **argv; 416 { 417 if (argc > 0) 418 (void) Parse(argc, argv, afilters); 419 else 420 printf("syntax error.\n"); 421 return(1); 422 } 423 424 static char *protoname[] = { 425 "none", "tcp", "udp", "icmp", 426 }; 427 428 static char *actname[] = { 429 "none ", "permit ", "deny ", 430 }; 431 432 static void 433 ShowFilter(fp) 434 struct filterent *fp; 435 { 436 int n; 437 438 for (n = 0; n < MAXFILTERS; n++, fp++) { 439 if (fp->action != A_NONE) { 440 printf("%2d %s", n, actname[fp->action]); 441 442 printf("%s/%d ", inet_ntoa(fp->saddr), fp->swidth); 443 printf("%s/%d ", inet_ntoa(fp->daddr), fp->dwidth); 444 if (fp->proto) { 445 printf("%s", protoname[fp->proto]); 446 447 if (fp->opt.srcop) 448 printf(" src %s %d", opname[fp->opt.srcop], fp->opt.srcport); 449 if (fp->opt.dstop) 450 printf(" dst %s %d", opname[fp->opt.dstop], fp->opt.dstport); 451 if (fp->opt.estab) 452 printf(" estab"); 453 454 } 455 printf("\n"); 456 } 457 } 458 } 459 460 int 461 ShowIfilter(list, argc, argv) 462 struct cmdtab *list; 463 int argc; 464 char **argv; 465 { 466 ShowFilter(ifilters); 467 return(1); 468 } 469 470 int 471 ShowOfilter(list, argc, argv) 472 struct cmdtab *list; 473 int argc; 474 char **argv; 475 { 476 ShowFilter(ofilters); 477 return(1); 478 } 479 480 int 481 ShowDfilter(list, argc, argv) 482 struct cmdtab *list; 483 int argc; 484 char **argv; 485 { 486 ShowFilter(dfilters); 487 return(1); 488 } 489 490 int 491 ShowAfilter(list, argc, argv) 492 struct cmdtab *list; 493 int argc; 494 char **argv; 495 { 496 ShowFilter(afilters); 497 return(1); 498 } 499