|
|
1.1 root 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) 1993-1997 by Darren Reed.
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: #if !defined(lint)
30: /* static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed"; */
31: #endif
32:
33:
34: #if !defined(KERNEL)
35: # include <string.h>
36: # include <stdlib.h>
37: #endif
38: #include <sys/errno.h>
39: #include <sys/types.h>
40: #include <sys/param.h>
41: #include <sys/time.h>
42: #include <sys/file.h>
43: #if defined(KERNEL)
44: #include <sys/filio.h>
45: #include <sys/fcntl.h>
46: #include <sys/malloc.h>
47: #else
48: #include <sys/ioctl.h>
49: #endif
50: #include <sys/uio.h>
51: #ifndef linux
52: #include <sys/protosw.h>
53: #endif
54: #include <sys/socket.h>
55: #if defined(KERNEL)
56: # include <sys/systm.h>
57: #endif
58: #if !defined(__SVR4) && !defined(__svr4__)
59: # ifndef linux
60: # include <sys/mbuf.h>
61: # endif
62: #else
63: # include <sys/byteorder.h>
64: # include <sys/dditypes.h>
65: # include <sys/stream.h>
66: # include <sys/kmem.h>
67: #endif
68: #if defined(KERNEL)
69: #include <sys/malloc.h>
70: #endif
71:
72: #include <net/if.h>
73: #ifdef sun
74: #include <net/af.h>
75: #endif
76: #include <net/route.h>
77: #include <netinet/in.h>
78: #include <netinet/in_systm.h>
79: #include <netinet/ip.h>
80: #ifndef linux
81: #include <netinet/ip_var.h>
82: #endif
83: #include <netinet/tcp.h>
84: #include <netinet/udp.h>
85: #include <netinet/ip_icmp.h>
86: #include "netinet/ip_compat.h"
87: #include <netinet/tcpip.h>
88: #include "netinet/ip_fil.h"
89: #include "netinet/ip_proxy.h"
90: #include "netinet/ip_nat.h"
91: #include "netinet/ip_frag.h"
92: #include "netinet/ip_state.h"
93: #include "netinet/ip_auth.h"
94:
95: static ipfr_t *ipfr_heads[IPFT_SIZE];
96: static ipfr_t *ipfr_nattab[IPFT_SIZE];
97: static ipfrstat_t ipfr_stats;
98: static int ipfr_inuse = 0;
99: int fr_ipfrttl = 120; /* 60 seconds */
100: #ifdef KERNEL
101: extern int ipfr_timer_id;
102: #endif
103: #if (SOLARIS || defined(__sgi)) && defined(KERNEL)
104: extern kmutex_t ipf_frag;
105: extern kmutex_t ipf_natfrag;
106: extern kmutex_t ipf_nat;
107: #endif
108:
109:
110: static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, int, ipfr_t **));
111: static ipfr_t *ipfr_lookup __P((ip_t *, fr_info_t *, ipfr_t **));
112:
113:
114: ipfrstat_t *ipfr_fragstats()
115: {
116: ipfr_stats.ifs_table = ipfr_heads;
117: ipfr_stats.ifs_nattab = ipfr_nattab;
118: ipfr_stats.ifs_inuse = ipfr_inuse;
119: return &ipfr_stats;
120: }
121:
122:
123: /*
124: * add a new entry to the fragment cache, registering it as having come
125: * through this box, with the result of the filter operation.
126: */
127: static ipfr_t *ipfr_new(ip, fin, pass, table)
128: ip_t *ip;
129: fr_info_t *fin;
130: int pass;
131: ipfr_t *table[];
132: {
133: ipfr_t **fp, *fr, frag;
134: u_int idx;
135:
136: frag.ipfr_p = ip->ip_p;
137: idx = ip->ip_p;
138: frag.ipfr_id = ip->ip_id;
139: idx += ip->ip_id;
140: frag.ipfr_tos = ip->ip_tos;
141: frag.ipfr_src.s_addr = ip->ip_src.s_addr;
142: idx += ip->ip_src.s_addr;
143: frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
144: idx += ip->ip_dst.s_addr;
145: idx *= 127;
146: idx %= IPFT_SIZE;
147:
148: /*
149: * first, make sure it isn't already there...
150: */
151: for (fp = &table[idx]; (fr = *fp); fp = &fr->ipfr_next)
152: if (!bcmp((char *)&frag.ipfr_src, (char *)&fr->ipfr_src,
153: IPFR_CMPSZ)) {
154: ipfr_stats.ifs_exists++;
155: return NULL;
156: }
157:
158: /*
159: * allocate some memory, if possible, if not, just record that we
160: * failed to do so.
161: */
162: KMALLOC(fr, ipfr_t *, sizeof(*fr));
163: if (fr == NULL) {
164: ipfr_stats.ifs_nomem++;
165: return NULL;
166: }
167:
168: /*
169: * Instert the fragment into the fragment table, copy the struct used
170: * in the search using bcopy rather than reassign each field.
171: * Set the ttl to the default and mask out logging from "pass"
172: */
173: if ((fr->ipfr_next = table[idx]))
174: table[idx]->ipfr_prev = fr;
175: fr->ipfr_prev = NULL;
176: fr->ipfr_data = NULL;
177: table[idx] = fr;
178: bcopy((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, IPFR_CMPSZ);
179: fr->ipfr_ttl = fr_ipfrttl;
180: fr->ipfr_pass = pass & ~(FR_LOGFIRST|FR_LOG);
181: /*
182: * Compute the offset of the expected start of the next packet.
183: */
184: fr->ipfr_off = (ip->ip_off & 0x1fff) + (fin->fin_dlen >> 3);
185: ipfr_stats.ifs_new++;
186: ipfr_inuse++;
187: return fr;
188: }
189:
190:
191: int ipfr_newfrag(ip, fin, pass)
192: ip_t *ip;
193: fr_info_t *fin;
194: int pass;
195: {
196: ipfr_t *ipf;
197:
198: MUTEX_ENTER(&ipf_frag);
199: ipf = ipfr_new(ip, fin, pass, ipfr_heads);
200: MUTEX_EXIT(&ipf_frag);
201: return ipf ? 0 : -1;
202: }
203:
204:
205: int ipfr_nat_newfrag(ip, fin, pass, nat)
206: ip_t *ip;
207: fr_info_t *fin;
208: int pass;
209: nat_t *nat;
210: {
211: ipfr_t *ipf;
212:
213: MUTEX_ENTER(&ipf_natfrag);
214: if ((ipf = ipfr_new(ip, fin, pass, ipfr_nattab))) {
215: ipf->ipfr_data = nat;
216: nat->nat_data = ipf;
217: }
218: MUTEX_EXIT(&ipf_natfrag);
219: return ipf ? 0 : -1;
220: }
221:
222:
223: /*
224: * check the fragment cache to see if there is already a record of this packet
225: * with its filter result known.
226: */
227: static ipfr_t *ipfr_lookup(ip, fin, table)
228: ip_t *ip;
229: fr_info_t *fin;
230: ipfr_t *table[];
231: {
232: ipfr_t *f, frag;
233: u_int idx;
234:
235: /*
236: * For fragments, we record protocol, packet id, TOS and both IP#'s
237: * (these should all be the same for all fragments of a packet).
238: *
239: * build up a hash value to index the table with.
240: */
241: frag.ipfr_p = ip->ip_p;
242: idx = ip->ip_p;
243: frag.ipfr_id = ip->ip_id;
244: idx += ip->ip_id;
245: frag.ipfr_tos = ip->ip_tos;
246: frag.ipfr_src.s_addr = ip->ip_src.s_addr;
247: idx += ip->ip_src.s_addr;
248: frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
249: idx += ip->ip_dst.s_addr;
250: idx *= 127;
251: idx %= IPFT_SIZE;
252:
253: /*
254: * check the table, careful to only compare the right amount of data
255: */
256: for (f = table[idx]; f; f = f->ipfr_next)
257: if (!bcmp((char *)&frag.ipfr_src, (char *)&f->ipfr_src,
258: IPFR_CMPSZ)) {
259: u_short atoff, off;
260:
261: if (f != table[idx]) {
262: /*
263: * move fragment info. to the top of the list
264: * to speed up searches.
265: */
266: if ((f->ipfr_prev->ipfr_next = f->ipfr_next))
267: f->ipfr_next->ipfr_prev = f->ipfr_prev;
268: f->ipfr_next = table[idx];
269: table[idx]->ipfr_prev = f;
270: f->ipfr_prev = NULL;
271: table[idx] = f;
272: }
273: off = ip->ip_off;
274: atoff = off + (fin->fin_dlen >> 3);
275: /*
276: * If we've follwed the fragments, and this is the
277: * last (in order), shrink expiration time.
278: */
279: if ((off & 0x1fff) == f->ipfr_off) {
280: if (!(off & IP_MF))
281: f->ipfr_ttl = 1;
282: else
283: f->ipfr_off = atoff;
284: }
285: ipfr_stats.ifs_hits++;
286: return f;
287: }
288: return NULL;
289: }
290:
291:
292: /*
293: * functional interface for NAT lookups of the NAT fragment cache
294: */
295: nat_t *ipfr_nat_knownfrag(ip, fin)
296: ip_t *ip;
297: fr_info_t *fin;
298: {
299: nat_t *nat;
300: ipfr_t *ipf;
301:
302: MUTEX_ENTER(&ipf_natfrag);
303: ipf = ipfr_lookup(ip, fin, ipfr_nattab);
304: if (ipf) {
305: nat = ipf->ipfr_data;
306: /*
307: * This is the last fragment for this packet.
308: */
309: if (ipf->ipfr_ttl == 1) {
310: nat->nat_data = NULL;
311: ipf->ipfr_data = NULL;
312: }
313: } else
314: nat = NULL;
315: MUTEX_EXIT(&ipf_natfrag);
316: return nat;
317: }
318:
319:
320: /*
321: * functional interface for normal lookups of the fragment cache
322: */
323: int ipfr_knownfrag(ip, fin)
324: ip_t *ip;
325: fr_info_t *fin;
326: {
327: int ret;
328: ipfr_t *ipf;
329:
330: MUTEX_ENTER(&ipf_frag);
331: ipf = ipfr_lookup(ip, fin, ipfr_heads);
332: ret = ipf ? ipf->ipfr_pass : 0;
333: MUTEX_EXIT(&ipf_frag);
334: return ret;
335: }
336:
337:
338: /*
339: * forget any references to this external object.
340: */
341: void ipfr_forget(nat)
342: void *nat;
343: {
344: ipfr_t *fr;
345: int idx;
346:
347: MUTEX_ENTER(&ipf_natfrag);
348: for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
349: for (fr = ipfr_heads[idx]; fr; fr = fr->ipfr_next)
350: if (fr->ipfr_data == nat)
351: fr->ipfr_data = NULL;
352:
353: MUTEX_EXIT(&ipf_natfrag);
354: }
355:
356:
357: /*
358: * Free memory in use by fragment state info. kept.
359: */
360: void ipfr_unload()
361: {
362: ipfr_t **fp, *fr;
363: nat_t *nat;
364: int idx;
365:
366: MUTEX_ENTER(&ipf_frag);
367: for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
368: for (fp = &ipfr_heads[idx]; (fr = *fp); ) {
369: *fp = fr->ipfr_next;
370: KFREE(fr);
371: }
372: MUTEX_EXIT(&ipf_frag);
373:
374: MUTEX_ENTER(&ipf_nat);
375: MUTEX_ENTER(&ipf_natfrag);
376: for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
377: for (fp = &ipfr_nattab[idx]; (fr = *fp); ) {
378: *fp = fr->ipfr_next;
379: if ((nat = (nat_t *)fr->ipfr_data)) {
380: if (nat->nat_data == fr)
381: nat->nat_data = NULL;
382: }
383: KFREE(fr);
384: }
385: MUTEX_EXIT(&ipf_natfrag);
386: MUTEX_EXIT(&ipf_nat);
387: }
388:
389:
390: #ifdef KERNEL
391: /*
392: * Slowly expire held state for fragments. Timeouts are set * in expectation
393: * of this being called twice per second.
394: */
395: # if (BSD >= 199306) || SOLARIS || defined(__sgi)
396: void ipfr_slowtimer()
397: # else
398: int ipfr_slowtimer()
399: # endif
400: {
401: ipfr_t **fp, *fr;
402: nat_t *nat;
403: int s, idx;
404:
405: #ifdef __sgi
406: ipfilter_sgi_intfsync();
407: #endif
408:
409: SPL_NET(s);
410: MUTEX_ENTER(&ipf_frag);
411:
412: /*
413: * Go through the entire table, looking for entries to expire,
414: * decreasing the ttl by one for each entry. If it reaches 0,
415: * remove it from the chain and free it.
416: */
417: for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
418: for (fp = &ipfr_heads[idx]; (fr = *fp); ) {
419: --fr->ipfr_ttl;
420: if (fr->ipfr_ttl == 0) {
421: if (fr->ipfr_prev)
422: fr->ipfr_prev->ipfr_next =
423: fr->ipfr_next;
424: if (fr->ipfr_next)
425: fr->ipfr_next->ipfr_prev =
426: fr->ipfr_prev;
427: *fp = fr->ipfr_next;
428: ipfr_stats.ifs_expire++;
429: ipfr_inuse--;
430: KFREE(fr);
431: } else
432: fp = &fr->ipfr_next;
433: }
434: MUTEX_EXIT(&ipf_frag);
435:
436: /*
437: * Same again for the NAT table, except that if the structure also
438: * still points to a NAT structure, and the NAT structure points back
439: * at the one to be free'd, NULL the reference from the NAT struct.
440: * NOTE: We need to grab both mutex's early, and in this order so as
441: * to prevent a deadlock if both try to expire at the same time.
442: */
443: MUTEX_ENTER(&ipf_nat);
444: MUTEX_ENTER(&ipf_natfrag);
445: for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
446: for (fp = &ipfr_nattab[idx]; (fr = *fp); ) {
447: --fr->ipfr_ttl;
448: if (fr->ipfr_ttl == 0) {
449: if (fr->ipfr_prev)
450: fr->ipfr_prev->ipfr_next =
451: fr->ipfr_next;
452: if (fr->ipfr_next)
453: fr->ipfr_next->ipfr_prev =
454: fr->ipfr_prev;
455: *fp = fr->ipfr_next;
456: ipfr_stats.ifs_expire++;
457: ipfr_inuse--;
458: if ((nat = (nat_t *)fr->ipfr_data)) {
459: if (nat->nat_data == fr)
460: nat->nat_data = NULL;
461: }
462: KFREE(fr);
463: } else
464: fp = &fr->ipfr_next;
465: }
466: MUTEX_EXIT(&ipf_natfrag);
467: MUTEX_EXIT(&ipf_nat);
468: SPL_X(s);
469: fr_timeoutstate();
470: ip_natexpire();
471: fr_authexpire();
472: # if SOLARIS
473: ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000));
474: # else
475: # ifndef linux
476: ip_slowtimo();
477: # endif
478: # if (BSD < 199306) && !defined(__sgi)
479: return 0;
480: # endif
481: # endif
482: }
483: #endif /* defined(KERNEL) */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.