From: Dave Hart Date: Wed, 14 Apr 2010 04:44:52 +0000 (+0000) Subject: [Bug 1503] Auto-enabling of monitor for "restrict ... limited" wrong. X-Git-Tag: NTP_4_2_6P2_RC1~4^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=78afdb896c7ba5504f0b68137d0d2c55bfa2fa4f;p=thirdparty%2Fntp.git [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. bk: 4bc54844aYpe8cMZ5Rry78f-Ct9KNw --- diff --git a/ChangeLog b/ChangeLog index 7bcf74ffb..47e7db3f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ --- + +* [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 (4.2.6p1-RC6) 2010/03/31 Released by Harlan Stenn diff --git a/include/ntp.h b/include/ntp.h index b60523af1..11285f47b 100644 --- a/include/ntp.h +++ b/include/ntp.h @@ -4,6 +4,7 @@ #ifndef NTP_H #define NTP_H +#include #include #include @@ -772,23 +773,31 @@ struct mon_data { /* * 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)) /* diff --git a/include/ntp_lists.h b/include/ntp_lists.h index 2bac38a52..ee3f9c299 100644 --- a/include/ntp_lists.h +++ b/include/ntp_lists.h @@ -1,5 +1,8 @@ /* - * 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 @@ -19,6 +22,13 @@ * 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. @@ -30,21 +40,30 @@ * * 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 +#ifndef TRUE +# define TRUE 1 +# define NTP_LISTS_UNDEF_TRUE #endif -#include - - #define LINK_SLIST(listhead, pentry, nextlink) \ do { \ (pentry)->nextlink = (listhead); \ @@ -63,6 +82,30 @@ do { \ *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); \ @@ -72,6 +115,9 @@ do { \ } \ } 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 { \ @@ -94,11 +140,118 @@ 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 */ diff --git a/include/ntp_net.h b/include/ntp_net.h index 9cfebe1c7..da2a22ab5 100644 --- a/include/ntp_net.h +++ b/include/ntp_net.h @@ -17,7 +17,6 @@ typedef union { struct sockaddr sa; - struct sockaddr_storage sas; struct sockaddr_in sa4; struct sockaddr_in6 sa6; } sockaddr_u; @@ -31,7 +30,7 @@ typedef union { #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)) @@ -95,6 +94,11 @@ typedef union { ? 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) \ @@ -106,11 +110,11 @@ typedef union { : 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) \ @@ -129,19 +133,30 @@ typedef union { 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 \ @@ -150,6 +165,12 @@ typedef union { : (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) \ diff --git a/include/ntpd.h b/include/ntpd.h index 14cf0add2..afb7ef4fc 100644 --- a/include/ntpd.h +++ b/include/ntpd.h @@ -213,8 +213,8 @@ extern void process_private (struct recvbuf *, int); /* 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); @@ -455,8 +455,8 @@ extern int fdpps; /* pps file descriptor */ 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 */ diff --git a/ntpd/ntp_io.c b/ntpd/ntp_io.c index 3cd8ab0cb..7eaa9c0b6 100644 --- a/ntpd/ntp_io.c +++ b/ntpd/ntp_io.c @@ -595,11 +595,11 @@ static void 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++) { diff --git a/ntpd/ntp_monitor.c b/ntpd/ntp_monitor.c index 05dca322e..200a9028d 100644 --- a/ntpd/ntp_monitor.c +++ b/ntpd/ntp_monitor.c @@ -310,9 +310,9 @@ ntp_monitor( * 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; @@ -329,7 +329,7 @@ ntp_monitor( */ 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)); diff --git a/ntpd/ntp_request.c b/ntpd/ntp_request.c index c863d2c56..95cb1e5c2 100644 --- a/ntpd/ntp_request.c +++ b/ntpd/ntp_request.c @@ -848,7 +848,7 @@ peer_info ( 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) @@ -981,7 +981,7 @@ peer_stats ( 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))); @@ -1407,7 +1407,7 @@ do_conf( } 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 ??? */ @@ -1571,7 +1571,7 @@ do_unconf( } 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; @@ -1616,7 +1616,7 @@ do_unconf( } 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; @@ -1731,6 +1731,58 @@ setclr_flags( 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 @@ -1742,43 +1794,26 @@ list_restrict( 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) */ @@ -2100,7 +2135,7 @@ reset_peer( } #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) @@ -2131,7 +2166,7 @@ reset_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) { @@ -2637,7 +2672,7 @@ get_clock_info( 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); @@ -2709,7 +2744,7 @@ set_clock_fudge( 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) || @@ -2776,7 +2811,7 @@ get_clkbug_info( 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); diff --git a/ntpd/ntp_restrict.c b/ntpd/ntp_restrict.c index 2ea4f35aa..e087b6ce4 100644 --- a/ntpd/ntp_restrict.c +++ b/ntpd/ntp_restrict.c @@ -10,7 +10,9 @@ #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 @@ -41,57 +43,74 @@ * 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 *); /* @@ -100,81 +119,306 @@ static struct restrictlist6 resinit6[INITRESLIST]; 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, @@ -183,21 +427,15 @@ restrictions( 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++; @@ -206,46 +444,23 @@ restrictions( /* 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); } @@ -256,326 +471,130 @@ restrictions( */ 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; } + } + diff --git a/ntpdate/ntpdate.c b/ntpdate/ntpdate.c index 16b8e7fe0..a906ae283 100644 --- a/ntpdate/ntpdate.c +++ b/ntpdate/ntpdate.c @@ -58,7 +58,7 @@ struct timeval timeout = {0,0}; #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 @@ -88,7 +88,7 @@ UINT wTimerRes; # 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 @@ -419,8 +419,18 @@ ntpdatemain ( } 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': @@ -828,6 +838,19 @@ receive( 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. */ @@ -845,8 +868,9 @@ receive( * 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; } @@ -895,10 +919,10 @@ receive( } /* - * 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; } @@ -1260,7 +1284,7 @@ clock_adjust(void) 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), @@ -1346,12 +1370,16 @@ addserver( /* 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 @@ -1479,7 +1507,7 @@ alarming( { alarm_flag++; } -#else +#else /* SYS_WINNT follows */ void CALLBACK alarming(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { @@ -1505,16 +1533,14 @@ static void 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; @@ -1523,7 +1549,7 @@ init_alarm(void) 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 @@ -1545,44 +1571,26 @@ init_alarm(void) * 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(); /* diff --git a/ntpdate/ntpdate.h b/ntpdate/ntpdate.h index 00bc3ff06..75fba4291 100644 --- a/ntpdate/ntpdate.h +++ b/ntpdate/ntpdate.h @@ -91,7 +91,8 @@ struct server { /* * 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 */ diff --git a/ntpdc/ntpdc_ops.c b/ntpdc/ntpdc_ops.c index 0d26a65c4..b1d9a0429 100644 --- a/ntpdc/ntpdc_ops.c +++ b/ntpdc/ntpdc_ops.c @@ -236,7 +236,7 @@ struct xcmd opcmds[] = { #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) @@ -841,8 +841,8 @@ again: 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)); diff --git a/sntp/networking.c b/sntp/networking.c index a73585d1c..17992510b 100644 --- a/sntp/networking.c +++ b/sntp/networking.c @@ -148,7 +148,7 @@ recvdata ( #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 @@ -305,7 +305,7 @@ recv_bcst_data ( 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); }