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