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