1 /* Copyright © 2012 Brandon L Black <blblack@gmail.com>
2 *
3 * This file is part of gdnsd.
4 *
5 * gdnsd is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * gdnsd is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with gdnsd. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #ifndef GDNSD_MISC_H
21 #define GDNSD_MISC_H
22
23 #include <gdnsd/compiler.h>
24 #include <gdnsd/dmn.h>
25
26 #include <inttypes.h>
27 #include <stdbool.h>
28 #include <pthread.h>
29 #include <dirent.h>
30 #include <sys/types.h>
31
32 typedef struct _gdnsd_rstate32_t {
33 uint32_t x;
34 uint32_t y;
35 uint32_t z;
36 uint32_t w;
37 uint32_t c;
38 } gdnsd_rstate32_t;
39
40 typedef struct _gdnsd_rstate64_t {
41 uint64_t x;
42 uint64_t y;
43 uint32_t z1;
44 uint32_t c1;
45 uint32_t z2;
46 uint32_t c2;
47 } gdnsd_rstate64_t;
48
49 #pragma GCC visibility push(default)
50
51 // Get system/filesystem-specific dirent buffer size for readdir_r() safely
52 // (dirname is just for error output)
53 // readdir_r() is being deprecated in libc/POSIX in favor of assuming readdir() is
54 // thread-safe for different streams, and using your own locking for
55 // multi-thread access to the same stream. Therefore this function is
56 // deprecated as well.
57 F_NONNULL F_DEPRECATED
58 size_t gdnsd_dirent_bufsize(DIR* d V_UNUSED, const char* dirname);
59
60 // Register a child process that exists for the life of the daemon, so that
61 // the core can SIGTERM and reap it on clean shutdown.
62 void gdnsd_register_child_pid(pid_t child);
63
64 // allocate a new string, concatenating s1 + s2.
65 // retval is the new string
66 // if s2_offs is not NULL, *s2_offs will be set
67 // to the offset of the copy of s2 within the retval.
68 F_MALLOC F_NONNULLX(1,2)
69 char* gdnsd_str_combine(const char* s1, const char* s2, const char** s2_offs);
70
71 // allocate a new string and concatenate all "count" strings
72 // from the args list into it.
73 F_MALLOC F_NONNULL
74 char* gdnsd_str_combine_n(const unsigned count, ...);
75
76 // set thread name (via pthread_setname_np or similar)
77 void gdnsd_thread_setname(const char* n);
78
79 // Returns true if running on Linux with a kernel version >= x.y.z
80 // Returns false for non-Linux systems, or Linux kernels older than specified.
81 bool gdnsd_linux_min_version(const unsigned x, const unsigned y, const unsigned z);
82
83 // State initializers for gdnsd_randXX_get() below
84 gdnsd_rstate32_t* gdnsd_rand32_init(void);
85 gdnsd_rstate64_t* gdnsd_rand64_init(void);
86
87 // scale an unsigned by a double in the range [0.0 - 1.0]
88 // and get the ceiling of the result. Cannot overflow.
89 F_UNUSED F_CONST
90 unsigned gdnsd_uscale_ceil(unsigned v, double s);
91
92 #pragma GCC visibility pop
93
94 // downcase an array of bytes of known length
95 F_NONNULL F_UNUSED
gdnsd_downcase_bytes(char * bytes,unsigned len)96 static void gdnsd_downcase_bytes(char* bytes, unsigned len) {
97 for(unsigned i = 0; i < len; i++)
98 if(unlikely((bytes[i] < 0x5B) && (bytes[i] > 0x40)))
99 bytes[i] |= 0x20;
100 }
101
102 // downcase an asciiz string
103 F_NONNULL F_UNUSED
gdnsd_downcase_str(char * str)104 static void gdnsd_downcase_str(char* str) {
105 while(*str) {
106 if(unlikely((*str < 0x5B) && (*str > 0x40)))
107 *str |= 0x20;
108 str++;
109 }
110 }
111
112 /***************
113 * These are Public-Domain JKISS32/JLKISS64 PRNG implementations
114 * which I initially got from David Jones' RNG paper here:
115 * http://www.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf
116 * ... and then incorporated some usage/optimization hints from
117 * https://github.com/bhickey/librng
118 * The actual algorithms ultimately came from George Marsaglia.
119 * I've made cosmetic modifications (style, C99) and given them a
120 * state pointer for threading, and renamed them into the gdnsd API
121 * namespace so they can be swapped out easily later.
122 * I've also wrapped everything up such that there's one
123 * global PRNG initialized at startup from decent sources,
124 * which is mutex-protected and used to set seeds for later
125 * runtime per-thread/plugin PRNG initializations.
126 ***************/
127
128 /* Note there are separate 64-bit and 32-bit interfaces here.
129 * Both have periods sufficient for this software in general,
130 * given an analysis of high end per-thread DNS query rates and
131 * daemon uptimes, etc. The 32-bit one is faster and should
132 * be used by default.
133 * The 64-bit one is supplied for cases (such as plugin_weighted)
134 * where the result is being used in an integer modulo operation
135 * with unpredictable mod values which could be large enough to
136 * induce bias with the 32-bit one.
137 * For "gdnsd_rand32_get() % N":
138 * maxN -> bias
139 * ---- ----
140 * 2^24 -> 0.39%
141 * 2^28 -> 6.25%
142 * 2^29 -> 12.5%
143 * 2^30 -> 25%
144 * ... whereas rand64_get() will have an almost immeasurably small
145 * bias for modvals up to 2^32.
146 */
147
148 // This is JLKISS64
149 F_NONNULL F_UNUSED
gdnsd_rand64_get(gdnsd_rstate64_t * rs)150 static uint64_t gdnsd_rand64_get(gdnsd_rstate64_t* rs) {
151 rs->x = 1490024343005336237ULL * rs->x + 123456789;
152
153 uint64_t y = rs->y;
154 y ^= y << 21;
155 y ^= y >> 17;
156 y ^= y << 30;
157 rs->y = y;
158
159 uint64_t t = 4294584393ULL * rs->z1 + rs->c1;
160 rs->c1 = t >> 32;
161 rs->z1 = t;
162
163 t = 4246477509ULL * rs->z2 + rs->c2;
164 rs->c2 = t >> 32;
165 rs->z2 = t;
166
167 return rs->x + y + rs->z1 + ((uint64_t)rs->z2 << 32);
168 }
169
170 // This is JKISS32
171 F_NONNULL F_UNUSED
gdnsd_rand32_get(gdnsd_rstate32_t * rs)172 static uint32_t gdnsd_rand32_get(gdnsd_rstate32_t* rs) {
173 uint32_t y = rs->y;
174 y ^= y << 5;
175 y ^= y >> 7;
176 y ^= y << 22;
177 rs->y = y;
178
179 // Note local mods to how t is handled (results are the same)
180 uint32_t t = rs->z + rs->w + rs->c;
181 rs->z = rs->w;
182 rs->c = (t & 1U << 31) >> 31;
183 rs->w = t & 2147483647;
184
185 rs->x += 1411392427;
186
187 return rs->x + y + rs->w;
188 }
189
190 /***************
191 * End PRNG Stuff
192 ***************/
193
194 // gdnsd_lookup2 is lookup2() by Bob Jenkins,
195 // from http://www.burtleburtle.net/bob/c/lookup2.c,
196 // which is in the public domain.
197 // It's just been reformatted/styled to match my code.
198
199 #define mix(a,b,c) { \
200 a -= b; a -= c; a ^= (c>>13); \
201 b -= c; b -= a; b ^= (a<<8); \
202 c -= a; c -= b; c ^= (b>>13); \
203 a -= b; a -= c; a ^= (c>>12); \
204 b -= c; b -= a; b ^= (a<<16); \
205 c -= a; c -= b; c ^= (b>>5); \
206 a -= b; a -= c; a ^= (c>>3); \
207 b -= c; b -= a; b ^= (a<<10); \
208 c -= a; c -= b; c ^= (b>>15); \
209 }
210
211 F_PURE F_UNUSED F_WUNUSED
gdnsd_lookup2(const uint8_t * k,uint32_t len)212 static uint32_t gdnsd_lookup2(const uint8_t *k, uint32_t len) {
213 dmn_assert(k || !len);
214
215 const uint32_t orig_len = len;
216
217 uint32_t a = 0x9e3779b9;
218 uint32_t b = 0x9e3779b9;
219 uint32_t c = 0xdeadbeef;
220
221 while(len >= 12) {
222 a += (k[0] + ((uint32_t)k[1] << 8)
223 + ((uint32_t)k[2] << 16)
224 + ((uint32_t)k[3] << 24));
225 b += (k[4] + ((uint32_t)k[5] << 8)
226 + ((uint32_t)k[6] << 16)
227 + ((uint32_t)k[7] << 24));
228 c += (k[8] + ((uint32_t)k[9] << 8)
229 + ((uint32_t)k[10] << 16)
230 + ((uint32_t)k[11] << 24));
231 mix(a,b,c);
232 k += 12; len -= 12;
233 }
234
235 c += orig_len;
236
237 switch(len) {
238 case 11: c += ((uint32_t)k[10] << 24);
239 case 10: c += ((uint32_t)k[9] << 16);
240 case 9 : c += ((uint32_t)k[8] << 8);
241 case 8 : b += ((uint32_t)k[7] << 24);
242 case 7 : b += ((uint32_t)k[6] << 16);
243 case 6 : b += ((uint32_t)k[5] << 8);
244 case 5 : b += k[4];
245 case 4 : a += ((uint32_t)k[3] << 24);
246 case 3 : a += ((uint32_t)k[2] << 16);
247 case 2 : a += ((uint32_t)k[1] << 8);
248 case 1 : a += k[0];
249 default: break;
250 }
251
252 mix(a,b,c);
253 return c;
254 }
255
256 #endif // GDNSD_MISC_H
257