filter.c revision 6059
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:$ 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 fp->proto = 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 343 switch (proto) { 344 case P_TCP: 345 val = ParseTcp(argc, argv); 346 break; 347 case P_UDP: 348 val = ParseUdp(argc, argv); 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 371int 372SetIfilter(list, argc, argv) 373struct cmdtab *list; 374int argc; 375char **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 385int 386SetOfilter(list, argc, argv) 387struct cmdtab *list; 388int argc; 389char **argv; 390{ 391 if (argc > 0) 392 (void) Parse(argc, argv, ofilters); 393 else 394 printf("syntax error.\n"); 395 return(1); 396} 397 398int 399SetDfilter(list, argc, argv) 400struct cmdtab *list; 401int argc; 402char **argv; 403{ 404 if (argc > 0) 405 (void) Parse(argc, argv, dfilters); 406 else 407 printf("syntax error.\n"); 408 return(1); 409} 410 411static char *protoname[] = { 412 "none", "tcp", "udp", "icmp", 413}; 414 415static char *actname[] = { 416 "none ", "permit ", "deny ", 417}; 418 419static void 420ShowFilter(fp) 421struct filterent *fp; 422{ 423 int n; 424 425 for (n = 0; n < MAXFILTERS; n++, fp++) { 426 if (fp->action != A_NONE) { 427 printf("%2d %s", n, actname[fp->action]); 428 429 printf("%s/%d ", inet_ntoa(fp->saddr), fp->swidth); 430 printf("%s/%d ", inet_ntoa(fp->daddr), fp->dwidth); 431 if (fp->proto) { 432 printf("%s", protoname[fp->proto]); 433 434 if (fp->opt.srcop) 435 printf(" src %s %d", opname[fp->opt.srcop], fp->opt.srcport); 436 if (fp->opt.dstop) 437 printf(" dst %s %d", opname[fp->opt.dstop], fp->opt.dstport); 438 if (fp->opt.estab) 439 printf(" estab"); 440 441 } 442 printf("\n"); 443 } 444 } 445} 446 447int 448ShowIfilter(list, argc, argv) 449struct cmdtab *list; 450int argc; 451char **argv; 452{ 453 ShowFilter(ifilters); 454 return(1); 455} 456 457int 458ShowOfilter(list, argc, argv) 459struct cmdtab *list; 460int argc; 461char **argv; 462{ 463 ShowFilter(ofilters); 464 return(1); 465} 466 467int 468ShowDfilter(list, argc, argv) 469struct cmdtab *list; 470int argc; 471char **argv; 472{ 473 ShowFilter(dfilters); 474 return(1); 475} 476