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