Define _KERNEL_STRUCTURES instead of _KERNEL to get just the
[dragonfly.git] / contrib / ipfilter / common.c
1 /*
2  * Copyright (C) 1993-2001 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  */
6 #if defined(__sgi) && (IRIX > 602)
7 # include <sys/ptimers.h>
8 #endif
9 #include <sys/types.h>
10 #if !defined(__SVR4) && !defined(__svr4__)
11 #include <strings.h>
12 #else
13 #include <sys/byteorder.h>
14 #endif
15 #include <sys/param.h>
16 #include <sys/time.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <netinet/in_systm.h>
20 #include <netinet/ip.h>
21 #include <netinet/tcp.h>
22 #include <net/if.h>
23 #if __FreeBSD_version >= 300000
24 # include <net/if_var.h>
25 #endif
26 #include <stdio.h>
27 #include <string.h>
28 #include <limits.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <stddef.h>
32 #include <netdb.h>
33 #include <arpa/nameser.h>
34 #include <arpa/inet.h>
35 #include <resolv.h>
36 #include <ctype.h>
37 #include <syslog.h>
38 #include "ip_compat.h"
39 #include "ip_fil.h"
40 #include "ipf.h"
41 #include "facpri.h"
42
43 #if !defined(lint)
44 static const char sccsid[] = "@(#)parse.c       1.44 6/5/96 (C) 1993-2000 Darren Reed";
45 static const char rcsid[] = "@(#)$IPFilter: parse.c,v 2.8 1999/12/28 10:49:46 darrenr Exp $";
46 #endif
47
48 extern  struct  ipopt_names     ionames[], secclass[];
49 extern  int     opts;
50 extern  int     use_inet6;
51
52
53 char    *proto = NULL;
54 char    flagset[] = "FSRPAUEC";
55 u_char  flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG,
56                     TH_ECN, TH_CWR };
57
58 void fill6bits __P((int, u_32_t *));
59 int count6bits __P((u_32_t *));
60
61 static  char    thishost[MAXHOSTNAMELEN];
62
63
64 void initparse()
65 {
66         gethostname(thishost, sizeof(thishost));
67         thishost[sizeof(thishost) - 1] = '\0';
68 }
69
70
71 int genmask(msk, mskp)
72 char *msk;
73 u_32_t *mskp;
74 {
75         char *endptr = NULL;
76 #ifdef  USE_INET6
77         u_32_t addr;
78 #endif
79         int bits;
80
81         if (index(msk, '.') || index(msk, 'x') || index(msk, ':')) {
82                 /* possibly of the form xxx.xxx.xxx.xxx
83                  * or 0xYYYYYYYY */
84 #ifdef  USE_INET6
85                 if (use_inet6) {
86                         if (inet_pton(AF_INET6, msk, &addr) != 1)
87                                 return -1;
88                 } else
89 #endif
90                 if (inet_aton(msk, (struct in_addr *)mskp) == 0)
91                         return -1;
92         } else {
93                 /*
94                  * set x most significant bits
95                  */
96                 bits = (int)strtol(msk, &endptr, 0);
97                 if ((*endptr != '\0') ||
98                     ((bits > 32) && !use_inet6) || (bits < 0) ||
99                     ((bits > 128) && use_inet6))
100                         return -1;
101                 if (use_inet6)
102                         fill6bits(bits, mskp);
103                 else {
104                         if (bits == 0)
105                                 *mskp = 0;
106                         else
107                                 *mskp = htonl(0xffffffff << (32 - bits));
108                 }
109         }
110         return 0;
111 }
112
113
114
115 void fill6bits(bits, msk)
116 int bits;
117 u_32_t *msk;
118 {
119         int i;
120         
121         for (i = 0; bits >= 32 && i < 4 ; ++i, bits -= 32)
122                 msk[i] = 0xffffffff;
123         
124         if (bits > 0 && i < 4)
125                 msk[i++] = htonl(0xffffffff << (32 - bits));
126
127         while (i < 4)
128                 msk[i++] = 0;
129 }
130
131
132 /*
133  * returns -1 if neither "hostmask/num" or "hostmask mask addr" are
134  * found in the line segments, there is an error processing this information,
135  * or there is an error processing ports information.
136  */
137 int     hostmask(seg, sa, msk, pp, cp, tp, linenum)
138 char    ***seg;
139 u_32_t  *sa, *msk;
140 u_short *pp, *tp;
141 int     *cp;
142 int     linenum;
143 {
144         struct in_addr maskaddr;
145         char *s;
146
147         /*
148          * is it possibly hostname/num ?
149          */
150         if ((s = index(**seg, '/')) ||
151             ((s = index(**seg, ':')) && !index(s + 1, ':'))) {
152                 *s++ = '\0';
153                 if (genmask(s, msk) == -1) {
154                         fprintf(stderr, "%d: bad mask (%s)\n", linenum, s);
155                         return -1;
156                 }
157                 if (hostnum(sa, **seg, linenum) == -1) {
158                         fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
159                         return -1;
160                 }
161                 *sa &= *msk;
162                 (*seg)++;
163                 return ports(seg, pp, cp, tp, linenum);
164         }
165
166         /*
167          * look for extra segments if "mask" found in right spot
168          */
169         if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) {
170                 if (hostnum(sa, **seg, linenum) == -1) {
171                         fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
172                         return -1;
173                 }
174                 (*seg)++;
175                 (*seg)++;
176                 if (inet_aton(**seg, &maskaddr) == 0) {
177                         fprintf(stderr, "%d: bad mask (%s)\n", linenum, **seg);
178                         return -1;
179                 }
180                 *msk = maskaddr.s_addr;
181                 (*seg)++;
182                 *sa &= *msk;
183                 return ports(seg, pp, cp, tp, linenum);
184         }
185
186         if (**seg) {
187                 if (hostnum(sa, **seg, linenum) == -1) {
188                         fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
189                         return -1;
190                 }
191                 (*seg)++;
192                 if (use_inet6) {
193                         u_32_t k = 0;
194                         if (sa[0] || sa[1] || sa[2] || sa[3])
195                                 k = 0xffffffff;
196                         msk[0] = msk[1] = msk[2] = msk[3] = k;
197                 }
198                 else
199                         *msk = *sa ? 0xffffffff : 0;
200                 return ports(seg, pp, cp, tp, linenum);
201         }
202         fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
203         return -1;
204 }
205
206 /*
207  * returns an ip address as a long var as a result of either a DNS lookup or
208  * straight inet_addr() call
209  */
210 int     hostnum(ipa, host, linenum)
211 u_32_t  *ipa;
212 char    *host;
213 int     linenum;
214 {
215         struct  hostent *hp;
216         struct  netent  *np;
217         struct  in_addr ip;
218
219         if (!strcasecmp("any", host))
220                 return 0;
221 #ifdef  USE_INET6
222         if (use_inet6) {
223                 if (inet_pton(AF_INET6, host, ipa) == 1)
224                         return 0;
225                 else
226                         return -1;
227         }
228 #endif
229         if (isdigit(*host) && inet_aton(host, &ip)) {
230                 *ipa = ip.s_addr;
231                 return 0;
232         }
233
234         if (!strcasecmp("<thishost>", host))
235                 host = thishost;
236
237         if (!(hp = gethostbyname(host))) {
238                 if (!(np = getnetbyname(host))) {
239                         fprintf(stderr, "%d: can't resolve hostname: %s\n",
240                                 linenum, host);
241                         return -1;
242                 }
243                 *ipa = htonl(np->n_net);
244                 return 0;
245         }
246         *ipa = *(u_32_t *)hp->h_addr;
247         return 0;
248 }
249
250
251 /*
252  * check for possible presence of the port fields in the line
253  */
254 int     ports(seg, pp, cp, tp, linenum)
255 char    ***seg;
256 u_short *pp, *tp;
257 int     *cp;
258 int     linenum;
259 {
260         int     comp = -1;
261
262         if (!*seg || !**seg || !***seg)
263                 return 0;
264         if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) {
265                 (*seg)++;
266                 if (isalnum(***seg) && *(*seg + 2)) {
267                         if (portnum(**seg, pp, linenum) == 0)
268                                 return -1;
269                         (*seg)++;
270                         if (!strcmp(**seg, "<>"))
271                                 comp = FR_OUTRANGE;
272                         else if (!strcmp(**seg, "><"))
273                                 comp = FR_INRANGE;
274                         else {
275                                 fprintf(stderr,
276                                         "%d: unknown range operator (%s)\n",
277                                         linenum, **seg);
278                                 return -1;
279                         }
280                         (*seg)++;
281                         if (**seg == NULL) {
282                                 fprintf(stderr, "%d: missing 2nd port value\n",
283                                         linenum);
284                                 return -1;
285                         }
286                         if (portnum(**seg, tp, linenum) == 0)
287                                 return -1;
288                 } else if (!strcmp(**seg, "=") || !strcasecmp(**seg, "eq"))
289                         comp = FR_EQUAL;
290                 else if (!strcmp(**seg, "!=") || !strcasecmp(**seg, "ne"))
291                         comp = FR_NEQUAL;
292                 else if (!strcmp(**seg, "<") || !strcasecmp(**seg, "lt"))
293                         comp = FR_LESST;
294                 else if (!strcmp(**seg, ">") || !strcasecmp(**seg, "gt"))
295                         comp = FR_GREATERT;
296                 else if (!strcmp(**seg, "<=") || !strcasecmp(**seg, "le"))
297                         comp = FR_LESSTE;
298                 else if (!strcmp(**seg, ">=") || !strcasecmp(**seg, "ge"))
299                         comp = FR_GREATERTE;
300                 else {
301                         fprintf(stderr, "%d: unknown comparator (%s)\n",
302                                         linenum, **seg);
303                         return -1;
304                 }
305                 if (comp != FR_OUTRANGE && comp != FR_INRANGE) {
306                         (*seg)++;
307                         if (portnum(**seg, pp, linenum) == 0)
308                                 return -1;
309                 }
310                 *cp = comp;
311                 (*seg)++;
312         }
313         return 0;
314 }
315
316
317 /*
318  * find the port number given by the name, either from getservbyname() or
319  * straight atoi(). Return 1 on success, 0 on failure
320  */
321 int     portnum(name, port, linenum)
322 char    *name;
323 u_short *port;
324 int     linenum;
325 {
326         struct  servent *sp, *sp2;
327         u_short p1 = 0;
328         int i;
329
330         if (isdigit(*name)) {
331                 if (ratoi(name, &i, 0, USHRT_MAX)) {
332                         *port = (u_short)i;
333                         return 1;
334                 }
335                 fprintf(stderr, "%d: unknown port \"%s\"\n", linenum, name);
336                 return 0;
337         }
338         if (proto != NULL && strcasecmp(proto, "tcp/udp") != 0) {
339                 sp = getservbyname(name, proto);
340                 if (sp) {
341                         *port = ntohs(sp->s_port);
342                         return 1;
343                 }
344                 fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name);
345                 return 0;
346         }
347         sp = getservbyname(name, "tcp");
348         if (sp)
349                 p1 = sp->s_port;
350         sp2 = getservbyname(name, "udp");
351         if (!sp || !sp2) {
352                 fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n",
353                         linenum, name);
354                 return 0;
355         }
356         if (p1 != sp2->s_port) {
357                 fprintf(stderr, "%d: %s %d/tcp is a different port to ",
358                         linenum, name, p1);
359                 fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port);
360                 return 0;
361         }
362         *port = ntohs(p1);
363         return 1;
364 }
365
366
367 u_char tcp_flags(flgs, mask, linenum)
368 char *flgs;
369 u_char *mask;
370 int    linenum;
371 {
372         u_char tcpf = 0, tcpfm = 0, *fp = &tcpf;
373         char *s, *t;
374
375         if (*flgs == '0') {
376                 s = strchr(flgs, '/');
377                 if (s)
378                         *s++ = '\0';
379                 tcpf = strtol(flgs, NULL, 0);
380                 fp = &tcpfm;
381         } else
382                 s = flgs;
383
384         for (; *s; s++) {
385                 if (*s == '/' && fp == &tcpf) {
386                         fp = &tcpfm;
387                         if (*(s + 1) == '0')
388                                 break;
389                         continue;
390                 }
391                 if (!(t = index(flagset, *s))) {
392                         fprintf(stderr, "%d: unknown flag (%c)\n", linenum, *s);
393                         return 0;
394                 }
395                 *fp |= flags[t - flagset];
396         }
397
398         if (s && *s == '0')
399                 tcpfm = strtol(s, NULL, 0);
400
401         if (!tcpfm) {
402                 if (tcpf == TH_SYN)
403                         tcpfm = 0xff & ~(TH_ECN|TH_CWR);
404                 else
405                         tcpfm = 0xff & ~(TH_ECN);
406         }
407         *mask = tcpfm;
408         return tcpf;
409 }
410
411
412 /*
413  * count consecutive 1's in bit mask.  If the mask generated by counting
414  * consecutive 1's is different to that passed, return -1, else return #
415  * of bits.
416  */
417 int     countbits(ip)
418 u_32_t  ip;
419 {
420         u_32_t  ipn;
421         int     cnt = 0, i, j;
422
423         ip = ipn = ntohl(ip);
424         for (i = 32; i; i--, ipn *= 2)
425                 if (ipn & 0x80000000)
426                         cnt++;
427                 else
428                         break;
429         ipn = 0;
430         for (i = 32, j = cnt; i; i--, j--) {
431                 ipn *= 2;
432                 if (j > 0)
433                         ipn++;
434         }
435         if (ipn == ip)
436                 return cnt;
437         return -1;
438 }
439
440
441 int count6bits(msk)
442 u_32_t *msk;
443 {
444         int i = 0, k;
445         u_32_t j;
446
447         for (k = 3; k >= 0; k--)
448                 if (msk[k] == 0xffffffff)
449                         i += 32;
450                 else {
451                         for (j = msk[k]; j; j <<= 1)
452                                 if (j & 0x80000000)
453                                         i++;
454                 }
455         return i;
456 }
457
458
459 char    *portname(pr, port)
460 int     pr, port;
461 {
462         static  char    buf[32];
463         struct  protoent        *p = NULL;
464         struct  servent *sv = NULL, *sv1 = NULL;
465
466         if (pr == -1) {
467                 if ((sv = getservbyport(htons(port), "tcp"))) {
468                         strncpy(buf, sv->s_name, sizeof(buf)-1);
469                         buf[sizeof(buf)-1] = '\0';
470                         sv1 = getservbyport(htons(port), "udp");
471                         sv = strncasecmp(buf, sv->s_name, strlen(buf)) ?
472                              NULL : sv1;
473                 }
474                 if (sv)
475                         return buf;
476         } else if (pr && (p = getprotobynumber(pr))) {
477                 if ((sv = getservbyport(htons(port), p->p_name))) {
478                         strncpy(buf, sv->s_name, sizeof(buf)-1);
479                         buf[sizeof(buf)-1] = '\0';
480                         return buf;
481                 }
482         }
483
484         (void) sprintf(buf, "%d", port);
485         return buf;
486 }
487
488
489 int     ratoi(ps, pi, min, max)
490 char    *ps;
491 int     *pi, min, max;
492 {
493         int i;
494         char *pe;
495
496         i = (int)strtol(ps, &pe, 0);
497         if (*pe != '\0' || i < min || i > max)
498                 return 0;
499         *pi = i;
500         return 1;
501 }
502
503
504 int     ratoui(ps, pi, min, max)
505 char    *ps;
506 u_int   *pi, min, max;
507 {
508         u_int i;
509         char *pe;
510
511         i = (u_int)strtol(ps, &pe, 0);
512         if (*pe != '\0' || i < min || i > max)
513                 return 0;
514         *pi = i;
515         return 1;
516 }
517
518
519 void    printhostmask(v, addr, mask)
520 int     v;
521 u_32_t  *addr, *mask;
522 {
523         struct in_addr ipa;
524         int ones;
525
526 #ifdef USE_INET6
527         if (v == 6) {
528                 ones = count6bits(mask);
529                 if (ones == 0 && !addr[0] && !addr[1] && !addr[2] && !addr[3])
530                         printf("any");
531                 else {
532                         char ipbuf[64];
533                         printf("%s/%d",
534                                inet_ntop(AF_INET6, addr, ipbuf, sizeof(ipbuf)),
535                                ones);
536                 }
537         }
538         else
539 #endif
540         if (!*addr && !*mask)
541                 printf("any");
542         else {
543                 ipa.s_addr = *addr;
544                 printf("%s", inet_ntoa(ipa));
545                 if ((ones = countbits(*mask)) == -1) {
546                         ipa.s_addr = *mask;
547                         printf("/%s", inet_ntoa(ipa));
548                 } else
549                         printf("/%d", ones);
550         }
551 }
552
553
554 void    printportcmp(pr, frp)
555 int     pr;
556 frpcmp_t        *frp;
557 {
558         static char *pcmp1[] = { "*", "=", "!=", "<", ">", "<=", ">=",
559                                  "<>", "><"};
560
561         if (frp->frp_cmp == FR_INRANGE || frp->frp_cmp == FR_OUTRANGE)
562                 printf(" port %d %s %d", frp->frp_port,
563                              pcmp1[frp->frp_cmp], frp->frp_top);
564         else
565                 printf(" port %s %s", pcmp1[frp->frp_cmp],
566                              portname(pr, frp->frp_port));
567 }
568
569
570 void printbuf(buf, len, zend)
571 char *buf;
572 int len, zend;
573 {
574         char *s, c;
575         int i;
576
577         for (s = buf, i = len; i; i--) {
578                 c = *s++;
579                 if (isprint(c))
580                         putchar(c);
581                 else
582                         printf("\\%03o", c);
583                 if ((c == '\0') && zend)
584                         break;
585         }
586 }
587
588
589
590 char *hostname(v, ip)
591 int v;
592 void *ip;
593 {
594 #ifdef  USE_INET6
595         static char hostbuf[MAXHOSTNAMELEN+1];
596 #endif
597         struct in_addr ipa;
598
599         if (v == 4) {
600                 ipa.s_addr = *(u_32_t *)ip;
601                 return inet_ntoa(ipa);
602         }
603 #ifdef  USE_INET6
604         (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1);
605         hostbuf[MAXHOSTNAMELEN] = '\0';
606         return hostbuf;
607 #else
608         return "IPv6";
609 #endif
610 }