---
+
+* [Bug 1503] Auto-enabling of monitor for "restrict ... limited" wrong.
+* [Bug 1504] ntpdate tickles ntpd "discard minimum 1" rate limit if
+ "restrict ... limited" is used.
+
+---
(4.2.6p1) 2010/04/09 Released by Harlan Stenn <stenn@ntp.org>
(4.2.6p1-RC6) 2010/03/31 Released by Harlan Stenn <stenn@ntp.org>
#ifndef NTP_H
#define NTP_H
+#include <stddef.h>
#include <math.h>
#include <ntp_fp.h>
/*
* Structure used for restrictlist entries
*/
-struct restrictlist {
- struct restrictlist *next; /* link to next entry */
- u_int32 addr; /* Ipv4 host address (host byte order) */
- u_int32 mask; /* Ipv4 mask for address (host byte order) */
- u_long count; /* number of packets matched */
- u_short flags; /* accesslist flags */
- u_short mflags; /* match flags */
-};
-
-struct restrictlist6 {
- struct restrictlist6 *next; /* link to next entry */
- struct in6_addr addr6; /* Ipv6 host address */
- struct in6_addr mask6; /* Ipv6 mask address */
- u_long count; /* number of packets matched */
- u_short flags; /* accesslist flags */
- u_short mflags; /* match flags */
+typedef struct res_addr4_tag {
+ u_int32 addr; /* IPv4 addr (host order) */
+ u_int32 mask; /* IPv4 mask (host order) */
+} res_addr4;
+
+typedef struct res_addr6_tag {
+ struct in6_addr addr; /* IPv6 addr (net order) */
+ struct in6_addr mask; /* IPv6 mask (net order) */
+} res_addr6;
+
+typedef struct restrict_u_tag restrict_u;
+struct restrict_u_tag {
+ restrict_u * link; /* link to next entry */
+ u_int32 count; /* number of packets matched */
+ u_short flags; /* accesslist flags */
+ u_short mflags; /* match flags */
+ union { /* variant starting here */
+ res_addr4 v4;
+ res_addr6 v6;
+ } u;
};
+#define V4_SIZEOF_RESTRICT_U (offsetof(restrict_u, u) \
+ + sizeof(res_addr4))
+#define V6_SIZEOF_RESTRICT_U (offsetof(restrict_u, u) \
+ + sizeof(res_addr6))
/*
/*
- * ntp_lists.h - singly-linked lists common code
+ * ntp_lists.h - linked lists common code
+ *
+ * SLIST: singly-linked lists
+ * ==========================
*
* These macros implement a simple singly-linked list template. Both
* the listhead and per-entry next fields are declared as pointers to
* LINK_TAIL_SLIST(listhead, pentry, nextlink, entrytype)
* add entry at tail
*
+ * LINK_SORT_SLIST(listhead, pentry, beforecur, nextlink, entrytype)
+ * add entry in sorted order. beforecur is an expression comparing
+ * pentry with the current list entry. The current entry can be
+ * referenced within beforecur as L_S_S_CUR(), which is short for
+ * LINK_SORT_SLIST_CUR(). beforecur is nonzero if pentry sorts
+ * before L_S_S_CUR().
+ *
* UNLINK_HEAD_SLIST(punlinked, listhead, nextlink)
* unlink first entry and point punlinked to it, or set punlinked
* to NULL if the list is empty.
*
* UNLINK_EXPR_SLIST(punlinked, listhead, expr, nextlink, entrytype)
* unlink entry where expression expr is nonzero. expr can refer
- * to the entry being tested using UNLINK_EXPR_SLIST_CURRENT().
- * See the implementation of UNLINK_SLIST() below for an example.
+ * to the entry being tested using UNLINK_EXPR_SLIST_CURRENT(),
+ * alias U_E_S_CUR(). See the implementation of UNLINK_SLIST()
+ * below for an example.
* punlinked is pointed to the removed entry or NULL if none
* satisfy expr.
+ *
+ * DLIST: doubly-linked lists
+ * ==========================
+ *
+ * Elements on DLISTs always have non-NULL forward and back links,
+ * because both link chains are circular. The beginning/end is marked
+ * by the listhead, which is the same type as elements for simplicity.
+ * An empty list's listhead has both links set to its own address.
+ *
+ *
*/
#ifndef NTP_LISTS_H
#define NTP_LISTS_H
-#ifdef HAVE_CONFIG_H
-# include <config.h>
+#ifndef TRUE
+# define TRUE 1
+# define NTP_LISTS_UNDEF_TRUE
#endif
-#include <isc/list.h>
-
-
#define LINK_SLIST(listhead, pentry, nextlink) \
do { \
(pentry)->nextlink = (listhead); \
*pptail = (pentry); \
} while (0)
+#define LINK_SORT_SLIST_CURRENT() (*ppentry)
+#define L_S_S_CUR() LINK_SORT_SLIST_CURRENT()
+
+#define LINK_SORT_SLIST(listhead, pentry, beforecur, nextlink, \
+ entrytype) \
+do { \
+ entrytype **ppentry; \
+ \
+ ppentry = &(listhead); \
+ while (*ppentry != NULL) { \
+ if (beforecur) { \
+ (pentry)->nextlink = *ppentry; \
+ *ppentry = (pentry); \
+ break; \
+ } \
+ ppentry = &((*ppentry)->nextlink); \
+ if (NULL == *ppentry) { \
+ (pentry)->nextlink = NULL; \
+ *ppentry = (pentry); \
+ break; \
+ } \
+ } \
+} while (0)
+
#define UNLINK_HEAD_SLIST(punlinked, listhead, nextlink) \
do { \
(punlinked) = (listhead); \
} \
} while (0)
+#define UNLINK_EXPR_SLIST_CURRENT() (*ppentry)
+#define U_E_S_CUR() UNLINK_EXPR_SLIST_CURRENT()
+
#define UNLINK_EXPR_SLIST(punlinked, listhead, expr, nextlink, \
entrytype) \
do { \
} else \
(punlinked) = NULL; \
} while (0)
-#define UNLINK_EXPR_SLIST_CURRENT() (*ppentry)
#define UNLINK_SLIST(punlinked, listhead, ptounlink, nextlink, \
entrytype) \
UNLINK_EXPR_SLIST(punlinked, listhead, (ptounlink) == \
- UNLINK_EXPR_SLIST_CURRENT(), nextlink, entrytype)
+ U_E_S_CUR(), nextlink, entrytype)
+
+#define CHECK_SLIST(listhead, nextlink, entrytype) \
+do { \
+ entrytype *pentry; \
+ \
+ for (pentry = (listhead); \
+ pentry != NULL; \
+ pentry = pentry->nextlink){ \
+ NTP_INSIST(pentry != pentry->nextlink); \
+ NTP_INSIST((listhead) != pentry->nextlink); \
+ } \
+} while (0)
+
+/*
+ * DLIST
+ */
+#define DECL_DLIST_LINK(entrytype, link) \
+struct { \
+ entrytype * b; \
+ entrytype * f; \
+} link
+
+#define INIT_DLIST(listhead, link) \
+do { \
+ (listhead).link.f = &(listhead); \
+ (listhead).link.b = &(listhead); \
+} while (0)
+
+#define HEAD_DLIST(listhead, link) \
+ ( \
+ (&(listhead) != (listhead).link.f) \
+ ? (listhead).link.f \
+ : NULL \
+ )
+
+#define TAIL_DLIST(listhead, link) \
+ ( \
+ (&(listhead) != (listhead).link.b) \
+ ? (listhead).link.b \
+ : NULL \
+ )
+
+#define NEXT_DLIST(listhead, entry, link) \
+ ( \
+ (&(listhead) != (entry)->link.f) \
+ ? (entry)->link.f \
+ : NULL \
+ )
+
+#define PREV_DLIST(listhead, entry, link) \
+ ( \
+ (&(listhead) != (entry)->link.b) \
+ ? (entry)->link.b \
+ : NULL \
+ )
+
+#define LINK_DLIST(listhead, pentry, link) \
+do { \
+ (pentry)->link.f = (listhead).link.f; \
+ (pentry)->link.b = &(listhead); \
+ (listhead).link.f->link.b = (pentry); \
+ (listhead).link.f = (pentry); \
+} while (0)
+
+#define LINK_TAIL_DLIST(listhead, pentry, link) \
+do { \
+ (pentry)->link.b = (listhead).link.b; \
+ (pentry)->link.f = &(listhead); \
+ (listhead).link.b->link.f = (pentry); \
+ (listhead).link.b = (pentry); \
+} while (0)
+
+#define UNLINK_DLIST(ptounlink, link) \
+do { \
+ (ptounlink)->link.b->link.f = (ptounlink)->link.f; \
+ (ptounlink)->link.f->link.b = (ptounlink)->link.b; \
+ (ptounlink)->link.b = NULL; \
+ (ptounlink)->link.f = NULL; \
+} while (0)
+
+#define ITER_DLIST_BEGIN(listhead, iter, link, entrytype) \
+{ \
+ entrytype *i_dl_nextiter; \
+ \
+ for ((iter) = (listhead).link.f; \
+ (iter) != &(listhead) \
+ && ((i_dl_nextiter = (iter)->link.f), TRUE); \
+ (iter) = i_dl_nextiter) {
+#define ITER_DLIST_END() \
+ } \
+}
+
+#define REV_ITER_DLIST_BEGIN(listhead, iter, link, entrytype) \
+{ \
+ entrytype *i_dl_nextiter; \
+ \
+ for ((iter) = (listhead).link.b; \
+ (iter) != &(listhead) \
+ && ((i_dl_nextiter = (iter)->link.b), TRUE); \
+ (iter) = i_dl_nextiter) {
+#define REV_ITER_DLIST_END() \
+ } \
+}
+
+
+#ifdef NTP_LISTS_UNDEF_TRUE
+# undef TRUE
+#endif
#endif /* NTP_LISTS_H */
typedef union {
struct sockaddr sa;
- struct sockaddr_storage sas;
struct sockaddr_in sa4;
struct sockaddr_in6 sa6;
} sockaddr_u;
#define PSOCK_ADDR4(psau) (&SOCK_ADDR4(psau))
#define PSOCK_ADDR6(psau) (&SOCK_ADDR6(psau))
-#define AF(psau) ((psau)->sas.ss_family)
+#define AF(psau) ((psau)->sa.sa_family)
#define IS_IPV4(psau) (AF_INET == AF(psau))
#define IS_IPV6(psau) (AF_INET6 == AF(psau))
? IN_CLASSD(SRCADR(psau)) \
: IN6_IS_ADDR_MULTICAST(PSOCK_ADDR6(psau)))
+#define SIZEOF_INADDR(fam) \
+ ((AF_INET == (fam)) \
+ ? sizeof(struct in_addr) \
+ : sizeof(struct in6_addr))
+
#define SIZEOF_SOCKADDR(fam) \
((AF_INET == (fam)) \
? sizeof(struct sockaddr_in) \
: sizeof((psau)->sa6))
#define ZERO_SOCK(psau) \
- memset(&(psau)->sas, 0, sizeof((psau)->sas))
+ memset((psau), 0, sizeof(*(psau)))
/* blast a byte value across sockaddr_u v6 address */
#define MEMSET_ADDR6(psau, v) \
- memset((void *)(psau)->sa6.sin6_addr.s6_addr, (v), \
+ memset((psau)->sa6.sin6_addr.s6_addr, (v), \
sizeof((psau)->sa6.sin6_addr.s6_addr))
#define SET_ONESMASK(psau) \
SET_ONESMASK(psau); \
} while (0)
-/* compare a in6_addr with socket address */
+/*
+ * compare two in6_addr returning negative, 0, or positive.
+ * ADDR6_CMP is negative if *pin6A is lower than *pin6B, zero if they
+ * are equal, positive if *pin6A is higher than *pin6B. IN6ADDR_ANY
+ * is the lowest address (128 zero bits).
+ */
+#define ADDR6_CMP(pin6A, pin6B) \
+ memcmp((pin6A)->s6_addr, (pin6B)->s6_addr, \
+ sizeof(pin6A)->s6_addr)
+
+/* compare two in6_addr for equality only */
#if !defined(SYS_WINNT) || !defined(in_addr6)
-#define S_ADDR6_EQ(psau, my_in6_addr) \
- (!memcmp(&(psau)->sa6.sin6_addr, \
- (my_in6_addr), \
- sizeof((psau)->sa6.sin6_addr)))
+#define ADDR6_EQ(pin6A, pin6B) \
+ (!ADDR6_CMP(pin6A, pin6B))
#else
-#define S_ADDR6_EQ(psau, my_in6_addr) \
- IN6_ADDR_EQUAL(&(psau)->sa6.sin6_addr, \
- (my_in6_addr))
+#define ADDR6_EQ(pin6A, pin6B) \
+ IN6_ADDR_EQUAL(pin6A, pin6B)
#endif
-/* are two sockaddr_u's addresses equal? */
+/* compare a in6_addr with socket address */
+#define S_ADDR6_EQ(psau, pin6) \
+ ADDR6_EQ(&(psau)->sa6.sin6_addr, pin6)
+
+/* are two sockaddr_u's addresses equal? (port excluded) */
#define SOCK_EQ(psau1, psau2) \
((AF(psau1) != AF(psau2)) \
? 0 \
: (S_ADDR6_EQ((psau1), PSOCK_ADDR6(psau2)) \
&& SCOPE_EQ((psau1), (psau2))))
+/* are two sockaddr_u's addresses and ports equal? */
+#define ADDR_PORT_EQ(psau1, psau2) \
+ ((NSRCPORT(psau1) != NSRCPORT(psau2) \
+ ? 0 \
+ : SOCK_EQ((psau1), (psau2))))
+
/* is sockaddr_u address unspecified? */
#define SOCK_UNSPEC(psau) \
(IS_IPV4(psau) \
/* ntp_restrict.c */
extern void init_restrict (void);
-extern int restrictions (sockaddr_u *);
-extern void hack_restrict (int, sockaddr_u *, sockaddr_u *, int, int);
+extern u_short restrictions (sockaddr_u *);
+extern void hack_restrict (int, sockaddr_u *, sockaddr_u *, u_short, u_short);
/* ntp_timer.c */
extern void init_timer (void);
extern keyid_t info_auth_keyid; /* keyid used to authenticate requests */
/* ntp_restrict.c */
-extern struct restrictlist *restrictlist; /* the ipv4 restriction list */
-extern struct restrictlist6 *restrictlist6; /* the ipv6 restriction list */
+extern restrict_u * restrictlist4; /* IPv4 restriction list */
+extern restrict_u * restrictlist6; /* IPv6 restriction list */
extern int ntp_minpkt;
extern int ntp_minpoll;
extern int mon_age; /* monitor preempt age */
sockaddr_dump(sockaddr_u *psau)
{
/* Limit the size of the sockaddr_storage hex dump */
- const int maxsize = min(32, sizeof(psau->sas));
+ const int maxsize = min(32, sizeof(psau->sa6));
u_char * cp;
int i;
- cp = (u_char *)&psau->sas;
+ cp = (u_char *)&psau->sa;
for(i = 0; i < maxsize; i++)
{
* Preempt from the MRU list if old enough.
*/
md = mon_mru_list.mru_prev;
- if (md->count == 1 || ntp_random() / (2. * FRAC) >
- (double)(current_time - md->lasttime) / mon_age)
- return (flags & ~RES_LIMITED);
+ if (ntp_random() / (2. * FRAC) > (double)(current_time
+ - md->lasttime) / mon_age)
+ return (flags & ~(RES_LIMITED | RES_KOD));
md->mru_prev->mru_next = &mon_mru_list;
mon_mru_list.mru_prev = md->mru_prev;
*/
md->lasttime = md->firsttime = current_time;
md->count = 1;
- md->flags = flags & ~RES_LIMITED;
+ md->flags = flags & ~(RES_LIMITED | RES_KOD);
md->leak = 0;
memset(&md->rmtadr, 0, sizeof(md->rmtadr));
memcpy(&md->rmtadr, &addr, sizeof(addr));
NSRCADR(&addr) = ipl->addr;
}
#ifdef ISC_PLATFORM_HAVESALEN
- addr.sas.ss_len = SOCKLEN(&addr);
+ addr.sa.sa_len = SOCKLEN(&addr);
#endif
ipl++;
if ((pp = findexistingpeer(&addr, (struct peer *)0, -1)) == 0)
NSRCADR(&addr) = ipl->addr;
}
#ifdef ISC_PLATFORM_HAVESALEN
- addr.sas.ss_len = SOCKLEN(&addr);
+ addr.sa.sa_len = SOCKLEN(&addr);
#endif
DPRINTF(1, ("peer_stats: looking for %s, %d, %d\n",
stoa(&addr), ipl->port, NSRCPORT(&addr)));
}
NSRCPORT(&peeraddr) = htons(NTP_PORT);
#ifdef ISC_PLATFORM_HAVESALEN
- peeraddr.sas.ss_len = SOCKLEN(&peeraddr);
+ peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
#endif
/* XXX W2DO? minpoll/maxpoll arguments ??? */
}
SET_PORT(&peeraddr, NTP_PORT);
#ifdef ISC_PLATFORM_HAVESALEN
- peeraddr.sas.ss_len = SOCKLEN(&peeraddr);
+ peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
#endif
found = 0;
peer = NULL;
}
SET_PORT(&peeraddr, NTP_PORT);
#ifdef ISC_PLATFORM_HAVESALEN
- peeraddr.sas.ss_len = SOCKLEN(&peeraddr);
+ peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
#endif
found = 0;
peer = NULL;
loop_config(LOOP_DRIFTCOMP, drift_comp);
}
+/*
+ * list_restrict4 - recursive helper for list_restrict dumps IPv4
+ * restriction list in reverse order.
+ */
+static void
+list_restrict4(
+ restrict_u * res,
+ struct info_restrict ** ppir
+ )
+{
+ struct info_restrict * pir;
+
+ if (res->link != NULL)
+ list_restrict4(res->link, ppir);
+
+ pir = *ppir;
+ pir->addr = htonl(res->u.v4.addr);
+ if (client_v6_capable)
+ pir->v6_flag = 0;
+ pir->mask = htonl(res->u.v4.mask);
+ pir->count = htonl(res->count);
+ pir->flags = htons(res->flags);
+ pir->mflags = htons(res->mflags);
+ *ppir = (struct info_restrict *)more_pkt();
+}
+
+
+/*
+ * list_restrict6 - recursive helper for list_restrict dumps IPv6
+ * restriction list in reverse order.
+ */
+static void
+list_restrict6(
+ restrict_u * res,
+ struct info_restrict ** ppir
+ )
+{
+ struct info_restrict * pir;
+
+ if (res->link != NULL)
+ list_restrict6(res->link, ppir);
+
+ pir = *ppir;
+ pir->addr6 = res->u.v6.addr;
+ pir->mask6 = res->u.v6.mask;
+ pir->v6_flag = 1;
+ pir->count = htonl(res->count);
+ pir->flags = htons(res->flags);
+ pir->mflags = htons(res->mflags);
+ *ppir = (struct info_restrict *)more_pkt();
+}
+
/*
* list_restrict - return the restrict list
struct req_pkt *inpkt
)
{
- register struct info_restrict *ir;
- register struct restrictlist *rl;
- register struct restrictlist6 *rl6;
+ struct info_restrict *ir;
-#ifdef DEBUG
- if (debug > 2)
- printf("wants restrict list summary\n");
-#endif
+ DPRINTF(3, ("wants restrict list summary\n"));
ir = (struct info_restrict *)prepare_pkt(srcadr, inter, inpkt,
v6sizeof(struct info_restrict));
- for (rl = restrictlist; rl != 0 && ir != 0; rl = rl->next) {
- ir->addr = htonl(rl->addr);
- if (client_v6_capable)
- ir->v6_flag = 0;
- ir->mask = htonl(rl->mask);
- ir->count = htonl((u_int32)rl->count);
- ir->flags = htons(rl->flags);
- ir->mflags = htons(rl->mflags);
- ir = (struct info_restrict *)more_pkt();
- }
+ /*
+ * The restriction lists are kept sorted in the reverse order
+ * than they were originally. To preserve the output semantics,
+ * dump each list in reverse order. A recursive helper function
+ * achieves that.
+ */
+ list_restrict4(restrictlist4, &ir);
if (client_v6_capable)
- for (rl6 = restrictlist6; rl6 != 0 && ir != 0; rl6 = rl6->next) {
- ir->addr6 = rl6->addr6;
- ir->mask6 = rl6->mask6;
- ir->v6_flag = 1;
- ir->count = htonl((u_int32)rl6->count);
- ir->flags = htons(rl6->flags);
- ir->mflags = htons(rl6->mflags);
- ir = (struct info_restrict *)more_pkt();
- }
+ list_restrict6(restrictlist6, &ir);
flush_pkt();
}
-
/*
* do_resaddflags - add flags to a restrict entry (or create one)
*/
}
#ifdef ISC_PLATFORM_HAVESALEN
- peeraddr.sas.ss_len = SOCKLEN(&peeraddr);
+ peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
#endif
peer = findexistingpeer(&peeraddr, NULL, -1);
if (NULL == peer)
}
SET_PORT(&peeraddr, 123);
#ifdef ISC_PLATFORM_HAVESALEN
- peeraddr.sas.ss_len = SOCKLEN(&peeraddr);
+ peeraddr.sa.sa_len = SOCKLEN(&peeraddr);
#endif
peer = findexistingpeer(&peeraddr, NULL, -1);
while (peer != NULL) {
ZERO_SOCK(&addr);
AF(&addr) = AF_INET;
#ifdef ISC_PLATFORM_HAVESALEN
- addr.sas.ss_len = SOCKLEN(&addr);
+ addr.sa.sa_len = SOCKLEN(&addr);
#endif
SET_PORT(&addr, NTP_PORT);
items = INFO_NITEMS(inpkt->err_nitems);
AF(&addr) = AF_INET;
NSRCADR(&addr) = cf->clockadr;
#ifdef ISC_PLATFORM_HAVESALEN
- addr.sas.ss_len = SOCKLEN(&addr);
+ addr.sa.sa_len = SOCKLEN(&addr);
#endif
SET_PORT(&addr, NTP_PORT);
if (!ISREFCLOCKADR(&addr) ||
ZERO_SOCK(&addr);
AF(&addr) = AF_INET;
#ifdef ISC_PLATFORM_HAVESALEN
- addr.sas.ss_len = SOCKLEN(&addr);
+ addr.sa.sa_len = SOCKLEN(&addr);
#endif
SET_PORT(&addr, NTP_PORT);
items = INFO_NITEMS(inpkt->err_nitems);
#include "ntpd.h"
#include "ntp_if.h"
+#include "ntp_lists.h"
#include "ntp_stdlib.h"
+#include "ntp_assert.h"
/*
* This code keeps a simple address-and-mask list of hosts we want
* 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 SET_IPV6_ADDR_MASK(dst, src, msk) \
- do { \
- int idx; \
- for (idx = 0; idx < 16; idx++) { \
- (dst)->s6_addr[idx] = \
- (u_char) ((src)->s6_addr[idx] & (msk)->s6_addr[idx]); \
- } \
+#define MASK_IPV6_ADDR(dst, src, msk) \
+ do { \
+ int idx; \
+ for (idx = 0; idx < COUNTOF((dst)->s6_addr); idx++) { \
+ (dst)->s6_addr[idx] = (src)->s6_addr[idx] \
+ & (msk)->s6_addr[idx]; \
+ } \
} while (0)
/*
- * Memory allocation parameters. We allocate INITRESLIST entries
- * initially, and add INCRESLIST entries to the free list whenever
- * we run out.
+ * 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
+ * for allocator overhead).
*/
-#define INITRESLIST 10
-#define INCRESLIST 5
+#define INC_RESLIST4 ((1024 - 16) / V4_SIZEOF_RESTRICT_U)
+#define INC_RESLIST6 ((1024 - 16) / V6_SIZEOF_RESTRICT_U)
/*
* The restriction list
*/
-struct restrictlist *restrictlist;
-struct restrictlist6 *restrictlist6;
-static int restrictcount; /* count of entries in the res list */
-static int restrictcount6; /* count of entries in the res list 2*/
+restrict_u *restrictlist4;
+restrict_u *restrictlist6;
+static int restrictcount; /* count in the restrict lists */
/*
* The free list and associated counters. Also some uninteresting
* stat counters.
*/
-static struct restrictlist *resfree;
-static struct restrictlist6 *resfree6;
-static int numresfree; /* number of struct on free list */
-static int numresfree6; /* number of struct on free list 2 */
+static restrict_u *resfree4; /* available entries (free list) */
+static restrict_u *resfree6;
static u_long res_calls;
static u_long res_found;
static u_long res_not_found;
/*
- * Count number of restriction entries referring to RES_LIMITED controls
- * activation/deactivation of monitoring (with respect to RES_LIMITED
- * control)
+ * Count number of restriction entries referring to RES_LIMITED, to
+ * control implicit activation/deactivation of the MRU monlist.
*/
static u_long res_limited_refcnt;
-static u_long res_limited_refcnt6;
/*
- * Our initial allocation of lists entries.
+ * Our default entries.
*/
-static struct restrictlist resinit[INITRESLIST];
-static struct restrictlist6 resinit6[INITRESLIST];
+static restrict_u restrict_def4;
+static restrict_u restrict_def6;
+
+/*
+ * "restrict source ..." enabled knob and restriction bits.
+ */
+static int restrict_source_enabled;
+static u_short restrict_source_flags;
+static u_short restrict_source_mflags;
+
+/*
+ * 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 *,
+ 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 *);
/*
void
init_restrict(void)
{
- register int i;
-
/*
- * Zero the list and put all but one on the free list
+ * The restriction lists begin 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:
+ *
+ * address mask
+ * 192.168.0.0 255.255.255.0 kod limited noquery nopeer
+ * 192.168.0.0 255.255.0.0 kod limited
+ * 0.0.0.0 0.0.0.0 kod limited noquery
+ *
+ * The first entry which matches an address is used. With the
+ * example restrictions above, 192.168.0.0/24 matches the first
+ * entry, the rest of 192.168.0.0/16 matches the second, and
+ * everything else matches the third (default).
+ *
+ * Note this achieves the same result a little more efficiently
+ * than the documented behavior, which is to keep the lists
+ * sorted by ascending address followed by ascending mask, with
+ * the _last_ matching entry used.
+ *
+ * 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.
+ *
*/
- resfree = 0;
- memset((char *)resinit, 0, sizeof resinit);
- resfree6 = 0;
- memset((char *)resinit6, 0, sizeof resinit6);
- for (i = 1; i < INITRESLIST; i++) {
- resinit[i].next = resfree;
- resinit6[i].next = resfree6;
- resfree = &resinit[i];
- resfree6 = &resinit6[i];
+ LINK_SLIST(restrictlist4, &restrict_def4, link);
+ LINK_SLIST(restrictlist6, &restrict_def6, link);
+ restrictcount = 2;
+}
+
+
+static restrict_u *
+alloc_res4(void)
+{
+ const size_t cb = V4_SIZEOF_RESTRICT_U;
+ const size_t count = INC_RESLIST4;
+ restrict_u * rl;
+ restrict_u * res;
+ int i;
+
+ UNLINK_HEAD_SLIST(res, resfree4, link);
+ if (res != NULL)
+ return res;
+
+ rl = emalloc(count * cb);
+ memset(rl, 0, count * cb);
+ /* link all but the first onto free list */
+ res = (void *)((char *)rl + (count - 1) * cb);
+ for (i = count - 1; i > 0; i--) {
+ LINK_SLIST(resfree4, res, link);
+ res = (void *)((char *)res - cb);
}
- numresfree = INITRESLIST-1;
- numresfree6 = INITRESLIST-1;
+ NTP_INSIST(rl == res);
+ /* allocate the first */
+ return res;
+}
- /*
- * Put the remaining item at the head of the list as our default
- * entry. Everything in here should be zero for now.
- */
- resinit[0].addr = htonl(INADDR_ANY);
- resinit[0].mask = 0;
- memset(&resinit6[0].addr6, 0, sizeof(struct in6_addr));
- memset(&resinit6[0].mask6, 0, sizeof(struct in6_addr));
- restrictlist = &resinit[0];
- restrictlist6 = &resinit6[0];
- restrictcount = 1;
- restrictcount = 2;
- /*
- * fix up stat counters
- */
- res_calls = 0;
- res_found = 0;
- res_not_found = 0;
+static restrict_u *
+alloc_res6(void)
+{
+ const size_t cb = V6_SIZEOF_RESTRICT_U;
+ const size_t count = INC_RESLIST6;
+ restrict_u * rl;
+ restrict_u * res;
+ int i;
+
+ UNLINK_HEAD_SLIST(res, resfree6, link);
+ if (res != NULL)
+ return res;
+
+ rl = emalloc(count * cb);
+ memset(rl, 0, count * cb);
+ /* link all but the first onto free list */
+ res = (void *)((char *)rl + (count - 1) * cb);
+ for (i = count - 1; i > 0; i--) {
+ LINK_SLIST(resfree6, res, link);
+ res = (void *)((char *)res - cb);
+ }
+ NTP_INSIST(rl == res);
+ /* allocate the first */
+ return res;
+}
- /*
- * set default values for RES_LIMIT functionality
- */
- res_limited_refcnt = 0;
- res_limited_refcnt6 = 0;
+
+static void
+free_res(
+ restrict_u * res,
+ int v6
+ )
+{
+ restrict_u ** plisthead;
+ restrict_u * unlinked;
+
+ restrictcount--;
+ if (RES_LIMITED && res->flags)
+ dec_res_limited();
+
+ if (v6)
+ plisthead = &restrictlist6;
+ else
+ plisthead = &restrictlist4;
+ UNLINK_SLIST(unlinked, *plisthead, res, link, restrict_u);
+ NTP_INSIST(unlinked == res);
+
+ if (v6) {
+ memset(res, 0, V6_SIZEOF_RESTRICT_U);
+ plisthead = &resfree6;
+ } else {
+ memset(res, 0, V4_SIZEOF_RESTRICT_U);
+ plisthead = &resfree4;
+ }
+ LINK_SLIST(*plisthead, res, link);
+}
+
+
+static void
+inc_res_limited(void)
+{
+ if (!res_limited_refcnt)
+ mon_start(MON_RES);
+ res_limited_refcnt++;
+}
+
+
+static void
+dec_res_limited(void)
+{
+ res_limited_refcnt--;
+ if (!res_limited_refcnt)
+ mon_stop(MON_RES);
+}
+
+
+static restrict_u *
+match_restrict4_addr(
+ u_int32 addr,
+ u_short port
+ )
+{
+ restrict_u * res;
+ restrict_u * next;
+
+ for (res = restrictlist4; res != NULL; res = next) {
+ next = res->link;
+ if (res->u.v4.addr == (addr & res->u.v4.mask)
+ && (!(RESM_NTPONLY & res->mflags)
+ || NTP_PORT == port))
+ break;
+ }
+ return res;
+}
+
+
+static restrict_u *
+match_restrict6_addr(
+ const struct in6_addr * addr,
+ u_short port
+ )
+{
+ restrict_u * res;
+ restrict_u * next;
+ struct in6_addr masked;
+
+ for (res = restrictlist6; res != NULL; res = next) {
+ next = res->link;
+ NTP_INSIST(next != res);
+ MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask);
+ if (ADDR6_EQ(&masked, &res->u.v6.addr)
+ && (!(RESM_NTPONLY & res->mflags)
+ || NTP_PORT == port))
+ break;
+ }
+ return res;
+}
+
+
+/*
+ * match_restrict_entry - find an exact match on a restrict list.
+ *
+ * Exact match is addr, mask, and mflags all equal.
+ * In order to use more common code for IPv4 and IPv6, this routine
+ * requires the caller to populate a restrict_u with mflags and either
+ * the v4 or v6 address and mask as appropriate. Other fields in the
+ * input restrict_u are ignored.
+ */
+static restrict_u *
+match_restrict_entry(
+ const restrict_u * pmatch,
+ int v6
+ )
+{
+ restrict_u *res;
+ restrict_u *rlist;
+ size_t cb;
+
+ if (v6) {
+ rlist = restrictlist6;
+ cb = sizeof(pmatch->u.v6);
+ } else {
+ rlist = restrictlist4;
+ cb = sizeof(pmatch->u.v4);
+ }
+
+ for (res = rlist; res != NULL; res = res->link)
+ if (res->mflags == pmatch->mflags &&
+ !memcmp(&res->u, &pmatch->u, cb))
+ break;
+ return res;
+}
+
+
+/*
+ * res_sorts_before4 - compare two restrict4 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.
+ */
+static int
+res_sorts_before4(
+ restrict_u *r1,
+ restrict_u *r2
+ )
+{
+ 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;
+
+ return r1_before_r2;
+}
+
+
+/*
+ * res_sorts_before6 - compare two restrict6 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.
+ */
+static int
+res_sorts_before6(
+ 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 {
+ 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;
+ }
+
+ return r1_before_r2;
}
/*
* restrictions - return restrictions for this host
*/
-int
+u_short
restrictions(
sockaddr_u *srcadr
)
{
- struct restrictlist *rl;
- struct restrictlist *match = NULL;
- struct restrictlist6 *rl6;
- struct restrictlist6 *match6 = NULL;
- struct in6_addr hostaddr6;
- struct in6_addr hostservaddr6;
- u_int32 hostaddr;
- int flags = 0;
- int isntpport;
+ restrict_u *match;
+ struct in6_addr *pin6;
+ u_short flags;
res_calls++;
+ flags = 0;
/* IPv4 source address */
if (IS_IPV4(srcadr)) {
-
- /*
- * We need the host address in host order. Also need to
- * know whether this is from the ntp port or not.
- */
- hostaddr = SRCADR(srcadr);
- isntpport = (NTP_PORT == SRCPORT(srcadr));
-
/*
* Ignore any packets with a multicast source address
* (this should be done early in the receive process,
if (IN_CLASSD(SRCADR(srcadr)))
return (int)RES_IGNORE;
+ match = match_restrict4_addr(SRCADR(srcadr),
+ SRCPORT(srcadr));
+ match->count++;
/*
- * Set match to first entry, which is default entry.
- * Work our way down from there.
+ * res_not_found counts only use of the final default
+ * entry, not any "restrict default ntpport ...", which
+ * would be just before the final default.
*/
- match = restrictlist;
- for (rl = match->next; rl != 0 && rl->addr <= hostaddr;
- rl = rl->next)
- if ((hostaddr & rl->mask) == rl->addr) {
- if ((rl->mflags & RESM_NTPONLY) &&
- !isntpport)
- continue;
- match = rl;
- }
- match->count++;
- if (match == restrictlist)
+ if (&restrict_def4 == match)
res_not_found++;
else
res_found++;
/* IPv6 source address */
if (IS_IPV6(srcadr)) {
-
- /*
- * We need the host address in network order. Also need
- * to know whether this is from the ntp port or not.
- */
- hostaddr6 = SOCK_ADDR6(srcadr);
- isntpport = (NTP_PORT == SRCPORT(srcadr));
+ pin6 = PSOCK_ADDR6(srcadr);
/*
* Ignore any packets with a multicast source address
* (this should be done early in the receive process,
* not later!)
*/
- if (IN6_IS_ADDR_MULTICAST(&hostaddr6))
+ if (IN6_IS_ADDR_MULTICAST(pin6))
return (int)RES_IGNORE;
- /*
- * Set match to first entry, which is default entry.
- * Work our way down from there.
- */
- match6 = restrictlist6;
- for (rl6 = match6->next; rl6 != 0 &&
- (memcmp(&(rl6->addr6), &hostaddr6,
- sizeof(hostaddr6)) <= 0); rl6 = rl6->next) {
- SET_IPV6_ADDR_MASK(&hostservaddr6, &hostaddr6,
- &rl6->mask6);
- if (memcmp(&hostservaddr6, &(rl6->addr6),
- sizeof(hostservaddr6)) == 0) {
- if ((rl6->mflags & RESM_NTPONLY) &&
- !isntpport)
- continue;
- match6 = rl6;
- }
- }
- match6->count++;
- if (match6 == restrictlist6)
+ match = match_restrict6_addr(pin6, SRCPORT(srcadr));
+ match->count++;
+ if (&restrict_def6 == match)
res_not_found++;
else
res_found++;
- flags = match6->flags;
+ flags = match->flags;
}
return (flags);
}
*/
void
hack_restrict(
- int op,
- sockaddr_u *resaddr,
- sockaddr_u *resmask,
- int mflags,
- int flags
+ int op,
+ sockaddr_u * resaddr,
+ sockaddr_u * resmask,
+ u_short mflags,
+ u_short flags
)
{
- register u_int32 addr = 0;
- register u_int32 mask = 0;
- struct in6_addr addr6;
- struct in6_addr mask6;
- register struct restrictlist *rl = NULL;
- register struct restrictlist *rlprev = NULL;
- register struct restrictlist6 *rl6 = NULL;
- register struct restrictlist6 *rlprev6 = NULL;
- int i, addr_cmp, mask_cmp;
- memset(&addr6, 0, sizeof(struct in6_addr));
- memset(&mask6, 0, sizeof(struct in6_addr));
-
- if (IS_IPV4(resaddr)) {
+ int v6;
+ restrict_u match;
+ restrict_u * res;
+ restrict_u ** plisthead;
+
+ DPRINTF(1, ("restrict: op %d addr %s mask %s mflags %08x flags %08x\n",
+ op, stoa(resaddr), stoa(resmask), mflags, flags));
+
+ if (NULL == resaddr) {
+ NTP_REQUIRE(NULL == resmask);
+ NTP_REQUIRE(RESTRICT_FLAGS == op);
+ restrict_source_flags = flags;
+ restrict_source_mflags = mflags;
+ restrict_source_enabled = 1;
+ return;
+ }
- DPRINTF(1, ("restrict: addr %08x mask %08x mflags %08x flags %08x\n",
- SRCADR(resaddr), SRCADR(resmask), mflags, flags));
+ memset(&match, 0, sizeof(match));
+ /* silence VC9 potentially uninit warnings */
+ res = NULL;
+ v6 = 0;
+ if (IS_IPV4(resaddr)) {
+ v6 = 0;
/*
- * Get address and mask in host byte order
+ * Get address and mask in host byte order for easy
+ * comparison as u_int32
*/
- addr = SRCADR(resaddr);
- mask = SRCADR(resmask);
- addr &= mask; /* make sure low bits zero */
+ 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;
/*
- * If this is the default address, point at first on
- * list. Else go searching for it.
+ * Get address and mask in network byte order for easy
+ * comparison as byte sequences (e.g. memcmp())
*/
- if (addr == 0) {
- rlprev = 0;
- rl = restrictlist;
- } else {
- rlprev = restrictlist;
- rl = rlprev->next;
- while (rl != 0) {
- if (rl->addr > addr) {
- rl = 0;
- break;
- } else if (rl->addr == addr) {
- if (rl->mask == mask) {
- if ((mflags &
- RESM_NTPONLY) ==
- (rl->mflags &
- RESM_NTPONLY))
- break;
-
- if (!(mflags &
- RESM_NTPONLY)) {
- rl = 0;
- break;
- }
- } else if (rl->mask > mask) {
- rl = 0;
- break;
- }
- }
- rlprev = rl;
- rl = rl->next;
- }
- }
- }
+ match.u.v6.mask = SOCK_ADDR6(resmask);
+ MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr),
+ &match.u.v6.mask);
- if (IS_IPV6(resaddr)) {
- mask6 = SOCK_ADDR6(resmask);
- SET_IPV6_ADDR_MASK(&addr6,
- PSOCK_ADDR6(resaddr), &mask6);
- if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) {
- rlprev6 = NULL;
- rl6 = restrictlist6;
- } else {
- rlprev6 = restrictlist6;
- rl6 = rlprev6->next;
- while (rl6 != 0) {
- addr_cmp = memcmp(&rl6->addr6, &addr6,
- sizeof(addr6));
- if (addr_cmp > 0) {
- rl6 = 0;
- break;
-
- } else if (addr_cmp == 0) {
- mask_cmp = memcmp(&rl6->mask6,
- &mask6, sizeof(mask6));
- if (mask_cmp == 0) {
- if ((mflags &
- RESM_NTPONLY) ==
- (rl6->mflags &
- RESM_NTPONLY))
- break;
-
- if (!(mflags &
- RESM_NTPONLY)) {
- rl6 = 0;
- break;
- }
- } else if (mask_cmp > 0) {
- rl6 = 0;
- break;
- }
- }
- rlprev6 = rl6;
- rl6 = rl6->next;
- }
- }
- }
+ } else /* not IPv4 nor IPv6 */
+ NTP_REQUIRE(0);
- /*
- * In case the above wasn't clear :-), either rl now points
- * at the entry this call refers to, or rl is zero and rlprev
- * points to the entry prior to where this one should go in
- * the sort.
- */
- /*
- * Switch based on operation
- */
- if (IS_IPV4(resaddr)) {
- switch (op) {
- case RESTRICT_FLAGS:
-
- /*
- * Here we add bits to the flags. If this is a
- * new restriction add it.
- */
- if (rl == 0) {
- if (numresfree == 0) {
- rl = (struct restrictlist *)
- emalloc(INCRESLIST *
- sizeof(struct
- restrictlist));
- memset((char *)rl, 0,
- INCRESLIST * sizeof(struct
- restrictlist));
- for (i = 0; i < INCRESLIST;
- i++) {
- rl->next = resfree;
- resfree = rl;
- rl++;
- }
- numresfree = INCRESLIST;
- }
- rl = resfree;
- resfree = rl->next;
- numresfree--;
- rl->addr = addr;
- rl->mask = mask;
- rl->mflags = (u_short)mflags;
- if (rlprev == NULL) {
- rl->next = restrictlist;
- restrictlist = rl;
- } else {
- rl->next = rlprev->next;
- rlprev->next = rl;
- }
- restrictcount++;
- }
- if ((rl->flags ^ (u_short)flags) &
- RES_LIMITED) {
- res_limited_refcnt++;
- mon_start(MON_RES);
- }
- rl->flags |= (u_short)flags;
- break;
+ match.flags = flags;
+ match.mflags = mflags;
+ res = match_restrict_entry(&match, v6);
- case RESTRICT_UNFLAG:
-
- /*
- * Remove some bits from the flags. If we didn't
- * find this one, just return.
- */
- if (rl != 0) {
- if ((rl->flags ^ (u_short)flags) &
- RES_LIMITED) {
- res_limited_refcnt--;
- if (res_limited_refcnt == 0)
- mon_stop(MON_RES);
- }
- rl->flags &= (u_short)~flags;
- }
- break;
-
- 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.
- */
- if (rl != 0
- && rl->addr != htonl(INADDR_ANY)
- && !(rl->mflags & RESM_INTERFACE && op !=
- RESTRICT_REMOVEIF)) {
- if (rlprev != NULL) {
- rlprev->next = rl->next;
- } else {
- restrictlist = rl->next;
- }
- restrictcount--;
- if (rl->flags & RES_LIMITED) {
- res_limited_refcnt--;
- if (res_limited_refcnt == 0)
- mon_stop(MON_RES);
- }
- memset((char *)rl, 0,
- sizeof(struct restrictlist));
-
- rl->next = resfree;
- resfree = rl;
- numresfree++;
- }
- break;
+ switch (op) {
- default:
- break;
- }
- } else if (IS_IPV6(resaddr)) {
- switch (op) {
- case RESTRICT_FLAGS:
-
- /*
- * Here we add bits to the flags. If this is a
- * new restriction add it.
- */
- if (rl6 == 0) {
- if (numresfree6 == 0) {
- rl6 = (struct
- restrictlist6 *)emalloc(
- INCRESLIST * sizeof(struct
- restrictlist6));
- memset((char *)rl6, 0,
- INCRESLIST * sizeof(struct
- restrictlist6));
-
- for (i = 0; i < INCRESLIST;
- i++) {
- rl6->next = resfree6;
- resfree6 = rl6;
- rl6++;
- }
- numresfree6 = INCRESLIST;
- }
- rl6 = resfree6;
- resfree6 = rl6->next;
- numresfree6--;
- rl6->addr6 = addr6;
- rl6->mask6 = mask6;
- rl6->mflags = (u_short)mflags;
- if (rlprev6 != NULL) {
- rl6->next = rlprev6->next;
- rlprev6->next = rl6;
- } else {
- rl6->next = restrictlist6;
- restrictlist6 = rl6;
- }
- restrictcount6++;
- }
- if ((rl6->flags ^ (u_short)flags) &
- RES_LIMITED) {
- res_limited_refcnt6++;
- mon_start(MON_RES);
- }
- rl6->flags |= (u_short)flags;
- break;
-
- case RESTRICT_UNFLAG:
-
- /*
- * Remove some bits from the flags. If we didn't
- * find this one, just return.
- */
- if (rl6 != 0) {
- if ((rl6->flags ^ (u_short)flags) &
- RES_LIMITED) {
- res_limited_refcnt6--;
- if (res_limited_refcnt6 == 0)
- mon_stop(MON_RES);
- }
- rl6->flags &= (u_short)~flags;
- }
- break;
-
- 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.
- */
- if (rl6 != 0 &&
- !IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6)
- && !(rl6->mflags & RESM_INTERFACE && op !=
- RESTRICT_REMOVEIF)) {
- if (rlprev6 != NULL) {
- rlprev6->next = rl6->next;
- } else {
- restrictlist6 = rl6->next;
- }
- restrictcount6--;
- if (rl6->flags & RES_LIMITED) {
- res_limited_refcnt6--;
- if (res_limited_refcnt6 == 0)
- mon_stop(MON_RES);
- }
- memset((char *)rl6, 0,
- sizeof(struct restrictlist6));
- rl6->next = resfree6;
- resfree6 = rl6;
- numresfree6++;
+ case RESTRICT_FLAGS:
+ /*
+ * Here we add bits to the flags. If this is a
+ * new restriction add it.
+ */
+ if (NULL == res) {
+ if (v6) {
+ res = alloc_res6();
+ memcpy(res, &match,
+ V6_SIZEOF_RESTRICT_U);
+ plisthead = &restrictlist6;
+ } else {
+ res = alloc_res4();
+ memcpy(res, &match,
+ V4_SIZEOF_RESTRICT_U);
+ plisthead = &restrictlist4;
}
- break;
+ LINK_SORT_SLIST(
+ *plisthead, res,
+ (v6)
+ ? res_sorts_before6(res, L_S_S_CUR())
+ : res_sorts_before4(res, L_S_S_CUR()),
+ link, restrict_u);
+ restrictcount++;
+ if (RES_LIMITED & flags)
+ inc_res_limited();
+ } else {
+ if ((RES_LIMITED & flags) &&
+ !(RES_LIMITED & res->flags))
+ inc_res_limited();
+ res->flags |= flags;
+ }
+ break;
- default:
- break;
+ case RESTRICT_UNFLAG:
+ /*
+ * Remove some bits from the flags. If we didn't
+ * find this one, just return.
+ */
+ if (res != NULL) {
+ if ((RES_LIMITED & res->flags)
+ && (RES_LIMITED & flags))
+ dec_res_limited();
+ res->flags &= ~flags;
}
+ break;
+
+ 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.
+ */
+ if (res != NULL
+ && (RESTRICT_REMOVEIF == op
+ || !(RESM_INTERFACE & res->mflags))
+ && res != &restrict_def4
+ && res != &restrict_def6)
+ free_res(res, v6);
+ break;
+
+ default: /* unknown op */
+ NTP_INSIST(0);
+ break;
}
+
}
+
#elif defined(SYS_WINNT)
/*
* Windows does not abort a select select call if SIGALRM goes off
- * so a 200 ms timeout is needed
+ * so a 200 ms timeout is needed (TIMER_HZ is 5).
*/
struct sock_timeval timeout = {0,1000000/TIMER_HZ};
#else
# define NTPDATE_PRIO (100)
#endif
-#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE)
+#ifdef HAVE_TIMER_CREATE
/* POSIX TIMERS - vxWorks doesn't have itimer - casey */
static timer_t ntpdate_timerid;
#endif
} else {
sys_timeout = ((LFPTOFP(&tmp) * TIMER_HZ)
+ 0x8000) >> 16;
- if (sys_timeout == 0)
- sys_timeout = 1;
+ /*
+ * No less than 1s between requests to
+ * a server to stay within ntpd's
+ * default "discard minimum 1" (and 1s
+ * enforcement slop). That is enforced
+ * only if the nondefault limited
+ * restriction is in place, such as with
+ * "restrict ... limited" and "restrict
+ * ... kod limited".
+ */
+ if (MINTIMEOUT < sys_timeout)
+ sys_timeout = MINTIMEOUT;
}
break;
case 'v':
if (!is_authentic)
server->trust |= 1;
+ /*
+ * Check for a KoD (rate limiting) response, cease and decist.
+ */
+ if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode) &&
+ STRATUM_PKT_UNSPEC == rpkt->stratum &&
+ !memcmp("RATE", &rpkt->refid, 4)) {
+ msyslog(LOG_ERR, "%s rate limit response from server.\n",
+ stoa(&rbufp->recv_srcadr));
+ server->event_time = 0;
+ complete_servers++;
+ return;
+ }
+
/*
* Looks good. Record info from the packet.
*/
* Make sure the server is at least somewhat sane. If not, try
* again.
*/
- if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)) {
- transmit(server);
+ if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec)
+ || L_ISEQU(&rec, &server->org)) {
+ server->event_time = current_time + sys_timeout;
return;
}
}
/*
- * Shift this data in, then transmit again.
+ * Shift this data in, then schedule another transmit.
*/
server_data(server, (s_fp) di, &ci, 0);
- transmit(server);
+ server->event_time = current_time + sys_timeout;
}
lfptoa(&server->offset, 6));
}
} else {
-#if !defined SYS_WINNT && !defined SYS_CYGWIN32
+#ifndef SYS_WINNT
if (simple_query || l_adj_systime(&server->offset)) {
msyslog(LOG_NOTICE, "adjust time server %s offset %s sec",
stoa(&server->srcadr),
/* Name server is unusable. Exit after failing on the
first server, in order to shorten the timeout caused
by waiting for resolution of several servers */
- fprintf(stderr, "Name server cannot be used, exiting");
- msyslog(LOG_ERR, "name server cannot be used, reason: %s\n", gai_strerror(error));
+ fprintf(stderr, "Exiting, name server cannot be used: %s (%d)",
+ gai_strerror(error), error);
+ msyslog(LOG_ERR, "name server cannot be used: %s (%d)\n",
+ gai_strerror(error), error);
exit(1);
}
- fprintf(stderr, "Error : %s\n", gai_strerror(error));
- msyslog(LOG_ERR, "can't find host %s\n", serv);
+ fprintf(stderr, "Error resolving %s: %s (%d)\n", serv,
+ gai_strerror(error), error);
+ msyslog(LOG_ERR, "Can't find host %s: %s (%d)\n", serv,
+ gai_strerror(error), error);
return;
}
#ifdef DEBUG
{
alarm_flag++;
}
-#else
+#else /* SYS_WINNT follows */
void CALLBACK
alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
init_alarm(void)
{
#ifndef SYS_WINNT
-# ifndef HAVE_TIMER_SETTIME
- struct itimerval itimer;
+# ifdef HAVE_TIMER_CREATE
+ struct itimerspec its;
# else
- struct itimerspec ntpdate_itimer;
+ struct itimerval itv;
# endif
-#else
+#else /* SYS_WINNT follows */
TIMECAPS tc;
UINT wTimerID;
-# endif /* SYS_WINNT */
-#if defined SYS_CYGWIN32 || defined SYS_WINNT
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
DWORD dwUser = 0;
alarm_flag = 0;
#ifndef SYS_WINNT
-# if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
+# ifdef HAVE_TIMER_CREATE
alarm_flag = 0;
/* this code was put in as setitimer() is non existant this us the
* POSIX "equivalents" setup - casey
* Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ)
* seconds from now and they continue on every 1/TIMER_HZ seconds.
*/
- (void) signal_no_reset(SIGALRM, alarming);
- ntpdate_itimer.it_interval.tv_sec = ntpdate_itimer.it_value.tv_sec = 0;
- ntpdate_itimer.it_interval.tv_nsec = 1000000000/TIMER_HZ;
- ntpdate_itimer.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1);
- timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &ntpdate_itimer, NULL);
-# else
+ signal_no_reset(SIGALRM, alarming);
+ its.it_interval.tv_sec = 0;
+ its.it_value.tv_sec = 0;
+ its.it_interval.tv_nsec = 1000000000/TIMER_HZ;
+ its.it_value.tv_nsec = 1000000000/(TIMER_HZ<<1);
+ timer_settime(ntpdate_timerid, 0 /* !TIMER_ABSTIME */, &its, NULL);
+# else /* !HAVE_TIMER_CREATE follows */
/*
* Set up the alarm interrupt. The first comes 1/(2*TIMER_HZ)
* seconds from now and they continue on every 1/TIMER_HZ seconds.
*/
- (void) signal_no_reset(SIGALRM, alarming);
- itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
- itimer.it_interval.tv_usec = 1000000/TIMER_HZ;
- itimer.it_value.tv_usec = 1000000/(TIMER_HZ<<1);
-
- setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
-# endif
-#if defined SYS_CYGWIN32
- /*
- * Get privileges needed for fiddling with the clock
- */
-
- /* get the current process token handle */
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
- msyslog(LOG_ERR, "OpenProcessToken failed: %m");
- exit(1);
- }
- /* get the LUID for system-time privilege. */
- LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
- tkp.PrivilegeCount = 1; /* one privilege to set */
- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- /* get set-time privilege for this process. */
- AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES) NULL, 0);
- /* cannot test return value of AdjustTokenPrivileges. */
- if (GetLastError() != ERROR_SUCCESS)
- msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
-#endif
-#else /* SYS_WINNT */
+ signal_no_reset(SIGALRM, alarming);
+ itv.it_interval.tv_sec = 0;
+ itv.it_value.tv_sec = 0;
+ itv.it_interval.tv_usec = 1000000/TIMER_HZ;
+ itv.it_value.tv_usec = 1000000/(TIMER_HZ<<1);
+
+ setitimer(ITIMER_REAL, &itv, NULL);
+# endif /* !HAVE_TIMER_CREATE */
+#else /* SYS_WINNT follows */
_tzset();
/*
/*
* Some defaults
*/
-#define DEFTIMEOUT 5 /* 5 timer increments */
+#define MINTIMEOUT (2 * TIMER_HZ) /* 2s min. between packets */
+#define DEFTIMEOUT MINTIMEOUT /* (to the same server) */
#define DEFSAMPLES 4 /* get 4 samples per server */
#define DEFPRECISION (-5) /* the precision we claim */
#define DEFMAXPERIOD 60 /* maximum time to wait */
#ifdef ISC_PLATFORM_HAVESALEN
#define SET_SS_LEN_IF_PRESENT(psau) \
do { \
- (psau)->sas.ss_len = SOCKLEN(psau); \
+ (psau)->sa.sa_len = SOCKLEN(psau); \
} while (0)
#else
#define SET_SS_LEN_IF_PRESENT(psau) do { } while (0)
NSRCADR(&src) = pp->srcadr;
}
#ifdef ISC_PLATFORM_HAVESALEN
- src.sas.ss_len = SOCKLEN(&src);
- dst.sas.ss_len = SOCKLEN(&dst);
+ src.sa.sa_len = SOCKLEN(&src);
+ dst.sa.sa_len = SOCKLEN(&dst);
#endif
(void) fprintf(fp, "remote host: %s\n",
nntohost(&src));
#ifdef DEBUG
printf("sntp recvdata: Trying to receive data from...\n");
#endif
- slen = sizeof(sender->sas);
+ slen = sizeof(sender);
recvc = recvfrom(rsock, rdata, rdata_length, 0,
&sender->sa, &slen);
#ifdef DEBUG
default:
{
- GETSOCKNAME_SOCKLEN_TYPE ss_len = sizeof(ras->sas);
+ GETSOCKNAME_SOCKLEN_TYPE ss_len = sizeof(ras);
recv_bytes = recvfrom(rsock, rdata, rdata_len, 0, &ras->sa, &ss_len);
}