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