aboutsummaryrefslogtreecommitdiff
path: root/ntpd/ntp_restrict.c
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2024-05-10 15:15:56 +0000
committerCy Schubert <cy@FreeBSD.org>2024-05-26 22:55:52 +0000
commit1f833b3fc9968c3dd7ed79ccf0525ebf16c891ad (patch)
tree85801af20e3b694584668aeb39ecec75ee71f72c /ntpd/ntp_restrict.c
parentab1f1aa8333369a83ff284848fc3fc2e52d5f29f (diff)
Diffstat (limited to 'ntpd/ntp_restrict.c')
-rw-r--r--ntpd/ntp_restrict.c725
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 */