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