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