filter.c revision 10858
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 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 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 256char *opname[] = { "none", "eq", "gt", "lt" }; 257 258static int 259Parse(argc, argv, ofp) 260int argc; 261char **argv; 262struct 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 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 411int 412SetAfilter(list, argc, argv) 413struct cmdtab *list; 414int argc; 415char **argv; 416{ 417 if (argc > 0) 418 (void) Parse(argc, argv, afilters); 419 else 420 printf("syntax error.\n"); 421 return(1); 422} 423 424static char *protoname[] = { 425 "none", "tcp", "udp", "icmp", 426}; 427 428static char *actname[] = { 429 "none ", "permit ", "deny ", 430}; 431 432static void 433ShowFilter(fp) 434struct 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 460int 461ShowIfilter(list, argc, argv) 462struct cmdtab *list; 463int argc; 464char **argv; 465{ 466 ShowFilter(ifilters); 467 return(1); 468} 469 470int 471ShowOfilter(list, argc, argv) 472struct cmdtab *list; 473int argc; 474char **argv; 475{ 476 ShowFilter(ofilters); 477 return(1); 478} 479 480int 481ShowDfilter(list, argc, argv) 482struct cmdtab *list; 483int argc; 484char **argv; 485{ 486 ShowFilter(dfilters); 487 return(1); 488} 489 490int 491ShowAfilter(list, argc, argv) 492struct cmdtab *list; 493int argc; 494char **argv; 495{ 496 ShowFilter(afilters); 497 return(1); 498} 499