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