source: rtems-libbsd/freebsd/sys/netinet/ip_id.c @ 3d1e767

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 3d1e767 was 3d1e767, checked in by Sebastian Huber <sebastian.huber@…>, on 04/27/16 at 08:25:22

Directly use <sys/types.h> provided by Newlib

  • Property mode set to 100644
File size: 7.1 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3
4/*-
5 * Copyright (c) 2008 Michael J. Silbersack.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice unmodified, this list of conditions, and the following
13 *    disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD$");
32
33/*
34 * IP ID generation is a fascinating topic.
35 *
36 * In order to avoid ID collisions during packet reassembly, common sense
37 * dictates that the period between reuse of IDs be as large as possible.
38 * This leads to the classic implementation of a system-wide counter, thereby
39 * ensuring that IDs repeat only once every 2^16 packets.
40 *
41 * Subsequent security researchers have pointed out that using a global
42 * counter makes ID values predictable.  This predictability allows traffic
43 * analysis, idle scanning, and even packet injection in specific cases.
44 * These results suggest that IP IDs should be as random as possible.
45 *
46 * The "searchable queues" algorithm used in this IP ID implementation was
47 * proposed by Amit Klein.  It is a compromise between the above two
48 * viewpoints that has provable behavior that can be tuned to the user's
49 * requirements.
50 *
51 * The basic concept is that we supplement a standard random number generator
52 * with a queue of the last L IDs that we have handed out to ensure that all
53 * IDs have a period of at least L.
54 *
55 * To efficiently implement this idea, we keep two data structures: a
56 * circular array of IDs of size L and a bitstring of 65536 bits.
57 *
58 * To start, we ask the RNG for a new ID.  A quick index into the bitstring
59 * is used to determine if this is a recently used value.  The process is
60 * repeated until a value is returned that is not in the bitstring.
61 *
62 * Having found a usable ID, we remove the ID stored at the current position
63 * in the queue from the bitstring and replace it with our new ID.  Our new
64 * ID is then added to the bitstring and the queue pointer is incremented.
65 *
66 * The lower limit of 512 was chosen because there doesn't seem to be much
67 * point to having a smaller value.  The upper limit of 32768 was chosen for
68 * two reasons.  First, every step above 32768 decreases the entropy.  Taken
69 * to an extreme, 65533 would offer 1 bit of entropy.  Second, the number of
70 * attempts it takes the algorithm to find an unused ID drastically
71 * increases, killing performance.  The default value of 8192 was chosen
72 * because it provides a good tradeoff between randomness and non-repetition.
73 *
74 * With L=8192, the queue will use 16K of memory.  The bitstring always
75 * uses 8K of memory.  No memory is allocated until the use of random ids is
76 * enabled.
77 */
78
79#include <sys/types.h>
80#include <sys/malloc.h>
81#include <rtems/bsd/sys/param.h>
82#include <sys/time.h>
83#include <sys/kernel.h>
84#include <sys/libkern.h>
85#include <rtems/bsd/sys/lock.h>
86#include <sys/mutex.h>
87#include <sys/random.h>
88#include <sys/systm.h>
89#include <sys/sysctl.h>
90#include <netinet/in.h>
91#include <netinet/ip_var.h>
92#include <sys/bitstring.h>
93
94static MALLOC_DEFINE(M_IPID, "ipid", "randomized ip id state");
95
96static u_int16_t        *id_array = NULL;
97static bitstr_t         *id_bits = NULL;
98static int               array_ptr = 0;
99static int               array_size = 8192;
100static int               random_id_collisions = 0;
101static int               random_id_total = 0;
102static struct mtx        ip_id_mtx;
103
104static void     ip_initid(void);
105static int      sysctl_ip_id_change(SYSCTL_HANDLER_ARGS);
106
107MTX_SYSINIT(ip_id_mtx, &ip_id_mtx, "ip_id_mtx", MTX_DEF);
108
109SYSCTL_DECL(_net_inet_ip);
110SYSCTL_PROC(_net_inet_ip, OID_AUTO, random_id_period, CTLTYPE_INT|CTLFLAG_RW,
111    &array_size, 0, sysctl_ip_id_change, "IU", "IP ID Array size");
112SYSCTL_INT(_net_inet_ip, OID_AUTO, random_id_collisions, CTLFLAG_RD,
113    &random_id_collisions, 0, "Count of IP ID collisions");
114SYSCTL_INT(_net_inet_ip, OID_AUTO, random_id_total, CTLFLAG_RD,
115    &random_id_total, 0, "Count of IP IDs created");
116
117static int
118sysctl_ip_id_change(SYSCTL_HANDLER_ARGS)
119{
120        int error, new;
121
122        new = array_size;
123        error = sysctl_handle_int(oidp, &new, 0, req);
124        if (error == 0 && req->newptr) {
125                if (new >= 512 && new <= 32768) {
126                        mtx_lock(&ip_id_mtx);
127                        array_size = new;
128                        ip_initid();
129                        mtx_unlock(&ip_id_mtx);
130                } else
131                        error = EINVAL;
132        }
133        return (error);
134}
135
136/*
137 * ip_initid() runs with a mutex held and may execute in a network context.
138 * As a result, it uses M_NOWAIT.  Ideally, we would always do this
139 * allocation from the sysctl contact and have it be an invariant that if
140 * this random ID allocation mode is selected, the buffers are present.  This
141 * would also avoid potential network context failures of IP ID generation.
142 */
143static void
144ip_initid(void)
145{
146
147        mtx_assert(&ip_id_mtx, MA_OWNED);
148
149        if (id_array != NULL) {
150                free(id_array, M_IPID);
151                free(id_bits, M_IPID);
152        }
153        random_id_collisions = 0;
154        random_id_total = 0;
155        array_ptr = 0;
156        id_array = (u_int16_t *) malloc(array_size * sizeof(u_int16_t),
157            M_IPID, M_NOWAIT | M_ZERO);
158        id_bits = (bitstr_t *) malloc(bitstr_size(65536), M_IPID,
159            M_NOWAIT | M_ZERO);
160        if (id_array == NULL || id_bits == NULL) {
161                /* Neither or both. */
162                if (id_array != NULL) {
163                        free(id_array, M_IPID);
164                        id_array = NULL;
165                }
166                if (id_bits != NULL) {
167                        free(id_bits, M_IPID);
168                        id_bits = NULL;
169                }
170        }
171}
172
173u_int16_t
174ip_randomid(void)
175{
176        u_int16_t new_id;
177
178        mtx_lock(&ip_id_mtx);
179        if (id_array == NULL)
180                ip_initid();
181
182        /*
183         * Fail gracefully; return a fixed id if memory allocation failed;
184         * ideally we wouldn't do allocation in this context in order to
185         * avoid the possibility of this failure mode.
186         */
187        if (id_array == NULL) {
188                mtx_unlock(&ip_id_mtx);
189                return (1);
190        }
191
192        /*
193         * To avoid a conflict with the zeros that the array is initially
194         * filled with, we never hand out an id of zero.
195         */
196        new_id = 0;
197        do {
198                if (new_id != 0)
199                        random_id_collisions++;
200                arc4rand(&new_id, sizeof(new_id), 0);
201        } while (bit_test(id_bits, new_id) || new_id == 0);
202        bit_clear(id_bits, id_array[array_ptr]);
203        bit_set(id_bits, new_id);
204        id_array[array_ptr] = new_id;
205        array_ptr++;
206        if (array_ptr == array_size)
207                array_ptr = 0;
208        random_id_total++;
209        mtx_unlock(&ip_id_mtx);
210        return (new_id);
211}
Note: See TracBrowser for help on using the repository browser.