/src/ntp-dev/ntpd/ntp_restrict.c
Line | Count | Source |
1 | | /* |
2 | | * ntp_restrict.c - determine host restrictions |
3 | | */ |
4 | | #ifdef HAVE_CONFIG_H |
5 | | #include <config.h> |
6 | | #endif |
7 | | |
8 | | #include <stdio.h> |
9 | | #include <sys/types.h> |
10 | | |
11 | | #include "ntpd.h" |
12 | | #include "ntp_if.h" |
13 | | #include "ntp_lists.h" |
14 | | #include "ntp_stdlib.h" |
15 | | #include "ntp_assert.h" |
16 | | |
17 | | /* |
18 | | * This code keeps a simple address-and-mask list of addressses we want |
19 | | * to place restrictions on (or remove them from). The restrictions are |
20 | | * implemented as a set of flags which tell you what matching addresses |
21 | | * can't do. The list is sorted retrieve the restrictions most specific |
22 | | * to the address. |
23 | | * |
24 | | * This was originally intended to restrict you from sync'ing to your |
25 | | * own broadcasts when you are doing that, by restricting yourself from |
26 | | * your own interfaces. It was also thought it would sometimes be useful |
27 | | * to keep a misbehaving host or two from abusing your primary clock. It |
28 | | * has been expanded, however, to suit the needs of those with more |
29 | | * restrictive access policies. |
30 | | */ |
31 | | #define MASK_IPV6_ADDR(dst, src, msk) \ |
32 | 0 | do { \ |
33 | 0 | int x; \ |
34 | 0 | \ |
35 | 0 | for (x = 0; x < (int)COUNTOF((dst)->s6_addr); x++) { \ |
36 | 0 | (dst)->s6_addr[x] = (src)->s6_addr[x] \ |
37 | 0 | & (msk)->s6_addr[x]; \ |
38 | 0 | } \ |
39 | 0 | } while (FALSE) |
40 | | |
41 | | /* |
42 | | * We allocate INC_RESLIST{4|6} entries to the free list whenever empty. |
43 | | * Auto-tune these to be just less than 1 KB (leaving at least 32 bytes |
44 | | * for allocator overhead). We'll use one entry for each "restrict" |
45 | | * in ntp.conf, plus one for each local address. This tuning gives us |
46 | | * room for 31 IPv4 entries and 17 IPv6 entries per allocation on a |
47 | | * 64-bit system, which is enough for the most common configurations |
48 | | * to have all the restrictions in a a pair of 1 KB "hot zones" that will |
49 | | * be accessed on every incoming packet of the respective address family |
50 | | * and should stay in cache. This is a performance optimization |
51 | | * compared to allocating and freeing each entry as needed. |
52 | | */ |
53 | 2 | #define INC_RESLIST4 ((1024 - 32) / V4_SIZEOF_RESTRICT_U) |
54 | 0 | #define INC_RESLIST6 ((1024 - 32) / V6_SIZEOF_RESTRICT_U) |
55 | | |
56 | | /* |
57 | | * The restriction list |
58 | | */ |
59 | | restrict_u *restrictlist4; |
60 | | restrict_u *restrictlist6; |
61 | | static int restrictcount; /* count in the restrict lists */ |
62 | | |
63 | | /* |
64 | | * The free list and associated counters. Also some uninteresting |
65 | | * stat counters. |
66 | | */ |
67 | | static restrict_u *resfree4; /* available entries (free list) */ |
68 | | static restrict_u *resfree6; |
69 | | |
70 | | static u_long res_calls; |
71 | | static u_long res_found; |
72 | | static u_long res_not_found; |
73 | | |
74 | | /* |
75 | | * Count number of restriction entries referring to RES_LIMITED, to |
76 | | * control implicit activation/deactivation of the MRU monlist. |
77 | | */ |
78 | | static u_long res_limited_refcnt; |
79 | | |
80 | | /* |
81 | | * Our default entries. |
82 | | * |
83 | | * We can make this cleaner with c99 support: see init_restrict(). |
84 | | */ |
85 | | static restrict_u restrict_def4; |
86 | | static restrict_u restrict_def6; |
87 | | |
88 | | /* |
89 | | * "restrict source ..." enabled knob and restriction bits. |
90 | | */ |
91 | | static int restrict_source_enabled; |
92 | | static u_int32 restrict_source_rflags; |
93 | | static u_short restrict_source_mflags; |
94 | | static short restrict_source_ippeerlimit; |
95 | | |
96 | | /* |
97 | | * private functions |
98 | | */ |
99 | | static restrict_u * alloc_res4(void); |
100 | | static restrict_u * alloc_res6(void); |
101 | | static void free_res(restrict_u *, int); |
102 | | static inline void inc_res_limited(void); |
103 | | static inline void dec_res_limited(void); |
104 | | static restrict_u * match_restrict4_addr(u_int32, u_short); |
105 | | static restrict_u * match_restrict6_addr(const struct in6_addr *, |
106 | | u_short); |
107 | | static restrict_u * match_restrict_entry(const restrict_u *, int); |
108 | | static inline int/*BOOL*/ mflags_sorts_before(u_short, u_short); |
109 | | static int/*BOOL*/ res_sorts_before4(restrict_u *, restrict_u *); |
110 | | static int/*BOOL*/ res_sorts_before6(restrict_u *, restrict_u *); |
111 | | |
112 | | typedef int (*res_sort_fn)(restrict_u *, restrict_u *); |
113 | | |
114 | | |
115 | | /* dump_restrict() & dump_restricts() are DEBUG-only */ |
116 | | #ifdef DEBUG |
117 | | static void dump_restrict(restrict_u *, int); |
118 | | |
119 | | |
120 | | /* |
121 | | * dump_restrict - spit out a single restriction entry |
122 | | */ |
123 | | static void |
124 | | dump_restrict( |
125 | | restrict_u * res, |
126 | | int is_ipv6 |
127 | | ) |
128 | 0 | { |
129 | 0 | char as[INET6_ADDRSTRLEN]; |
130 | 0 | char ms[INET6_ADDRSTRLEN]; |
131 | |
|
132 | 0 | if (is_ipv6) { |
133 | 0 | inet_ntop(AF_INET6, &res->u.v6.addr, as, sizeof as); |
134 | 0 | inet_ntop(AF_INET6, &res->u.v6.mask, ms, sizeof ms); |
135 | 0 | } else { |
136 | 0 | struct in_addr sia, sim; |
137 | |
|
138 | 0 | sia.s_addr = htonl(res->u.v4.addr); |
139 | 0 | sim.s_addr = htonl(res->u.v4.addr); |
140 | 0 | inet_ntop(AF_INET, &sia, as, sizeof as); |
141 | 0 | inet_ntop(AF_INET, &sim, ms, sizeof ms); |
142 | 0 | } |
143 | 0 | printf("%s/%s: hits %u ippeerlimit %hd mflags %s rflags %s", |
144 | 0 | as, ms, res->count, res->ippeerlimit, |
145 | 0 | mflags_str(res->mflags), |
146 | 0 | rflags_str(res->rflags)); |
147 | 0 | if (res->expire > 0) { |
148 | 0 | printf(" expire %u\n", res->expire); |
149 | 0 | } else { |
150 | 0 | printf("\n"); |
151 | 0 | } |
152 | 0 | } |
153 | | |
154 | | |
155 | | /* |
156 | | * dump_restricts - spit out the 'restrict' entries |
157 | | */ |
158 | | void |
159 | | dump_restricts(void) |
160 | 0 | { |
161 | 0 | restrict_u * res; |
162 | | |
163 | | /* Spit out the IPv4 list */ |
164 | 0 | printf("dump_restricts: restrictlist4: %p\n", restrictlist4); |
165 | 0 | for (res = restrictlist4; res != NULL; res = res->link) { |
166 | 0 | dump_restrict(res, 0); |
167 | 0 | } |
168 | | |
169 | | /* Spit out the IPv6 list */ |
170 | 0 | printf("dump_restricts: restrictlist6: %p\n", restrictlist6); |
171 | 0 | for (res = restrictlist6; res != NULL; res = res->link) { |
172 | 0 | dump_restrict(res, 1); |
173 | 0 | } |
174 | 0 | } |
175 | | #endif /* DEBUG - dump_restrict() / dump_restricts() */ |
176 | | |
177 | | |
178 | | /* |
179 | | * init_restrict - initialize the restriction data structures |
180 | | */ |
181 | | void |
182 | | init_restrict(void) |
183 | 1 | { |
184 | | /* |
185 | | * The restriction lists end with a default entry with address |
186 | | * and mask 0, which will match any entry. The lists are kept |
187 | | * sorted by descending address followed by descending mask: |
188 | | * |
189 | | * address mask |
190 | | * 192.168.0.0 255.255.255.0 kod limited noquery nopeer |
191 | | * 192.168.0.0 255.255.0.0 kod limited |
192 | | * 0.0.0.0 0.0.0.0 kod limited noquery |
193 | | * |
194 | | * The first entry which matches an address is used. With the |
195 | | * example restrictions above, 192.168.0.0/24 matches the first |
196 | | * entry, the rest of 192.168.0.0/16 matches the second, and |
197 | | * everything else matches the third (default). |
198 | | * |
199 | | * Note this achieves the same result a little more efficiently |
200 | | * than the documented behavior, which is to keep the lists |
201 | | * sorted by ascending address followed by ascending mask, with |
202 | | * the _last_ matching entry used. |
203 | | * |
204 | | * An additional wrinkle is we may have multiple entries with |
205 | | * the same address and mask but differing match flags (mflags). |
206 | | * We want to never talk to ourself, so RES_IGNORE entries for |
207 | | * each local address are added by ntp_io.c with a host mask and |
208 | | * both RESM_INTERFACE and RESM_NTPONLY set. We sort those |
209 | | * entries before entries without those flags to achieve this. |
210 | | * The remaining match flag is RESM_SOURCE, used to dynamically |
211 | | * set restrictions for each peer based on the prototype set by |
212 | | * "restrict source" in the configuration. We want those entries |
213 | | * to be considered only when there is not a static host |
214 | | * restriction for the address in the configuration, to allow |
215 | | * operators to blacklist pool and manycast servers at runtime as |
216 | | * desired using ntpq runtime configuration. Such static entries |
217 | | * have no RESM_ bits set, so the sort order for mflags is first |
218 | | * RESM_INTERFACE, then entries without RESM_SOURCE, finally the |
219 | | * remaining. |
220 | | */ |
221 | | |
222 | 1 | restrict_def4.ippeerlimit = -1; /* Cleaner if we have C99 */ |
223 | 1 | restrict_def6.ippeerlimit = -1; /* Cleaner if we have C99 */ |
224 | | |
225 | 1 | LINK_SLIST(restrictlist4, &restrict_def4, link); |
226 | 1 | LINK_SLIST(restrictlist6, &restrict_def6, link); |
227 | 1 | restrictcount = 2; |
228 | 1 | } |
229 | | |
230 | | |
231 | | static restrict_u * |
232 | | alloc_res4(void) |
233 | 2 | { |
234 | 2 | const size_t cb = V4_SIZEOF_RESTRICT_U; |
235 | 2 | const size_t count = INC_RESLIST4; |
236 | 2 | restrict_u* rl; |
237 | 2 | restrict_u* res; |
238 | 2 | size_t i; |
239 | | |
240 | 2 | UNLINK_HEAD_SLIST(res, resfree4, link); |
241 | 2 | if (res != NULL) { |
242 | 1 | return res; |
243 | 1 | } |
244 | 1 | rl = eallocarray(count, cb); /* zeroes */ |
245 | | /* link all but the first onto free list */ |
246 | 1 | res = INCR_PTR(rl, (count - 1) * cb); |
247 | 31 | for (i = count - 1; i > 0; i--) { |
248 | 30 | LINK_SLIST(resfree4, res, link); |
249 | 30 | res = (void *)((char *)res - cb); |
250 | 30 | } |
251 | 1 | DEBUG_INSIST(rl == res); |
252 | | /* allocate the first */ |
253 | 0 | return res; |
254 | 2 | } |
255 | | |
256 | | |
257 | | static restrict_u * |
258 | | alloc_res6(void) |
259 | 0 | { |
260 | 0 | const size_t cb = V6_SIZEOF_RESTRICT_U; |
261 | 0 | const size_t count = INC_RESLIST6; |
262 | 0 | restrict_u * rl; |
263 | 0 | restrict_u * res; |
264 | 0 | size_t i; |
265 | |
|
266 | 0 | UNLINK_HEAD_SLIST(res, resfree6, link); |
267 | 0 | if (res != NULL) { |
268 | 0 | return res; |
269 | 0 | } |
270 | 0 | rl = eallocarray(count, cb); /* zeroes */ |
271 | | /* link all but the first onto free list */ |
272 | 0 | res = INCR_PTR(rl, (count - 1) * cb); |
273 | 0 | for (i = count - 1; i > 0; i--) { |
274 | 0 | LINK_SLIST(resfree6, res, link); |
275 | 0 | res = (void *)((char *)res - cb); |
276 | 0 | } |
277 | 0 | DEBUG_INSIST(rl == res); |
278 | | /* allocate the first */ |
279 | 0 | return res; |
280 | 0 | } |
281 | | |
282 | | |
283 | | static void |
284 | | free_res( |
285 | | restrict_u * res, |
286 | | int v6 |
287 | | ) |
288 | 0 | { |
289 | 0 | restrict_u ** rlisthead_ptr; |
290 | 0 | restrict_u ** flisthead_ptr; |
291 | 0 | restrict_u * unlinked; |
292 | 0 | size_t sz; |
293 | |
|
294 | 0 | restrictcount--; |
295 | 0 | if (RES_LIMITED & res->rflags) { |
296 | 0 | dec_res_limited(); |
297 | 0 | } |
298 | 0 | if (v6) { |
299 | 0 | rlisthead_ptr = &restrictlist6; |
300 | 0 | flisthead_ptr = &resfree6; |
301 | 0 | sz = V6_SIZEOF_RESTRICT_U; |
302 | 0 | } else { |
303 | 0 | rlisthead_ptr = &restrictlist4; |
304 | 0 | flisthead_ptr = &resfree4; |
305 | 0 | sz = V4_SIZEOF_RESTRICT_U; |
306 | 0 | } |
307 | 0 | UNLINK_SLIST(unlinked, *rlisthead_ptr, res, link, restrict_u); |
308 | 0 | INSIST(unlinked == res); |
309 | 0 | zero_mem(res, sz); |
310 | 0 | LINK_SLIST(*flisthead_ptr, res, link); |
311 | 0 | } |
312 | | |
313 | | |
314 | | static inline void |
315 | | inc_res_limited(void) |
316 | 0 | { |
317 | 0 | if (0 == res_limited_refcnt) { |
318 | 0 | mon_start(MON_RES); |
319 | 0 | } |
320 | 0 | res_limited_refcnt++; |
321 | 0 | } |
322 | | |
323 | | |
324 | | static inline void |
325 | | dec_res_limited(void) |
326 | 0 | { |
327 | 0 | res_limited_refcnt--; |
328 | 0 | if (0 == res_limited_refcnt) { |
329 | 0 | mon_stop(MON_RES); |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | | |
334 | | static restrict_u * |
335 | | match_restrict4_addr( |
336 | | u_int32 addr, |
337 | | u_short port |
338 | | ) |
339 | 2.20k | { |
340 | 2.20k | const int v6 = FALSE; |
341 | 2.20k | restrict_u * res; |
342 | 2.20k | restrict_u * next; |
343 | | |
344 | 4.41k | for (res = restrictlist4; res != NULL; res = next) { |
345 | 4.41k | next = res->link; |
346 | 4.41k | if (res->expire > 0 && res->expire <= current_time) { |
347 | 0 | free_res(res, v6); /* zeroes the contents */ |
348 | 0 | continue; |
349 | 0 | } |
350 | 4.41k | if ( res->u.v4.addr == (addr & res->u.v4.mask) |
351 | 2.20k | && ( !(RESM_NTPONLY & res->mflags) |
352 | 2.20k | || NTP_PORT == port)) { |
353 | | |
354 | 2.20k | break; |
355 | 2.20k | } |
356 | 4.41k | } |
357 | 2.20k | return res; |
358 | 2.20k | } |
359 | | |
360 | | |
361 | | static restrict_u * |
362 | | match_restrict6_addr( |
363 | | const struct in6_addr * addr, |
364 | | u_short port |
365 | | ) |
366 | 0 | { |
367 | 0 | const int v6 = TRUE; |
368 | 0 | restrict_u * res; |
369 | 0 | restrict_u * next; |
370 | 0 | struct in6_addr masked; |
371 | |
|
372 | 0 | for (res = restrictlist6; res != NULL; res = next) { |
373 | 0 | next = res->link; |
374 | 0 | if (res->expire > 0 && res->expire <= current_time) { |
375 | 0 | free_res(res, v6); /* zeroes the contents */ |
376 | 0 | continue; |
377 | 0 | } |
378 | 0 | MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask); |
379 | 0 | if (ADDR6_EQ(&masked, &res->u.v6.addr) |
380 | 0 | && ( !(RESM_NTPONLY & res->mflags) |
381 | 0 | || NTP_PORT == (int)port)) { |
382 | |
|
383 | 0 | break; |
384 | 0 | } |
385 | 0 | } |
386 | 0 | return res; |
387 | 0 | } |
388 | | |
389 | | |
390 | | /* |
391 | | * match_restrict_entry - find an exact match on a restrict list. |
392 | | * |
393 | | * Exact match is addr, mask, and mflags all equal. |
394 | | * In order to use more common code for IPv4 and IPv6, this routine |
395 | | * requires the caller to populate a restrict_u with mflags and either |
396 | | * the v4 or v6 address and mask as appropriate. Other fields in the |
397 | | * input restrict_u are ignored. |
398 | | */ |
399 | | static restrict_u * |
400 | | match_restrict_entry( |
401 | | const restrict_u * pmatch, |
402 | | int v6 |
403 | | ) |
404 | 2 | { |
405 | 2 | restrict_u *res; |
406 | 2 | restrict_u *rlist; |
407 | 2 | size_t cb; |
408 | | |
409 | 2 | if (v6) { |
410 | 0 | rlist = restrictlist6; |
411 | 0 | cb = sizeof(pmatch->u.v6); |
412 | 2 | } else { |
413 | 2 | rlist = restrictlist4; |
414 | 2 | cb = sizeof(pmatch->u.v4); |
415 | 2 | } |
416 | | |
417 | 5 | for (res = rlist; res != NULL; res = res->link) { |
418 | 3 | if (res->mflags == pmatch->mflags && |
419 | 1 | !memcmp(&res->u, &pmatch->u, cb)) { |
420 | 0 | break; |
421 | 0 | } |
422 | 3 | } |
423 | 2 | return res; |
424 | 2 | } |
425 | | |
426 | | |
427 | | /* |
428 | | * mflags_sorts_before - common mflags sorting code |
429 | | * |
430 | | * See block comment in init_restrict() above for rationale. |
431 | | */ |
432 | | static inline int/*BOOL*/ |
433 | | mflags_sorts_before( |
434 | | u_short m1, |
435 | | u_short m2 |
436 | | ) |
437 | 0 | { |
438 | 0 | if ( (RESM_INTERFACE & m1) |
439 | 0 | && !(RESM_INTERFACE & m2)) { |
440 | 0 | return TRUE; |
441 | 0 | } else if ( !(RESM_SOURCE & m1) |
442 | 0 | && (RESM_SOURCE & m2)) { |
443 | 0 | return TRUE; |
444 | 0 | } else { |
445 | 0 | return FALSE; |
446 | 0 | } |
447 | 0 | } |
448 | | |
449 | | |
450 | | /* |
451 | | * res_sorts_before4 - compare IPv4 restriction entries |
452 | | * |
453 | | * Returns nonzero if r1 sorts before r2. We sort by descending |
454 | | * address, then descending mask, then an intricate mflags sort |
455 | | * order explained in a block comment near the top of this file. |
456 | | */ |
457 | | static int/*BOOL*/ |
458 | | res_sorts_before4( |
459 | | restrict_u *r1, |
460 | | restrict_u *r2 |
461 | | ) |
462 | 2 | { |
463 | 2 | int r1_before_r2; |
464 | | |
465 | 2 | if (r1->u.v4.addr > r2->u.v4.addr) { |
466 | 2 | r1_before_r2 = TRUE; |
467 | 2 | } else if (r1->u.v4.addr < r2->u.v4.addr) { |
468 | 0 | r1_before_r2 = FALSE; |
469 | 0 | } else if (r1->u.v4.mask > r2->u.v4.mask) { |
470 | 0 | r1_before_r2 = TRUE; |
471 | 0 | } else if (r1->u.v4.mask < r2->u.v4.mask) { |
472 | 0 | r1_before_r2 = FALSE; |
473 | 0 | } else { |
474 | 0 | r1_before_r2 = mflags_sorts_before(r1->mflags, r2->mflags); |
475 | 0 | } |
476 | | |
477 | 2 | return r1_before_r2; |
478 | 2 | } |
479 | | |
480 | | |
481 | | /* |
482 | | * res_sorts_before6 - compare IPv6 restriction entries |
483 | | * |
484 | | * Returns nonzero if r1 sorts before r2. We sort by descending |
485 | | * address, then descending mask, then an intricate mflags sort |
486 | | * order explained in a block comment near the top of this file. |
487 | | */ |
488 | | static int/*BOOL*/ |
489 | | res_sorts_before6( |
490 | | restrict_u* r1, |
491 | | restrict_u* r2 |
492 | | ) |
493 | 0 | { |
494 | 0 | int r1_before_r2; |
495 | 0 | int cmp; |
496 | |
|
497 | 0 | cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr); |
498 | 0 | if (cmp > 0) { /* r1->addr > r2->addr */ |
499 | 0 | r1_before_r2 = TRUE; |
500 | 0 | } else if (cmp < 0) { /* r2->addr > r1->addr */ |
501 | 0 | r1_before_r2 = FALSE; |
502 | 0 | } else { |
503 | 0 | cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask); |
504 | 0 | if (cmp > 0) { /* r1->mask > r2->mask*/ |
505 | 0 | r1_before_r2 = TRUE; |
506 | 0 | } else if (cmp < 0) { /* r2->mask > r1->mask */ |
507 | 0 | r1_before_r2 = FALSE; |
508 | 0 | } else { |
509 | 0 | r1_before_r2 = mflags_sorts_before(r1->mflags, |
510 | 0 | r2->mflags); |
511 | 0 | } |
512 | 0 | } |
513 | |
|
514 | 0 | return r1_before_r2; |
515 | 0 | } |
516 | | |
517 | | |
518 | | /* |
519 | | * restrictions - return restrictions for this host in *r4a |
520 | | */ |
521 | | void |
522 | | restrictions( |
523 | | sockaddr_u *srcadr, |
524 | | r4addr *r4a |
525 | | ) |
526 | 2.20k | { |
527 | 2.20k | restrict_u *match; |
528 | 2.20k | struct in6_addr *pin6; |
529 | | |
530 | 2.20k | DEBUG_REQUIRE(NULL != r4a); |
531 | | |
532 | 0 | res_calls++; |
533 | | |
534 | 2.20k | if (IS_IPV4(srcadr)) { |
535 | | /* |
536 | | * Ignore any packets with a multicast source address |
537 | | * (this should be done early in the receive process, |
538 | | * not later!) |
539 | | */ |
540 | 2.20k | if (IN_CLASSD(SRCADR(srcadr))) { |
541 | 0 | goto multicast; |
542 | 0 | } |
543 | | |
544 | 2.20k | match = match_restrict4_addr(SRCADR(srcadr), |
545 | 2.20k | SRCPORT(srcadr)); |
546 | 2.20k | DEBUG_INSIST(match != NULL); |
547 | 0 | match->count++; |
548 | | /* |
549 | | * res_not_found counts only use of the final default |
550 | | * entry, not any "restrict default ntpport ...", which |
551 | | * would be just before the final default. |
552 | | */ |
553 | 2.20k | if (&restrict_def4 == match) |
554 | 0 | res_not_found++; |
555 | 2.20k | else |
556 | 2.20k | res_found++; |
557 | 2.20k | r4a->rflags = match->rflags; |
558 | 2.20k | r4a->ippeerlimit = match->ippeerlimit; |
559 | 2.20k | } else { |
560 | 0 | DEBUG_REQUIRE(IS_IPV6(srcadr)); |
561 | | |
562 | 0 | pin6 = PSOCK_ADDR6(srcadr); |
563 | | |
564 | | /* |
565 | | * Ignore any packets with a multicast source address |
566 | | * (this should be done early in the receive process, |
567 | | * not later!) |
568 | | */ |
569 | 0 | if (IN6_IS_ADDR_MULTICAST(pin6)) { |
570 | 0 | goto multicast; |
571 | 0 | } |
572 | 0 | match = match_restrict6_addr(pin6, SRCPORT(srcadr)); |
573 | 0 | DEBUG_INSIST(match != NULL); |
574 | 0 | match->count++; |
575 | 0 | if (&restrict_def6 == match) |
576 | 0 | res_not_found++; |
577 | 0 | else |
578 | 0 | res_found++; |
579 | 0 | r4a->rflags = match->rflags; |
580 | 0 | r4a->ippeerlimit = match->ippeerlimit; |
581 | 0 | } |
582 | | |
583 | 2.20k | return; |
584 | | |
585 | 2.20k | multicast: |
586 | 0 | r4a->rflags = RES_IGNORE; |
587 | 0 | r4a->ippeerlimit = 0; |
588 | 0 | } |
589 | | |
590 | | |
591 | | #ifdef DEBUG |
592 | | /* display string for restrict_op */ |
593 | | const char * |
594 | | resop_str(restrict_op op) |
595 | 0 | { |
596 | 0 | switch (op) { |
597 | 0 | case RESTRICT_FLAGS: return "RESTRICT_FLAGS"; |
598 | 0 | case RESTRICT_UNFLAG: return "RESTRICT_UNFLAG"; |
599 | 0 | case RESTRICT_REMOVE: return "RESTRICT_REMOVE"; |
600 | 0 | case RESTRICT_REMOVEIF: return "RESTRICT_REMOVEIF"; |
601 | 0 | } |
602 | 0 | DEBUG_INVARIANT(!"bad restrict_op in resop_str"); |
603 | 0 | return ""; /* silence not all paths return value warning */ |
604 | 0 | } |
605 | | #endif /* DEBUG */ |
606 | | |
607 | | |
608 | | /* |
609 | | * hack_restrict - add/subtract/manipulate entries on the restrict list |
610 | | */ |
611 | | int/*BOOL*/ |
612 | | hack_restrict( |
613 | | restrict_op op, |
614 | | sockaddr_u * resaddr, |
615 | | sockaddr_u * resmask, |
616 | | short ippeerlimit, |
617 | | u_short mflags, |
618 | | u_short rflags, |
619 | | u_int32 expire |
620 | | ) |
621 | 2 | { |
622 | 2 | int v6; |
623 | 2 | int bump_res_limited = FALSE; |
624 | 2 | restrict_u match; |
625 | 2 | restrict_u * res; |
626 | 2 | restrict_u ** plisthead; |
627 | 2 | res_sort_fn pfn_sort; |
628 | | |
629 | 2 | #ifdef DEBUG |
630 | 2 | if (debug > 0) { |
631 | 0 | printf("hack_restrict: op %s addr %s mask %s", |
632 | 0 | resop_str(op), stoa(resaddr), stoa(resmask)); |
633 | 0 | if (ippeerlimit >= 0) { |
634 | 0 | printf(" ippeerlimit %d", ippeerlimit); |
635 | 0 | } |
636 | 0 | printf(" mflags %s rflags %s", mflags_str(mflags), |
637 | 0 | rflags_str(rflags)); |
638 | 0 | if (expire) { |
639 | 0 | printf("lifetime %u\n", |
640 | 0 | expire - (u_int32)current_time); |
641 | 0 | } else { |
642 | 0 | printf("\n"); |
643 | 0 | } |
644 | 0 | } |
645 | 2 | #endif |
646 | | |
647 | 2 | if (NULL == resaddr) { |
648 | 0 | DEBUG_REQUIRE(NULL == resmask); |
649 | 0 | DEBUG_REQUIRE(RESTRICT_FLAGS == op); |
650 | 0 | DEBUG_REQUIRE(RESM_SOURCE & mflags); |
651 | 0 | restrict_source_rflags = rflags; |
652 | 0 | restrict_source_mflags = mflags; |
653 | 0 | restrict_source_ippeerlimit = ippeerlimit; |
654 | 0 | restrict_source_enabled = TRUE; |
655 | 0 | DPRINTF(1, ("restrict source template saved\n")); |
656 | 0 | return TRUE; |
657 | 0 | } |
658 | | |
659 | 2 | ZERO(match); |
660 | | |
661 | 2 | if (IS_IPV4(resaddr)) { |
662 | 2 | DEBUG_INVARIANT(IS_IPV4(resmask)); |
663 | 2 | v6 = FALSE; |
664 | | /* |
665 | | * Get address and mask in host byte order for easy |
666 | | * comparison as u_int32 |
667 | | */ |
668 | 2 | match.u.v4.addr = SRCADR(resaddr); |
669 | 2 | match.u.v4.mask = SRCADR(resmask); |
670 | 2 | match.u.v4.addr &= match.u.v4.mask; |
671 | 2 | } else { |
672 | 0 | DEBUG_INVARIANT(IS_IPV6(resaddr)); |
673 | 0 | DEBUG_INVARIANT(IS_IPV6(resmask)); |
674 | 0 | v6 = TRUE; |
675 | | /* |
676 | | * Get address and mask in network byte order for easy |
677 | | * comparison as byte sequences (e.g. memcmp()) |
678 | | */ |
679 | 0 | match.u.v6.mask = SOCK_ADDR6(resmask); |
680 | 0 | MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr), |
681 | 0 | &match.u.v6.mask); |
682 | 0 | } |
683 | | |
684 | 0 | match.mflags = mflags; |
685 | 2 | res = match_restrict_entry(&match, v6); |
686 | | |
687 | 2 | switch (op) { |
688 | | |
689 | 2 | case RESTRICT_FLAGS: |
690 | | /* |
691 | | * Here we add bits to the rflags. If we already have |
692 | | * this restriction modify it. |
693 | | */ |
694 | 2 | if (NULL != res) { |
695 | 0 | if ( (RES_LIMITED & rflags) |
696 | 0 | && !(RES_LIMITED & res->rflags)) { |
697 | |
|
698 | 0 | bump_res_limited = TRUE; |
699 | 0 | } |
700 | 0 | res->rflags |= rflags; |
701 | 0 | res->expire = expire; |
702 | 2 | } else { |
703 | 2 | match.rflags = rflags; |
704 | 2 | match.expire = expire; |
705 | 2 | match.ippeerlimit = ippeerlimit; |
706 | 2 | if (v6) { |
707 | 0 | res = alloc_res6(); |
708 | 0 | memcpy(res, &match, V6_SIZEOF_RESTRICT_U); |
709 | 0 | plisthead = &restrictlist6; |
710 | 0 | pfn_sort = &res_sorts_before6; |
711 | 2 | } else { |
712 | 2 | res = alloc_res4(); |
713 | 2 | memcpy(res, &match, V4_SIZEOF_RESTRICT_U); |
714 | 2 | plisthead = &restrictlist4; |
715 | 2 | pfn_sort = &res_sorts_before4; |
716 | 2 | } |
717 | 2 | LINK_SORT_SLIST( |
718 | 2 | *plisthead, res, |
719 | 2 | (*pfn_sort)(res, L_S_S_CUR()), |
720 | 2 | link, restrict_u); |
721 | 2 | restrictcount++; |
722 | 2 | if (RES_LIMITED & rflags) { |
723 | 0 | bump_res_limited = TRUE; |
724 | 0 | } |
725 | 2 | } |
726 | 2 | if (bump_res_limited) { |
727 | 0 | inc_res_limited(); |
728 | 0 | } |
729 | 2 | return TRUE; |
730 | | |
731 | 0 | case RESTRICT_UNFLAG: |
732 | | /* |
733 | | * Remove some bits from the rflags. If we didn't |
734 | | * find this one, just return. |
735 | | */ |
736 | 0 | if (NULL == res) { |
737 | 0 | DPRINTF(1, ("No match for %s %s removing rflags %s\n", |
738 | 0 | stoa(resaddr), stoa(resmask), |
739 | 0 | rflags_str(rflags))); |
740 | 0 | return FALSE; |
741 | 0 | } |
742 | 0 | if ( (RES_LIMITED & res->rflags) |
743 | 0 | && (RES_LIMITED & rflags)) { |
744 | 0 | dec_res_limited(); |
745 | 0 | } |
746 | 0 | res->rflags &= ~rflags; |
747 | 0 | return TRUE; |
748 | | |
749 | 0 | case RESTRICT_REMOVE: |
750 | 0 | case RESTRICT_REMOVEIF: |
751 | | /* |
752 | | * Remove an entry from the table entirely if we |
753 | | * found one. Don't remove the default entry and |
754 | | * don't remove an interface entry unless asked. |
755 | | */ |
756 | 0 | if ( res != NULL |
757 | 0 | && ( RESTRICT_REMOVEIF == op |
758 | 0 | || !(RESM_INTERFACE & res->mflags)) |
759 | 0 | && res != &restrict_def4 |
760 | 0 | && res != &restrict_def6) { |
761 | |
|
762 | 0 | free_res(res, v6); |
763 | 0 | return TRUE; |
764 | 0 | } |
765 | 0 | DPRINTF(1, ("No match removing %s %s restriction\n", |
766 | 0 | stoa(resaddr), stoa(resmask))); |
767 | 0 | return FALSE; |
768 | 2 | } |
769 | | /* notreached */ |
770 | 0 | return FALSE; |
771 | 2 | } |
772 | | |
773 | | |
774 | | /* |
775 | | * restrict_source - maintains dynamic "restrict source ..." entries as |
776 | | * peers come and go. |
777 | | */ |
778 | | void |
779 | | restrict_source( |
780 | | sockaddr_u * addr, |
781 | | int farewell, /* TRUE to remove */ |
782 | | u_int32 lifetime /* seconds, 0 forever */ |
783 | | ) |
784 | 0 | { |
785 | 0 | sockaddr_u onesmask; |
786 | 0 | int/*BOOL*/ success; |
787 | |
|
788 | 0 | if ( !restrict_source_enabled || SOCK_UNSPEC(addr) |
789 | 0 | || IS_MCAST(addr) || ISREFCLOCKADR(addr)) { |
790 | 0 | return; |
791 | 0 | } |
792 | | |
793 | 0 | REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr)); |
794 | | |
795 | 0 | SET_HOSTMASK(&onesmask, AF(addr)); |
796 | 0 | if (farewell) { |
797 | 0 | success = hack_restrict(RESTRICT_REMOVE, addr, &onesmask, |
798 | 0 | 0, RESM_SOURCE, 0, 0); |
799 | 0 | if (success) { |
800 | 0 | DPRINTF(1, ("%s %s removed", __func__, |
801 | 0 | stoa(addr))); |
802 | 0 | } else { |
803 | 0 | msyslog(LOG_ERR, "%s remove %s failed", |
804 | 0 | __func__, stoa(addr)); |
805 | 0 | } |
806 | 0 | return; |
807 | 0 | } |
808 | | |
809 | 0 | success = hack_restrict(RESTRICT_FLAGS, addr, &onesmask, |
810 | 0 | restrict_source_ippeerlimit, |
811 | 0 | restrict_source_mflags, |
812 | 0 | restrict_source_rflags, |
813 | 0 | lifetime > 0 |
814 | 0 | ? lifetime + current_time |
815 | 0 | : 0); |
816 | 0 | if (success) { |
817 | 0 | DPRINTF(1, ("%s %s add/upd\n", __func__, |
818 | 0 | stoa(addr))); |
819 | 0 | } else { |
820 | 0 | msyslog(LOG_ERR, "%s %s failed", __func__, stoa(addr)); |
821 | 0 | } |
822 | 0 | } |
823 | | |
824 | | |
825 | | #ifdef DEBUG |
826 | | /* Convert restriction RES_ flag bits into a display string */ |
827 | | const char * |
828 | | rflags_str( |
829 | | u_short rflags |
830 | | ) |
831 | 0 | { |
832 | 0 | const size_t sz = LIB_BUFLENGTH; |
833 | 0 | char * rfs; |
834 | |
|
835 | 0 | LIB_GETBUF(rfs); |
836 | 0 | rfs[0] = '\0'; |
837 | |
|
838 | 0 | if (rflags & RES_FLAKE) { |
839 | 0 | CLEAR_BIT_IF_DEBUG(RES_FLAKE, rflags); |
840 | 0 | append_flagstr(rfs, sz, "flake"); |
841 | 0 | } |
842 | |
|
843 | 0 | if (rflags & RES_IGNORE) { |
844 | 0 | CLEAR_BIT_IF_DEBUG(RES_IGNORE, rflags); |
845 | 0 | append_flagstr(rfs, sz, "ignore"); |
846 | 0 | } |
847 | |
|
848 | 0 | if (rflags & RES_KOD) { |
849 | 0 | CLEAR_BIT_IF_DEBUG(RES_KOD, rflags); |
850 | 0 | append_flagstr(rfs, sz, "kod"); |
851 | 0 | } |
852 | |
|
853 | 0 | if (rflags & RES_MSSNTP) { |
854 | 0 | CLEAR_BIT_IF_DEBUG(RES_MSSNTP, rflags); |
855 | 0 | append_flagstr(rfs, sz, "mssntp"); |
856 | 0 | } |
857 | |
|
858 | 0 | if (rflags & RES_LIMITED) { |
859 | 0 | CLEAR_BIT_IF_DEBUG(RES_LIMITED, rflags); |
860 | 0 | append_flagstr(rfs, sz, "limited"); |
861 | 0 | } |
862 | |
|
863 | 0 | if (rflags & RES_LPTRAP) { |
864 | 0 | CLEAR_BIT_IF_DEBUG(RES_LPTRAP, rflags); |
865 | 0 | append_flagstr(rfs, sz, "lptrap"); |
866 | 0 | } |
867 | |
|
868 | 0 | if (rflags & RES_NOMODIFY) { |
869 | 0 | CLEAR_BIT_IF_DEBUG(RES_NOMODIFY, rflags); |
870 | 0 | append_flagstr(rfs, sz, "nomodify"); |
871 | 0 | } |
872 | |
|
873 | 0 | if (rflags & RES_NOMRULIST) { |
874 | 0 | CLEAR_BIT_IF_DEBUG(RES_NOMRULIST, rflags); |
875 | 0 | append_flagstr(rfs, sz, "nomrulist"); |
876 | 0 | } |
877 | |
|
878 | 0 | if (rflags & RES_NOEPEER) { |
879 | 0 | CLEAR_BIT_IF_DEBUG(RES_NOEPEER, rflags); |
880 | 0 | append_flagstr(rfs, sz, "noepeer"); |
881 | 0 | } |
882 | |
|
883 | 0 | if (rflags & RES_NOPEER) { |
884 | 0 | CLEAR_BIT_IF_DEBUG(RES_NOPEER, rflags); |
885 | 0 | append_flagstr(rfs, sz, "nopeer"); |
886 | 0 | } |
887 | |
|
888 | 0 | if (rflags & RES_NOQUERY) { |
889 | 0 | CLEAR_BIT_IF_DEBUG(RES_NOQUERY, rflags); |
890 | 0 | append_flagstr(rfs, sz, "noquery"); |
891 | 0 | } |
892 | |
|
893 | 0 | if (rflags & RES_DONTSERVE) { |
894 | 0 | CLEAR_BIT_IF_DEBUG(RES_DONTSERVE, rflags); |
895 | 0 | append_flagstr(rfs, sz, "dontserve"); |
896 | 0 | } |
897 | |
|
898 | 0 | if (rflags & RES_NOTRAP) { |
899 | 0 | CLEAR_BIT_IF_DEBUG(RES_NOTRAP, rflags); |
900 | 0 | append_flagstr(rfs, sz, "notrap"); |
901 | 0 | } |
902 | |
|
903 | 0 | if (rflags & RES_DONTTRUST) { |
904 | 0 | CLEAR_BIT_IF_DEBUG(RES_DONTTRUST, rflags); |
905 | 0 | append_flagstr(rfs, sz, "notrust"); |
906 | 0 | } |
907 | |
|
908 | 0 | if (rflags & RES_SRVRSPFUZ) { |
909 | 0 | CLEAR_BIT_IF_DEBUG(RES_SRVRSPFUZ, rflags); |
910 | 0 | append_flagstr(rfs, sz, "srvrspfuz"); |
911 | 0 | } |
912 | |
|
913 | 0 | if (rflags & RES_VERSION) { |
914 | 0 | CLEAR_BIT_IF_DEBUG(RES_VERSION, rflags); |
915 | 0 | append_flagstr(rfs, sz, "version"); |
916 | 0 | } |
917 | |
|
918 | 0 | DEBUG_INVARIANT(!rflags); |
919 | | |
920 | 0 | if ('\0' == rfs[0]) { |
921 | 0 | append_flagstr(rfs, sz, "(none)"); |
922 | 0 | } |
923 | |
|
924 | 0 | return rfs; |
925 | 0 | } |
926 | | |
927 | | |
928 | | /* Convert restriction match RESM_ flag bits into a display string */ |
929 | | const char * |
930 | | mflags_str( |
931 | | u_short mflags |
932 | | ) |
933 | 0 | { |
934 | 0 | const size_t sz = LIB_BUFLENGTH; |
935 | 0 | char * mfs; |
936 | |
|
937 | 0 | LIB_GETBUF(mfs); |
938 | 0 | mfs[0] = '\0'; |
939 | |
|
940 | 0 | if (mflags & RESM_NTPONLY) { |
941 | 0 | CLEAR_BIT_IF_DEBUG(RESM_NTPONLY, mflags); |
942 | 0 | append_flagstr(mfs, sz, "ntponly"); |
943 | 0 | } |
944 | |
|
945 | 0 | if (mflags & RESM_SOURCE) { |
946 | 0 | CLEAR_BIT_IF_DEBUG(RESM_SOURCE, mflags); |
947 | 0 | append_flagstr(mfs, sz, "source"); |
948 | 0 | } |
949 | |
|
950 | 0 | if (mflags & RESM_INTERFACE) { |
951 | 0 | CLEAR_BIT_IF_DEBUG(RESM_INTERFACE, mflags); |
952 | 0 | append_flagstr(mfs, sz, "interface"); |
953 | 0 | } |
954 | |
|
955 | 0 | DEBUG_INVARIANT(!mflags); |
956 | | |
957 | 0 | return mfs; |
958 | 0 | } |
959 | | #endif /* DEBUG */ |