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