]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/ip_auth.c
This commit was generated by cvs2svn to compensate for changes in r54816,
[FreeBSD/FreeBSD.git] / contrib / ipfilter / ip_auth.c
1 /*
2  * Copyright (C) 1998 by Darren Reed & Guido van Rooij.
3  *
4  * Redistribution and use in source and binary forms are permitted
5  * provided that this notice is preserved and due credit is given
6  * to the original author and the contributors.
7  */
8 #if !defined(lint)
9 static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.1.2.1 1999/09/28 11:44:04 darrenr Exp $";
10 #endif
11
12 #include <sys/errno.h>
13 #include <sys/types.h>
14 #include <sys/param.h>
15 #include <sys/time.h>
16 #include <sys/file.h>
17 #if !defined(_KERNEL) && !defined(KERNEL)
18 # include <stdio.h>
19 # include <stdlib.h>
20 # include <string.h>
21 #endif
22 #if defined(KERNEL) && (__FreeBSD_version >= 220000)
23 # include <sys/filio.h>
24 # include <sys/fcntl.h>
25 #else
26 # include <sys/ioctl.h>
27 #endif
28 #include <sys/uio.h>
29 #ifndef linux
30 # include <sys/protosw.h>
31 #endif
32 #include <sys/socket.h>
33 #if defined(_KERNEL) && !defined(linux)
34 # include <sys/systm.h>
35 #endif
36 #if !defined(__SVR4) && !defined(__svr4__)
37 # ifndef linux
38 #  include <sys/mbuf.h>
39 # endif
40 #else
41 # include <sys/filio.h>
42 # include <sys/byteorder.h>
43 # ifdef _KERNEL
44 #  include <sys/dditypes.h>
45 # endif
46 # include <sys/stream.h>
47 # include <sys/kmem.h>
48 #endif
49 #if _BSDI_VERSION >= 199802
50 # include <sys/queue.h>
51 #endif
52 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
53 # include <machine/cpu.h>
54 #endif
55 #include <net/if.h>
56 #ifdef sun
57 # include <net/af.h>
58 #endif
59 #include <net/route.h>
60 #include <netinet/in.h>
61 #include <netinet/in_systm.h>
62 #include <netinet/ip.h>
63 #ifndef KERNEL
64 # define        KERNEL
65 # define        NOT_KERNEL
66 #endif
67 #ifndef linux
68 # include <netinet/ip_var.h>
69 #endif
70 #ifdef  NOT_KERNEL
71 # undef KERNEL
72 #endif
73 #ifdef __sgi
74 # ifdef IFF_DRVRLOCK /* IRIX6 */
75 #  include <sys/hashing.h>
76 # endif
77 #endif
78 #include <netinet/tcp.h>
79 #if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */
80 extern struct ifqueue   ipintrq;                /* ip packet input queue */
81 #else
82 # ifndef linux
83 #  if __FreeBSD_version >= 300000
84 #   include <net/if_var.h>
85 #  endif
86 #  include <netinet/in_var.h>
87 #  include <netinet/tcp_fsm.h>
88 # endif
89 #endif
90 #include <netinet/udp.h>
91 #include <netinet/ip_icmp.h>
92 #include "netinet/ip_compat.h"
93 #include <netinet/tcpip.h>
94 #include "netinet/ip_fil.h"
95 #include "netinet/ip_auth.h"
96 #if !SOLARIS && !defined(linux)
97 # include <net/netisr.h>
98 # ifdef __FreeBSD__
99 #  include <machine/cpufunc.h>
100 # endif
101 #endif
102 #if (__FreeBSD_version >= 300000)
103 # include <sys/malloc.h>
104 # if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM)
105 #  include <sys/libkern.h>
106 #  include <sys/systm.h>
107 # endif
108 #endif
109
110
111
112 #if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
113 extern KRWLOCK_T ipf_auth;
114 extern kmutex_t ipf_authmx;
115 # if SOLARIS
116 extern kcondvar_t ipfauthwait;
117 # endif
118 #endif
119 #ifdef linux
120 static struct wait_queue *ipfauthwait = NULL;
121 #endif
122
123 int     fr_authsize = FR_NUMAUTH;
124 int     fr_authused = 0;
125 int     fr_defaultauthage = 600;
126 fr_authstat_t   fr_authstats;
127 frauth_t fr_auth[FR_NUMAUTH];
128 mb_t    *fr_authpkts[FR_NUMAUTH];
129 int     fr_authstart = 0, fr_authend = 0, fr_authnext = 0;
130 frauthent_t     *fae_list = NULL;
131 frentry_t       *ipauth = NULL;
132
133
134 /*
135  * Check if a packet has authorization.  If the packet is found to match an
136  * authorization result and that would result in a feedback loop (i.e. it
137  * will end up returning FR_AUTH) then return FR_BLOCK instead.
138  */
139 u_32_t fr_checkauth(ip, fin)
140 ip_t *ip;
141 fr_info_t *fin;
142 {
143         u_short id = ip->ip_id;
144         u_32_t pass;
145         int i;
146
147         READ_ENTER(&ipf_auth);
148         for (i = fr_authstart; i != fr_authend; ) {
149                 /*
150                  * index becomes -2 only after an SIOCAUTHW.  Check this in
151                  * case the same packet gets sent again and it hasn't yet been
152                  * auth'd.
153                  */
154                 if ((fr_auth[i].fra_index == -2) &&
155                     (id == fr_auth[i].fra_info.fin_id) &&
156                     !bcmp((char *)fin,(char *)&fr_auth[i].fra_info,FI_CSIZE)) {
157                         /*
158                          * Avoid feedback loop.
159                          */
160                         if (!(pass = fr_auth[i].fra_pass) || (pass & FR_AUTH))
161                                 pass = FR_BLOCK;
162                         RWLOCK_EXIT(&ipf_auth);
163                         WRITE_ENTER(&ipf_auth);
164                         fr_authstats.fas_hits++;
165                         fr_auth[i].fra_index = -1;
166                         fr_authused--;
167                         if (i == fr_authstart) {
168                                 while (fr_auth[i].fra_index == -1) {
169                                         i++;
170                                         if (i == FR_NUMAUTH)
171                                                 i = 0;
172                                         fr_authstart = i;
173                                         if (i == fr_authend)
174                                                 break;
175                                 }
176                                 if (fr_authstart == fr_authend) {
177                                         fr_authnext = 0;
178                                         fr_authstart = fr_authend = 0;
179                                 }
180                         }
181                         RWLOCK_EXIT(&ipf_auth);
182                         return pass;
183                 }
184                 i++;
185                 if (i == FR_NUMAUTH)
186                         i = 0;
187         }
188         fr_authstats.fas_miss++;
189         RWLOCK_EXIT(&ipf_auth);
190         return 0;
191 }
192
193
194 /*
195  * Check if we have room in the auth array to hold details for another packet.
196  * If we do, store it and wake up any user programs which are waiting to
197  * hear about these events.
198  */
199 int fr_newauth(m, fin, ip
200 #if defined(_KERNEL) && SOLARIS
201 , qif)
202 qif_t *qif;
203 #else
204 )
205 #endif
206 mb_t *m;
207 fr_info_t *fin;
208 ip_t *ip;
209 {
210         int i;
211
212         WRITE_ENTER(&ipf_auth);
213         if (fr_authstart > fr_authend) {
214                 fr_authstats.fas_nospace++;
215                 RWLOCK_EXIT(&ipf_auth);
216                 return 0;
217         } else {
218                 if ((fr_authstart == 0) && (fr_authend == FR_NUMAUTH - 1)) {
219                         fr_authstats.fas_nospace++;
220                         RWLOCK_EXIT(&ipf_auth);
221                         return 0;
222                 }
223         }
224
225         fr_authstats.fas_added++;
226         fr_authused++;
227         i = fr_authend++;
228         if (fr_authend == FR_NUMAUTH)
229                 fr_authend = 0;
230         RWLOCK_EXIT(&ipf_auth);
231         fr_auth[i].fra_index = i;
232         fr_auth[i].fra_pass = 0;
233         fr_auth[i].fra_age = fr_defaultauthage;
234         bcopy((char *)fin, (char *)&fr_auth[i].fra_info, sizeof(*fin));
235 #if !defined(sparc) && !defined(m68k)
236         /*
237          * No need to copyback here as we want to undo the changes, not keep
238          * them.
239          */
240 # if SOLARIS && defined(_KERNEL)
241         if (ip == (ip_t *)m->b_rptr)
242 # endif
243         {
244                 register u_short bo;
245
246                 bo = ip->ip_len;
247                 ip->ip_len = htons(bo);
248 # if !SOLARIS   /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */
249                 bo = ip->ip_id;
250                 ip->ip_id = htons(bo);
251 # endif
252                 bo = ip->ip_off;
253                 ip->ip_off = htons(bo);
254         }
255 #endif
256 #if SOLARIS && defined(_KERNEL)
257         m->b_rptr -= qif->qf_off;
258         fr_authpkts[i] = *(mblk_t **)fin->fin_mp;
259         fr_auth[i].fra_q = qif->qf_q;
260         cv_signal(&ipfauthwait);
261 #else
262         fr_authpkts[i] = m;
263 # if defined(linux) && defined(_KERNEL)
264         wake_up_interruptible(&ipfauthwait);
265 # else
266         WAKEUP(&fr_authnext);
267 # endif
268 #endif
269         return 1;
270 }
271
272
273 int fr_auth_ioctl(data, cmd, fr, frptr)
274 caddr_t data;
275 #if defined(__NetBSD__) || defined(__OpenBSD__)
276 u_long cmd;
277 #else
278 int cmd;
279 #endif
280 frentry_t *fr, **frptr;
281 {
282         mb_t *m;
283 #if defined(_KERNEL)
284 # if !SOLARIS
285         struct ifqueue *ifq;
286         int s;
287 # endif
288 #endif
289         frauth_t auth, *au = &auth;
290         frauthent_t *fae, **faep;
291         int i, error = 0;
292
293         switch (cmd)
294         {
295         case SIOCINIFR :
296         case SIOCRMIFR :
297         case SIOCADIFR :
298                 error = EINVAL;
299                 break;
300         case SIOCINAFR :
301         case SIOCRMAFR :
302         case SIOCADAFR :
303                 for (faep = &fae_list; (fae = *faep); )
304                         if (&fae->fae_fr == fr)
305                                 break;
306                         else
307                                 faep = &fae->fae_next;
308                 if (cmd == SIOCRMAFR) {
309                         if (!fae)
310                                 error = ESRCH;
311                         else {
312                                 WRITE_ENTER(&ipf_auth);
313                                 *faep = fae->fae_next;
314                                 *frptr = fr->fr_next;
315                                 RWLOCK_EXIT(&ipf_auth);
316                                 KFREE(fae);
317                         }
318                 } else {
319                         KMALLOC(fae, frauthent_t *);
320                         if (fae != NULL) {
321                                 IRCOPY((char *)data, (char *)&fae->fae_fr,
322                                        sizeof(fae->fae_fr));
323                                 WRITE_ENTER(&ipf_auth);
324                                 fae->fae_age = fr_defaultauthage;
325                                 fae->fae_fr.fr_hits = 0;
326                                 fae->fae_fr.fr_next = *frptr;
327                                 *frptr = &fae->fae_fr;
328                                 fae->fae_next = *faep;
329                                 *faep = fae;
330                                 ipauth = &fae_list->fae_fr;
331                                 RWLOCK_EXIT(&ipf_auth);
332                         } else
333                                 error = ENOMEM;
334                 }
335                 break;
336         case SIOCATHST:
337                 READ_ENTER(&ipf_auth);
338                 fr_authstats.fas_faelist = fae_list;
339                 RWLOCK_EXIT(&ipf_auth);
340                 IWCOPY((char *)&fr_authstats, data, sizeof(fr_authstats));
341                 break;
342         case SIOCAUTHW:
343 fr_authioctlloop:
344                 READ_ENTER(&ipf_auth);
345                 if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) {
346                         IWCOPY((char *)&fr_auth[fr_authnext], data,
347                                sizeof(fr_info_t));
348                         RWLOCK_EXIT(&ipf_auth);
349                         WRITE_ENTER(&ipf_auth);
350                         fr_authnext++;
351                         if (fr_authnext == FR_NUMAUTH)
352                                 fr_authnext = 0;
353                         RWLOCK_EXIT(&ipf_auth);
354                         return 0;
355                 }
356 #ifdef  _KERNEL
357 # if    SOLARIS
358                 mutex_enter(&ipf_authmx);
359                 if (!cv_wait_sig(&ipfauthwait, &ipf_authmx)) {
360                         mutex_exit(&ipf_authmx);
361                         return EINTR;
362                 }
363                 mutex_exit(&ipf_authmx);
364 # else
365 #  ifdef linux
366                 interruptible_sleep_on(&ipfauthwait);
367                 if (current->signal & ~current->blocked)
368                         error = -EINTR;
369 #  else
370                 error = SLEEP(&fr_authnext, "fr_authnext");
371 # endif
372 # endif
373 #endif
374                 RWLOCK_EXIT(&ipf_auth);
375                 if (!error)
376                         goto fr_authioctlloop;
377                 break;
378         case SIOCAUTHR:
379                 IRCOPY(data, (caddr_t)&auth, sizeof(auth));
380                 WRITE_ENTER(&ipf_auth);
381                 i = au->fra_index;
382                 if ((i < 0) || (i > FR_NUMAUTH) ||
383                     (fr_auth[i].fra_info.fin_id != au->fra_info.fin_id)) {
384                         RWLOCK_EXIT(&ipf_auth);
385                         return EINVAL;
386                 }
387                 m = fr_authpkts[i];
388                 fr_auth[i].fra_index = -2;
389                 fr_auth[i].fra_pass = au->fra_pass;
390                 fr_authpkts[i] = NULL;
391 #ifdef  _KERNEL
392                 RWLOCK_EXIT(&ipf_auth);
393                 SPL_NET(s);
394 # ifndef linux
395                 if (m && au->fra_info.fin_out) {
396 #  if SOLARIS
397                         error = fr_qout(fr_auth[i].fra_q, m);
398 #  else /* SOLARIS */
399 #   if _BSDI_VERSION >= 199802
400                         error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL,
401                                           NULL);
402 #   else
403                         error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
404 #   endif
405 #  endif /* SOLARIS */
406                         if (error)
407                                 fr_authstats.fas_sendfail++;
408                         else
409                                 fr_authstats.fas_sendok++;
410                 } else if (m) {
411 # if SOLARIS
412                         error = fr_qin(fr_auth[i].fra_q, m);
413 # else /* SOLARIS */
414                         ifq = &ipintrq;
415                         if (IF_QFULL(ifq)) {
416                                 IF_DROP(ifq);
417                                 m_freem(m);
418                                 error = ENOBUFS;
419                         } else {
420                                 IF_ENQUEUE(ifq, m);
421                                 schednetisr(NETISR_IP);
422                         }
423 # endif /* SOLARIS */
424                         if (error)
425                                 fr_authstats.fas_quefail++;
426                         else
427                                 fr_authstats.fas_queok++;
428                 } else
429                         error = EINVAL;
430 # endif
431 # if SOLARIS
432                 if (error)
433                         error = EINVAL;
434 # else
435                 /*
436                  * If we experience an error which will result in the packet
437                  * not being processed, make sure we advance to the next one.
438                  */ 
439                 if (error == ENOBUFS) {
440                         fr_authused--;
441                         fr_auth[i].fra_index = -1;
442                         fr_auth[i].fra_pass = 0;
443                         if (i == fr_authstart) {
444                                 while (fr_auth[i].fra_index == -1) {
445                                         i++;
446                                         if (i == FR_NUMAUTH)
447                                                 i = 0;
448                                         fr_authstart = i;
449                                         if (i == fr_authend)
450                                                 break;
451                                 }
452                                 if (fr_authstart == fr_authend) {
453                                         fr_authnext = 0;
454                                         fr_authstart = fr_authend = 0;
455                                 }
456                         }
457                 }
458 # endif
459                 SPL_X(s);
460 #endif /* _KERNEL */
461                 break;
462         default :
463                 error = EINVAL;
464                 break;
465         }
466         return error;
467 }
468
469
470 #ifdef  _KERNEL
471 /*
472  * Free all network buffer memory used to keep saved packets.
473  */
474 void fr_authunload()
475 {
476         register int i;
477         register frauthent_t *fae, **faep;
478         mb_t *m;
479
480         WRITE_ENTER(&ipf_auth);
481         for (i = 0; i < FR_NUMAUTH; i++) {
482                 if ((m = fr_authpkts[i])) {
483                         FREE_MB_T(m);
484                         fr_authpkts[i] = NULL;
485                         fr_auth[i].fra_index = -1;
486                 }
487         }
488
489
490         for (faep = &fae_list; (fae = *faep); ) {
491                 *faep = fae->fae_next;
492                 KFREE(fae);
493         }
494         ipauth = NULL;
495         RWLOCK_EXIT(&ipf_auth);
496 }
497
498
499 /*
500  * Slowly expire held auth records.  Timeouts are set
501  * in expectation of this being called twice per second.
502  */
503 void fr_authexpire()
504 {
505         register int i;
506         register frauth_t *fra;
507         register frauthent_t *fae, **faep;
508         mb_t *m;
509 #if !SOLARIS
510         int s;
511 #endif
512
513         SPL_NET(s);
514         WRITE_ENTER(&ipf_auth);
515         for (i = 0, fra = fr_auth; i < FR_NUMAUTH; i++, fra++) {
516                 if ((!--fra->fra_age) && (m = fr_authpkts[i])) {
517                         FREE_MB_T(m);
518                         fr_authpkts[i] = NULL;
519                         fr_auth[i].fra_index = -1;
520                         fr_authstats.fas_expire++;
521                         fr_authused--;
522                 }
523         }
524
525         for (faep = &fae_list; (fae = *faep); ) {
526                 if (!--fae->fae_age) {
527                         *faep = fae->fae_next;
528                         KFREE(fae);
529                         fr_authstats.fas_expire++;
530                 } else
531                         faep = &fae->fae_next;
532         }
533         ipauth = &fae_list->fae_fr;
534         RWLOCK_EXIT(&ipf_auth);
535         SPL_X(s);
536 }
537 #endif