xref: /freebsd/usr.sbin/ppp/filter.c (revision df7f5d4de4592a8948a25ce01e5bddfbb7ce39dc)
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 <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 
204   if (argc == 0) {
205     /* permit/deny all tcp traffic */
206     filterdata.opt.srcop = filterdata.opt.dstop = A_NONE;
207     return(1);
208   }
209   if (argc < 3) {
210 #ifdef notdef
211     printf("bad udp syntax.\n");
212 #endif
213     return(0);
214   }
215   if (argc >= 3 && STREQ(*argv, "src")) {
216     filterdata.opt.srcop = ParseOp(argv[1]);
217     if (filterdata.opt.srcop == OP_NONE) {
218       printf("bad operation\n");
219       return(0);
220     }
221     filterdata.opt.srcport = ParsePort(argv[2], proto);
222     if (filterdata.opt.srcport == 0)
223       return(0);
224     argc -= 3; argv += 3;
225     if (argc == 0)
226       return(1);
227   }
228   if (argc >= 3 && STREQ(argv[0], "dst")) {
229     filterdata.opt.dstop = ParseOp(argv[1]);
230     if (filterdata.opt.dstop == OP_NONE) {
231       printf("bad operation\n");
232       return(0);
233     }
234     filterdata.opt.dstport = ParsePort(argv[2], proto);
235     if (filterdata.opt.dstport == 0)
236       return(0);
237     argc -= 3; argv += 3;
238     if (argc == 0)
239       return(1);
240   }
241   if (argc == 1) {
242     if (STREQ(*argv, "estab")) {
243       filterdata.opt.estab = 1;
244       return(1);
245     }
246     printf("estab is expected: %s\n", *argv);
247     return(0);
248   }
249   if (argc > 0)
250     printf("bad src/dst port syntax: %s\n", *argv);
251   return(0);
252 }
253 
254 char *opname[] = { "none", "eq", "gt", "lt" };
255 
256 static int
257 Parse(argc, argv, ofp)
258 int argc;
259 char **argv;
260 struct filterent *ofp;
261 {
262   int action, proto;
263   int val;
264   char *wp;
265   struct filterent *fp = &filterdata;
266 
267   val = strtol(*argv, &wp, 0);
268   if (*argv == wp || val > MAXFILTERS) {
269     printf("invalid filter number.\n");
270     return(0);
271   }
272   if (val < 0) {
273     for (val = 0; val < MAXFILTERS; val++) {
274       ofp->action = A_NONE;
275       ofp++;
276     }
277     printf("filter cleard.\n");
278     return(1);
279   }
280   ofp += val;
281 
282   if (--argc == 0) {
283     printf("missing action.\n");
284     return(0);
285   }
286   argv++;
287 
288   proto = P_NONE;
289   bzero(&filterdata, sizeof(filterdata));
290 
291   if (STREQ(*argv, "permit")) {
292     action = A_PERMIT;
293   } else if (STREQ(*argv, "deny")) {
294     action = A_DENY;
295   } else if (STREQ(*argv, "clear")) {
296     ofp->action = A_NONE;
297     return(1);
298   } else {
299     printf("bad action: %s\n", *argv);
300     return(0);
301   }
302   fp->action = action;
303 
304   argc--; argv++;
305 
306   if (ofp->action == A_DENY) {
307     if (STREQ(*argv, "host")) {
308       fp->action |= A_UHOST;
309       argc--; argv++;
310     } else if (STREQ(*argv, "port")) {
311       fp->action |= A_UPORT;
312       argc--; argv++;
313     }
314   }
315 
316   proto = ParseProto(argc, argv);
317   if (proto == P_NONE) {
318     if (ParseAddr(argc, argv, &fp->saddr, &fp->smask, &fp->swidth)) {
319       argc--; argv++;
320       proto = ParseProto(argc, argv);
321       if (proto == P_NONE) {
322 	if (ParseAddr(argc, argv, &fp->daddr, &fp->dmask, &fp->dwidth)) {
323 	  argc--; argv++;
324 	}
325 	proto = ParseProto(argc, argv);
326 	if (proto) {
327 	  argc--; argv++;
328 	}
329       }
330     } else {
331       printf("Address/protocol expected.\n");
332       return(0);
333     }
334   } else {
335     argc--; argv++;
336   }
337 
338   val = 1;
339   fp->proto = proto;
340 
341   switch (proto) {
342   case P_TCP:
343     val = ParseUdpOrTcp(argc, argv, P_TCP);
344     break;
345   case P_UDP:
346     val = ParseUdpOrTcp(argc, argv, P_UDP);
347     break;
348   case P_ICMP:
349     val = ParseIcmp(argc, argv);
350     break;
351   }
352 
353 #ifdef DEBUG
354   printf("src: %s/", inet_ntoa(fp->saddr));
355   printf("%s ", inet_ntoa(fp->smask));
356   printf("dst: %s/", inet_ntoa(fp->daddr));
357   printf("%s proto = %d\n", inet_ntoa(fp->dmask), proto);
358 
359   printf("src:  %s (%d)\n", opname[fp->opt.srcop], fp->opt.srcport);
360   printf("dst:  %s (%d)\n", opname[fp->opt.dstop], fp->opt.dstport);
361   printf("estab: %d\n", fp->opt.estab);
362 #endif
363 
364   if (val)
365     *ofp = *fp;
366   return(val);
367 }
368 
369 int
370 SetIfilter(list, argc, argv)
371 struct cmdtab *list;
372 int argc;
373 char **argv;
374 {
375   if (argc > 0)
376     (void) Parse(argc, argv, ifilters);
377   else
378     printf("syntax error.\n");
379 
380   return(1);
381 }
382 
383 int
384 SetOfilter(list, argc, argv)
385 struct cmdtab *list;
386 int argc;
387 char **argv;
388 {
389   if (argc > 0)
390     (void) Parse(argc, argv, ofilters);
391   else
392     printf("syntax error.\n");
393   return(1);
394 }
395 
396 int
397 SetDfilter(list, argc, argv)
398 struct cmdtab *list;
399 int argc;
400 char **argv;
401 {
402   if (argc > 0)
403     (void) Parse(argc, argv, dfilters);
404   else
405     printf("syntax error.\n");
406   return(1);
407 }
408 
409 int
410 SetAfilter(list, argc, argv)
411 struct cmdtab *list;
412 int argc;
413 char **argv;
414 {
415   if (argc > 0)
416     (void) Parse(argc, argv, afilters);
417   else
418     printf("syntax error.\n");
419   return(1);
420 }
421 
422 static char *protoname[] = {
423   "none", "tcp", "udp", "icmp",
424 };
425 
426 static char *actname[] = {
427   "none   ", "permit ", "deny   ",
428 };
429 
430 static void
431 ShowFilter(fp)
432 struct filterent *fp;
433 {
434   int n;
435 
436   for (n = 0; n < MAXFILTERS; n++, fp++) {
437     if (fp->action != A_NONE) {
438       printf("%2d %s", n, actname[fp->action]);
439 
440       printf("%s/%d ", inet_ntoa(fp->saddr), fp->swidth);
441       printf("%s/%d ", inet_ntoa(fp->daddr), fp->dwidth);
442       if (fp->proto) {
443 	printf("%s", protoname[fp->proto]);
444 
445 	if (fp->opt.srcop)
446 	  printf(" src %s %d", opname[fp->opt.srcop], fp->opt.srcport);
447 	if (fp->opt.dstop)
448 	  printf(" dst %s %d", opname[fp->opt.dstop], fp->opt.dstport);
449 	if (fp->opt.estab)
450 	  printf(" estab");
451 
452       }
453       printf("\n");
454     }
455   }
456 }
457 
458 int
459 ShowIfilter(list, argc, argv)
460 struct cmdtab *list;
461 int argc;
462 char **argv;
463 {
464   ShowFilter(ifilters);
465   return(1);
466 }
467 
468 int
469 ShowOfilter(list, argc, argv)
470 struct cmdtab *list;
471 int argc;
472 char **argv;
473 {
474   ShowFilter(ofilters);
475   return(1);
476 }
477 
478 int
479 ShowDfilter(list, argc, argv)
480 struct cmdtab *list;
481 int argc;
482 char **argv;
483 {
484   ShowFilter(dfilters);
485   return(1);
486 }
487 
488 int
489 ShowAfilter(list, argc, argv)
490 struct cmdtab *list;
491 int argc;
492 char **argv;
493 {
494   ShowFilter(afilters);
495   return(1);
496 }
497