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