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