2 * Copyright (C) 1997 by Darren Reed & Guido van Rooij.
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.
9 static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.0.2.21.2.2 1997/11/12 10:45:51 darrenr Exp $";
12 #if !defined(_KERNEL) && !defined(KERNEL)
16 #include <sys/errno.h>
17 #include <sys/types.h>
18 #include <sys/param.h>
21 #if defined(KERNEL) && (__FreeBSD_version >= 220000)
22 # include <sys/filio.h>
23 # include <sys/fcntl.h>
25 # include <sys/ioctl.h>
29 # include <sys/protosw.h>
31 #include <sys/socket.h>
32 #if defined(_KERNEL) && !defined(linux)
33 # include <sys/systm.h>
35 #if !defined(__SVR4) && !defined(__svr4__)
37 # include <sys/mbuf.h>
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>
46 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
47 # include <machine/cpu.h>
53 #include <net/route.h>
54 #include <netinet/in.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/ip.h>
62 # include <netinet/ip_var.h>
68 # ifdef IFF_DRVRLOCK /* IRIX6 */
69 #include <sys/hashing.h>
72 #include <netinet/tcp.h>
73 #if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */
74 extern struct ifqueue ipintrq; /* ip packet input queue */
77 # include <netinet/in_var.h>
78 # include <netinet/tcp_fsm.h>
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>
92 #if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
93 extern kmutex_t ipf_auth;
95 extern kcondvar_t ipfauthwait;
99 static struct wait_queue *ipfauthwait = NULL;
102 int fr_authsize = FR_NUMAUTH;
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;
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.
118 int fr_checkauth(ip, fin)
122 u_short id = ip->ip_id;
126 MUTEX_ENTER(&ipf_auth);
127 for (i = fr_authstart; i != fr_authend; ) {
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
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)) {
137 * Avoid feedback loop.
139 if (!(pass = fr_auth[i].fra_pass) || (pass & FR_AUTH))
141 fr_authstats.fas_hits++;
142 fr_auth[i].fra_index = -1;
144 if (i == fr_authstart) {
145 while (fr_auth[i].fra_index == -1) {
153 if (fr_authstart == fr_authend) {
155 fr_authstart = fr_authend = 0;
158 MUTEX_EXIT(&ipf_auth);
165 fr_authstats.fas_miss++;
166 MUTEX_EXIT(&ipf_auth);
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.
176 int fr_newauth(m, fin, ip
177 #if defined(_KERNEL) && SOLARIS
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);
195 if (fr_authend - fr_authstart == FR_NUMAUTH - 1) {
196 fr_authstats.fas_nospace++;
197 MUTEX_EXIT(&ipf_auth);
201 fr_authstats.fas_added++;
204 if (fr_authend == FR_NUMAUTH)
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)
213 * No need to copyback here as we want to undo the changes, not keep
216 # if SOLARIS && defined(_KERNEL)
217 if (ip == (ip_t *)m->b_rptr)
223 ip->ip_len = htons(bo);
224 # if !SOLARIS /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */
226 ip->ip_id = htons(bo);
229 ip->ip_off = htons(bo);
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);
239 # if defined(linux) && defined(_KERNEL)
240 wake_up_interruptible(&ipfauthwait);
242 WAKEUP(&fr_authnext);
249 int fr_auth_ioctl(data, cmd, fr, frptr)
251 #if defined(__NetBSD__) || defined(__OpenBSD__)
256 frentry_t *fr, **frptr;
265 frauth_t auth, *au = &auth;
266 frauthent_t *fae, **faep;
279 for (faep = &fae_list; (fae = *faep); )
280 if (&fae->fae_fr == fr)
283 faep = &fae->fae_next;
284 if (cmd == SIOCRMAFR) {
288 *faep = fae->fae_next;
289 *frptr = fr->fr_next;
293 KMALLOC(fae, frauthent_t *, sizeof(*fae));
295 IRCOPY((char *)data, (char *)&fae->fae_fr,
296 sizeof(fae->fae_fr));
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;
309 IWCOPY((char *)&fr_authstats, data, sizeof(fr_authstats));
313 MUTEX_ENTER(&ipf_auth);
314 if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) {
315 IWCOPY((char *)&fr_auth[fr_authnext++], data,
317 if (fr_authnext == FR_NUMAUTH)
319 MUTEX_EXIT(&ipf_auth);
324 if (!cv_wait_sig(&ipfauthwait, &ipf_auth)) {
325 mutex_exit(&ipf_auth);
330 interruptible_sleep_on(&ipfauthwait);
331 if (current->signal & ~current->blocked)
334 error = SLEEP(&fr_authnext, "fr_authnext");
338 MUTEX_EXIT(&ipf_auth);
340 goto fr_authioctlloop;
343 IRCOPY(data, (caddr_t)&auth, sizeof(auth));
344 MUTEX_ENTER(&ipf_auth);
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);
352 fr_auth[i].fra_index = -2;
353 fr_auth[i].fra_pass = au->fra_pass;
354 fr_authpkts[i] = NULL;
356 MUTEX_EXIT(&ipf_auth);
359 if (m && au->fra_info.fin_out) {
361 error = fr_qout(fr_auth[i].fra_q, m);
363 error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
364 # endif /* SOLARIS */
366 fr_authstats.fas_sendfail++;
368 fr_authstats.fas_sendok++;
371 error = fr_qin(fr_auth[i].fra_q, m);
380 schednetisr(NETISR_IP);
382 # endif /* SOLARIS */
384 fr_authstats.fas_quefail++;
386 fr_authstats.fas_queok++;
395 * If we experience an error which will result in the packet
396 * not being processed, make sure we advance to the next one.
398 if (error == ENOBUFS) {
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) {
411 if (fr_authstart == fr_authend) {
413 fr_authstart = fr_authend = 0;
431 * Free all network buffer memory used to keep saved packets.
436 register frauthent_t *fae, **faep;
439 MUTEX_ENTER(&ipf_auth);
440 for (i = 0; i < FR_NUMAUTH; i++) {
441 if ((m = fr_authpkts[i])) {
443 fr_authpkts[i] = NULL;
444 fr_auth[i].fra_index = -1;
449 for (faep = &fae_list; (fae = *faep); ) {
450 *faep = fae->fae_next;
453 MUTEX_EXIT(&ipf_auth);
458 * Slowly expire held auth records. Timeouts are set
459 * in expectation of this being called twice per second.
464 register frauth_t *fra;
465 register frauthent_t *fae, **faep;
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])) {
476 fr_authpkts[i] = NULL;
477 fr_auth[i].fra_index = -1;
478 fr_authstats.fas_expire++;
483 for (faep = &fae_list; (fae = *faep); ) {
484 if (!--fra->fra_age) {
485 *faep = fae->fae_next;
487 fr_authstats.fas_expire++;
489 faep = &fae->fae_next;
491 MUTEX_EXIT(&ipf_auth);