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