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