From: Harlan Stenn Date: Mon, 22 Jan 2018 10:55:41 +0000 (-0800) Subject: restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7c37b9f164302b288918c44b97550c6275ba2228;p=thirdparty%2Fntp.git restrictions() must return restrict flags and ippeerlimit. Implement ippeerlimit. bk: 5a65c32dr6iWPIzadIF-NgPCyN0R9Q --- diff --git a/ChangeLog b/ChangeLog index 62c5f99e5..17e9243e5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -85,6 +85,7 @@ * Decode interface flags on receive() debug output. HStenn. * Warn the user if deprecated "driftfile name WanderThreshold" is used. HStenn. * Update the documentation in ntp.conf.def . HStenn. +* restrictions() must return restrict flags and ippeerlimit. HStenn. --- (4.2.8p10) 2017/03/21 Released by Harlan Stenn diff --git a/include/ntp.h b/include/ntp.h index 3d56528ca..deec06851 100644 --- a/include/ntp.h +++ b/include/ntp.h @@ -840,6 +840,12 @@ struct restrict_u_tag { #define V6_SIZEOF_RESTRICT_U (offsetof(restrict_u, u) \ + sizeof(res_addr6)) +typedef struct r4addr_tag r4addr; +struct r4addr_tag { + u_short rflags; /* match flags */ + short ippeerlimit; /* IP peer limit */ +}; + char *build_iflags(u_int32 flags); char *build_mflags(u_short flags); char *build_rflags(u_short flags); diff --git a/include/ntpd.h b/include/ntpd.h index 0de7f04e9..f226f6448 100644 --- a/include/ntpd.h +++ b/include/ntpd.h @@ -172,15 +172,15 @@ extern struct peer *findexistingpeer(sockaddr_u *, const char *, extern struct peer *findpeer (struct recvbuf *, int, int *); extern struct peer *findpeerbyassoc(associd_t); extern void set_peerdstadr (struct peer *, endpt *); -extern struct peer *newpeer (sockaddr_u *, const char *, - endpt *, u_char, u_char, - u_char, u_char, u_int, u_char, u_int32, +extern struct peer *newpeer (sockaddr_u *, const char *, endpt *, + int, u_char, u_char, u_char, u_char, + u_int, u_char, u_int32, keyid_t, const char *); extern void peer_all_reset (void); extern void peer_clr_stats (void); -extern struct peer *peer_config(sockaddr_u *, const char *, - endpt *, u_char, u_char, - u_char, u_char, u_int, u_int32, +extern struct peer *peer_config(sockaddr_u *, const char *, endpt *, + int, u_char, u_char, u_char, u_char, + u_int, u_int32, keyid_t, const char *); extern void peer_reset (struct peer *); extern void refresh_all_peerinterfaces(void); @@ -257,7 +257,7 @@ extern void reset_auth_stats(void); /* ntp_restrict.c */ extern void init_restrict (void); -extern u_short restrictions (sockaddr_u *); +extern void restrictions (sockaddr_u *, r4addr *); extern void hack_restrict (int, sockaddr_u *, sockaddr_u *, short, u_short, u_short, u_long); extern void restrict_source (sockaddr_u *, int, u_long); diff --git a/ntpd/ntp_config.c b/ntpd/ntp_config.c index de0433311..07d7b1c57 100644 --- a/ntpd/ntp_config.c +++ b/ntpd/ntp_config.c @@ -3978,6 +3978,9 @@ config_peers( * If we have a numeric address, we can safely * proceed in the mainline with it. Otherwise, hand * the hostname off to the blocking child. + * + * Note that if we're told to add the peer here, we + * do that regardless of ippeerlimit. */ if (is_ip_address(*cmdline_servers, AF_UNSPEC, &peeraddr)) { @@ -3989,6 +3992,7 @@ config_peers( &peeraddr, NULL, NULL, + -1, MODE_CLIENT, NTP_VERSION, 0, @@ -4039,6 +4043,7 @@ config_peers( &peeraddr, curr_peer->addr->address, NULL, + -1, hmode, curr_peer->peerversion, curr_peer->minpoll, @@ -4062,6 +4067,7 @@ config_peers( &peeraddr, NULL, NULL, + -1, hmode, curr_peer->peerversion, curr_peer->minpoll, @@ -4162,6 +4168,7 @@ peer_name_resolved( &peeraddr, NULL, NULL, + -1, ctx->hmode, ctx->version, ctx->minpoll, diff --git a/ntpd/ntp_peer.c b/ntpd/ntp_peer.c index ed7bd904e..f594ee950 100644 --- a/ntpd/ntp_peer.c +++ b/ntpd/ntp_peer.c @@ -568,6 +568,7 @@ peer_config( sockaddr_u * srcadr, const char * hostname, endpt * dstadr, + int ippeerlimit, u_char hmode, u_char version, u_char minpoll, @@ -618,7 +619,7 @@ peer_config( flags |= FLAG_IBURST; if ((MDF_ACAST | MDF_POOL) & cast_flags) flags &= ~FLAG_PREEMPT; - return newpeer(srcadr, hostname, dstadr, hmode, version, + return newpeer(srcadr, hostname, dstadr, ippeerlimit, hmode, version, minpoll, maxpoll, flags, cast_flags, ttl, key, ident); } @@ -760,6 +761,7 @@ newpeer( sockaddr_u * srcadr, const char * hostname, endpt * dstadr, + int ippeerlimit, u_char hmode, u_char version, u_char minpoll, @@ -848,6 +850,18 @@ DPRINTF(1, ("newpeer(%s) found no existing and %d other associations\n", : stoa(srcadr), ip_count)); + /* Check ippeerlimit wrt ip_count */ + if (ippeerlimit > -1) { + if (ip_count + 1 > ippeerlimit) { + DPRINTF(2, ("newpeer(%s) denied - ippeerlimit %d\n", + (hostname) + ? hostname + : stoa(srcadr), + ippeerlimit)); + return NULL; + } + } + /* * Allocate a new peer structure. Some dirt here, since some of * the initialization requires knowlege of our system state. diff --git a/ntpd/ntp_proto.c b/ntpd/ntp_proto.c index c09d8f4da..9d99c88a4 100644 --- a/ntpd/ntp_proto.c +++ b/ntpd/ntp_proto.c @@ -579,6 +579,7 @@ receive( u_char hisleap; /* packet leap indicator */ u_char hismode; /* packet mode */ u_char hisstratum; /* packet stratum */ + r4addr r4a; /* address restrictions */ u_short restrict_mask; /* restrict bits */ const char *hm_str; /* hismode string */ const char *am_str; /* association match string */ @@ -629,7 +630,9 @@ receive( sys_badlength++; return; /* bogus port */ } - restrict_mask = restrictions(&rbufp->recv_srcadr); + restrictions(&rbufp->recv_srcadr, &r4a); + restrict_mask = r4a.rflags; + pkt = &rbufp->recv_pkt; hisversion = PKT_VERSION(pkt->li_vn_mode); hisleap = PKT_LEAP(pkt->li_vn_mode); @@ -1235,7 +1238,7 @@ receive( sys_declined++; return; /* no help */ } - peer = newpeer(&rbufp->recv_srcadr, NULL, rbufp->dstadr, + peer = newpeer(&rbufp->recv_srcadr, NULL, rbufp->dstadr, -1, MODE_CLIENT, hisversion, peer2->minpoll, peer2->maxpoll, FLAG_PREEMPT | (FLAG_IBURST & peer2->flags), MDF_UCAST | @@ -1356,10 +1359,9 @@ receive( * Do not execute the volley. Start out in * broadcast client mode. */ - peer = newpeer(&rbufp->recv_srcadr, NULL, - match_ep, MODE_BCLIENT, hisversion, - pkt->ppoll, pkt->ppoll, FLAG_PREEMPT, - MDF_BCLNT, 0, skeyid, sys_ident); + peer = newpeer(&rbufp->recv_srcadr, NULL, match_ep, -1, + MODE_BCLIENT, hisversion, pkt->ppoll, pkt->ppoll, + FLAG_PREEMPT, MDF_BCLNT, 0, skeyid, sys_ident); if (NULL == peer) { DPRINTF(2, ("receive: AM_NEWBCL drop: duplicate\n")); sys_restricted++; @@ -1380,7 +1382,7 @@ receive( * packet, normally 6 (64 s) and that the poll interval * is fixed at this value. */ - peer = newpeer(&rbufp->recv_srcadr, NULL, match_ep, + peer = newpeer(&rbufp->recv_srcadr, NULL, match_ep, -1, MODE_CLIENT, hisversion, pkt->ppoll, pkt->ppoll, FLAG_BC_VOL | FLAG_IBURST | FLAG_PREEMPT, MDF_BCLNT, 0, skeyid, sys_ident); @@ -1481,12 +1483,13 @@ receive( /* * The message is correctly authenticated and allowed. - * Mobilize a symmetric passive association. + * Mobilize a symmetric passive association, if we won't + * exceed the ippeerlimit. */ - if ((peer = newpeer(&rbufp->recv_srcadr, NULL, - rbufp->dstadr, MODE_PASSIVE, hisversion, pkt->ppoll, - NTP_MAXDPOLL, 0, MDF_UCAST, 0, skeyid, - sys_ident)) == NULL) { + if ((peer = newpeer(&rbufp->recv_srcadr, NULL, rbufp->dstadr, + -1, MODE_PASSIVE, hisversion, pkt->ppoll, + NTP_MAXDPOLL, 0, MDF_UCAST, 0, skeyid, + sys_ident)) == NULL) { DPRINTF(2, ("receive: AM_NEWPASS drop: newpeer() failed\n")); sys_declined++; return; /* ignore duplicate */ @@ -4408,6 +4411,7 @@ pool_xmit( int rc; struct interface * lcladr; sockaddr_u * rmtadr; + r4addr r4a; int restrict_mask; struct peer * p; l_fp xmt_tx; @@ -4448,7 +4452,8 @@ pool_xmit( } while (p != NULL && pool->ai != NULL); if (p != NULL) return; /* out of addresses, re-query DNS next poll */ - restrict_mask = restrictions(rmtadr); + restrictions(rmtadr, &r4a); + restrict_mask = r4a.rflags; if (RES_FLAGS & restrict_mask) restrict_source(rmtadr, 0, current_time + POOL_SOLICIT_WINDOW + 1); diff --git a/ntpd/ntp_request.c b/ntpd/ntp_request.c index 1636fdc35..6cdb1f440 100644 --- a/ntpd/ntp_request.c +++ b/ntpd/ntp_request.c @@ -1369,10 +1369,13 @@ do_conf( * * - minpoll/maxpoll, but they are treated properly * for all cases internally. Checking not necessary. + * + * Note that we ignore any previously-specified ippeerlimit. + * If we're told to create the peer, we create the peer. */ /* finally create the peer */ - if (peer_config(&peeraddr, NULL, NULL, + if (peer_config(&peeraddr, NULL, NULL, -1, temp_cp.hmode, temp_cp.version, temp_cp.minpoll, temp_cp.maxpoll, fl, temp_cp.ttl, temp_cp.keyid, NULL) == 0) diff --git a/ntpd/ntp_restrict.c b/ntpd/ntp_restrict.c index abf9e2cd2..49b68b5fb 100644 --- a/ntpd/ntp_restrict.c +++ b/ntpd/ntp_restrict.c @@ -411,19 +411,23 @@ res_sorts_before6( /* - * restrictions - return restrictions for this host + * restrictions - return restrictions for this host in *r4a */ -u_short +void restrictions( - sockaddr_u *srcadr + sockaddr_u *srcadr, + r4addr *r4a ) { restrict_u *match; struct in6_addr *pin6; - u_short flags; + + REQUIRE(NULL != r4a); res_calls++; - flags = 0; + r4a->rflags = RES_IGNORE; + r4a->ippeerlimit = 0; + /* IPv4 source address */ if (IS_IPV4(srcadr)) { /* @@ -432,7 +436,7 @@ restrictions( * not later!) */ if (IN_CLASSD(SRCADR(srcadr))) - return (int)RES_IGNORE; + return; match = match_restrict4_addr(SRCADR(srcadr), SRCPORT(srcadr)); @@ -449,7 +453,8 @@ restrictions( res_not_found++; else res_found++; - flags = match->flags; + r4a->rflags = match->flags; + r4a->ippeerlimit = match->ippeerlimit; } /* IPv6 source address */ @@ -462,7 +467,7 @@ restrictions( * not later!) */ if (IN6_IS_ADDR_MULTICAST(pin6)) - return (int)RES_IGNORE; + return; match = match_restrict6_addr(pin6, SRCPORT(srcadr)); INSIST(match != NULL); @@ -471,9 +476,10 @@ restrictions( res_not_found++; else res_found++; - flags = match->flags; + r4a->rflags = match->flags; + r4a->ippeerlimit = match->ippeerlimit; } - return (flags); + return; } diff --git a/ntpd/ntpsim.c b/ntpd/ntpsim.c index b7c3218fc..5ae05b7ab 100644 --- a/ntpd/ntpsim.c +++ b/ntpd/ntpsim.c @@ -79,6 +79,7 @@ void create_server_associations(void) NULL, loopback_interface, MODE_CLIENT, + -1, NTP_VERSION, NTP_MINDPOLL, NTP_MAXDPOLL, diff --git a/tests/ntpd/ntp_restrict.c b/tests/ntpd/ntp_restrict.c index ea1a25d0a..1420323db 100644 --- a/tests/ntpd/ntp_restrict.c +++ b/tests/ntpd/ntp_restrict.c @@ -92,10 +92,11 @@ void test_ReturnsCorrectDefaultRestrictions(void) { sockaddr_u sockaddr = create_sockaddr_u(AF_INET, 54321, "63.161.169.137"); + r4addr r4a; - u_short retval = restrictions(&sockaddr); + restrictions(&sockaddr, &r4a); - TEST_ASSERT_EQUAL(0, retval); + TEST_ASSERT_EQUAL(0, r4a.rflags); } @@ -108,6 +109,7 @@ void test_HackingDefaultRestriction(void) */ const u_short flags = 42; + r4addr r4a; sockaddr_u resaddr = create_sockaddr_u(AF_INET, 54321, "0.0.0.0"); @@ -119,7 +121,8 @@ void test_HackingDefaultRestriction(void) sockaddr_u sockaddr = create_sockaddr_u(AF_INET, 54321, "111.123.251.124"); - TEST_ASSERT_EQUAL(flags, restrictions(&sockaddr)); + restrictions(&sockaddr, &r4a); + TEST_ASSERT_EQUAL(flags, r4a.rflags); } @@ -128,10 +131,12 @@ void test_CantRemoveDefaultEntry(void) { sockaddr_u resaddr = create_sockaddr_u(AF_INET, 54321, "0.0.0.0"); sockaddr_u resmask = create_sockaddr_u(AF_INET, 54321, "0.0.0.0"); + r4addr r4a; hack_restrict(RESTRICT_REMOVE, &resaddr, &resmask, -1, 0, 0, 0); - TEST_ASSERT_EQUAL(0, restrictions(&resaddr)); + restrictions(&resaddr, &r4a); + TEST_ASSERT_EQUAL(0, r4a.rflags); } @@ -140,12 +145,14 @@ void test_AddingNewRestriction(void) { sockaddr_u resaddr = create_sockaddr_u(AF_INET, 54321, "11.22.33.44"); sockaddr_u resmask = create_sockaddr_u(AF_INET, 54321, "128.0.0.0"); + r4addr r4a; const u_short flags = 42; hack_restrict(RESTRICT_FLAGS, &resaddr, &resmask, -1, 0, flags, 0); - TEST_ASSERT_EQUAL(flags, restrictions(&resaddr)); + restrictions(&resaddr, &r4a); + TEST_ASSERT_EQUAL(flags, r4a.rflags); } @@ -163,12 +170,14 @@ void test_TheMostFittingRestrictionIsMatched(void) /* it also matches, but we prefer the one above, as it's more specific */ sockaddr_u resaddr_second_match = create_sockaddr_u(AF_INET, 54321, "11.99.33.44"); sockaddr_u resmask_second_match = create_sockaddr_u(AF_INET, 54321, "255.0.0.0"); + r4addr r4a; hack_restrict(RESTRICT_FLAGS, &resaddr_not_matching, &resmask_not_matching, -1, 0, 11, 0); hack_restrict(RESTRICT_FLAGS, &resaddr_best_match, &resmask_best_match, -1, 0, 22, 0); hack_restrict(RESTRICT_FLAGS, &resaddr_second_match, &resmask_second_match, -1, 0, 128, 0); - TEST_ASSERT_EQUAL(22, restrictions(&resaddr_target)); + restrictions(&resaddr_target, &r4a); + TEST_ASSERT_EQUAL(22, r4a.rflags); } @@ -185,6 +194,7 @@ void test_DeletedRestrictionIsNotMatched(void) sockaddr_u resaddr_second_match = create_sockaddr_u(AF_INET, 54321, "11.99.33.44"); sockaddr_u resmask_second_match = create_sockaddr_u(AF_INET, 54321, "255.0.0.0"); + r4addr r4a; hack_restrict(RESTRICT_FLAGS, &resaddr_not_matching, &resmask_not_matching, -1, 0, 11, 0); hack_restrict(RESTRICT_FLAGS, &resaddr_best_match, &resmask_best_match, -1, 0, 22, 0); @@ -193,7 +203,8 @@ void test_DeletedRestrictionIsNotMatched(void) /* deleting the best match*/ hack_restrict(RESTRICT_REMOVE, &resaddr_best_match, &resmask_best_match, -1, 0, 22, 0); - TEST_ASSERT_EQUAL(128, restrictions(&resaddr_target)); + restrictions(&resaddr_target, &r4a); + TEST_ASSERT_EQUAL(128, r4a.rflags); } @@ -202,10 +213,12 @@ void test_RestrictUnflagWorks(void) { sockaddr_u resaddr = create_sockaddr_u(AF_INET, 54321, "11.22.30.20"); sockaddr_u resmask = create_sockaddr_u(AF_INET, 54321, "255.255.0.0"); + r4addr r4a; hack_restrict(RESTRICT_FLAGS, &resaddr, &resmask, -1, 0, 11, 0); hack_restrict(RESTRICT_UNFLAG, &resaddr, &resmask, -1, 0, 10, 0); - TEST_ASSERT_EQUAL(1, restrictions(&resaddr)); + restrictions(&resaddr, &r4a); + TEST_ASSERT_EQUAL(1, r4a.rflags); }