filter.c revision 6059
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:$
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  fp->proto = 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
343  switch (proto) {
344  case P_TCP:
345    val = ParseTcp(argc, argv);
346    break;
347  case P_UDP:
348    val = ParseUdp(argc, argv);
349    break;
350  case P_ICMP:
351    val = ParseIcmp(argc, argv);
352    break;
353  }
354
355#ifdef DEBUG
356  printf("src: %s/", inet_ntoa(fp->saddr));
357  printf("%s ", inet_ntoa(fp->smask));
358  printf("dst: %s/", inet_ntoa(fp->daddr));
359  printf("%s proto = %d\n", inet_ntoa(fp->dmask), proto);
360
361  printf("src:  %s (%d)\n", opname[fp->opt.srcop], fp->opt.srcport);
362  printf("dst:  %s (%d)\n", opname[fp->opt.dstop], fp->opt.dstport);
363  printf("estab: %d\n", fp->opt.estab);
364#endif
365
366  if (val)
367    *ofp = *fp;
368  return(val);
369}
370
371int
372SetIfilter(list, argc, argv)
373struct cmdtab *list;
374int argc;
375char **argv;
376{
377  if (argc > 0)
378    (void) Parse(argc, argv, ifilters);
379  else
380    printf("syntax error.\n");
381
382  return(1);
383}
384
385int
386SetOfilter(list, argc, argv)
387struct cmdtab *list;
388int argc;
389char **argv;
390{
391  if (argc > 0)
392    (void) Parse(argc, argv, ofilters);
393  else
394    printf("syntax error.\n");
395  return(1);
396}
397
398int
399SetDfilter(list, argc, argv)
400struct cmdtab *list;
401int argc;
402char **argv;
403{
404  if (argc > 0)
405    (void) Parse(argc, argv, dfilters);
406  else
407    printf("syntax error.\n");
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(fp)
421struct filterent *fp;
422{
423  int n;
424
425  for (n = 0; n < MAXFILTERS; n++, fp++) {
426    if (fp->action != A_NONE) {
427      printf("%2d %s", n, actname[fp->action]);
428
429      printf("%s/%d ", inet_ntoa(fp->saddr), fp->swidth);
430      printf("%s/%d ", inet_ntoa(fp->daddr), fp->dwidth);
431      if (fp->proto) {
432	printf("%s", protoname[fp->proto]);
433
434	if (fp->opt.srcop)
435	  printf(" src %s %d", opname[fp->opt.srcop], fp->opt.srcport);
436	if (fp->opt.dstop)
437	  printf(" dst %s %d", opname[fp->opt.dstop], fp->opt.dstport);
438	if (fp->opt.estab)
439	  printf(" estab");
440
441      }
442      printf("\n");
443    }
444  }
445}
446
447int
448ShowIfilter(list, argc, argv)
449struct cmdtab *list;
450int argc;
451char **argv;
452{
453  ShowFilter(ifilters);
454  return(1);
455}
456
457int
458ShowOfilter(list, argc, argv)
459struct cmdtab *list;
460int argc;
461char **argv;
462{
463  ShowFilter(ofilters);
464  return(1);
465}
466
467int
468ShowDfilter(list, argc, argv)
469struct cmdtab *list;
470int argc;
471char **argv;
472{
473  ShowFilter(dfilters);
474  return(1);
475}
476