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