filter.c revision 13379
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 37static struct filterent filterdata; 38 39static 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 51int 52ParseAddr(argc, argv, paddr, pmask, pwidth) 53int argc; 54char **argv; 55struct in_addr *paddr; 56struct in_addr *pmask; 57int *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 92static int 93ParseProto(argc, argv) 94int argc; 95char **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 113static int 114ParsePort(service, proto) 115char *service; 116int 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 */ 148static int 149ParseIcmp(argc, argv) 150int argc; 151char **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 179static int 180ParseOp(cp) 181char *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 */ 197static int 198ParseUdpOrTcp(argc, argv, proto) 199int argc; 200char **argv; 201int 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 254char *opname[] = { "none", "eq", "gt", "lt" }; 255 256static int 257Parse(argc, argv, ofp) 258int argc; 259char **argv; 260struct 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 369int 370SetIfilter(list, argc, argv) 371struct cmdtab *list; 372int argc; 373char **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 383int 384SetOfilter(list, argc, argv) 385struct cmdtab *list; 386int argc; 387char **argv; 388{ 389 if (argc > 0) 390 (void) Parse(argc, argv, ofilters); 391 else 392 printf("syntax error.\n"); 393 return(1); 394} 395 396int 397SetDfilter(list, argc, argv) 398struct cmdtab *list; 399int argc; 400char **argv; 401{ 402 if (argc > 0) 403 (void) Parse(argc, argv, dfilters); 404 else 405 printf("syntax error.\n"); 406 return(1); 407} 408 409int 410SetAfilter(list, argc, argv) 411struct cmdtab *list; 412int argc; 413char **argv; 414{ 415 if (argc > 0) 416 (void) Parse(argc, argv, afilters); 417 else 418 printf("syntax error.\n"); 419 return(1); 420} 421 422static char *protoname[] = { 423 "none", "tcp", "udp", "icmp", 424}; 425 426static char *actname[] = { 427 "none ", "permit ", "deny ", 428}; 429 430static void 431ShowFilter(fp) 432struct 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 458int 459ShowIfilter(list, argc, argv) 460struct cmdtab *list; 461int argc; 462char **argv; 463{ 464 ShowFilter(ifilters); 465 return(1); 466} 467 468int 469ShowOfilter(list, argc, argv) 470struct cmdtab *list; 471int argc; 472char **argv; 473{ 474 ShowFilter(ofilters); 475 return(1); 476} 477 478int 479ShowDfilter(list, argc, argv) 480struct cmdtab *list; 481int argc; 482char **argv; 483{ 484 ShowFilter(dfilters); 485 return(1); 486} 487 488int 489ShowAfilter(list, argc, argv) 490struct cmdtab *list; 491int argc; 492char **argv; 493{ 494 ShowFilter(afilters); 495 return(1); 496} 497