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