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