164dddc18SKris Kennaway /* $OpenBSD: ip_id.c,v 1.2 1999/08/26 13:37:01 provos Exp $ */ 264dddc18SKris Kennaway 3c398230bSWarner Losh /*- 464dddc18SKris Kennaway * Copyright 1998 Niels Provos <provos@citi.umich.edu> 564dddc18SKris Kennaway * All rights reserved. 664dddc18SKris Kennaway * 764dddc18SKris Kennaway * Theo de Raadt <deraadt@openbsd.org> came up with the idea of using 864dddc18SKris Kennaway * such a mathematical system to generate more random (yet non-repeating) 964dddc18SKris Kennaway * ids to solve the resolver/named problem. But Niels designed the 1064dddc18SKris Kennaway * actual system based on the constraints. 1164dddc18SKris Kennaway * 1264dddc18SKris Kennaway * Redistribution and use in source and binary forms, with or without 1364dddc18SKris Kennaway * modification, are permitted provided that the following conditions 1464dddc18SKris Kennaway * are met: 1564dddc18SKris Kennaway * 1. Redistributions of source code must retain the above copyright 1664dddc18SKris Kennaway * notice, this list of conditions and the following disclaimer. 1764dddc18SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 1864dddc18SKris Kennaway * notice, this list of conditions and the following disclaimer in the 1964dddc18SKris Kennaway * documentation and/or other materials provided with the distribution. 2064dddc18SKris Kennaway * 3. All advertising materials mentioning features or use of this software 2164dddc18SKris Kennaway * must display the following acknowledgement: 2264dddc18SKris Kennaway * This product includes software developed by Niels Provos. 2364dddc18SKris Kennaway * 4. The name of the author may not be used to endorse or promote products 2464dddc18SKris Kennaway * derived from this software without specific prior written permission. 2564dddc18SKris Kennaway * 2664dddc18SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2764dddc18SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2864dddc18SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2964dddc18SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3064dddc18SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3164dddc18SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3264dddc18SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3364dddc18SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3464dddc18SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3564dddc18SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3664dddc18SKris Kennaway * 3764dddc18SKris Kennaway * $FreeBSD$ 3864dddc18SKris Kennaway */ 3964dddc18SKris Kennaway 4064dddc18SKris Kennaway /* 4164dddc18SKris Kennaway * seed = random 15bit 4264dddc18SKris Kennaway * n = prime, g0 = generator to n, 4364dddc18SKris Kennaway * j = random so that gcd(j,n-1) == 1 4464dddc18SKris Kennaway * g = g0^j mod n will be a generator again. 4564dddc18SKris Kennaway * 4664dddc18SKris Kennaway * X[0] = random seed. 4764dddc18SKris Kennaway * X[n] = a*X[n-1]+b mod m is a Linear Congruential Generator 4864dddc18SKris Kennaway * with a = 7^(even random) mod m, 4964dddc18SKris Kennaway * b = random with gcd(b,m) == 1 5064dddc18SKris Kennaway * m = 31104 and a maximal period of m-1. 5164dddc18SKris Kennaway * 5264dddc18SKris Kennaway * The transaction id is determined by: 5364dddc18SKris Kennaway * id[n] = seed xor (g^X[n] mod n) 5464dddc18SKris Kennaway * 5564dddc18SKris Kennaway * Effectivly the id is restricted to the lower 15 bits, thus 5664dddc18SKris Kennaway * yielding two different cycles by toggling the msb on and off. 5764dddc18SKris Kennaway * This avoids reuse issues caused by reseeding. 5864dddc18SKris Kennaway */ 5964dddc18SKris Kennaway 60cc5934f5SMax Laier #include "opt_pf.h" 6164dddc18SKris Kennaway #include <sys/param.h> 6264dddc18SKris Kennaway #include <sys/time.h> 6364dddc18SKris Kennaway #include <sys/kernel.h> 6464dddc18SKris Kennaway #include <sys/random.h> 6564dddc18SKris Kennaway 6664dddc18SKris Kennaway #define RU_OUT 180 /* Time after wich will be reseeded */ 6764dddc18SKris Kennaway #define RU_MAX 30000 /* Uniq cycle, avoid blackjack prediction */ 6864dddc18SKris Kennaway #define RU_GEN 2 /* Starting generator */ 6964dddc18SKris Kennaway #define RU_N 32749 /* RU_N-1 = 2*2*3*2729 */ 7064dddc18SKris Kennaway #define RU_AGEN 7 /* determine ru_a as RU_AGEN^(2*rand) */ 7164dddc18SKris Kennaway #define RU_M 31104 /* RU_M = 2^7*3^5 - don't change */ 7264dddc18SKris Kennaway 7364dddc18SKris Kennaway #define PFAC_N 3 7464dddc18SKris Kennaway const static u_int16_t pfacts[PFAC_N] = { 7564dddc18SKris Kennaway 2, 7664dddc18SKris Kennaway 3, 7764dddc18SKris Kennaway 2729 7864dddc18SKris Kennaway }; 7964dddc18SKris Kennaway 8064dddc18SKris Kennaway static u_int16_t ru_x; 8164dddc18SKris Kennaway static u_int16_t ru_seed, ru_seed2; 8264dddc18SKris Kennaway static u_int16_t ru_a, ru_b; 8364dddc18SKris Kennaway static u_int16_t ru_g; 8464dddc18SKris Kennaway static u_int16_t ru_counter = 0; 8564dddc18SKris Kennaway static u_int16_t ru_msb = 0; 8664dddc18SKris Kennaway static long ru_reseed; 8764dddc18SKris Kennaway static u_int32_t tmp; /* Storage for unused random */ 8864dddc18SKris Kennaway 894d77a549SAlfred Perlstein static u_int16_t pmod(u_int16_t, u_int16_t, u_int16_t); 904d77a549SAlfred Perlstein static void ip_initid(void); 914d77a549SAlfred Perlstein u_int16_t ip_randomid(void); 9264dddc18SKris Kennaway 9364dddc18SKris Kennaway /* 9464dddc18SKris Kennaway * Do a fast modular exponation, returned value will be in the range 9564dddc18SKris Kennaway * of 0 - (mod-1) 9664dddc18SKris Kennaway */ 9764dddc18SKris Kennaway 9864dddc18SKris Kennaway #ifdef __STDC__ 9964dddc18SKris Kennaway static u_int16_t 10064dddc18SKris Kennaway pmod(u_int16_t gen, u_int16_t exp, u_int16_t mod) 10164dddc18SKris Kennaway #else 10264dddc18SKris Kennaway static u_int16_t 10364dddc18SKris Kennaway pmod(gen, exp, mod) 10464dddc18SKris Kennaway u_int16_t gen, exp, mod; 10564dddc18SKris Kennaway #endif 10664dddc18SKris Kennaway { 10764dddc18SKris Kennaway u_int16_t s, t, u; 10864dddc18SKris Kennaway 10964dddc18SKris Kennaway s = 1; 11064dddc18SKris Kennaway t = gen; 11164dddc18SKris Kennaway u = exp; 11264dddc18SKris Kennaway 11364dddc18SKris Kennaway while (u) { 11464dddc18SKris Kennaway if (u & 1) 11564dddc18SKris Kennaway s = (s*t) % mod; 11664dddc18SKris Kennaway u >>= 1; 11764dddc18SKris Kennaway t = (t*t) % mod; 11864dddc18SKris Kennaway } 11964dddc18SKris Kennaway return (s); 12064dddc18SKris Kennaway } 12164dddc18SKris Kennaway 12264dddc18SKris Kennaway /* 12364dddc18SKris Kennaway * Initalizes the seed and chooses a suitable generator. Also toggles 12464dddc18SKris Kennaway * the msb flag. The msb flag is used to generate two distinct 12564dddc18SKris Kennaway * cycles of random numbers and thus avoiding reuse of ids. 12664dddc18SKris Kennaway * 12764dddc18SKris Kennaway * This function is called from id_randomid() when needed, an 12864dddc18SKris Kennaway * application does not have to worry about it. 12964dddc18SKris Kennaway */ 13064dddc18SKris Kennaway static void 13164dddc18SKris Kennaway ip_initid(void) 13264dddc18SKris Kennaway { 13364dddc18SKris Kennaway u_int16_t j, i; 13464dddc18SKris Kennaway int noprime = 1; 13564dddc18SKris Kennaway struct timeval time; 13664dddc18SKris Kennaway 13764dddc18SKris Kennaway getmicrotime(&time); 13864dddc18SKris Kennaway read_random((void *) &tmp, sizeof(tmp)); 13964dddc18SKris Kennaway ru_x = (tmp & 0xFFFF) % RU_M; 14064dddc18SKris Kennaway 14164dddc18SKris Kennaway /* 15 bits of random seed */ 14264dddc18SKris Kennaway ru_seed = (tmp >> 16) & 0x7FFF; 14364dddc18SKris Kennaway read_random((void *) &tmp, sizeof(tmp)); 14464dddc18SKris Kennaway ru_seed2 = tmp & 0x7FFF; 14564dddc18SKris Kennaway 14664dddc18SKris Kennaway read_random((void *) &tmp, sizeof(tmp)); 14764dddc18SKris Kennaway 14864dddc18SKris Kennaway /* Determine the LCG we use */ 14964dddc18SKris Kennaway ru_b = (tmp & 0xfffe) | 1; 15064dddc18SKris Kennaway ru_a = pmod(RU_AGEN, (tmp >> 16) & 0xfffe, RU_M); 15164dddc18SKris Kennaway while (ru_b % 3 == 0) 15264dddc18SKris Kennaway ru_b += 2; 15364dddc18SKris Kennaway 15464dddc18SKris Kennaway read_random((void *) &tmp, sizeof(tmp)); 15564dddc18SKris Kennaway j = tmp % RU_N; 15664dddc18SKris Kennaway tmp = tmp >> 16; 15764dddc18SKris Kennaway 15864dddc18SKris Kennaway /* 15964dddc18SKris Kennaway * Do a fast gcd(j,RU_N-1), so we can find a j with 16064dddc18SKris Kennaway * gcd(j, RU_N-1) == 1, giving a new generator for 16164dddc18SKris Kennaway * RU_GEN^j mod RU_N 16264dddc18SKris Kennaway */ 16364dddc18SKris Kennaway 16464dddc18SKris Kennaway while (noprime) { 16564dddc18SKris Kennaway for (i=0; i<PFAC_N; i++) 16664dddc18SKris Kennaway if (j%pfacts[i] == 0) 16764dddc18SKris Kennaway break; 16864dddc18SKris Kennaway 16964dddc18SKris Kennaway if (i>=PFAC_N) 17064dddc18SKris Kennaway noprime = 0; 17164dddc18SKris Kennaway else 17264dddc18SKris Kennaway j = (j+1) % RU_N; 17364dddc18SKris Kennaway } 17464dddc18SKris Kennaway 17564dddc18SKris Kennaway ru_g = pmod(RU_GEN,j,RU_N); 17664dddc18SKris Kennaway ru_counter = 0; 17764dddc18SKris Kennaway 17864dddc18SKris Kennaway ru_reseed = time.tv_sec + RU_OUT; 17964dddc18SKris Kennaway ru_msb = ru_msb == 0x8000 ? 0 : 0x8000; 18064dddc18SKris Kennaway } 18164dddc18SKris Kennaway 18264dddc18SKris Kennaway u_int16_t 18364dddc18SKris Kennaway ip_randomid(void) 18464dddc18SKris Kennaway { 18564dddc18SKris Kennaway int i, n; 18664dddc18SKris Kennaway struct timeval time; 18764dddc18SKris Kennaway 188aab621f0SSam Leffler /* XXX not reentrant */ 18964dddc18SKris Kennaway getmicrotime(&time); 19064dddc18SKris Kennaway if (ru_counter >= RU_MAX || time.tv_sec > ru_reseed) 19164dddc18SKris Kennaway ip_initid(); 19264dddc18SKris Kennaway 19364dddc18SKris Kennaway if (!tmp) 19464dddc18SKris Kennaway read_random((void *) &tmp, sizeof(tmp)); 19564dddc18SKris Kennaway 19664dddc18SKris Kennaway /* Skip a random number of ids */ 19764dddc18SKris Kennaway n = tmp & 0x3; tmp = tmp >> 2; 19864dddc18SKris Kennaway if (ru_counter + n >= RU_MAX) 19964dddc18SKris Kennaway ip_initid(); 20064dddc18SKris Kennaway 20164dddc18SKris Kennaway for (i = 0; i <= n; i++) 20264dddc18SKris Kennaway /* Linear Congruential Generator */ 20364dddc18SKris Kennaway ru_x = (ru_a*ru_x + ru_b) % RU_M; 20464dddc18SKris Kennaway 20564dddc18SKris Kennaway ru_counter += i; 20664dddc18SKris Kennaway 20764dddc18SKris Kennaway return (ru_seed ^ pmod(ru_g,ru_seed2 ^ ru_x,RU_N)) | ru_msb; 20864dddc18SKris Kennaway } 20964dddc18SKris Kennaway 210