diff options
author | Cy Schubert <cy@FreeBSD.org> | 2024-05-10 15:15:56 +0000 |
---|---|---|
committer | Cy Schubert <cy@FreeBSD.org> | 2024-05-26 22:55:52 +0000 |
commit | 1f833b3fc9968c3dd7ed79ccf0525ebf16c891ad (patch) | |
tree | 85801af20e3b694584668aeb39ecec75ee71f72c /ntpd/ntp_restrict.c | |
parent | ab1f1aa8333369a83ff284848fc3fc2e52d5f29f (diff) |
Diffstat (limited to 'ntpd/ntp_restrict.c')
-rw-r--r-- | ntpd/ntp_restrict.c | 725 |
1 files changed, 437 insertions, 288 deletions
diff --git a/ntpd/ntp_restrict.c b/ntpd/ntp_restrict.c index fe2935d9e071..f1df8ccf3079 100644 --- a/ntpd/ntp_restrict.c +++ b/ntpd/ntp_restrict.c @@ -15,21 +15,11 @@ #include "ntp_assert.h" /* - * This code keeps a simple address-and-mask list of hosts we want - * to place restrictions on (or remove them from). The restrictions - * are implemented as a set of flags which tell you what the host - * can't do. There is a subroutine entry to return the flags. The - * list is kept sorted to reduce the average number of comparisons - * and make sure you get the set of restrictions most specific to - * the address. - * - * The algorithm is that, when looking up a host, it is first assumed - * that the default set of restrictions will apply. It then searches - * down through the list. Whenever it finds a match it adopts the - * match's flags instead. When you hit the point where the sorted - * address is greater than the target, you return with the last set of - * flags you found. Because of the ordering of the list, the most - * specific match will provide the final set of flags. + * This code keeps a simple address-and-mask list of addressses we want + * to place restrictions on (or remove them from). The restrictions are + * implemented as a set of flags which tell you what matching addresses + * can't do. The list is sorted retrieve the restrictions most specific +* to the address. * * This was originally intended to restrict you from sync'ing to your * own broadcasts when you are doing that, by restricting yourself from @@ -38,27 +28,23 @@ * has been expanded, however, to suit the needs of those with more * restrictive access policies. */ -/* - * We will use two lists, one for IPv4 addresses and one for IPv6 - * addresses. This is not protocol-independant but for now I can't - * find a way to respect this. We'll check this later... JFB 07/2001 - */ #define MASK_IPV6_ADDR(dst, src, msk) \ do { \ - int idx; \ - for (idx = 0; idx < (int)COUNTOF((dst)->s6_addr); idx++) { \ - (dst)->s6_addr[idx] = (src)->s6_addr[idx] \ - & (msk)->s6_addr[idx]; \ + int x; \ + \ + for (x = 0; x < (int)COUNTOF((dst)->s6_addr); x++) { \ + (dst)->s6_addr[x] = (src)->s6_addr[x] \ + & (msk)->s6_addr[x]; \ } \ - } while (0) + } while (FALSE) /* * We allocate INC_RESLIST{4|6} entries to the free list whenever empty. - * Auto-tune these to be just less than 1KB (leaving at least 16 bytes + * Auto-tune these to be just less than 1KB (leaving at least 32 bytes * for allocator overhead). */ -#define INC_RESLIST4 ((1024 - 16) / V4_SIZEOF_RESTRICT_U) -#define INC_RESLIST6 ((1024 - 16) / V6_SIZEOF_RESTRICT_U) +#define INC_RESLIST4 ((1024 - 32) / V4_SIZEOF_RESTRICT_U) +#define INC_RESLIST6 ((1024 - 32) / V6_SIZEOF_RESTRICT_U) /* * The restriction list @@ -103,30 +89,35 @@ static short restrict_source_ippeerlimit; /* * private functions */ -static restrict_u * alloc_res4(void); -static restrict_u * alloc_res6(void); -static void free_res(restrict_u *, int); -static void inc_res_limited(void); -static void dec_res_limited(void); -static restrict_u * match_restrict4_addr(u_int32, u_short); -static restrict_u * match_restrict6_addr(const struct in6_addr *, +static restrict_u * alloc_res4(void); +static restrict_u * alloc_res6(void); +static void free_res(restrict_u *, int); +static inline void inc_res_limited(void); +static inline void dec_res_limited(void); +static restrict_u * match_restrict4_addr(u_int32, u_short); +static restrict_u * match_restrict6_addr(const struct in6_addr *, u_short); -static restrict_u * match_restrict_entry(const restrict_u *, int); -static int res_sorts_before4(restrict_u *, restrict_u *); -static int res_sorts_before6(restrict_u *, restrict_u *); -static char * roptoa(restrict_op op); +static restrict_u * match_restrict_entry(const restrict_u *, int); +static inline int/*BOOL*/ mflags_sorts_before(u_short, u_short); +static int/*BOOL*/ res_sorts_before4(restrict_u *, restrict_u *); +static int/*BOOL*/ res_sorts_before6(restrict_u *, restrict_u *); +typedef int (*res_sort_fn)(restrict_u *, restrict_u *); + + +/* dump_restrict() & dump_restricts() are DEBUG-only */ +#ifdef DEBUG +static void dump_restrict(restrict_u *, int); -void dump_restricts(void); /* - * dump_restrict - spit out a restrict_u + * dump_restrict - spit out a single restriction entry */ static void dump_restrict( restrict_u * res, int is_ipv6 - ) +) { char as[INET6_ADDRSTRLEN]; char ms[INET6_ADDRSTRLEN]; @@ -135,57 +126,47 @@ dump_restrict( inet_ntop(AF_INET6, &res->u.v6.addr, as, sizeof as); inet_ntop(AF_INET6, &res->u.v6.mask, ms, sizeof ms); } else { - struct in_addr sia = { htonl(res->u.v4.addr) }; - struct in_addr sim = { htonl(res->u.v4.mask) }; + struct in_addr sia, sim; + sia.s_addr = htonl(res->u.v4.addr); + sim.s_addr = htonl(res->u.v4.addr); inet_ntop(AF_INET, &sia, as, sizeof as); inet_ntop(AF_INET, &sim, ms, sizeof ms); } - mprintf("restrict node at %p: %s/%s count %d, rflags %08x, mflags %04x, ippeerlimit %d, expire %lu, next %p\n", - res, as, ms, res->count, res->rflags, res->mflags, - res->ippeerlimit, res->expire, res->link); - return; + printf("%s/%s: hits %u ippeerlimit %hd mflags %s rflags %s", + as, ms, res->count, res->ippeerlimit, + mflags_str(res->mflags), + rflags_str(res->rflags)); + if (res->expire > 0) { + printf(" expire %u\n", res->expire); + } else { + printf("\n"); + } } /* - * dump_restricts - spit out the 'restrict' lines + * dump_restricts - spit out the 'restrict' entries */ void dump_restricts(void) { restrict_u * res; - restrict_u * next; - - mprintf("dump_restrict: restrict_def4: %p\n", &restrict_def4); - /* Spit out 'restrict {,-4,-6} default ...' lines, if needed */ - for (res = &restrict_def4; res != NULL; res = next) { - dump_restrict(res, 0); - next = res->link; - } - - mprintf("dump_restrict: restrict_def6: %p\n", &restrict_def6); - for (res = &restrict_def6; res != NULL; res = next) { - dump_restrict(res, 1); - next = res->link; - } /* Spit out the IPv4 list */ - mprintf("dump_restrict: restrictlist4: %p\n", &restrictlist4); - for (res = restrictlist4; res != NULL; res = next) { + printf("dump_restricts: restrictlist4: %p\n", restrictlist4); + for (res = restrictlist4; res != NULL; res = res->link) { dump_restrict(res, 0); - next = res->link; } /* Spit out the IPv6 list */ - mprintf("dump_restrict: restrictlist6: %p\n", &restrictlist6); - for (res = restrictlist6; res != NULL; res = next) { + printf("dump_restricts: restrictlist6: %p\n", restrictlist6); + for (res = restrictlist6; res != NULL; res = res->link) { dump_restrict(res, 1); - next = res->link; } - - return; } +#endif /* DEBUG - dump_restrict() / dump_restricts() */ + /* * init_restrict - initialize the restriction data structures @@ -194,7 +175,7 @@ void init_restrict(void) { /* - * The restriction lists begin with a default entry with address + * The restriction lists end with a default entry with address * and mask 0, which will match any entry. The lists are kept * sorted by descending address followed by descending mask: * @@ -215,11 +196,20 @@ init_restrict(void) * * An additional wrinkle is we may have multiple entries with * the same address and mask but differing match flags (mflags). - * At present there is only one, RESM_NTPONLY. Entries with - * RESM_NTPONLY are sorted earlier so they take precedence over - * any otherwise similar entry without. Again, this is the same - * behavior as but reversed implementation compared to the docs. - * + * We want to never talk to ourself, so RES_IGNORE entries for + * each local address are added by ntp_io.c with a host mask and + * both RESM_INTERFACE and RESM_NTPONLY set. We sort those + * entries before entries without those flags to achieve this. + * The remaining match flag is RESM_SOURCE, used to dynamically + * set restrictions for each peer based on the prototype set by + * "restrict source" in the configuration. We want those entries + * to be considered only when there is not a static host + * restriction for the address in the configuration, to allow + * operators to blacklist pool and manycast servers at runtime as + * desired using ntpq runtime configuration. Such static entries + * have no RESM_ bits set, so the sort order for mflags is first + * RESM_INTERFACE, then entries without RESM_SOURCE, finally the + * remaining. */ restrict_def4.ippeerlimit = -1; /* Cleaner if we have C99 */ @@ -236,14 +226,14 @@ alloc_res4(void) { const size_t cb = V4_SIZEOF_RESTRICT_U; const size_t count = INC_RESLIST4; - restrict_u * rl; - restrict_u * res; + restrict_u* rl; + restrict_u* res; size_t i; UNLINK_HEAD_SLIST(res, resfree4, link); - if (res != NULL) + if (res != NULL) { return res; - + } rl = eallocarray(count, cb); /* link all but the first onto free list */ res = (void *)((char *)rl + (count - 1) * cb); @@ -251,7 +241,7 @@ alloc_res4(void) LINK_SLIST(resfree4, res, link); res = (void *)((char *)res - cb); } - INSIST(rl == res); + DEBUG_INSIST(rl == res); /* allocate the first */ return res; } @@ -267,9 +257,9 @@ alloc_res6(void) size_t i; UNLINK_HEAD_SLIST(res, resfree6, link); - if (res != NULL) + if (res != NULL) { return res; - + } rl = eallocarray(count, cb); /* link all but the first onto free list */ res = (void *)((char *)rl + (count - 1) * cb); @@ -277,7 +267,7 @@ alloc_res6(void) LINK_SLIST(resfree6, res, link); res = (void *)((char *)res - cb); } - INSIST(rl == res); + DEBUG_INSIST(rl == res); /* allocate the first */ return res; } @@ -289,46 +279,48 @@ free_res( int v6 ) { - restrict_u ** plisthead; + restrict_u ** rlisthead_ptr; + restrict_u ** flisthead_ptr; restrict_u * unlinked; + size_t sz; restrictcount--; - if (RES_LIMITED & res->rflags) + if (RES_LIMITED & res->rflags) { dec_res_limited(); - - if (v6) - plisthead = &restrictlist6; - else - plisthead = &restrictlist4; - UNLINK_SLIST(unlinked, *plisthead, res, link, restrict_u); - INSIST(unlinked == res); - + } if (v6) { - zero_mem(res, V6_SIZEOF_RESTRICT_U); - plisthead = &resfree6; + rlisthead_ptr = &restrictlist6; + flisthead_ptr = &resfree6; + sz = V6_SIZEOF_RESTRICT_U; } else { - zero_mem(res, V4_SIZEOF_RESTRICT_U); - plisthead = &resfree4; + rlisthead_ptr = &restrictlist4; + flisthead_ptr = &resfree4; + sz = V4_SIZEOF_RESTRICT_U; } - LINK_SLIST(*plisthead, res, link); + UNLINK_SLIST(unlinked, *rlisthead_ptr, res, link, restrict_u); + INSIST(unlinked == res); + zero_mem(res, sz); + LINK_SLIST(*flisthead_ptr, res, link); } -static void +static inline void inc_res_limited(void) { - if (!res_limited_refcnt) + if (0 == res_limited_refcnt) { mon_start(MON_RES); + } res_limited_refcnt++; } -static void +static inline void dec_res_limited(void) { res_limited_refcnt--; - if (!res_limited_refcnt) + if (0 == res_limited_refcnt) { mon_stop(MON_RES); + } } @@ -338,26 +330,21 @@ match_restrict4_addr( u_short port ) { - const int v6 = 0; + const int v6 = FALSE; restrict_u * res; restrict_u * next; for (res = restrictlist4; res != NULL; res = next) { - struct in_addr sia = { htonl(res->u.v4.addr) }; - next = res->link; - DPRINTF(2, ("match_restrict4_addr: Checking %s, port %d ... ", - inet_ntoa(sia), port)); - if ( res->expire - && res->expire <= current_time) + if (res->expire && res->expire <= current_time) { free_res(res, v6); /* zeroes the contents */ + } if ( res->u.v4.addr == (addr & res->u.v4.mask) && ( !(RESM_NTPONLY & res->mflags) || NTP_PORT == port)) { - DPRINTF(2, ("MATCH: ippeerlimit %d\n", res->ippeerlimit)); + break; } - DPRINTF(2, ("doesn't match: ippeerlimit %d\n", res->ippeerlimit)); } return res; } @@ -369,22 +356,23 @@ match_restrict6_addr( u_short port ) { - const int v6 = 1; + const int v6 = TRUE; restrict_u * res; restrict_u * next; struct in6_addr masked; for (res = restrictlist6; res != NULL; res = next) { next = res->link; - INSIST(next != res); - if (res->expire && - res->expire <= current_time) + if (res->expire && res->expire <= current_time) { free_res(res, v6); + } MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask); if (ADDR6_EQ(&masked, &res->u.v6.addr) - && (!(RESM_NTPONLY & res->mflags) - || NTP_PORT == (int)port)) + && ( !(RESM_NTPONLY & res->mflags) + || NTP_PORT == (int)port)) { + break; + } } return res; } @@ -417,22 +405,47 @@ match_restrict_entry( cb = sizeof(pmatch->u.v4); } - for (res = rlist; res != NULL; res = res->link) + for (res = rlist; res != NULL; res = res->link) { if (res->mflags == pmatch->mflags && - !memcmp(&res->u, &pmatch->u, cb)) + !memcmp(&res->u, &pmatch->u, cb)) { break; + } + } return res; } /* - * res_sorts_before4 - compare two restrict4 entries + * mflags_sorts_before - common mflags sorting code + * + * See block comment in init_restrict() above for rationale. + */ +static inline int/*BOOL*/ +mflags_sorts_before( + u_short m1, + u_short m2 + ) +{ + if ( (RESM_INTERFACE & m1) + && !(RESM_INTERFACE & m2)) { + return TRUE; + } else if ( !(RESM_SOURCE & m1) + && (RESM_SOURCE & m2)) { + return TRUE; + } else { + return FALSE; + } +} + + +/* + * res_sorts_before4 - compare IPv4 restriction entries * * Returns nonzero if r1 sorts before r2. We sort by descending - * address, then descending mask, then descending mflags, so sorting - * before means having a higher value. + * address, then descending mask, then an intricate mflags sort + * order explained in a block comment near the top of this file. */ -static int +static int/*BOOL*/ res_sorts_before4( restrict_u *r1, restrict_u *r2 @@ -440,54 +453,53 @@ res_sorts_before4( { int r1_before_r2; - if (r1->u.v4.addr > r2->u.v4.addr) - r1_before_r2 = 1; - else if (r1->u.v4.addr < r2->u.v4.addr) - r1_before_r2 = 0; - else if (r1->u.v4.mask > r2->u.v4.mask) - r1_before_r2 = 1; - else if (r1->u.v4.mask < r2->u.v4.mask) - r1_before_r2 = 0; - else if (r1->mflags > r2->mflags) - r1_before_r2 = 1; - else - r1_before_r2 = 0; + if (r1->u.v4.addr > r2->u.v4.addr) { + r1_before_r2 = TRUE; + } else if (r1->u.v4.addr < r2->u.v4.addr) { + r1_before_r2 = FALSE; + } else if (r1->u.v4.mask > r2->u.v4.mask) { + r1_before_r2 = TRUE; + } else if (r1->u.v4.mask < r2->u.v4.mask) { + r1_before_r2 = FALSE; + } else { + r1_before_r2 = mflags_sorts_before(r1->mflags, r2->mflags); + } return r1_before_r2; } /* - * res_sorts_before6 - compare two restrict6 entries + * res_sorts_before6 - compare IPv6 restriction entries * * Returns nonzero if r1 sorts before r2. We sort by descending - * address, then descending mask, then descending mflags, so sorting - * before means having a higher value. + * address, then descending mask, then an intricate mflags sort + * order explained in a block comment near the top of this file. */ -static int +static int/*BOOL*/ res_sorts_before6( - restrict_u *r1, - restrict_u *r2 - ) + restrict_u* r1, + restrict_u* r2 +) { int r1_before_r2; int cmp; cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr); - if (cmp > 0) /* r1->addr > r2->addr */ - r1_before_r2 = 1; - else if (cmp < 0) /* r2->addr > r1->addr */ - r1_before_r2 = 0; - else { + if (cmp > 0) { /* r1->addr > r2->addr */ + r1_before_r2 = TRUE; + } else if (cmp < 0) { /* r2->addr > r1->addr */ + r1_before_r2 = FALSE; + } else { cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask); - if (cmp > 0) /* r1->mask > r2->mask*/ - r1_before_r2 = 1; - else if (cmp < 0) /* r2->mask > r1->mask */ - r1_before_r2 = 0; - else if (r1->mflags > r2->mflags) - r1_before_r2 = 1; - else - r1_before_r2 = 0; + if (cmp > 0) { /* r1->mask > r2->mask*/ + r1_before_r2 = TRUE; + } else if (cmp < 0) { /* r2->mask > r1->mask */ + r1_before_r2 = FALSE; + } else { + r1_before_r2 = mflags_sorts_before(r1->mflags, + r2->mflags); + } } return r1_before_r2; @@ -506,15 +518,10 @@ restrictions( restrict_u *match; struct in6_addr *pin6; - REQUIRE(NULL != r4a); + DEBUG_REQUIRE(NULL != r4a); res_calls++; - r4a->rflags = RES_IGNORE; - r4a->ippeerlimit = 0; - DPRINTF(1, ("restrictions: looking up %s\n", stoa(srcadr))); - - /* IPv4 source address */ if (IS_IPV4(srcadr)) { /* * Ignore any packets with a multicast source address @@ -522,16 +529,12 @@ restrictions( * not later!) */ if (IN_CLASSD(SRCADR(srcadr))) { - DPRINTF(1, ("restrictions: srcadr %s is multicast\n", stoa(srcadr))); - r4a->ippeerlimit = 2; /* XXX: we should use a better value */ - return; + goto multicast; } match = match_restrict4_addr(SRCADR(srcadr), SRCPORT(srcadr)); - - INSIST(match != NULL); - + DEBUG_INSIST(match != NULL); match->count++; /* * res_not_found counts only use of the final default @@ -544,10 +547,9 @@ restrictions( res_found++; r4a->rflags = match->rflags; r4a->ippeerlimit = match->ippeerlimit; - } + } else { + DEBUG_REQUIRE(IS_IPV6(srcadr)); - /* IPv6 source address */ - if (IS_IPV6(srcadr)) { pin6 = PSOCK_ADDR6(srcadr); /* @@ -555,11 +557,11 @@ restrictions( * (this should be done early in the receive process, * not later!) */ - if (IN6_IS_ADDR_MULTICAST(pin6)) - return; - + if (IN6_IS_ADDR_MULTICAST(pin6)) { + goto multicast; + } match = match_restrict6_addr(pin6, SRCPORT(srcadr)); - INSIST(match != NULL); + DEBUG_INSIST(match != NULL); match->count++; if (&restrict_def6 == match) res_not_found++; @@ -570,32 +572,34 @@ restrictions( } return; -} + multicast: + r4a->rflags = RES_IGNORE; + r4a->ippeerlimit = 0; +} -/* - * roptoa - convert a restrict_op to a string - */ -char * -roptoa(restrict_op op) { - static char sb[30]; - switch(op) { +#ifdef DEBUG +/* display string for restrict_op */ +const char * +resop_str(restrict_op op) +{ + switch (op) { case RESTRICT_FLAGS: return "RESTRICT_FLAGS"; - case RESTRICT_UNFLAG: return "RESTRICT_UNFLAGS"; + case RESTRICT_UNFLAG: return "RESTRICT_UNFLAG"; case RESTRICT_REMOVE: return "RESTRICT_REMOVE"; case RESTRICT_REMOVEIF: return "RESTRICT_REMOVEIF"; - default: - snprintf(sb, sizeof sb, "**RESTRICT_#%d**", op); - return sb; } + DEBUG_INVARIANT(!"bad restrict_op in resop_str"); + return ""; /* silence not all paths return value warning */ } +#endif /* DEBUG */ /* * hack_restrict - add/subtract/manipulate entries on the restrict list */ -void +int/*BOOL*/ hack_restrict( restrict_op op, sockaddr_u * resaddr, @@ -603,38 +607,51 @@ hack_restrict( short ippeerlimit, u_short mflags, u_short rflags, - u_long expire + u_int32 expire ) { int v6; + int bump_res_limited = FALSE; restrict_u match; restrict_u * res; restrict_u ** plisthead; - - DPRINTF(1, ("hack_restrict: op %s addr %s mask %s ippeerlimit %d mflags %08x rflags %08x\n", - roptoa(op), stoa(resaddr), stoa(resmask), ippeerlimit, mflags, rflags)); + res_sort_fn pfn_sort; + +#ifdef DEBUG + if (debug > 0) { + printf("hack_restrict: op %s addr %s mask %s", + resop_str(op), stoa(resaddr), stoa(resmask)); + if (ippeerlimit >= 0) { + printf(" ippeerlimit %d", ippeerlimit); + } + printf(" mflags %s rflags %s", mflags_str(mflags), + rflags_str(rflags)); + if (expire) { + printf("lifetime %u\n", + expire - (u_int32)current_time); + } else { + printf("\n"); + } + } +#endif if (NULL == resaddr) { - REQUIRE(NULL == resmask); - REQUIRE(RESTRICT_FLAGS == op); + DEBUG_REQUIRE(NULL == resmask); + DEBUG_REQUIRE(RESTRICT_FLAGS == op); + DEBUG_REQUIRE(RESM_SOURCE & mflags); restrict_source_rflags = rflags; restrict_source_mflags = mflags; restrict_source_ippeerlimit = ippeerlimit; - restrict_source_enabled = 1; - return; + restrict_source_enabled = TRUE; + DPRINTF(1, ("restrict source template saved\n")); + return TRUE; } ZERO(match); -#if 0 - /* silence VC9 potentially uninit warnings */ - // HMS: let's use a compiler-specific "enable" for this. - res = NULL; - v6 = 0; -#endif - if (IS_IPV4(resaddr)) { - v6 = 0; + DEBUG_INVARIANT(IS_IPV4(resmask)); + v6 = FALSE; /* * Get address and mask in host byte order for easy * comparison as u_int32 @@ -642,9 +659,10 @@ hack_restrict( match.u.v4.addr = SRCADR(resaddr); match.u.v4.mask = SRCADR(resmask); match.u.v4.addr &= match.u.v4.mask; - - } else if (IS_IPV6(resaddr)) { - v6 = 1; + } else { + DEBUG_INVARIANT(IS_IPV6(resaddr)); + DEBUG_INVARIANT(IS_IPV6(resmask)); + v6 = TRUE; /* * Get address and mask in network byte order for easy * comparison as byte sequences (e.g. memcmp()) @@ -652,88 +670,95 @@ hack_restrict( match.u.v6.mask = SOCK_ADDR6(resmask); MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr), &match.u.v6.mask); + } - } else /* not IPv4 nor IPv6 */ - REQUIRE(0); - - match.rflags = rflags; match.mflags = mflags; - match.ippeerlimit = ippeerlimit; - match.expire = expire; res = match_restrict_entry(&match, v6); switch (op) { case RESTRICT_FLAGS: /* - * Here we add bits to the rflags. If this is a - * new restriction add it. + * Here we add bits to the rflags. If we already have + * this restriction modify it. */ - if (NULL == res) { + if (NULL != res) { + if ( (RES_LIMITED & rflags) + && !(RES_LIMITED & res->rflags)) { + + bump_res_limited = TRUE; + } + res->rflags |= rflags; + res->expire = expire; + } else { + match.rflags = rflags; + match.expire = expire; + match.ippeerlimit = ippeerlimit; if (v6) { res = alloc_res6(); - memcpy(res, &match, - V6_SIZEOF_RESTRICT_U); + memcpy(res, &match, V6_SIZEOF_RESTRICT_U); plisthead = &restrictlist6; + pfn_sort = &res_sorts_before6; } else { res = alloc_res4(); - memcpy(res, &match, - V4_SIZEOF_RESTRICT_U); + memcpy(res, &match, V4_SIZEOF_RESTRICT_U); plisthead = &restrictlist4; + pfn_sort = &res_sorts_before4; } LINK_SORT_SLIST( *plisthead, res, - (v6) - ? res_sorts_before6(res, L_S_S_CUR()) - : res_sorts_before4(res, L_S_S_CUR()), + (*pfn_sort)(res, L_S_S_CUR()), link, restrict_u); restrictcount++; - if (RES_LIMITED & rflags) - inc_res_limited(); - } else { - if ( (RES_LIMITED & rflags) - && !(RES_LIMITED & res->rflags)) - inc_res_limited(); - res->rflags |= rflags; + if (RES_LIMITED & rflags) { + bump_res_limited = TRUE; + } } - - res->ippeerlimit = match.ippeerlimit; - - break; + if (bump_res_limited) { + inc_res_limited(); + } + return TRUE; case RESTRICT_UNFLAG: /* * Remove some bits from the rflags. If we didn't * find this one, just return. */ - if (res != NULL) { - if ( (RES_LIMITED & res->rflags) - && (RES_LIMITED & rflags)) - dec_res_limited(); - res->rflags &= ~rflags; + if (NULL == res) { + DPRINTF(1, ("No match for %s %s removing rflags %s\n", + stoa(resaddr), stoa(resmask), + rflags_str(rflags))); + return FALSE; } - break; + if ( (RES_LIMITED & res->rflags) + && (RES_LIMITED & rflags)) { + dec_res_limited(); + } + res->rflags &= ~rflags; + return TRUE; case RESTRICT_REMOVE: case RESTRICT_REMOVEIF: /* * Remove an entry from the table entirely if we * found one. Don't remove the default entry and - * don't remove an interface entry. + * don't remove an interface entry unless asked. */ - if (res != NULL - && (RESTRICT_REMOVEIF == op + if ( res != NULL + && ( RESTRICT_REMOVEIF == op || !(RESM_INTERFACE & res->mflags)) && res != &restrict_def4 - && res != &restrict_def6) - free_res(res, v6); - break; + && res != &restrict_def6) { - default: /* unknown op */ - INSIST(0); - break; + free_res(res, v6); + return TRUE; + } + DPRINTF(1, ("No match removing %s %s restriction\n", + stoa(resaddr), stoa(resmask))); + return FALSE; } - + /* notreached */ + return FALSE; } @@ -744,58 +769,182 @@ hack_restrict( void restrict_source( sockaddr_u * addr, - int farewell, /* 0 to add, 1 to remove */ - u_long expire /* 0 is infinite, valid until */ + int farewell, /* TRUE to remove */ + u_int32 lifetime /* seconds, 0 forever */ ) { sockaddr_u onesmask; - restrict_u * res; - int found_specific; + int/*BOOL*/ success; - if (!restrict_source_enabled || SOCK_UNSPEC(addr) || - IS_MCAST(addr) || ISREFCLOCKADR(addr)) + if ( !restrict_source_enabled || SOCK_UNSPEC(addr) + || IS_MCAST(addr) || ISREFCLOCKADR(addr)) { return; + } REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr)); SET_HOSTMASK(&onesmask, AF(addr)); if (farewell) { - hack_restrict(RESTRICT_REMOVE, addr, &onesmask, - -2, 0, 0, 0); - DPRINTF(1, ("restrict_source: %s removed", stoa(addr))); + success = hack_restrict(RESTRICT_REMOVE, addr, &onesmask, + 0, RESM_SOURCE, 0, 0); + if (success) { + DPRINTF(1, ("%s %s removed", __func__, + stoa(addr))); + } else { + msyslog(LOG_ERR, "%s remove %s failed", + __func__, stoa(addr)); + } return; } - /* - * If there is a specific entry for this address, hands - * off, as it is condidered more specific than "restrict - * server ...". - * However, if the specific entry found is a fleeting one - * added by pool_xmit() before soliciting, replace it - * immediately regardless of the expire value to make way - * for the more persistent entry. - */ - if (IS_IPV4(addr)) { - res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr)); - INSIST(res != NULL); - found_specific = (SRCADR(&onesmask) == res->u.v4.mask); + success = hack_restrict(RESTRICT_FLAGS, addr, &onesmask, + restrict_source_ippeerlimit, + restrict_source_mflags, + restrict_source_rflags, + lifetime > 0 + ? lifetime + current_time + : 0); + if (success) { + DPRINTF(1, ("%s %s add/upd\n", __func__, + stoa(addr))); } else { - res = match_restrict6_addr(&SOCK_ADDR6(addr), - SRCPORT(addr)); - INSIST(res != NULL); - found_specific = ADDR6_EQ(&res->u.v6.mask, - &SOCK_ADDR6(&onesmask)); + msyslog(LOG_ERR, "%s %s failed", __func__, stoa(addr)); } - if (!expire && found_specific && res->expire) { - found_specific = 0; - free_res(res, IS_IPV6(addr)); +} + + +#ifdef DEBUG +/* Convert restriction RES_ flag bits into a display string */ +const char * +rflags_str( + u_short rflags + ) +{ + const size_t sz = LIB_BUFLENGTH; + char * rfs; + + LIB_GETBUF(rfs); + rfs[0] = '\0'; + + if (rflags & RES_FLAKE) { + CLEAR_BIT_IF_DEBUG(RES_FLAKE, rflags); + append_flagstr(rfs, sz, "flake"); } - if (found_specific) - return; - hack_restrict(RESTRICT_FLAGS, addr, &onesmask, - restrict_source_ippeerlimit, - restrict_source_mflags, restrict_source_rflags, expire); - DPRINTF(1, ("restrict_source: %s host restriction added\n", - stoa(addr))); + if (rflags & RES_IGNORE) { + CLEAR_BIT_IF_DEBUG(RES_IGNORE, rflags); + append_flagstr(rfs, sz, "ignore"); + } + + if (rflags & RES_KOD) { + CLEAR_BIT_IF_DEBUG(RES_KOD, rflags); + append_flagstr(rfs, sz, "kod"); + } + + if (rflags & RES_MSSNTP) { + CLEAR_BIT_IF_DEBUG(RES_MSSNTP, rflags); + append_flagstr(rfs, sz, "mssntp"); + } + + if (rflags & RES_LIMITED) { + CLEAR_BIT_IF_DEBUG(RES_LIMITED, rflags); + append_flagstr(rfs, sz, "limited"); + } + + if (rflags & RES_LPTRAP) { + CLEAR_BIT_IF_DEBUG(RES_LPTRAP, rflags); + append_flagstr(rfs, sz, "lptrap"); + } + + if (rflags & RES_NOMODIFY) { + CLEAR_BIT_IF_DEBUG(RES_NOMODIFY, rflags); + append_flagstr(rfs, sz, "nomodify"); + } + + if (rflags & RES_NOMRULIST) { + CLEAR_BIT_IF_DEBUG(RES_NOMRULIST, rflags); + append_flagstr(rfs, sz, "nomrulist"); + } + + if (rflags & RES_NOEPEER) { + CLEAR_BIT_IF_DEBUG(RES_NOEPEER, rflags); + append_flagstr(rfs, sz, "noepeer"); + } + + if (rflags & RES_NOPEER) { + CLEAR_BIT_IF_DEBUG(RES_NOPEER, rflags); + append_flagstr(rfs, sz, "nopeer"); + } + + if (rflags & RES_NOQUERY) { + CLEAR_BIT_IF_DEBUG(RES_NOQUERY, rflags); + append_flagstr(rfs, sz, "noquery"); + } + + if (rflags & RES_DONTSERVE) { + CLEAR_BIT_IF_DEBUG(RES_DONTSERVE, rflags); + append_flagstr(rfs, sz, "dontserve"); + } + + if (rflags & RES_NOTRAP) { + CLEAR_BIT_IF_DEBUG(RES_NOTRAP, rflags); + append_flagstr(rfs, sz, "notrap"); + } + + if (rflags & RES_DONTTRUST) { + CLEAR_BIT_IF_DEBUG(RES_DONTTRUST, rflags); + append_flagstr(rfs, sz, "notrust"); + } + + if (rflags & RES_SRVRSPFUZ) { + CLEAR_BIT_IF_DEBUG(RES_SRVRSPFUZ, rflags); + append_flagstr(rfs, sz, "srvrspfuz"); + } + + if (rflags & RES_VERSION) { + CLEAR_BIT_IF_DEBUG(RES_VERSION, rflags); + append_flagstr(rfs, sz, "version"); + } + + DEBUG_INVARIANT(!rflags); + + if ('\0' == rfs[0]) { + append_flagstr(rfs, sz, "(none)"); + } + + return rfs; +} + + +/* Convert restriction match RESM_ flag bits into a display string */ +const char * +mflags_str( + u_short mflags + ) +{ + const size_t sz = LIB_BUFLENGTH; + char * mfs; + + LIB_GETBUF(mfs); + mfs[0] = '\0'; + + if (mflags & RESM_NTPONLY) { + CLEAR_BIT_IF_DEBUG(RESM_NTPONLY, mflags); + append_flagstr(mfs, sz, "ntponly"); + } + + if (mflags & RESM_SOURCE) { + CLEAR_BIT_IF_DEBUG(RESM_SOURCE, mflags); + append_flagstr(mfs, sz, "source"); + } + + if (mflags & RESM_INTERFACE) { + CLEAR_BIT_IF_DEBUG(RESM_INTERFACE, mflags); + append_flagstr(mfs, sz, "interface"); + } + + DEBUG_INVARIANT(!mflags); + + return mfs; } +#endif /* DEBUG */ |