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