xref: /freebsd/usr.sbin/ppp/filter.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
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.1.1.1 1995/01/31 06:29:57 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 
35 static struct filterent filterdata;
36 
37 static 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 
49 int
50 ParseAddr(argc, argv, paddr, pmask, pwidth)
51 int argc;
52 char **argv;
53 struct in_addr *paddr;
54 struct in_addr *pmask;
55 int *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 
90 static int
91 ParseProto(argc, argv)
92 int argc;
93 char **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  */
114 static int
115 ParseIcmp(argc, argv)
116 int argc;
117 char **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 
145 static int
146 ParseOp(cp)
147 char *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  */
163 static int
164 ParseUdp(argc, argv)
165 int argc;
166 char **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  */
222 static int
223 ParseTcp(argc, argv)
224 int argc;
225 char **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) {
241 checkestab:
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 
257 char *opname[] = { "none", "eq", "gt", "lt" };
258 
259 static int
260 Parse(argc, argv, ofp)
261 int argc;
262 char **argv;
263 struct 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       }
330       if (proto) {
331         argc--; argv++;
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 
372 int
373 SetIfilter(list, argc, argv)
374 struct cmdtab *list;
375 int argc;
376 char **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 
386 int
387 SetOfilter(list, argc, argv)
388 struct cmdtab *list;
389 int argc;
390 char **argv;
391 {
392   if (argc > 0)
393     (void) Parse(argc, argv, ofilters);
394   else
395     printf("syntax error.\n");
396   return(1);
397 }
398 
399 int
400 SetDfilter(list, argc, argv)
401 struct cmdtab *list;
402 int argc;
403 char **argv;
404 {
405   if (argc > 0)
406     (void) Parse(argc, argv, dfilters);
407   else
408     printf("syntax error.\n");
409   return(1);
410 }
411 
412 static char *protoname[] = {
413   "none", "tcp", "udp", "icmp",
414 };
415 
416 static char *actname[] = {
417   "none   ", "permit ", "deny   ",
418 };
419 
420 static void
421 ShowFilter(fp)
422 struct filterent *fp;
423 {
424   int n;
425 
426   for (n = 0; n < MAXFILTERS; n++, fp++) {
427     if (fp->action != A_NONE) {
428       printf("%2d %s", n, actname[fp->action]);
429 
430       printf("%s/%d ", inet_ntoa(fp->saddr), fp->swidth);
431       printf("%s/%d ", inet_ntoa(fp->daddr), fp->dwidth);
432       if (fp->proto) {
433 	printf("%s", protoname[fp->proto]);
434 
435 	if (fp->opt.srcop)
436 	  printf(" src %s %d", opname[fp->opt.srcop], fp->opt.srcport);
437 	if (fp->opt.dstop)
438 	  printf(" dst %s %d", opname[fp->opt.dstop], fp->opt.dstport);
439 	if (fp->opt.estab)
440 	  printf(" estab");
441 
442       }
443       printf("\n");
444     }
445   }
446 }
447 
448 int
449 ShowIfilter(list, argc, argv)
450 struct cmdtab *list;
451 int argc;
452 char **argv;
453 {
454   ShowFilter(ifilters);
455   return(1);
456 }
457 
458 int
459 ShowOfilter(list, argc, argv)
460 struct cmdtab *list;
461 int argc;
462 char **argv;
463 {
464   ShowFilter(ofilters);
465   return(1);
466 }
467 
468 int
469 ShowDfilter(list, argc, argv)
470 struct cmdtab *list;
471 int argc;
472 char **argv;
473 {
474   ShowFilter(dfilters);
475   return(1);
476 }
477