154359Sroberto/* 2132451Sroberto * ntp_restrict.c - determine host restrictions 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 554359Sroberto#include <config.h> 654359Sroberto#endif 754359Sroberto 854359Sroberto#include <stdio.h> 954359Sroberto#include <sys/types.h> 1054359Sroberto 1154359Sroberto#include "ntpd.h" 1254359Sroberto#include "ntp_if.h" 13285612Sdelphij#include "ntp_lists.h" 1454359Sroberto#include "ntp_stdlib.h" 15285612Sdelphij#include "ntp_assert.h" 1654359Sroberto 1754359Sroberto/* 1854359Sroberto * This code keeps a simple address-and-mask list of hosts we want 19132451Sroberto * to place restrictions on (or remove them from). The restrictions 2054359Sroberto * are implemented as a set of flags which tell you what the host 21132451Sroberto * can't do. There is a subroutine entry to return the flags. The 2254359Sroberto * list is kept sorted to reduce the average number of comparisons 2354359Sroberto * and make sure you get the set of restrictions most specific to 2454359Sroberto * the address. 2554359Sroberto * 2654359Sroberto * The algorithm is that, when looking up a host, it is first assumed 27132451Sroberto * that the default set of restrictions will apply. It then searches 28132451Sroberto * down through the list. Whenever it finds a match it adopts the 29132451Sroberto * match's flags instead. When you hit the point where the sorted 30132451Sroberto * address is greater than the target, you return with the last set of 31132451Sroberto * flags you found. Because of the ordering of the list, the most 32132451Sroberto * specific match will provide the final set of flags. 3354359Sroberto * 3454359Sroberto * This was originally intended to restrict you from sync'ing to your 35132451Sroberto * own broadcasts when you are doing that, by restricting yourself from 36132451Sroberto * your own interfaces. It was also thought it would sometimes be useful 37132451Sroberto * to keep a misbehaving host or two from abusing your primary clock. It 38132451Sroberto * has been expanded, however, to suit the needs of those with more 39132451Sroberto * restrictive access policies. 4054359Sroberto */ 41132451Sroberto/* 42132451Sroberto * We will use two lists, one for IPv4 addresses and one for IPv6 43132451Sroberto * addresses. This is not protocol-independant but for now I can't 44132451Sroberto * find a way to respect this. We'll check this later... JFB 07/2001 45132451Sroberto */ 46285612Sdelphij#define MASK_IPV6_ADDR(dst, src, msk) \ 47285612Sdelphij do { \ 48285612Sdelphij int idx; \ 49285612Sdelphij for (idx = 0; idx < (int)COUNTOF((dst)->s6_addr); idx++) { \ 50285612Sdelphij (dst)->s6_addr[idx] = (src)->s6_addr[idx] \ 51285612Sdelphij & (msk)->s6_addr[idx]; \ 52285612Sdelphij } \ 53132451Sroberto } while (0) 5454359Sroberto 5554359Sroberto/* 56285612Sdelphij * We allocate INC_RESLIST{4|6} entries to the free list whenever empty. 57285612Sdelphij * Auto-tune these to be just less than 1KB (leaving at least 16 bytes 58285612Sdelphij * for allocator overhead). 5954359Sroberto */ 60285612Sdelphij#define INC_RESLIST4 ((1024 - 16) / V4_SIZEOF_RESTRICT_U) 61285612Sdelphij#define INC_RESLIST6 ((1024 - 16) / V6_SIZEOF_RESTRICT_U) 6254359Sroberto 6354359Sroberto/* 6454359Sroberto * The restriction list 6554359Sroberto */ 66285612Sdelphijrestrict_u *restrictlist4; 67285612Sdelphijrestrict_u *restrictlist6; 68285612Sdelphijstatic int restrictcount; /* count in the restrict lists */ 6954359Sroberto 7054359Sroberto/* 7154359Sroberto * The free list and associated counters. Also some uninteresting 7254359Sroberto * stat counters. 7354359Sroberto */ 74285612Sdelphijstatic restrict_u *resfree4; /* available entries (free list) */ 75285612Sdelphijstatic restrict_u *resfree6; 7654359Sroberto 77285612Sdelphijstatic u_long res_calls; 78285612Sdelphijstatic u_long res_found; 79285612Sdelphijstatic u_long res_not_found; 8054359Sroberto 8154359Sroberto/* 82285612Sdelphij * Count number of restriction entries referring to RES_LIMITED, to 83285612Sdelphij * control implicit activation/deactivation of the MRU monlist. 8454359Sroberto */ 85285612Sdelphijstatic u_long res_limited_refcnt; 86132451Sroberto 8754359Sroberto/* 88285612Sdelphij * Our default entries. 89330141Sdelphij * 90330141Sdelphij * We can make this cleaner with c99 support: see init_restrict(). 9154359Sroberto */ 92285612Sdelphijstatic restrict_u restrict_def4; 93285612Sdelphijstatic restrict_u restrict_def6; 9454359Sroberto 9554359Sroberto/* 96285612Sdelphij * "restrict source ..." enabled knob and restriction bits. 9754359Sroberto */ 98285612Sdelphijstatic int restrict_source_enabled; 99330141Sdelphijstatic u_short restrict_source_rflags; 100285612Sdelphijstatic u_short restrict_source_mflags; 101330141Sdelphijstatic short restrict_source_ippeerlimit; 10254359Sroberto 10354359Sroberto/* 104285612Sdelphij * private functions 105285612Sdelphij */ 106285612Sdelphijstatic restrict_u * alloc_res4(void); 107285612Sdelphijstatic restrict_u * alloc_res6(void); 108285612Sdelphijstatic void free_res(restrict_u *, int); 109285612Sdelphijstatic void inc_res_limited(void); 110285612Sdelphijstatic void dec_res_limited(void); 111285612Sdelphijstatic restrict_u * match_restrict4_addr(u_int32, u_short); 112285612Sdelphijstatic restrict_u * match_restrict6_addr(const struct in6_addr *, 113285612Sdelphij u_short); 114285612Sdelphijstatic restrict_u * match_restrict_entry(const restrict_u *, int); 115285612Sdelphijstatic int res_sorts_before4(restrict_u *, restrict_u *); 116285612Sdelphijstatic int res_sorts_before6(restrict_u *, restrict_u *); 117330141Sdelphijstatic char * roptoa(restrict_op op); 118285612Sdelphij 119285612Sdelphij 120330141Sdelphijvoid dump_restricts(void); 121330141Sdelphij 122285612Sdelphij/* 123330141Sdelphij * dump_restrict - spit out a restrict_u 124330141Sdelphij */ 125330141Sdelphijstatic void 126330141Sdelphijdump_restrict( 127330141Sdelphij restrict_u * res, 128330141Sdelphij int is_ipv6 129330141Sdelphij ) 130330141Sdelphij{ 131330141Sdelphij char as[INET6_ADDRSTRLEN]; 132330141Sdelphij char ms[INET6_ADDRSTRLEN]; 133330141Sdelphij 134330141Sdelphij if (is_ipv6) { 135330141Sdelphij inet_ntop(AF_INET6, &res->u.v6.addr, as, sizeof as); 136330141Sdelphij inet_ntop(AF_INET6, &res->u.v6.mask, ms, sizeof ms); 137330141Sdelphij } else { 138330141Sdelphij struct in_addr sia = { htonl(res->u.v4.addr) }; 139330141Sdelphij struct in_addr sim = { htonl(res->u.v4.mask) }; 140330141Sdelphij 141330141Sdelphij inet_ntop(AF_INET, &sia, as, sizeof as); 142330141Sdelphij inet_ntop(AF_INET, &sim, ms, sizeof ms); 143330141Sdelphij } 144330141Sdelphij mprintf("restrict node at %p: %s/%s count %d, rflags %05x, mflags %05x, ippeerlimit %d, expire %lu, next %p\n", 145330141Sdelphij res, as, ms, res->count, res->rflags, res->mflags, 146330141Sdelphij res->ippeerlimit, res->expire, res->link); 147330141Sdelphij return; 148330141Sdelphij} 149330141Sdelphij 150330141Sdelphij 151330141Sdelphij/* 152330141Sdelphij * dump_restricts - spit out the 'restrict' lines 153330141Sdelphij */ 154330141Sdelphijvoid 155330141Sdelphijdump_restricts(void) 156330141Sdelphij{ 157330141Sdelphij int defaultv4_done = 0; 158330141Sdelphij int defaultv6_done = 0; 159330141Sdelphij restrict_u * res; 160330141Sdelphij restrict_u * next; 161330141Sdelphij 162330141Sdelphij mprintf("dump_restrict: restrict_def4: %p\n", &restrict_def4); 163330141Sdelphij /* Spit out 'restrict {,-4,-6} default ...' lines, if needed */ 164330141Sdelphij for (res = &restrict_def4; res != NULL; res = next) { 165330141Sdelphij dump_restrict(res, 0); 166330141Sdelphij next = res->link; 167330141Sdelphij } 168330141Sdelphij 169330141Sdelphij mprintf("dump_restrict: restrict_def6: %p\n", &restrict_def6); 170330141Sdelphij for (res = &restrict_def6; res != NULL; res = next) { 171330141Sdelphij dump_restrict(res, 1); 172330141Sdelphij next = res->link; 173330141Sdelphij } 174330141Sdelphij 175330141Sdelphij /* Spit out the IPv4 list */ 176330141Sdelphij mprintf("dump_restrict: restrictlist4: %p\n", &restrictlist4); 177330141Sdelphij for (res = restrictlist4; res != NULL; res = next) { 178330141Sdelphij dump_restrict(res, 0); 179330141Sdelphij next = res->link; 180330141Sdelphij } 181330141Sdelphij 182330141Sdelphij /* Spit out the IPv6 list */ 183330141Sdelphij mprintf("dump_restrict: restrictlist6: %p\n", &restrictlist6); 184330141Sdelphij for (res = restrictlist6; res != NULL; res = next) { 185330141Sdelphij dump_restrict(res, 1); 186330141Sdelphij next = res->link; 187330141Sdelphij } 188330141Sdelphij 189330141Sdelphij return; 190330141Sdelphij} 191330141Sdelphij 192330141Sdelphij/* 19354359Sroberto * init_restrict - initialize the restriction data structures 19454359Sroberto */ 19554359Srobertovoid 19654359Srobertoinit_restrict(void) 19754359Sroberto{ 19854359Sroberto /* 199285612Sdelphij * The restriction lists begin with a default entry with address 200285612Sdelphij * and mask 0, which will match any entry. The lists are kept 201285612Sdelphij * sorted by descending address followed by descending mask: 202285612Sdelphij * 203285612Sdelphij * address mask 204285612Sdelphij * 192.168.0.0 255.255.255.0 kod limited noquery nopeer 205285612Sdelphij * 192.168.0.0 255.255.0.0 kod limited 206285612Sdelphij * 0.0.0.0 0.0.0.0 kod limited noquery 207285612Sdelphij * 208285612Sdelphij * The first entry which matches an address is used. With the 209285612Sdelphij * example restrictions above, 192.168.0.0/24 matches the first 210285612Sdelphij * entry, the rest of 192.168.0.0/16 matches the second, and 211285612Sdelphij * everything else matches the third (default). 212285612Sdelphij * 213285612Sdelphij * Note this achieves the same result a little more efficiently 214285612Sdelphij * than the documented behavior, which is to keep the lists 215285612Sdelphij * sorted by ascending address followed by ascending mask, with 216285612Sdelphij * the _last_ matching entry used. 217285612Sdelphij * 218285612Sdelphij * An additional wrinkle is we may have multiple entries with 219285612Sdelphij * the same address and mask but differing match flags (mflags). 220285612Sdelphij * At present there is only one, RESM_NTPONLY. Entries with 221285612Sdelphij * RESM_NTPONLY are sorted earlier so they take precedence over 222285612Sdelphij * any otherwise similar entry without. Again, this is the same 223285612Sdelphij * behavior as but reversed implementation compared to the docs. 224285612Sdelphij * 22554359Sroberto */ 226330141Sdelphij 227330141Sdelphij restrict_def4.ippeerlimit = -1; /* Cleaner if we have C99 */ 228330141Sdelphij restrict_def6.ippeerlimit = -1; /* Cleaner if we have C99 */ 229330141Sdelphij 230285612Sdelphij LINK_SLIST(restrictlist4, &restrict_def4, link); 231285612Sdelphij LINK_SLIST(restrictlist6, &restrict_def6, link); 232285612Sdelphij restrictcount = 2; 233285612Sdelphij} 234285612Sdelphij 235285612Sdelphij 236285612Sdelphijstatic restrict_u * 237285612Sdelphijalloc_res4(void) 238285612Sdelphij{ 239285612Sdelphij const size_t cb = V4_SIZEOF_RESTRICT_U; 240285612Sdelphij const size_t count = INC_RESLIST4; 241285612Sdelphij restrict_u * rl; 242285612Sdelphij restrict_u * res; 243293650Sglebius size_t i; 244285612Sdelphij 245285612Sdelphij UNLINK_HEAD_SLIST(res, resfree4, link); 246285612Sdelphij if (res != NULL) 247285612Sdelphij return res; 248285612Sdelphij 249316069Sdelphij rl = eallocarray(count, cb); 250285612Sdelphij /* link all but the first onto free list */ 251285612Sdelphij res = (void *)((char *)rl + (count - 1) * cb); 252285612Sdelphij for (i = count - 1; i > 0; i--) { 253285612Sdelphij LINK_SLIST(resfree4, res, link); 254285612Sdelphij res = (void *)((char *)res - cb); 25554359Sroberto } 256289997Sglebius INSIST(rl == res); 257285612Sdelphij /* allocate the first */ 258285612Sdelphij return res; 259285612Sdelphij} 26054359Sroberto 26154359Sroberto 262285612Sdelphijstatic restrict_u * 263285612Sdelphijalloc_res6(void) 264285612Sdelphij{ 265285612Sdelphij const size_t cb = V6_SIZEOF_RESTRICT_U; 266285612Sdelphij const size_t count = INC_RESLIST6; 267285612Sdelphij restrict_u * rl; 268285612Sdelphij restrict_u * res; 269293650Sglebius size_t i; 27054359Sroberto 271285612Sdelphij UNLINK_HEAD_SLIST(res, resfree6, link); 272285612Sdelphij if (res != NULL) 273285612Sdelphij return res; 274285612Sdelphij 275316069Sdelphij rl = eallocarray(count, cb); 276285612Sdelphij /* link all but the first onto free list */ 277285612Sdelphij res = (void *)((char *)rl + (count - 1) * cb); 278285612Sdelphij for (i = count - 1; i > 0; i--) { 279285612Sdelphij LINK_SLIST(resfree6, res, link); 280285612Sdelphij res = (void *)((char *)res - cb); 281285612Sdelphij } 282289997Sglebius INSIST(rl == res); 283285612Sdelphij /* allocate the first */ 284285612Sdelphij return res; 28554359Sroberto} 28654359Sroberto 28754359Sroberto 288285612Sdelphijstatic void 289285612Sdelphijfree_res( 290285612Sdelphij restrict_u * res, 291285612Sdelphij int v6 292285612Sdelphij ) 293285612Sdelphij{ 294285612Sdelphij restrict_u ** plisthead; 295285612Sdelphij restrict_u * unlinked; 296285612Sdelphij 297285612Sdelphij restrictcount--; 298330141Sdelphij if (RES_LIMITED & res->rflags) 299285612Sdelphij dec_res_limited(); 300285612Sdelphij 301285612Sdelphij if (v6) 302285612Sdelphij plisthead = &restrictlist6; 303285612Sdelphij else 304285612Sdelphij plisthead = &restrictlist4; 305285612Sdelphij UNLINK_SLIST(unlinked, *plisthead, res, link, restrict_u); 306289997Sglebius INSIST(unlinked == res); 307285612Sdelphij 308285612Sdelphij if (v6) { 309285612Sdelphij zero_mem(res, V6_SIZEOF_RESTRICT_U); 310285612Sdelphij plisthead = &resfree6; 311285612Sdelphij } else { 312285612Sdelphij zero_mem(res, V4_SIZEOF_RESTRICT_U); 313285612Sdelphij plisthead = &resfree4; 314285612Sdelphij } 315285612Sdelphij LINK_SLIST(*plisthead, res, link); 316285612Sdelphij} 317285612Sdelphij 318285612Sdelphij 319285612Sdelphijstatic void 320285612Sdelphijinc_res_limited(void) 321285612Sdelphij{ 322285612Sdelphij if (!res_limited_refcnt) 323285612Sdelphij mon_start(MON_RES); 324285612Sdelphij res_limited_refcnt++; 325285612Sdelphij} 326285612Sdelphij 327285612Sdelphij 328285612Sdelphijstatic void 329285612Sdelphijdec_res_limited(void) 330285612Sdelphij{ 331285612Sdelphij res_limited_refcnt--; 332285612Sdelphij if (!res_limited_refcnt) 333285612Sdelphij mon_stop(MON_RES); 334285612Sdelphij} 335285612Sdelphij 336285612Sdelphij 337285612Sdelphijstatic restrict_u * 338285612Sdelphijmatch_restrict4_addr( 339285612Sdelphij u_int32 addr, 340285612Sdelphij u_short port 341285612Sdelphij ) 342285612Sdelphij{ 343285612Sdelphij const int v6 = 0; 344285612Sdelphij restrict_u * res; 345285612Sdelphij restrict_u * next; 346285612Sdelphij 347285612Sdelphij for (res = restrictlist4; res != NULL; res = next) { 348330141Sdelphij struct in_addr sia = { htonl(res->u.v4.addr) }; 349330141Sdelphij 350285612Sdelphij next = res->link; 351330141Sdelphij DPRINTF(2, ("match_restrict4_addr: Checking %s, port %d ... ", 352330141Sdelphij inet_ntoa(sia), port)); 353330141Sdelphij if ( res->expire 354330141Sdelphij && res->expire <= current_time) 355330141Sdelphij free_res(res, v6); /* zeroes the contents */ 356330141Sdelphij if ( res->u.v4.addr == (addr & res->u.v4.mask) 357330141Sdelphij && ( !(RESM_NTPONLY & res->mflags) 358330141Sdelphij || NTP_PORT == port)) { 359330141Sdelphij DPRINTF(2, ("MATCH: ippeerlimit %d\n", res->ippeerlimit)); 360285612Sdelphij break; 361330141Sdelphij } 362330141Sdelphij DPRINTF(2, ("doesn't match: ippeerlimit %d\n", res->ippeerlimit)); 363285612Sdelphij } 364285612Sdelphij return res; 365285612Sdelphij} 366285612Sdelphij 367285612Sdelphij 368285612Sdelphijstatic restrict_u * 369285612Sdelphijmatch_restrict6_addr( 370285612Sdelphij const struct in6_addr * addr, 371285612Sdelphij u_short port 372285612Sdelphij ) 373285612Sdelphij{ 374285612Sdelphij const int v6 = 1; 375285612Sdelphij restrict_u * res; 376285612Sdelphij restrict_u * next; 377285612Sdelphij struct in6_addr masked; 378285612Sdelphij 379285612Sdelphij for (res = restrictlist6; res != NULL; res = next) { 380285612Sdelphij next = res->link; 381289997Sglebius INSIST(next != res); 382285612Sdelphij if (res->expire && 383285612Sdelphij res->expire <= current_time) 384285612Sdelphij free_res(res, v6); 385285612Sdelphij MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask); 386285612Sdelphij if (ADDR6_EQ(&masked, &res->u.v6.addr) 387285612Sdelphij && (!(RESM_NTPONLY & res->mflags) 388285612Sdelphij || NTP_PORT == (int)port)) 389285612Sdelphij break; 390285612Sdelphij } 391285612Sdelphij return res; 392285612Sdelphij} 393285612Sdelphij 394285612Sdelphij 39554359Sroberto/* 396285612Sdelphij * match_restrict_entry - find an exact match on a restrict list. 397285612Sdelphij * 398285612Sdelphij * Exact match is addr, mask, and mflags all equal. 399285612Sdelphij * In order to use more common code for IPv4 and IPv6, this routine 400285612Sdelphij * requires the caller to populate a restrict_u with mflags and either 401285612Sdelphij * the v4 or v6 address and mask as appropriate. Other fields in the 402285612Sdelphij * input restrict_u are ignored. 403285612Sdelphij */ 404285612Sdelphijstatic restrict_u * 405285612Sdelphijmatch_restrict_entry( 406285612Sdelphij const restrict_u * pmatch, 407285612Sdelphij int v6 408285612Sdelphij ) 409285612Sdelphij{ 410285612Sdelphij restrict_u *res; 411285612Sdelphij restrict_u *rlist; 412285612Sdelphij size_t cb; 413285612Sdelphij 414285612Sdelphij if (v6) { 415285612Sdelphij rlist = restrictlist6; 416285612Sdelphij cb = sizeof(pmatch->u.v6); 417285612Sdelphij } else { 418285612Sdelphij rlist = restrictlist4; 419285612Sdelphij cb = sizeof(pmatch->u.v4); 420285612Sdelphij } 421285612Sdelphij 422285612Sdelphij for (res = rlist; res != NULL; res = res->link) 423285612Sdelphij if (res->mflags == pmatch->mflags && 424285612Sdelphij !memcmp(&res->u, &pmatch->u, cb)) 425285612Sdelphij break; 426285612Sdelphij return res; 427285612Sdelphij} 428285612Sdelphij 429285612Sdelphij 430285612Sdelphij/* 431285612Sdelphij * res_sorts_before4 - compare two restrict4 entries 432285612Sdelphij * 433285612Sdelphij * Returns nonzero if r1 sorts before r2. We sort by descending 434285612Sdelphij * address, then descending mask, then descending mflags, so sorting 435285612Sdelphij * before means having a higher value. 436285612Sdelphij */ 437285612Sdelphijstatic int 438285612Sdelphijres_sorts_before4( 439285612Sdelphij restrict_u *r1, 440285612Sdelphij restrict_u *r2 441285612Sdelphij ) 442285612Sdelphij{ 443285612Sdelphij int r1_before_r2; 444285612Sdelphij 445285612Sdelphij if (r1->u.v4.addr > r2->u.v4.addr) 446285612Sdelphij r1_before_r2 = 1; 447285612Sdelphij else if (r1->u.v4.addr < r2->u.v4.addr) 448285612Sdelphij r1_before_r2 = 0; 449285612Sdelphij else if (r1->u.v4.mask > r2->u.v4.mask) 450285612Sdelphij r1_before_r2 = 1; 451285612Sdelphij else if (r1->u.v4.mask < r2->u.v4.mask) 452285612Sdelphij r1_before_r2 = 0; 453285612Sdelphij else if (r1->mflags > r2->mflags) 454285612Sdelphij r1_before_r2 = 1; 455285612Sdelphij else 456285612Sdelphij r1_before_r2 = 0; 457285612Sdelphij 458285612Sdelphij return r1_before_r2; 459285612Sdelphij} 460285612Sdelphij 461285612Sdelphij 462285612Sdelphij/* 463285612Sdelphij * res_sorts_before6 - compare two restrict6 entries 464285612Sdelphij * 465285612Sdelphij * Returns nonzero if r1 sorts before r2. We sort by descending 466285612Sdelphij * address, then descending mask, then descending mflags, so sorting 467285612Sdelphij * before means having a higher value. 468285612Sdelphij */ 469285612Sdelphijstatic int 470285612Sdelphijres_sorts_before6( 471285612Sdelphij restrict_u *r1, 472285612Sdelphij restrict_u *r2 473285612Sdelphij ) 474285612Sdelphij{ 475285612Sdelphij int r1_before_r2; 476285612Sdelphij int cmp; 477285612Sdelphij 478285612Sdelphij cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr); 479285612Sdelphij if (cmp > 0) /* r1->addr > r2->addr */ 480285612Sdelphij r1_before_r2 = 1; 481285612Sdelphij else if (cmp < 0) /* r2->addr > r1->addr */ 482285612Sdelphij r1_before_r2 = 0; 483285612Sdelphij else { 484285612Sdelphij cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask); 485285612Sdelphij if (cmp > 0) /* r1->mask > r2->mask*/ 486285612Sdelphij r1_before_r2 = 1; 487285612Sdelphij else if (cmp < 0) /* r2->mask > r1->mask */ 488285612Sdelphij r1_before_r2 = 0; 489285612Sdelphij else if (r1->mflags > r2->mflags) 490285612Sdelphij r1_before_r2 = 1; 491285612Sdelphij else 492285612Sdelphij r1_before_r2 = 0; 493285612Sdelphij } 494285612Sdelphij 495285612Sdelphij return r1_before_r2; 496285612Sdelphij} 497285612Sdelphij 498285612Sdelphij 499285612Sdelphij/* 500330141Sdelphij * restrictions - return restrictions for this host in *r4a 50154359Sroberto */ 502330141Sdelphijvoid 50354359Srobertorestrictions( 504330141Sdelphij sockaddr_u *srcadr, 505330141Sdelphij r4addr *r4a 50654359Sroberto ) 50754359Sroberto{ 508285612Sdelphij restrict_u *match; 509285612Sdelphij struct in6_addr *pin6; 51054359Sroberto 511330141Sdelphij REQUIRE(NULL != r4a); 512330141Sdelphij 51354359Sroberto res_calls++; 514330141Sdelphij r4a->rflags = RES_IGNORE; 515330141Sdelphij r4a->ippeerlimit = 0; 516330141Sdelphij 517330141Sdelphij DPRINTF(1, ("restrictions: looking up %s\n", stoa(srcadr))); 518330141Sdelphij 519285612Sdelphij /* IPv4 source address */ 520285612Sdelphij if (IS_IPV4(srcadr)) { 521132451Sroberto /* 522132451Sroberto * Ignore any packets with a multicast source address 523132451Sroberto * (this should be done early in the receive process, 524285612Sdelphij * not later!) 525132451Sroberto */ 526330141Sdelphij if (IN_CLASSD(SRCADR(srcadr))) { 527330141Sdelphij DPRINTF(1, ("restrictions: srcadr %s is multicast\n", stoa(srcadr))); 528330141Sdelphij r4a->ippeerlimit = 2; /* XXX: we should use a better value */ 529330141Sdelphij return; 530330141Sdelphij } 53154359Sroberto 532285612Sdelphij match = match_restrict4_addr(SRCADR(srcadr), 533285612Sdelphij SRCPORT(srcadr)); 534289997Sglebius 535289997Sglebius INSIST(match != NULL); 536289997Sglebius 537285612Sdelphij match->count++; 538132451Sroberto /* 539285612Sdelphij * res_not_found counts only use of the final default 540285612Sdelphij * entry, not any "restrict default ntpport ...", which 541285612Sdelphij * would be just before the final default. 542132451Sroberto */ 543285612Sdelphij if (&restrict_def4 == match) 544132451Sroberto res_not_found++; 545132451Sroberto else 546132451Sroberto res_found++; 547330141Sdelphij r4a->rflags = match->rflags; 548330141Sdelphij r4a->ippeerlimit = match->ippeerlimit; 549132451Sroberto } 55054359Sroberto 551132451Sroberto /* IPv6 source address */ 552285612Sdelphij if (IS_IPV6(srcadr)) { 553285612Sdelphij pin6 = PSOCK_ADDR6(srcadr); 55454359Sroberto 555132451Sroberto /* 556132451Sroberto * Ignore any packets with a multicast source address 557132451Sroberto * (this should be done early in the receive process, 558285612Sdelphij * not later!) 559132451Sroberto */ 560285612Sdelphij if (IN6_IS_ADDR_MULTICAST(pin6)) 561330141Sdelphij return; 56254359Sroberto 563285612Sdelphij match = match_restrict6_addr(pin6, SRCPORT(srcadr)); 564289997Sglebius INSIST(match != NULL); 565285612Sdelphij match->count++; 566285612Sdelphij if (&restrict_def6 == match) 567132451Sroberto res_not_found++; 568132451Sroberto else 569132451Sroberto res_found++; 570330141Sdelphij r4a->rflags = match->rflags; 571330141Sdelphij r4a->ippeerlimit = match->ippeerlimit; 57254359Sroberto } 573330141Sdelphij return; 57454359Sroberto} 57554359Sroberto 57654359Sroberto 57754359Sroberto/* 578330141Sdelphij * roptoa - convert a restrict_op to a string 579330141Sdelphij */ 580330141Sdelphijchar * 581330141Sdelphijroptoa(restrict_op op) { 582330141Sdelphij static char sb[30]; 583330141Sdelphij 584330141Sdelphij switch(op) { 585330141Sdelphij case RESTRICT_FLAGS: return "RESTRICT_FLAGS"; 586330141Sdelphij case RESTRICT_UNFLAG: return "RESTRICT_UNFLAGS"; 587330141Sdelphij case RESTRICT_REMOVE: return "RESTRICT_REMOVE"; 588330141Sdelphij case RESTRICT_REMOVEIF: return "RESTRICT_REMOVEIF"; 589330141Sdelphij default: 590330141Sdelphij snprintf(sb, sizeof sb, "**RESTRICT_#%d**", op); 591330141Sdelphij return sb; 592330141Sdelphij } 593330141Sdelphij} 594330141Sdelphij 595330141Sdelphij 596330141Sdelphij/* 59754359Sroberto * hack_restrict - add/subtract/manipulate entries on the restrict list 59854359Sroberto */ 59954359Srobertovoid 60054359Srobertohack_restrict( 601330141Sdelphij restrict_op op, 602285612Sdelphij sockaddr_u * resaddr, 603285612Sdelphij sockaddr_u * resmask, 604330141Sdelphij short ippeerlimit, 605285612Sdelphij u_short mflags, 606330141Sdelphij u_short rflags, 607285612Sdelphij u_long expire 60854359Sroberto ) 60954359Sroberto{ 610285612Sdelphij int v6; 611285612Sdelphij restrict_u match; 612285612Sdelphij restrict_u * res; 613285612Sdelphij restrict_u ** plisthead; 61454359Sroberto 615330141Sdelphij DPRINTF(1, ("hack_restrict: op %s addr %s mask %s ippeerlimit %d mflags %08x rflags %08x\n", 616330141Sdelphij roptoa(op), stoa(resaddr), stoa(resmask), ippeerlimit, mflags, rflags)); 617285612Sdelphij 618285612Sdelphij if (NULL == resaddr) { 619289997Sglebius REQUIRE(NULL == resmask); 620289997Sglebius REQUIRE(RESTRICT_FLAGS == op); 621330141Sdelphij restrict_source_rflags = rflags; 622285612Sdelphij restrict_source_mflags = mflags; 623330141Sdelphij restrict_source_ippeerlimit = ippeerlimit; 624285612Sdelphij restrict_source_enabled = 1; 625285612Sdelphij return; 626285612Sdelphij } 627285612Sdelphij 628285612Sdelphij ZERO(match); 629289997Sglebius 630289997Sglebius#if 0 631285612Sdelphij /* silence VC9 potentially uninit warnings */ 632289997Sglebius // HMS: let's use a compiler-specific "enable" for this. 633285612Sdelphij res = NULL; 634285612Sdelphij v6 = 0; 635289997Sglebius#endif 636285612Sdelphij 637285612Sdelphij if (IS_IPV4(resaddr)) { 638285612Sdelphij v6 = 0; 639132451Sroberto /* 640285612Sdelphij * Get address and mask in host byte order for easy 641285612Sdelphij * comparison as u_int32 642132451Sroberto */ 643285612Sdelphij match.u.v4.addr = SRCADR(resaddr); 644285612Sdelphij match.u.v4.mask = SRCADR(resmask); 645285612Sdelphij match.u.v4.addr &= match.u.v4.mask; 64654359Sroberto 647285612Sdelphij } else if (IS_IPV6(resaddr)) { 648285612Sdelphij v6 = 1; 649132451Sroberto /* 650285612Sdelphij * Get address and mask in network byte order for easy 651285612Sdelphij * comparison as byte sequences (e.g. memcmp()) 652132451Sroberto */ 653285612Sdelphij match.u.v6.mask = SOCK_ADDR6(resmask); 654285612Sdelphij MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr), 655285612Sdelphij &match.u.v6.mask); 656132451Sroberto 657285612Sdelphij } else /* not IPv4 nor IPv6 */ 658289997Sglebius REQUIRE(0); 659132451Sroberto 660330141Sdelphij match.rflags = rflags; 661285612Sdelphij match.mflags = mflags; 662330141Sdelphij match.ippeerlimit = ippeerlimit; 663285612Sdelphij match.expire = expire; 664285612Sdelphij res = match_restrict_entry(&match, v6); 665132451Sroberto 666285612Sdelphij switch (op) { 667285612Sdelphij 668285612Sdelphij case RESTRICT_FLAGS: 669285612Sdelphij /* 670330141Sdelphij * Here we add bits to the rflags. If this is a 671285612Sdelphij * new restriction add it. 672285612Sdelphij */ 673285612Sdelphij if (NULL == res) { 674285612Sdelphij if (v6) { 675285612Sdelphij res = alloc_res6(); 676285612Sdelphij memcpy(res, &match, 677285612Sdelphij V6_SIZEOF_RESTRICT_U); 678285612Sdelphij plisthead = &restrictlist6; 679285612Sdelphij } else { 680285612Sdelphij res = alloc_res4(); 681285612Sdelphij memcpy(res, &match, 682285612Sdelphij V4_SIZEOF_RESTRICT_U); 683285612Sdelphij plisthead = &restrictlist4; 68454359Sroberto } 685285612Sdelphij LINK_SORT_SLIST( 686285612Sdelphij *plisthead, res, 687285612Sdelphij (v6) 688285612Sdelphij ? res_sorts_before6(res, L_S_S_CUR()) 689285612Sdelphij : res_sorts_before4(res, L_S_S_CUR()), 690285612Sdelphij link, restrict_u); 691285612Sdelphij restrictcount++; 692330141Sdelphij if (RES_LIMITED & rflags) 693285612Sdelphij inc_res_limited(); 694285612Sdelphij } else { 695330141Sdelphij if ( (RES_LIMITED & rflags) 696330141Sdelphij && !(RES_LIMITED & res->rflags)) 697285612Sdelphij inc_res_limited(); 698330141Sdelphij res->rflags |= rflags; 69954359Sroberto } 700330141Sdelphij 701330141Sdelphij res->ippeerlimit = match.ippeerlimit; 702330141Sdelphij 703285612Sdelphij break; 704132451Sroberto 705285612Sdelphij case RESTRICT_UNFLAG: 706285612Sdelphij /* 707330141Sdelphij * Remove some bits from the rflags. If we didn't 708285612Sdelphij * find this one, just return. 709285612Sdelphij */ 710285612Sdelphij if (res != NULL) { 711330141Sdelphij if ( (RES_LIMITED & res->rflags) 712330141Sdelphij && (RES_LIMITED & rflags)) 713285612Sdelphij dec_res_limited(); 714330141Sdelphij res->rflags &= ~rflags; 715285612Sdelphij } 716285612Sdelphij break; 71754359Sroberto 718285612Sdelphij case RESTRICT_REMOVE: 719285612Sdelphij case RESTRICT_REMOVEIF: 720285612Sdelphij /* 721285612Sdelphij * Remove an entry from the table entirely if we 722285612Sdelphij * found one. Don't remove the default entry and 723285612Sdelphij * don't remove an interface entry. 724285612Sdelphij */ 725285612Sdelphij if (res != NULL 726285612Sdelphij && (RESTRICT_REMOVEIF == op 727285612Sdelphij || !(RESM_INTERFACE & res->mflags)) 728285612Sdelphij && res != &restrict_def4 729285612Sdelphij && res != &restrict_def6) 730285612Sdelphij free_res(res, v6); 731285612Sdelphij break; 73254359Sroberto 733285612Sdelphij default: /* unknown op */ 734289997Sglebius INSIST(0); 735285612Sdelphij break; 736285612Sdelphij } 73754359Sroberto 738285612Sdelphij} 73954359Sroberto 740132451Sroberto 741285612Sdelphij/* 742285612Sdelphij * restrict_source - maintains dynamic "restrict source ..." entries as 743285612Sdelphij * peers come and go. 744285612Sdelphij */ 745285612Sdelphijvoid 746285612Sdelphijrestrict_source( 747285612Sdelphij sockaddr_u * addr, 748285612Sdelphij int farewell, /* 0 to add, 1 to remove */ 749285612Sdelphij u_long expire /* 0 is infinite, valid until */ 750285612Sdelphij ) 751285612Sdelphij{ 752285612Sdelphij sockaddr_u onesmask; 753285612Sdelphij restrict_u * res; 754285612Sdelphij int found_specific; 755132451Sroberto 756285612Sdelphij if (!restrict_source_enabled || SOCK_UNSPEC(addr) || 757285612Sdelphij IS_MCAST(addr) || ISREFCLOCKADR(addr)) 758285612Sdelphij return; 759132451Sroberto 760289997Sglebius REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr)); 761132451Sroberto 762285612Sdelphij SET_HOSTMASK(&onesmask, AF(addr)); 763285612Sdelphij if (farewell) { 764285612Sdelphij hack_restrict(RESTRICT_REMOVE, addr, &onesmask, 765330141Sdelphij -2, 0, 0, 0); 766285612Sdelphij DPRINTF(1, ("restrict_source: %s removed", stoa(addr))); 767285612Sdelphij return; 768285612Sdelphij } 76954359Sroberto 770285612Sdelphij /* 771285612Sdelphij * If there is a specific entry for this address, hands 772285612Sdelphij * off, as it is condidered more specific than "restrict 773285612Sdelphij * server ...". 774285612Sdelphij * However, if the specific entry found is a fleeting one 775285612Sdelphij * added by pool_xmit() before soliciting, replace it 776285612Sdelphij * immediately regardless of the expire value to make way 777285612Sdelphij * for the more persistent entry. 778285612Sdelphij */ 779285612Sdelphij if (IS_IPV4(addr)) { 780285612Sdelphij res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr)); 781289997Sglebius INSIST(res != NULL); 782285612Sdelphij found_specific = (SRCADR(&onesmask) == res->u.v4.mask); 783285612Sdelphij } else { 784285612Sdelphij res = match_restrict6_addr(&SOCK_ADDR6(addr), 785285612Sdelphij SRCPORT(addr)); 786289997Sglebius INSIST(res != NULL); 787285612Sdelphij found_specific = ADDR6_EQ(&res->u.v6.mask, 788285612Sdelphij &SOCK_ADDR6(&onesmask)); 789285612Sdelphij } 790285612Sdelphij if (!expire && found_specific && res->expire) { 791285612Sdelphij found_specific = 0; 792285612Sdelphij free_res(res, IS_IPV6(addr)); 793285612Sdelphij } 794285612Sdelphij if (found_specific) 795285612Sdelphij return; 796132451Sroberto 797285612Sdelphij hack_restrict(RESTRICT_FLAGS, addr, &onesmask, 798330141Sdelphij restrict_source_ippeerlimit, restrict_source_mflags, 799330141Sdelphij restrict_source_rflags, expire); 800285612Sdelphij DPRINTF(1, ("restrict_source: %s host restriction added\n", 801285612Sdelphij stoa(addr))); 80254359Sroberto} 803