/src/ntp-dev/ntpd/ntp_restrict.c
Line | Count | Source (jump to first uncovered line) |
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 hosts we want |
19 | | * to place restrictions on (or remove them from). The restrictions |
20 | | * are implemented as a set of flags which tell you what the host |
21 | | * can't do. There is a subroutine entry to return the flags. The |
22 | | * list is kept sorted to reduce the average number of comparisons |
23 | | * and make sure you get the set of restrictions most specific to |
24 | | * the address. |
25 | | * |
26 | | * The algorithm is that, when looking up a host, it is first assumed |
27 | | * that the default set of restrictions will apply. It then searches |
28 | | * down through the list. Whenever it finds a match it adopts the |
29 | | * match's flags instead. When you hit the point where the sorted |
30 | | * address is greater than the target, you return with the last set of |
31 | | * flags you found. Because of the ordering of the list, the most |
32 | | * specific match will provide the final set of flags. |
33 | | * |
34 | | * This was originally intended to restrict you from sync'ing to your |
35 | | * own broadcasts when you are doing that, by restricting yourself from |
36 | | * your own interfaces. It was also thought it would sometimes be useful |
37 | | * to keep a misbehaving host or two from abusing your primary clock. It |
38 | | * has been expanded, however, to suit the needs of those with more |
39 | | * restrictive access policies. |
40 | | */ |
41 | | /* |
42 | | * We will use two lists, one for IPv4 addresses and one for IPv6 |
43 | | * addresses. This is not protocol-independant but for now I can't |
44 | | * find a way to respect this. We'll check this later... JFB 07/2001 |
45 | | */ |
46 | | #define MASK_IPV6_ADDR(dst, src, msk) \ |
47 | 1.01k | do { \ |
48 | 1.01k | int idx; \ |
49 | 17.2k | for (idx = 0; idx < (int)COUNTOF((dst)->s6_addr); idx++) { \ |
50 | 16.2k | (dst)->s6_addr[idx] = (src)->s6_addr[idx] \ |
51 | 16.2k | & (msk)->s6_addr[idx]; \ |
52 | 16.2k | } \ |
53 | 1.01k | } while (0) |
54 | | |
55 | | /* |
56 | | * We allocate INC_RESLIST{4|6} entries to the free list whenever empty. |
57 | | * Auto-tune these to be just less than 1KB (leaving at least 16 bytes |
58 | | * for allocator overhead). |
59 | | */ |
60 | 2 | #define INC_RESLIST4 ((1024 - 16) / V4_SIZEOF_RESTRICT_U) |
61 | 0 | #define INC_RESLIST6 ((1024 - 16) / V6_SIZEOF_RESTRICT_U) |
62 | | |
63 | | /* |
64 | | * The restriction list |
65 | | */ |
66 | | restrict_u *restrictlist4; |
67 | | restrict_u *restrictlist6; |
68 | | static int restrictcount; /* count in the restrict lists */ |
69 | | |
70 | | /* |
71 | | * The free list and associated counters. Also some uninteresting |
72 | | * stat counters. |
73 | | */ |
74 | | static restrict_u *resfree4; /* available entries (free list) */ |
75 | | static restrict_u *resfree6; |
76 | | |
77 | | static u_long res_calls; |
78 | | static u_long res_found; |
79 | | static u_long res_not_found; |
80 | | |
81 | | /* |
82 | | * Count number of restriction entries referring to RES_LIMITED, to |
83 | | * control implicit activation/deactivation of the MRU monlist. |
84 | | */ |
85 | | static u_long res_limited_refcnt; |
86 | | |
87 | | /* |
88 | | * Our default entries. |
89 | | * |
90 | | * We can make this cleaner with c99 support: see init_restrict(). |
91 | | */ |
92 | | static restrict_u restrict_def4; |
93 | | static restrict_u restrict_def6; |
94 | | |
95 | | /* |
96 | | * "restrict source ..." enabled knob and restriction bits. |
97 | | */ |
98 | | static int restrict_source_enabled; |
99 | | static u_short restrict_source_rflags; |
100 | | static u_short restrict_source_mflags; |
101 | | static short restrict_source_ippeerlimit; |
102 | | |
103 | | /* |
104 | | * private functions |
105 | | */ |
106 | | static restrict_u * alloc_res4(void); |
107 | | static restrict_u * alloc_res6(void); |
108 | | static void free_res(restrict_u *, int); |
109 | | static void inc_res_limited(void); |
110 | | static void dec_res_limited(void); |
111 | | static restrict_u * match_restrict4_addr(u_int32, u_short); |
112 | | static restrict_u * match_restrict6_addr(const struct in6_addr *, |
113 | | u_short); |
114 | | static restrict_u * match_restrict_entry(const restrict_u *, int); |
115 | | static int res_sorts_before4(restrict_u *, restrict_u *); |
116 | | static int res_sorts_before6(restrict_u *, restrict_u *); |
117 | | static char * roptoa(restrict_op op); |
118 | | |
119 | | |
120 | | void dump_restricts(void); |
121 | | |
122 | | /* |
123 | | * dump_restrict - spit out a restrict_u |
124 | | */ |
125 | | static void |
126 | | dump_restrict( |
127 | | restrict_u * res, |
128 | | int is_ipv6 |
129 | | ) |
130 | 0 | { |
131 | 0 | char as[INET6_ADDRSTRLEN]; |
132 | 0 | char ms[INET6_ADDRSTRLEN]; |
133 | |
|
134 | 0 | if (is_ipv6) { |
135 | 0 | inet_ntop(AF_INET6, &res->u.v6.addr, as, sizeof as); |
136 | 0 | inet_ntop(AF_INET6, &res->u.v6.mask, ms, sizeof ms); |
137 | 0 | } else { |
138 | 0 | struct in_addr sia = { htonl(res->u.v4.addr) }; |
139 | 0 | struct in_addr sim = { htonl(res->u.v4.mask) }; |
140 | |
|
141 | 0 | inet_ntop(AF_INET, &sia, as, sizeof as); |
142 | 0 | inet_ntop(AF_INET, &sim, ms, sizeof ms); |
143 | 0 | } |
144 | 0 | mprintf("restrict node at %p: %s/%s count %d, rflags %05x, mflags %05x, ippeerlimit %d, expire %lu, next %p\n", |
145 | 0 | res, as, ms, res->count, res->rflags, res->mflags, |
146 | 0 | res->ippeerlimit, res->expire, res->link); |
147 | 0 | return; |
148 | 0 | } |
149 | | |
150 | | |
151 | | /* |
152 | | * dump_restricts - spit out the 'restrict' lines |
153 | | */ |
154 | | void |
155 | | dump_restricts(void) |
156 | 0 | { |
157 | 0 | int defaultv4_done = 0; |
158 | 0 | int defaultv6_done = 0; |
159 | 0 | restrict_u * res; |
160 | 0 | restrict_u * next; |
161 | |
|
162 | 0 | mprintf("dump_restrict: restrict_def4: %p\n", &restrict_def4); |
163 | | /* Spit out 'restrict {,-4,-6} default ...' lines, if needed */ |
164 | 0 | for (res = &restrict_def4; res != NULL; res = next) { |
165 | 0 | dump_restrict(res, 0); |
166 | 0 | next = res->link; |
167 | 0 | } |
168 | |
|
169 | 0 | mprintf("dump_restrict: restrict_def6: %p\n", &restrict_def6); |
170 | 0 | for (res = &restrict_def6; res != NULL; res = next) { |
171 | 0 | dump_restrict(res, 1); |
172 | 0 | next = res->link; |
173 | 0 | } |
174 | | |
175 | | /* Spit out the IPv4 list */ |
176 | 0 | mprintf("dump_restrict: restrictlist4: %p\n", &restrictlist4); |
177 | 0 | for (res = restrictlist4; res != NULL; res = next) { |
178 | 0 | dump_restrict(res, 0); |
179 | 0 | next = res->link; |
180 | 0 | } |
181 | | |
182 | | /* Spit out the IPv6 list */ |
183 | 0 | mprintf("dump_restrict: restrictlist6: %p\n", &restrictlist6); |
184 | 0 | for (res = restrictlist6; res != NULL; res = next) { |
185 | 0 | dump_restrict(res, 1); |
186 | 0 | next = res->link; |
187 | 0 | } |
188 | |
|
189 | 0 | return; |
190 | 0 | } |
191 | | |
192 | | /* |
193 | | * init_restrict - initialize the restriction data structures |
194 | | */ |
195 | | void |
196 | | init_restrict(void) |
197 | 1 | { |
198 | | /* |
199 | | * The restriction lists begin with a default entry with address |
200 | | * and mask 0, which will match any entry. The lists are kept |
201 | | * sorted by descending address followed by descending mask: |
202 | | * |
203 | | * address mask |
204 | | * 192.168.0.0 255.255.255.0 kod limited noquery nopeer |
205 | | * 192.168.0.0 255.255.0.0 kod limited |
206 | | * 0.0.0.0 0.0.0.0 kod limited noquery |
207 | | * |
208 | | * The first entry which matches an address is used. With the |
209 | | * example restrictions above, 192.168.0.0/24 matches the first |
210 | | * entry, the rest of 192.168.0.0/16 matches the second, and |
211 | | * everything else matches the third (default). |
212 | | * |
213 | | * Note this achieves the same result a little more efficiently |
214 | | * than the documented behavior, which is to keep the lists |
215 | | * sorted by ascending address followed by ascending mask, with |
216 | | * the _last_ matching entry used. |
217 | | * |
218 | | * An additional wrinkle is we may have multiple entries with |
219 | | * the same address and mask but differing match flags (mflags). |
220 | | * At present there is only one, RESM_NTPONLY. Entries with |
221 | | * RESM_NTPONLY are sorted earlier so they take precedence over |
222 | | * any otherwise similar entry without. Again, this is the same |
223 | | * behavior as but reversed implementation compared to the docs. |
224 | | * |
225 | | */ |
226 | | |
227 | 1 | restrict_def4.ippeerlimit = -1; /* Cleaner if we have C99 */ |
228 | 1 | restrict_def6.ippeerlimit = -1; /* Cleaner if we have C99 */ |
229 | | |
230 | 1 | LINK_SLIST(restrictlist4, &restrict_def4, link); |
231 | 1 | LINK_SLIST(restrictlist6, &restrict_def6, link); |
232 | 1 | restrictcount = 2; |
233 | 1 | } |
234 | | |
235 | | |
236 | | static restrict_u * |
237 | | alloc_res4(void) |
238 | 2 | { |
239 | 2 | const size_t cb = V4_SIZEOF_RESTRICT_U; |
240 | 2 | const size_t count = INC_RESLIST4; |
241 | 2 | restrict_u * rl; |
242 | 2 | restrict_u * res; |
243 | 2 | size_t i; |
244 | | |
245 | 2 | UNLINK_HEAD_SLIST(res, resfree4, link); |
246 | 2 | if (res != NULL) |
247 | 1 | return res; |
248 | | |
249 | 1 | rl = eallocarray(count, cb); |
250 | | /* link all but the first onto free list */ |
251 | 1 | res = (void *)((char *)rl + (count - 1) * cb); |
252 | 25 | for (i = count - 1; i > 0; i--) { |
253 | 24 | LINK_SLIST(resfree4, res, link); |
254 | 24 | res = (void *)((char *)res - cb); |
255 | 24 | } |
256 | 1 | INSIST(rl == res); |
257 | | /* allocate the first */ |
258 | 0 | return res; |
259 | 2 | } |
260 | | |
261 | | |
262 | | static restrict_u * |
263 | | alloc_res6(void) |
264 | 0 | { |
265 | 0 | const size_t cb = V6_SIZEOF_RESTRICT_U; |
266 | 0 | const size_t count = INC_RESLIST6; |
267 | 0 | restrict_u * rl; |
268 | 0 | restrict_u * res; |
269 | 0 | size_t i; |
270 | |
|
271 | 0 | UNLINK_HEAD_SLIST(res, resfree6, link); |
272 | 0 | if (res != NULL) |
273 | 0 | return res; |
274 | | |
275 | 0 | rl = eallocarray(count, cb); |
276 | | /* link all but the first onto free list */ |
277 | 0 | res = (void *)((char *)rl + (count - 1) * cb); |
278 | 0 | for (i = count - 1; i > 0; i--) { |
279 | 0 | LINK_SLIST(resfree6, res, link); |
280 | 0 | res = (void *)((char *)res - cb); |
281 | 0 | } |
282 | 0 | INSIST(rl == res); |
283 | | /* allocate the first */ |
284 | 0 | return res; |
285 | 0 | } |
286 | | |
287 | | |
288 | | static void |
289 | | free_res( |
290 | | restrict_u * res, |
291 | | int v6 |
292 | | ) |
293 | 0 | { |
294 | 0 | restrict_u ** plisthead; |
295 | 0 | restrict_u * unlinked; |
296 | |
|
297 | 0 | restrictcount--; |
298 | 0 | if (RES_LIMITED & res->rflags) |
299 | 0 | dec_res_limited(); |
300 | |
|
301 | 0 | if (v6) |
302 | 0 | plisthead = &restrictlist6; |
303 | 0 | else |
304 | 0 | plisthead = &restrictlist4; |
305 | 0 | UNLINK_SLIST(unlinked, *plisthead, res, link, restrict_u); |
306 | 0 | INSIST(unlinked == res); |
307 | | |
308 | 0 | if (v6) { |
309 | 0 | zero_mem(res, V6_SIZEOF_RESTRICT_U); |
310 | 0 | plisthead = &resfree6; |
311 | 0 | } else { |
312 | 0 | zero_mem(res, V4_SIZEOF_RESTRICT_U); |
313 | 0 | plisthead = &resfree4; |
314 | 0 | } |
315 | 0 | LINK_SLIST(*plisthead, res, link); |
316 | 0 | } |
317 | | |
318 | | |
319 | | static void |
320 | | inc_res_limited(void) |
321 | 0 | { |
322 | 0 | if (!res_limited_refcnt) |
323 | 0 | mon_start(MON_RES); |
324 | 0 | res_limited_refcnt++; |
325 | 0 | } |
326 | | |
327 | | |
328 | | static void |
329 | | dec_res_limited(void) |
330 | 0 | { |
331 | 0 | res_limited_refcnt--; |
332 | 0 | if (!res_limited_refcnt) |
333 | 0 | mon_stop(MON_RES); |
334 | 0 | } |
335 | | |
336 | | |
337 | | static restrict_u * |
338 | | match_restrict4_addr( |
339 | | u_int32 addr, |
340 | | u_short port |
341 | | ) |
342 | 702 | { |
343 | 702 | const int v6 = 0; |
344 | 702 | restrict_u * res; |
345 | 702 | restrict_u * next; |
346 | | |
347 | 2.10k | for (res = restrictlist4; res != NULL; res = next) { |
348 | 2.10k | struct in_addr sia = { htonl(res->u.v4.addr) }; |
349 | | |
350 | 2.10k | next = res->link; |
351 | 2.10k | DPRINTF(2, ("match_restrict4_addr: Checking %s, port %d ... ", |
352 | 2.10k | inet_ntoa(sia), port)); |
353 | 2.10k | if ( res->expire |
354 | 2.10k | && res->expire <= current_time) |
355 | 0 | free_res(res, v6); /* zeroes the contents */ |
356 | 2.10k | if ( res->u.v4.addr == (addr & res->u.v4.mask) |
357 | 2.10k | && ( !(RESM_NTPONLY & res->mflags) |
358 | 703 | || NTP_PORT == port)) { |
359 | 702 | DPRINTF(2, ("MATCH: ippeerlimit %d\n", res->ippeerlimit)); |
360 | 702 | break; |
361 | 702 | } |
362 | 1.40k | DPRINTF(2, ("doesn't match: ippeerlimit %d\n", res->ippeerlimit)); |
363 | 1.40k | } |
364 | 702 | return res; |
365 | 702 | } |
366 | | |
367 | | |
368 | | static restrict_u * |
369 | | match_restrict6_addr( |
370 | | const struct in6_addr * addr, |
371 | | u_short port |
372 | | ) |
373 | 1.01k | { |
374 | 1.01k | const int v6 = 1; |
375 | 1.01k | restrict_u * res; |
376 | 1.01k | restrict_u * next; |
377 | 1.01k | struct in6_addr masked; |
378 | | |
379 | 1.01k | for (res = restrictlist6; res != NULL; res = next) { |
380 | 1.01k | next = res->link; |
381 | 1.01k | INSIST(next != res); |
382 | 1.01k | if (res->expire && |
383 | 1.01k | res->expire <= current_time) |
384 | 0 | free_res(res, v6); |
385 | 1.01k | MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask); |
386 | 1.01k | if (ADDR6_EQ(&masked, &res->u.v6.addr) |
387 | 1.01k | && (!(RESM_NTPONLY & res->mflags) |
388 | 1.01k | || NTP_PORT == (int)port)) |
389 | 1.01k | break; |
390 | 1.01k | } |
391 | 1.01k | return res; |
392 | 1.01k | } |
393 | | |
394 | | |
395 | | /* |
396 | | * match_restrict_entry - find an exact match on a restrict list. |
397 | | * |
398 | | * Exact match is addr, mask, and mflags all equal. |
399 | | * In order to use more common code for IPv4 and IPv6, this routine |
400 | | * requires the caller to populate a restrict_u with mflags and either |
401 | | * the v4 or v6 address and mask as appropriate. Other fields in the |
402 | | * input restrict_u are ignored. |
403 | | */ |
404 | | static restrict_u * |
405 | | match_restrict_entry( |
406 | | const restrict_u * pmatch, |
407 | | int v6 |
408 | | ) |
409 | 2 | { |
410 | 2 | restrict_u *res; |
411 | 2 | restrict_u *rlist; |
412 | 2 | size_t cb; |
413 | | |
414 | 2 | if (v6) { |
415 | 0 | rlist = restrictlist6; |
416 | 0 | cb = sizeof(pmatch->u.v6); |
417 | 2 | } else { |
418 | 2 | rlist = restrictlist4; |
419 | 2 | cb = sizeof(pmatch->u.v4); |
420 | 2 | } |
421 | | |
422 | 5 | for (res = rlist; res != NULL; res = res->link) |
423 | 3 | if (res->mflags == pmatch->mflags && |
424 | 3 | !memcmp(&res->u, &pmatch->u, cb)) |
425 | 0 | break; |
426 | 2 | return res; |
427 | 2 | } |
428 | | |
429 | | |
430 | | /* |
431 | | * res_sorts_before4 - compare two restrict4 entries |
432 | | * |
433 | | * Returns nonzero if r1 sorts before r2. We sort by descending |
434 | | * address, then descending mask, then descending mflags, so sorting |
435 | | * before means having a higher value. |
436 | | */ |
437 | | static int |
438 | | res_sorts_before4( |
439 | | restrict_u *r1, |
440 | | restrict_u *r2 |
441 | | ) |
442 | 2 | { |
443 | 2 | int r1_before_r2; |
444 | | |
445 | 2 | if (r1->u.v4.addr > r2->u.v4.addr) |
446 | 2 | r1_before_r2 = 1; |
447 | 0 | else if (r1->u.v4.addr < r2->u.v4.addr) |
448 | 0 | r1_before_r2 = 0; |
449 | 0 | else if (r1->u.v4.mask > r2->u.v4.mask) |
450 | 0 | r1_before_r2 = 1; |
451 | 0 | else if (r1->u.v4.mask < r2->u.v4.mask) |
452 | 0 | r1_before_r2 = 0; |
453 | 0 | else if (r1->mflags > r2->mflags) |
454 | 0 | r1_before_r2 = 1; |
455 | 0 | else |
456 | 0 | r1_before_r2 = 0; |
457 | | |
458 | 2 | return r1_before_r2; |
459 | 2 | } |
460 | | |
461 | | |
462 | | /* |
463 | | * res_sorts_before6 - compare two restrict6 entries |
464 | | * |
465 | | * Returns nonzero if r1 sorts before r2. We sort by descending |
466 | | * address, then descending mask, then descending mflags, so sorting |
467 | | * before means having a higher value. |
468 | | */ |
469 | | static int |
470 | | res_sorts_before6( |
471 | | restrict_u *r1, |
472 | | restrict_u *r2 |
473 | | ) |
474 | 0 | { |
475 | 0 | int r1_before_r2; |
476 | 0 | int cmp; |
477 | |
|
478 | 0 | cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr); |
479 | 0 | if (cmp > 0) /* r1->addr > r2->addr */ |
480 | 0 | r1_before_r2 = 1; |
481 | 0 | else if (cmp < 0) /* r2->addr > r1->addr */ |
482 | 0 | r1_before_r2 = 0; |
483 | 0 | else { |
484 | 0 | cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask); |
485 | 0 | if (cmp > 0) /* r1->mask > r2->mask*/ |
486 | 0 | r1_before_r2 = 1; |
487 | 0 | else if (cmp < 0) /* r2->mask > r1->mask */ |
488 | 0 | r1_before_r2 = 0; |
489 | 0 | else if (r1->mflags > r2->mflags) |
490 | 0 | r1_before_r2 = 1; |
491 | 0 | else |
492 | 0 | r1_before_r2 = 0; |
493 | 0 | } |
494 | |
|
495 | 0 | return r1_before_r2; |
496 | 0 | } |
497 | | |
498 | | |
499 | | /* |
500 | | * restrictions - return restrictions for this host in *r4a |
501 | | */ |
502 | | void |
503 | | restrictions( |
504 | | sockaddr_u *srcadr, |
505 | | r4addr *r4a |
506 | | ) |
507 | 1.74k | { |
508 | 1.74k | restrict_u *match; |
509 | 1.74k | struct in6_addr *pin6; |
510 | | |
511 | 1.74k | REQUIRE(NULL != r4a); |
512 | | |
513 | 0 | res_calls++; |
514 | 1.74k | r4a->rflags = RES_IGNORE; |
515 | 1.74k | r4a->ippeerlimit = 0; |
516 | | |
517 | 1.74k | DPRINTF(1, ("restrictions: looking up %s\n", stoa(srcadr))); |
518 | | |
519 | | /* IPv4 source address */ |
520 | 1.74k | if (IS_IPV4(srcadr)) { |
521 | | /* |
522 | | * Ignore any packets with a multicast source address |
523 | | * (this should be done early in the receive process, |
524 | | * not later!) |
525 | | */ |
526 | 703 | if (IN_CLASSD(SRCADR(srcadr))) { |
527 | 1 | DPRINTF(1, ("restrictions: srcadr %s is multicast\n", stoa(srcadr))); |
528 | 1 | r4a->ippeerlimit = 2; /* XXX: we should use a better value */ |
529 | 1 | return; |
530 | 1 | } |
531 | | |
532 | 702 | match = match_restrict4_addr(SRCADR(srcadr), |
533 | 702 | SRCPORT(srcadr)); |
534 | | |
535 | 702 | INSIST(match != NULL); |
536 | | |
537 | 0 | match->count++; |
538 | | /* |
539 | | * res_not_found counts only use of the final default |
540 | | * entry, not any "restrict default ntpport ...", which |
541 | | * would be just before the final default. |
542 | | */ |
543 | 702 | if (&restrict_def4 == match) |
544 | 702 | res_not_found++; |
545 | 0 | else |
546 | 0 | res_found++; |
547 | 702 | r4a->rflags = match->rflags; |
548 | 702 | r4a->ippeerlimit = match->ippeerlimit; |
549 | 702 | } |
550 | | |
551 | | /* IPv6 source address */ |
552 | 1.74k | if (IS_IPV6(srcadr)) { |
553 | 1.01k | 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 | 1.01k | if (IN6_IS_ADDR_MULTICAST(pin6)) |
561 | 1 | return; |
562 | | |
563 | 1.01k | match = match_restrict6_addr(pin6, SRCPORT(srcadr)); |
564 | 1.01k | INSIST(match != NULL); |
565 | 0 | match->count++; |
566 | 1.01k | if (&restrict_def6 == match) |
567 | 1.01k | res_not_found++; |
568 | 0 | else |
569 | 0 | res_found++; |
570 | 1.01k | r4a->rflags = match->rflags; |
571 | 1.01k | r4a->ippeerlimit = match->ippeerlimit; |
572 | 1.01k | } |
573 | 1.74k | return; |
574 | 1.74k | } |
575 | | |
576 | | |
577 | | /* |
578 | | * roptoa - convert a restrict_op to a string |
579 | | */ |
580 | | char * |
581 | 0 | roptoa(restrict_op op) { |
582 | 0 | static char sb[30]; |
583 | |
|
584 | 0 | switch(op) { |
585 | 0 | case RESTRICT_FLAGS: return "RESTRICT_FLAGS"; |
586 | 0 | case RESTRICT_UNFLAG: return "RESTRICT_UNFLAGS"; |
587 | 0 | case RESTRICT_REMOVE: return "RESTRICT_REMOVE"; |
588 | 0 | case RESTRICT_REMOVEIF: return "RESTRICT_REMOVEIF"; |
589 | 0 | default: |
590 | 0 | snprintf(sb, sizeof sb, "**RESTRICT_#%d**", op); |
591 | 0 | return sb; |
592 | 0 | } |
593 | 0 | } |
594 | | |
595 | | |
596 | | /* |
597 | | * hack_restrict - add/subtract/manipulate entries on the restrict list |
598 | | */ |
599 | | void |
600 | | hack_restrict( |
601 | | restrict_op op, |
602 | | sockaddr_u * resaddr, |
603 | | sockaddr_u * resmask, |
604 | | short ippeerlimit, |
605 | | u_short mflags, |
606 | | u_short rflags, |
607 | | u_long expire |
608 | | ) |
609 | 2 | { |
610 | 2 | int v6; |
611 | 2 | restrict_u match; |
612 | 2 | restrict_u * res; |
613 | 2 | restrict_u ** plisthead; |
614 | | |
615 | 2 | DPRINTF(1, ("hack_restrict: op %s addr %s mask %s ippeerlimit %d mflags %08x rflags %08x\n", |
616 | 2 | roptoa(op), stoa(resaddr), stoa(resmask), ippeerlimit, mflags, rflags)); |
617 | | |
618 | 2 | if (NULL == resaddr) { |
619 | 0 | REQUIRE(NULL == resmask); |
620 | 0 | REQUIRE(RESTRICT_FLAGS == op); |
621 | 0 | restrict_source_rflags = rflags; |
622 | 0 | restrict_source_mflags = mflags; |
623 | 0 | restrict_source_ippeerlimit = ippeerlimit; |
624 | 0 | restrict_source_enabled = 1; |
625 | 0 | return; |
626 | 0 | } |
627 | | |
628 | 2 | ZERO(match); |
629 | | |
630 | | #if 0 |
631 | | /* silence VC9 potentially uninit warnings */ |
632 | | // HMS: let's use a compiler-specific "enable" for this. |
633 | | res = NULL; |
634 | | v6 = 0; |
635 | | #endif |
636 | | |
637 | 2 | if (IS_IPV4(resaddr)) { |
638 | 2 | v6 = 0; |
639 | | /* |
640 | | * Get address and mask in host byte order for easy |
641 | | * comparison as u_int32 |
642 | | */ |
643 | 2 | match.u.v4.addr = SRCADR(resaddr); |
644 | 2 | match.u.v4.mask = SRCADR(resmask); |
645 | 2 | match.u.v4.addr &= match.u.v4.mask; |
646 | | |
647 | 2 | } else if (IS_IPV6(resaddr)) { |
648 | 0 | v6 = 1; |
649 | | /* |
650 | | * Get address and mask in network byte order for easy |
651 | | * comparison as byte sequences (e.g. memcmp()) |
652 | | */ |
653 | 0 | match.u.v6.mask = SOCK_ADDR6(resmask); |
654 | 0 | MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr), |
655 | 0 | &match.u.v6.mask); |
656 | |
|
657 | 0 | } else /* not IPv4 nor IPv6 */ |
658 | 0 | REQUIRE(0); |
659 | | |
660 | 0 | match.rflags = rflags; |
661 | 2 | match.mflags = mflags; |
662 | 2 | match.ippeerlimit = ippeerlimit; |
663 | 2 | match.expire = expire; |
664 | 2 | res = match_restrict_entry(&match, v6); |
665 | | |
666 | 2 | switch (op) { |
667 | | |
668 | 2 | case RESTRICT_FLAGS: |
669 | | /* |
670 | | * Here we add bits to the rflags. If this is a |
671 | | * new restriction add it. |
672 | | */ |
673 | 2 | if (NULL == res) { |
674 | 2 | if (v6) { |
675 | 0 | res = alloc_res6(); |
676 | 0 | memcpy(res, &match, |
677 | 0 | V6_SIZEOF_RESTRICT_U); |
678 | 0 | plisthead = &restrictlist6; |
679 | 2 | } else { |
680 | 2 | res = alloc_res4(); |
681 | 2 | memcpy(res, &match, |
682 | 2 | V4_SIZEOF_RESTRICT_U); |
683 | 2 | plisthead = &restrictlist4; |
684 | 2 | } |
685 | 2 | LINK_SORT_SLIST( |
686 | 2 | *plisthead, res, |
687 | 2 | (v6) |
688 | 2 | ? res_sorts_before6(res, L_S_S_CUR()) |
689 | 2 | : res_sorts_before4(res, L_S_S_CUR()), |
690 | 2 | link, restrict_u); |
691 | 2 | restrictcount++; |
692 | 2 | if (RES_LIMITED & rflags) |
693 | 0 | inc_res_limited(); |
694 | 2 | } else { |
695 | 0 | if ( (RES_LIMITED & rflags) |
696 | 0 | && !(RES_LIMITED & res->rflags)) |
697 | 0 | inc_res_limited(); |
698 | 0 | res->rflags |= rflags; |
699 | 0 | } |
700 | | |
701 | 2 | res->ippeerlimit = match.ippeerlimit; |
702 | | |
703 | 2 | break; |
704 | | |
705 | 0 | case RESTRICT_UNFLAG: |
706 | | /* |
707 | | * Remove some bits from the rflags. If we didn't |
708 | | * find this one, just return. |
709 | | */ |
710 | 0 | if (res != NULL) { |
711 | 0 | if ( (RES_LIMITED & res->rflags) |
712 | 0 | && (RES_LIMITED & rflags)) |
713 | 0 | dec_res_limited(); |
714 | 0 | res->rflags &= ~rflags; |
715 | 0 | } |
716 | 0 | break; |
717 | | |
718 | 0 | case RESTRICT_REMOVE: |
719 | 0 | case RESTRICT_REMOVEIF: |
720 | | /* |
721 | | * Remove an entry from the table entirely if we |
722 | | * found one. Don't remove the default entry and |
723 | | * don't remove an interface entry. |
724 | | */ |
725 | 0 | if (res != NULL |
726 | 0 | && (RESTRICT_REMOVEIF == op |
727 | 0 | || !(RESM_INTERFACE & res->mflags)) |
728 | 0 | && res != &restrict_def4 |
729 | 0 | && res != &restrict_def6) |
730 | 0 | free_res(res, v6); |
731 | 0 | break; |
732 | | |
733 | 0 | default: /* unknown op */ |
734 | 0 | INSIST(0); |
735 | 0 | break; |
736 | 2 | } |
737 | | |
738 | 2 | } |
739 | | |
740 | | |
741 | | /* |
742 | | * restrict_source - maintains dynamic "restrict source ..." entries as |
743 | | * peers come and go. |
744 | | */ |
745 | | void |
746 | | restrict_source( |
747 | | sockaddr_u * addr, |
748 | | int farewell, /* 0 to add, 1 to remove */ |
749 | | u_long expire /* 0 is infinite, valid until */ |
750 | | ) |
751 | 0 | { |
752 | 0 | sockaddr_u onesmask; |
753 | 0 | restrict_u * res; |
754 | 0 | int found_specific; |
755 | |
|
756 | 0 | if (!restrict_source_enabled || SOCK_UNSPEC(addr) || |
757 | 0 | IS_MCAST(addr) || ISREFCLOCKADR(addr)) |
758 | 0 | return; |
759 | | |
760 | 0 | REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr)); |
761 | | |
762 | 0 | SET_HOSTMASK(&onesmask, AF(addr)); |
763 | 0 | if (farewell) { |
764 | 0 | hack_restrict(RESTRICT_REMOVE, addr, &onesmask, |
765 | 0 | -2, 0, 0, 0); |
766 | 0 | DPRINTF(1, ("restrict_source: %s removed", stoa(addr))); |
767 | 0 | return; |
768 | 0 | } |
769 | | |
770 | | /* |
771 | | * If there is a specific entry for this address, hands |
772 | | * off, as it is condidered more specific than "restrict |
773 | | * server ...". |
774 | | * However, if the specific entry found is a fleeting one |
775 | | * added by pool_xmit() before soliciting, replace it |
776 | | * immediately regardless of the expire value to make way |
777 | | * for the more persistent entry. |
778 | | */ |
779 | 0 | if (IS_IPV4(addr)) { |
780 | 0 | res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr)); |
781 | 0 | INSIST(res != NULL); |
782 | 0 | found_specific = (SRCADR(&onesmask) == res->u.v4.mask); |
783 | 0 | } else { |
784 | 0 | res = match_restrict6_addr(&SOCK_ADDR6(addr), |
785 | 0 | SRCPORT(addr)); |
786 | 0 | INSIST(res != NULL); |
787 | 0 | found_specific = ADDR6_EQ(&res->u.v6.mask, |
788 | 0 | &SOCK_ADDR6(&onesmask)); |
789 | 0 | } |
790 | 0 | if (!expire && found_specific && res->expire) { |
791 | 0 | found_specific = 0; |
792 | 0 | free_res(res, IS_IPV6(addr)); |
793 | 0 | } |
794 | 0 | if (found_specific) |
795 | 0 | return; |
796 | | |
797 | 0 | hack_restrict(RESTRICT_FLAGS, addr, &onesmask, |
798 | 0 | restrict_source_ippeerlimit, restrict_source_mflags, |
799 | 0 | restrict_source_rflags, expire); |
800 | 0 | DPRINTF(1, ("restrict_source: %s host restriction added\n", |
801 | 0 | stoa(addr))); |
802 | 0 | } |