1c0b746e5SOllivier Robert /* 29c2daa00SOllivier Robert * ntp_restrict.c - determine host restrictions 3c0b746e5SOllivier Robert */ 4c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 5c0b746e5SOllivier Robert #include <config.h> 6c0b746e5SOllivier Robert #endif 7c0b746e5SOllivier Robert 8c0b746e5SOllivier Robert #include <stdio.h> 9c0b746e5SOllivier Robert #include <sys/types.h> 10c0b746e5SOllivier Robert 11c0b746e5SOllivier Robert #include "ntpd.h" 12c0b746e5SOllivier Robert #include "ntp_if.h" 132b15cb3dSCy Schubert #include "ntp_lists.h" 14c0b746e5SOllivier Robert #include "ntp_stdlib.h" 152b15cb3dSCy Schubert #include "ntp_assert.h" 16c0b746e5SOllivier Robert 17c0b746e5SOllivier Robert /* 18c0b746e5SOllivier Robert * This code keeps a simple address-and-mask list of hosts we want 19c0b746e5SOllivier Robert * to place restrictions on (or remove them from). The restrictions 20c0b746e5SOllivier Robert * are implemented as a set of flags which tell you what the host 21c0b746e5SOllivier Robert * can't do. There is a subroutine entry to return the flags. The 22c0b746e5SOllivier Robert * list is kept sorted to reduce the average number of comparisons 23c0b746e5SOllivier Robert * and make sure you get the set of restrictions most specific to 24c0b746e5SOllivier Robert * the address. 25c0b746e5SOllivier Robert * 26c0b746e5SOllivier Robert * The algorithm is that, when looking up a host, it is first assumed 27c0b746e5SOllivier Robert * that the default set of restrictions will apply. It then searches 289c2daa00SOllivier Robert * down through the list. Whenever it finds a match it adopts the 299c2daa00SOllivier Robert * match's flags instead. When you hit the point where the sorted 309c2daa00SOllivier Robert * address is greater than the target, you return with the last set of 319c2daa00SOllivier Robert * flags you found. Because of the ordering of the list, the most 329c2daa00SOllivier Robert * specific match will provide the final set of flags. 33c0b746e5SOllivier Robert * 34c0b746e5SOllivier Robert * This was originally intended to restrict you from sync'ing to your 359c2daa00SOllivier Robert * own broadcasts when you are doing that, by restricting yourself from 369c2daa00SOllivier Robert * your own interfaces. It was also thought it would sometimes be useful 379c2daa00SOllivier Robert * to keep a misbehaving host or two from abusing your primary clock. It 389c2daa00SOllivier Robert * has been expanded, however, to suit the needs of those with more 399c2daa00SOllivier Robert * restrictive access policies. 40c0b746e5SOllivier Robert */ 419c2daa00SOllivier Robert /* 429c2daa00SOllivier Robert * We will use two lists, one for IPv4 addresses and one for IPv6 439c2daa00SOllivier Robert * addresses. This is not protocol-independant but for now I can't 449c2daa00SOllivier Robert * find a way to respect this. We'll check this later... JFB 07/2001 459c2daa00SOllivier Robert */ 462b15cb3dSCy Schubert #define MASK_IPV6_ADDR(dst, src, msk) \ 479c2daa00SOllivier Robert do { \ 489c2daa00SOllivier Robert int idx; \ 492b15cb3dSCy Schubert for (idx = 0; idx < (int)COUNTOF((dst)->s6_addr); idx++) { \ 502b15cb3dSCy Schubert (dst)->s6_addr[idx] = (src)->s6_addr[idx] \ 512b15cb3dSCy Schubert & (msk)->s6_addr[idx]; \ 529c2daa00SOllivier Robert } \ 539c2daa00SOllivier Robert } while (0) 54c0b746e5SOllivier Robert 55c0b746e5SOllivier Robert /* 562b15cb3dSCy Schubert * We allocate INC_RESLIST{4|6} entries to the free list whenever empty. 572b15cb3dSCy Schubert * Auto-tune these to be just less than 1KB (leaving at least 16 bytes 582b15cb3dSCy Schubert * for allocator overhead). 59c0b746e5SOllivier Robert */ 602b15cb3dSCy Schubert #define INC_RESLIST4 ((1024 - 16) / V4_SIZEOF_RESTRICT_U) 612b15cb3dSCy Schubert #define INC_RESLIST6 ((1024 - 16) / V6_SIZEOF_RESTRICT_U) 629c2daa00SOllivier Robert 63c0b746e5SOllivier Robert /* 64c0b746e5SOllivier Robert * The restriction list 65c0b746e5SOllivier Robert */ 662b15cb3dSCy Schubert restrict_u *restrictlist4; 672b15cb3dSCy Schubert restrict_u *restrictlist6; 682b15cb3dSCy Schubert static int restrictcount; /* count in the restrict lists */ 69c0b746e5SOllivier Robert 70c0b746e5SOllivier Robert /* 71c0b746e5SOllivier Robert * The free list and associated counters. Also some uninteresting 72c0b746e5SOllivier Robert * stat counters. 73c0b746e5SOllivier Robert */ 742b15cb3dSCy Schubert static restrict_u *resfree4; /* available entries (free list) */ 752b15cb3dSCy Schubert static restrict_u *resfree6; 76c0b746e5SOllivier Robert 77c0b746e5SOllivier Robert static u_long res_calls; 78c0b746e5SOllivier Robert static u_long res_found; 79c0b746e5SOllivier Robert static u_long res_not_found; 80c0b746e5SOllivier Robert 81c0b746e5SOllivier Robert /* 822b15cb3dSCy Schubert * Count number of restriction entries referring to RES_LIMITED, to 832b15cb3dSCy Schubert * control implicit activation/deactivation of the MRU monlist. 849c2daa00SOllivier Robert */ 859c2daa00SOllivier Robert static u_long res_limited_refcnt; 869c2daa00SOllivier Robert 879c2daa00SOllivier Robert /* 882b15cb3dSCy Schubert * Our default entries. 89c0b746e5SOllivier Robert */ 902b15cb3dSCy Schubert static restrict_u restrict_def4; 912b15cb3dSCy Schubert static restrict_u restrict_def6; 922b15cb3dSCy Schubert 932b15cb3dSCy Schubert /* 942b15cb3dSCy Schubert * "restrict source ..." enabled knob and restriction bits. 952b15cb3dSCy Schubert */ 962b15cb3dSCy Schubert static int restrict_source_enabled; 972b15cb3dSCy Schubert static u_short restrict_source_flags; 982b15cb3dSCy Schubert static u_short restrict_source_mflags; 992b15cb3dSCy Schubert 1002b15cb3dSCy Schubert /* 1012b15cb3dSCy Schubert * private functions 1022b15cb3dSCy Schubert */ 1032b15cb3dSCy Schubert static restrict_u * alloc_res4(void); 1042b15cb3dSCy Schubert static restrict_u * alloc_res6(void); 1052b15cb3dSCy Schubert static void free_res(restrict_u *, int); 1062b15cb3dSCy Schubert static void inc_res_limited(void); 1072b15cb3dSCy Schubert static void dec_res_limited(void); 1082b15cb3dSCy Schubert static restrict_u * match_restrict4_addr(u_int32, u_short); 1092b15cb3dSCy Schubert static restrict_u * match_restrict6_addr(const struct in6_addr *, 1102b15cb3dSCy Schubert u_short); 1112b15cb3dSCy Schubert static restrict_u * match_restrict_entry(const restrict_u *, int); 1122b15cb3dSCy Schubert static int res_sorts_before4(restrict_u *, restrict_u *); 1132b15cb3dSCy Schubert static int res_sorts_before6(restrict_u *, restrict_u *); 1142b15cb3dSCy Schubert 115c0b746e5SOllivier Robert 116c0b746e5SOllivier Robert /* 117c0b746e5SOllivier Robert * init_restrict - initialize the restriction data structures 118c0b746e5SOllivier Robert */ 119c0b746e5SOllivier Robert void 120c0b746e5SOllivier Robert init_restrict(void) 121c0b746e5SOllivier Robert { 122c0b746e5SOllivier Robert /* 1232b15cb3dSCy Schubert * The restriction lists begin with a default entry with address 1242b15cb3dSCy Schubert * and mask 0, which will match any entry. The lists are kept 1252b15cb3dSCy Schubert * sorted by descending address followed by descending mask: 1262b15cb3dSCy Schubert * 1272b15cb3dSCy Schubert * address mask 1282b15cb3dSCy Schubert * 192.168.0.0 255.255.255.0 kod limited noquery nopeer 1292b15cb3dSCy Schubert * 192.168.0.0 255.255.0.0 kod limited 1302b15cb3dSCy Schubert * 0.0.0.0 0.0.0.0 kod limited noquery 1312b15cb3dSCy Schubert * 1322b15cb3dSCy Schubert * The first entry which matches an address is used. With the 1332b15cb3dSCy Schubert * example restrictions above, 192.168.0.0/24 matches the first 1342b15cb3dSCy Schubert * entry, the rest of 192.168.0.0/16 matches the second, and 1352b15cb3dSCy Schubert * everything else matches the third (default). 1362b15cb3dSCy Schubert * 1372b15cb3dSCy Schubert * Note this achieves the same result a little more efficiently 1382b15cb3dSCy Schubert * than the documented behavior, which is to keep the lists 1392b15cb3dSCy Schubert * sorted by ascending address followed by ascending mask, with 1402b15cb3dSCy Schubert * the _last_ matching entry used. 1412b15cb3dSCy Schubert * 1422b15cb3dSCy Schubert * An additional wrinkle is we may have multiple entries with 1432b15cb3dSCy Schubert * the same address and mask but differing match flags (mflags). 1442b15cb3dSCy Schubert * At present there is only one, RESM_NTPONLY. Entries with 1452b15cb3dSCy Schubert * RESM_NTPONLY are sorted earlier so they take precedence over 1462b15cb3dSCy Schubert * any otherwise similar entry without. Again, this is the same 1472b15cb3dSCy Schubert * behavior as but reversed implementation compared to the docs. 1482b15cb3dSCy Schubert * 149c0b746e5SOllivier Robert */ 1502b15cb3dSCy Schubert LINK_SLIST(restrictlist4, &restrict_def4, link); 1512b15cb3dSCy Schubert LINK_SLIST(restrictlist6, &restrict_def6, link); 1529c2daa00SOllivier Robert restrictcount = 2; 1532b15cb3dSCy Schubert } 1542b15cb3dSCy Schubert 1552b15cb3dSCy Schubert 1562b15cb3dSCy Schubert static restrict_u * 1572b15cb3dSCy Schubert alloc_res4(void) 1582b15cb3dSCy Schubert { 1592b15cb3dSCy Schubert const size_t cb = V4_SIZEOF_RESTRICT_U; 1602b15cb3dSCy Schubert const size_t count = INC_RESLIST4; 1612b15cb3dSCy Schubert restrict_u * rl; 1622b15cb3dSCy Schubert restrict_u * res; 1632b15cb3dSCy Schubert int i; 1642b15cb3dSCy Schubert 1652b15cb3dSCy Schubert UNLINK_HEAD_SLIST(res, resfree4, link); 1662b15cb3dSCy Schubert if (res != NULL) 1672b15cb3dSCy Schubert return res; 1682b15cb3dSCy Schubert 1692b15cb3dSCy Schubert rl = emalloc_zero(count * cb); 1702b15cb3dSCy Schubert /* link all but the first onto free list */ 1712b15cb3dSCy Schubert res = (void *)((char *)rl + (count - 1) * cb); 1722b15cb3dSCy Schubert for (i = count - 1; i > 0; i--) { 1732b15cb3dSCy Schubert LINK_SLIST(resfree4, res, link); 1742b15cb3dSCy Schubert res = (void *)((char *)res - cb); 1752b15cb3dSCy Schubert } 176*9034852cSGleb Smirnoff INSIST(rl == res); 1772b15cb3dSCy Schubert /* allocate the first */ 1782b15cb3dSCy Schubert return res; 1792b15cb3dSCy Schubert } 1802b15cb3dSCy Schubert 1812b15cb3dSCy Schubert 1822b15cb3dSCy Schubert static restrict_u * 1832b15cb3dSCy Schubert alloc_res6(void) 1842b15cb3dSCy Schubert { 1852b15cb3dSCy Schubert const size_t cb = V6_SIZEOF_RESTRICT_U; 1862b15cb3dSCy Schubert const size_t count = INC_RESLIST6; 1872b15cb3dSCy Schubert restrict_u * rl; 1882b15cb3dSCy Schubert restrict_u * res; 1892b15cb3dSCy Schubert int i; 1902b15cb3dSCy Schubert 1912b15cb3dSCy Schubert UNLINK_HEAD_SLIST(res, resfree6, link); 1922b15cb3dSCy Schubert if (res != NULL) 1932b15cb3dSCy Schubert return res; 1942b15cb3dSCy Schubert 1952b15cb3dSCy Schubert rl = emalloc_zero(count * cb); 1962b15cb3dSCy Schubert /* link all but the first onto free list */ 1972b15cb3dSCy Schubert res = (void *)((char *)rl + (count - 1) * cb); 1982b15cb3dSCy Schubert for (i = count - 1; i > 0; i--) { 1992b15cb3dSCy Schubert LINK_SLIST(resfree6, res, link); 2002b15cb3dSCy Schubert res = (void *)((char *)res - cb); 2012b15cb3dSCy Schubert } 202*9034852cSGleb Smirnoff INSIST(rl == res); 2032b15cb3dSCy Schubert /* allocate the first */ 2042b15cb3dSCy Schubert return res; 2052b15cb3dSCy Schubert } 2062b15cb3dSCy Schubert 2072b15cb3dSCy Schubert 2082b15cb3dSCy Schubert static void 2092b15cb3dSCy Schubert free_res( 2102b15cb3dSCy Schubert restrict_u * res, 2112b15cb3dSCy Schubert int v6 2122b15cb3dSCy Schubert ) 2132b15cb3dSCy Schubert { 2142b15cb3dSCy Schubert restrict_u ** plisthead; 2152b15cb3dSCy Schubert restrict_u * unlinked; 2162b15cb3dSCy Schubert 2172b15cb3dSCy Schubert restrictcount--; 2182b15cb3dSCy Schubert if (RES_LIMITED & res->flags) 2192b15cb3dSCy Schubert dec_res_limited(); 2202b15cb3dSCy Schubert 2212b15cb3dSCy Schubert if (v6) 2222b15cb3dSCy Schubert plisthead = &restrictlist6; 2232b15cb3dSCy Schubert else 2242b15cb3dSCy Schubert plisthead = &restrictlist4; 2252b15cb3dSCy Schubert UNLINK_SLIST(unlinked, *plisthead, res, link, restrict_u); 226*9034852cSGleb Smirnoff INSIST(unlinked == res); 2272b15cb3dSCy Schubert 2282b15cb3dSCy Schubert if (v6) { 2292b15cb3dSCy Schubert zero_mem(res, V6_SIZEOF_RESTRICT_U); 2302b15cb3dSCy Schubert plisthead = &resfree6; 2312b15cb3dSCy Schubert } else { 2322b15cb3dSCy Schubert zero_mem(res, V4_SIZEOF_RESTRICT_U); 2332b15cb3dSCy Schubert plisthead = &resfree4; 2342b15cb3dSCy Schubert } 2352b15cb3dSCy Schubert LINK_SLIST(*plisthead, res, link); 2362b15cb3dSCy Schubert } 2372b15cb3dSCy Schubert 2382b15cb3dSCy Schubert 2392b15cb3dSCy Schubert static void 2402b15cb3dSCy Schubert inc_res_limited(void) 2412b15cb3dSCy Schubert { 2422b15cb3dSCy Schubert if (!res_limited_refcnt) 2432b15cb3dSCy Schubert mon_start(MON_RES); 2442b15cb3dSCy Schubert res_limited_refcnt++; 2452b15cb3dSCy Schubert } 2462b15cb3dSCy Schubert 2472b15cb3dSCy Schubert 2482b15cb3dSCy Schubert static void 2492b15cb3dSCy Schubert dec_res_limited(void) 2502b15cb3dSCy Schubert { 2512b15cb3dSCy Schubert res_limited_refcnt--; 2522b15cb3dSCy Schubert if (!res_limited_refcnt) 2532b15cb3dSCy Schubert mon_stop(MON_RES); 2542b15cb3dSCy Schubert } 2552b15cb3dSCy Schubert 2562b15cb3dSCy Schubert 2572b15cb3dSCy Schubert static restrict_u * 2582b15cb3dSCy Schubert match_restrict4_addr( 2592b15cb3dSCy Schubert u_int32 addr, 2602b15cb3dSCy Schubert u_short port 2612b15cb3dSCy Schubert ) 2622b15cb3dSCy Schubert { 2632b15cb3dSCy Schubert const int v6 = 0; 2642b15cb3dSCy Schubert restrict_u * res; 2652b15cb3dSCy Schubert restrict_u * next; 2662b15cb3dSCy Schubert 2672b15cb3dSCy Schubert for (res = restrictlist4; res != NULL; res = next) { 2682b15cb3dSCy Schubert next = res->link; 2692b15cb3dSCy Schubert if (res->expire && 2702b15cb3dSCy Schubert res->expire <= current_time) 2712b15cb3dSCy Schubert free_res(res, v6); 2722b15cb3dSCy Schubert if (res->u.v4.addr == (addr & res->u.v4.mask) 2732b15cb3dSCy Schubert && (!(RESM_NTPONLY & res->mflags) 2742b15cb3dSCy Schubert || NTP_PORT == port)) 2752b15cb3dSCy Schubert break; 2762b15cb3dSCy Schubert } 2772b15cb3dSCy Schubert return res; 2782b15cb3dSCy Schubert } 2792b15cb3dSCy Schubert 2802b15cb3dSCy Schubert 2812b15cb3dSCy Schubert static restrict_u * 2822b15cb3dSCy Schubert match_restrict6_addr( 2832b15cb3dSCy Schubert const struct in6_addr * addr, 2842b15cb3dSCy Schubert u_short port 2852b15cb3dSCy Schubert ) 2862b15cb3dSCy Schubert { 2872b15cb3dSCy Schubert const int v6 = 1; 2882b15cb3dSCy Schubert restrict_u * res; 2892b15cb3dSCy Schubert restrict_u * next; 2902b15cb3dSCy Schubert struct in6_addr masked; 2912b15cb3dSCy Schubert 2922b15cb3dSCy Schubert for (res = restrictlist6; res != NULL; res = next) { 2932b15cb3dSCy Schubert next = res->link; 294*9034852cSGleb Smirnoff INSIST(next != res); 2952b15cb3dSCy Schubert if (res->expire && 2962b15cb3dSCy Schubert res->expire <= current_time) 2972b15cb3dSCy Schubert free_res(res, v6); 2982b15cb3dSCy Schubert MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask); 2992b15cb3dSCy Schubert if (ADDR6_EQ(&masked, &res->u.v6.addr) 3002b15cb3dSCy Schubert && (!(RESM_NTPONLY & res->mflags) 3012b15cb3dSCy Schubert || NTP_PORT == (int)port)) 3022b15cb3dSCy Schubert break; 3032b15cb3dSCy Schubert } 3042b15cb3dSCy Schubert return res; 3052b15cb3dSCy Schubert } 3062b15cb3dSCy Schubert 307c0b746e5SOllivier Robert 308c0b746e5SOllivier Robert /* 3092b15cb3dSCy Schubert * match_restrict_entry - find an exact match on a restrict list. 3102b15cb3dSCy Schubert * 3112b15cb3dSCy Schubert * Exact match is addr, mask, and mflags all equal. 3122b15cb3dSCy Schubert * In order to use more common code for IPv4 and IPv6, this routine 3132b15cb3dSCy Schubert * requires the caller to populate a restrict_u with mflags and either 3142b15cb3dSCy Schubert * the v4 or v6 address and mask as appropriate. Other fields in the 3152b15cb3dSCy Schubert * input restrict_u are ignored. 316c0b746e5SOllivier Robert */ 3172b15cb3dSCy Schubert static restrict_u * 3182b15cb3dSCy Schubert match_restrict_entry( 3192b15cb3dSCy Schubert const restrict_u * pmatch, 3202b15cb3dSCy Schubert int v6 3212b15cb3dSCy Schubert ) 3222b15cb3dSCy Schubert { 3232b15cb3dSCy Schubert restrict_u *res; 3242b15cb3dSCy Schubert restrict_u *rlist; 3252b15cb3dSCy Schubert size_t cb; 3262b15cb3dSCy Schubert 3272b15cb3dSCy Schubert if (v6) { 3282b15cb3dSCy Schubert rlist = restrictlist6; 3292b15cb3dSCy Schubert cb = sizeof(pmatch->u.v6); 3302b15cb3dSCy Schubert } else { 3312b15cb3dSCy Schubert rlist = restrictlist4; 3322b15cb3dSCy Schubert cb = sizeof(pmatch->u.v4); 3332b15cb3dSCy Schubert } 3342b15cb3dSCy Schubert 3352b15cb3dSCy Schubert for (res = rlist; res != NULL; res = res->link) 3362b15cb3dSCy Schubert if (res->mflags == pmatch->mflags && 3372b15cb3dSCy Schubert !memcmp(&res->u, &pmatch->u, cb)) 3382b15cb3dSCy Schubert break; 3392b15cb3dSCy Schubert return res; 3402b15cb3dSCy Schubert } 3412b15cb3dSCy Schubert 342c0b746e5SOllivier Robert 343c0b746e5SOllivier Robert /* 3442b15cb3dSCy Schubert * res_sorts_before4 - compare two restrict4 entries 3452b15cb3dSCy Schubert * 3462b15cb3dSCy Schubert * Returns nonzero if r1 sorts before r2. We sort by descending 3472b15cb3dSCy Schubert * address, then descending mask, then descending mflags, so sorting 3482b15cb3dSCy Schubert * before means having a higher value. 349c0b746e5SOllivier Robert */ 3502b15cb3dSCy Schubert static int 3512b15cb3dSCy Schubert res_sorts_before4( 3522b15cb3dSCy Schubert restrict_u *r1, 3532b15cb3dSCy Schubert restrict_u *r2 3542b15cb3dSCy Schubert ) 3552b15cb3dSCy Schubert { 3562b15cb3dSCy Schubert int r1_before_r2; 3572b15cb3dSCy Schubert 3582b15cb3dSCy Schubert if (r1->u.v4.addr > r2->u.v4.addr) 3592b15cb3dSCy Schubert r1_before_r2 = 1; 3602b15cb3dSCy Schubert else if (r1->u.v4.addr < r2->u.v4.addr) 3612b15cb3dSCy Schubert r1_before_r2 = 0; 3622b15cb3dSCy Schubert else if (r1->u.v4.mask > r2->u.v4.mask) 3632b15cb3dSCy Schubert r1_before_r2 = 1; 3642b15cb3dSCy Schubert else if (r1->u.v4.mask < r2->u.v4.mask) 3652b15cb3dSCy Schubert r1_before_r2 = 0; 3662b15cb3dSCy Schubert else if (r1->mflags > r2->mflags) 3672b15cb3dSCy Schubert r1_before_r2 = 1; 3682b15cb3dSCy Schubert else 3692b15cb3dSCy Schubert r1_before_r2 = 0; 3702b15cb3dSCy Schubert 3712b15cb3dSCy Schubert return r1_before_r2; 3722b15cb3dSCy Schubert } 3732b15cb3dSCy Schubert 3742b15cb3dSCy Schubert 3752b15cb3dSCy Schubert /* 3762b15cb3dSCy Schubert * res_sorts_before6 - compare two restrict6 entries 3772b15cb3dSCy Schubert * 3782b15cb3dSCy Schubert * Returns nonzero if r1 sorts before r2. We sort by descending 3792b15cb3dSCy Schubert * address, then descending mask, then descending mflags, so sorting 3802b15cb3dSCy Schubert * before means having a higher value. 3812b15cb3dSCy Schubert */ 3822b15cb3dSCy Schubert static int 3832b15cb3dSCy Schubert res_sorts_before6( 3842b15cb3dSCy Schubert restrict_u *r1, 3852b15cb3dSCy Schubert restrict_u *r2 3862b15cb3dSCy Schubert ) 3872b15cb3dSCy Schubert { 3882b15cb3dSCy Schubert int r1_before_r2; 3892b15cb3dSCy Schubert int cmp; 3902b15cb3dSCy Schubert 3912b15cb3dSCy Schubert cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr); 3922b15cb3dSCy Schubert if (cmp > 0) /* r1->addr > r2->addr */ 3932b15cb3dSCy Schubert r1_before_r2 = 1; 3942b15cb3dSCy Schubert else if (cmp < 0) /* r2->addr > r1->addr */ 3952b15cb3dSCy Schubert r1_before_r2 = 0; 3962b15cb3dSCy Schubert else { 3972b15cb3dSCy Schubert cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask); 3982b15cb3dSCy Schubert if (cmp > 0) /* r1->mask > r2->mask*/ 3992b15cb3dSCy Schubert r1_before_r2 = 1; 4002b15cb3dSCy Schubert else if (cmp < 0) /* r2->mask > r1->mask */ 4012b15cb3dSCy Schubert r1_before_r2 = 0; 4022b15cb3dSCy Schubert else if (r1->mflags > r2->mflags) 4032b15cb3dSCy Schubert r1_before_r2 = 1; 4042b15cb3dSCy Schubert else 4052b15cb3dSCy Schubert r1_before_r2 = 0; 4062b15cb3dSCy Schubert } 4072b15cb3dSCy Schubert 4082b15cb3dSCy Schubert return r1_before_r2; 409c0b746e5SOllivier Robert } 410c0b746e5SOllivier Robert 411c0b746e5SOllivier Robert 412c0b746e5SOllivier Robert /* 413c0b746e5SOllivier Robert * restrictions - return restrictions for this host 414c0b746e5SOllivier Robert */ 4152b15cb3dSCy Schubert u_short 416c0b746e5SOllivier Robert restrictions( 4172b15cb3dSCy Schubert sockaddr_u *srcadr 418c0b746e5SOllivier Robert ) 419c0b746e5SOllivier Robert { 4202b15cb3dSCy Schubert restrict_u *match; 4212b15cb3dSCy Schubert struct in6_addr *pin6; 4222b15cb3dSCy Schubert u_short flags; 423c0b746e5SOllivier Robert 424c0b746e5SOllivier Robert res_calls++; 4252b15cb3dSCy Schubert flags = 0; 4262b15cb3dSCy Schubert /* IPv4 source address */ 4272b15cb3dSCy Schubert if (IS_IPV4(srcadr)) { 428c0b746e5SOllivier Robert /* 429c0b746e5SOllivier Robert * Ignore any packets with a multicast source address 4309c2daa00SOllivier Robert * (this should be done early in the receive process, 4312b15cb3dSCy Schubert * not later!) 432c0b746e5SOllivier Robert */ 4339c2daa00SOllivier Robert if (IN_CLASSD(SRCADR(srcadr))) 434c0b746e5SOllivier Robert return (int)RES_IGNORE; 435c0b746e5SOllivier Robert 4362b15cb3dSCy Schubert match = match_restrict4_addr(SRCADR(srcadr), 4372b15cb3dSCy Schubert SRCPORT(srcadr)); 438*9034852cSGleb Smirnoff 439*9034852cSGleb Smirnoff INSIST(match != NULL); 440*9034852cSGleb Smirnoff 441c0b746e5SOllivier Robert match->count++; 4422b15cb3dSCy Schubert /* 4432b15cb3dSCy Schubert * res_not_found counts only use of the final default 4442b15cb3dSCy Schubert * entry, not any "restrict default ntpport ...", which 4452b15cb3dSCy Schubert * would be just before the final default. 4462b15cb3dSCy Schubert */ 4472b15cb3dSCy Schubert if (&restrict_def4 == match) 448c0b746e5SOllivier Robert res_not_found++; 449c0b746e5SOllivier Robert else 450c0b746e5SOllivier Robert res_found++; 4519c2daa00SOllivier Robert flags = match->flags; 4529c2daa00SOllivier Robert } 4539c2daa00SOllivier Robert 4549c2daa00SOllivier Robert /* IPv6 source address */ 4552b15cb3dSCy Schubert if (IS_IPV6(srcadr)) { 4562b15cb3dSCy Schubert pin6 = PSOCK_ADDR6(srcadr); 457c0b746e5SOllivier Robert 458c0b746e5SOllivier Robert /* 4599c2daa00SOllivier Robert * Ignore any packets with a multicast source address 4609c2daa00SOllivier Robert * (this should be done early in the receive process, 4612b15cb3dSCy Schubert * not later!) 462c0b746e5SOllivier Robert */ 4632b15cb3dSCy Schubert if (IN6_IS_ADDR_MULTICAST(pin6)) 4649c2daa00SOllivier Robert return (int)RES_IGNORE; 465c0b746e5SOllivier Robert 4662b15cb3dSCy Schubert match = match_restrict6_addr(pin6, SRCPORT(srcadr)); 467*9034852cSGleb Smirnoff INSIST(match != NULL); 4682b15cb3dSCy Schubert match->count++; 4692b15cb3dSCy Schubert if (&restrict_def6 == match) 4709c2daa00SOllivier Robert res_not_found++; 4719c2daa00SOllivier Robert else 4729c2daa00SOllivier Robert res_found++; 4732b15cb3dSCy Schubert flags = match->flags; 474c0b746e5SOllivier Robert } 4759c2daa00SOllivier Robert return (flags); 476c0b746e5SOllivier Robert } 477c0b746e5SOllivier Robert 478c0b746e5SOllivier Robert 479c0b746e5SOllivier Robert /* 480c0b746e5SOllivier Robert * hack_restrict - add/subtract/manipulate entries on the restrict list 481c0b746e5SOllivier Robert */ 482c0b746e5SOllivier Robert void 483c0b746e5SOllivier Robert hack_restrict( 484c0b746e5SOllivier Robert int op, 4852b15cb3dSCy Schubert sockaddr_u * resaddr, 4862b15cb3dSCy Schubert sockaddr_u * resmask, 4872b15cb3dSCy Schubert u_short mflags, 4882b15cb3dSCy Schubert u_short flags, 4892b15cb3dSCy Schubert u_long expire 490c0b746e5SOllivier Robert ) 491c0b746e5SOllivier Robert { 4922b15cb3dSCy Schubert int v6; 4932b15cb3dSCy Schubert restrict_u match; 4942b15cb3dSCy Schubert restrict_u * res; 4952b15cb3dSCy Schubert restrict_u ** plisthead; 496c0b746e5SOllivier Robert 4972b15cb3dSCy Schubert DPRINTF(1, ("restrict: op %d addr %s mask %s mflags %08x flags %08x\n", 4982b15cb3dSCy Schubert op, stoa(resaddr), stoa(resmask), mflags, flags)); 4992b15cb3dSCy Schubert 5002b15cb3dSCy Schubert if (NULL == resaddr) { 501*9034852cSGleb Smirnoff REQUIRE(NULL == resmask); 502*9034852cSGleb Smirnoff REQUIRE(RESTRICT_FLAGS == op); 5032b15cb3dSCy Schubert restrict_source_flags = flags; 5042b15cb3dSCy Schubert restrict_source_mflags = mflags; 5052b15cb3dSCy Schubert restrict_source_enabled = 1; 5062b15cb3dSCy Schubert return; 5072b15cb3dSCy Schubert } 5082b15cb3dSCy Schubert 5092b15cb3dSCy Schubert ZERO(match); 510*9034852cSGleb Smirnoff 511*9034852cSGleb Smirnoff #if 0 5122b15cb3dSCy Schubert /* silence VC9 potentially uninit warnings */ 513*9034852cSGleb Smirnoff // HMS: let's use a compiler-specific "enable" for this. 5142b15cb3dSCy Schubert res = NULL; 5152b15cb3dSCy Schubert v6 = 0; 516*9034852cSGleb Smirnoff #endif 5172b15cb3dSCy Schubert 5182b15cb3dSCy Schubert if (IS_IPV4(resaddr)) { 5192b15cb3dSCy Schubert v6 = 0; 520c0b746e5SOllivier Robert /* 5212b15cb3dSCy Schubert * Get address and mask in host byte order for easy 5222b15cb3dSCy Schubert * comparison as u_int32 523c0b746e5SOllivier Robert */ 5242b15cb3dSCy Schubert match.u.v4.addr = SRCADR(resaddr); 5252b15cb3dSCy Schubert match.u.v4.mask = SRCADR(resmask); 5262b15cb3dSCy Schubert match.u.v4.addr &= match.u.v4.mask; 527c0b746e5SOllivier Robert 5282b15cb3dSCy Schubert } else if (IS_IPV6(resaddr)) { 5292b15cb3dSCy Schubert v6 = 1; 530c0b746e5SOllivier Robert /* 5312b15cb3dSCy Schubert * Get address and mask in network byte order for easy 5322b15cb3dSCy Schubert * comparison as byte sequences (e.g. memcmp()) 533c0b746e5SOllivier Robert */ 5342b15cb3dSCy Schubert match.u.v6.mask = SOCK_ADDR6(resmask); 5352b15cb3dSCy Schubert MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr), 5362b15cb3dSCy Schubert &match.u.v6.mask); 5379c2daa00SOllivier Robert 5382b15cb3dSCy Schubert } else /* not IPv4 nor IPv6 */ 539*9034852cSGleb Smirnoff REQUIRE(0); 5409c2daa00SOllivier Robert 5412b15cb3dSCy Schubert match.flags = flags; 5422b15cb3dSCy Schubert match.mflags = mflags; 5432b15cb3dSCy Schubert match.expire = expire; 5442b15cb3dSCy Schubert res = match_restrict_entry(&match, v6); 5459c2daa00SOllivier Robert 546c0b746e5SOllivier Robert switch (op) { 5472b15cb3dSCy Schubert 548c0b746e5SOllivier Robert case RESTRICT_FLAGS: 549c0b746e5SOllivier Robert /* 5509c2daa00SOllivier Robert * Here we add bits to the flags. If this is a 5519c2daa00SOllivier Robert * new restriction add it. 552c0b746e5SOllivier Robert */ 5532b15cb3dSCy Schubert if (NULL == res) { 5542b15cb3dSCy Schubert if (v6) { 5552b15cb3dSCy Schubert res = alloc_res6(); 5562b15cb3dSCy Schubert memcpy(res, &match, 5572b15cb3dSCy Schubert V6_SIZEOF_RESTRICT_U); 5582b15cb3dSCy Schubert plisthead = &restrictlist6; 559ea906c41SOllivier Robert } else { 5602b15cb3dSCy Schubert res = alloc_res4(); 5612b15cb3dSCy Schubert memcpy(res, &match, 5622b15cb3dSCy Schubert V4_SIZEOF_RESTRICT_U); 5632b15cb3dSCy Schubert plisthead = &restrictlist4; 564ea906c41SOllivier Robert } 5652b15cb3dSCy Schubert LINK_SORT_SLIST( 5662b15cb3dSCy Schubert *plisthead, res, 5672b15cb3dSCy Schubert (v6) 5682b15cb3dSCy Schubert ? res_sorts_before6(res, L_S_S_CUR()) 5692b15cb3dSCy Schubert : res_sorts_before4(res, L_S_S_CUR()), 5702b15cb3dSCy Schubert link, restrict_u); 571c0b746e5SOllivier Robert restrictcount++; 5722b15cb3dSCy Schubert if (RES_LIMITED & flags) 5732b15cb3dSCy Schubert inc_res_limited(); 5742b15cb3dSCy Schubert } else { 5752b15cb3dSCy Schubert if ((RES_LIMITED & flags) && 5762b15cb3dSCy Schubert !(RES_LIMITED & res->flags)) 5772b15cb3dSCy Schubert inc_res_limited(); 5782b15cb3dSCy Schubert res->flags |= flags; 579c0b746e5SOllivier Robert } 580c0b746e5SOllivier Robert break; 581c0b746e5SOllivier Robert 582c0b746e5SOllivier Robert case RESTRICT_UNFLAG: 583c0b746e5SOllivier Robert /* 584c0b746e5SOllivier Robert * Remove some bits from the flags. If we didn't 585c0b746e5SOllivier Robert * find this one, just return. 586c0b746e5SOllivier Robert */ 5872b15cb3dSCy Schubert if (res != NULL) { 5882b15cb3dSCy Schubert if ((RES_LIMITED & res->flags) 5892b15cb3dSCy Schubert && (RES_LIMITED & flags)) 5902b15cb3dSCy Schubert dec_res_limited(); 5912b15cb3dSCy Schubert res->flags &= ~flags; 592c0b746e5SOllivier Robert } 593c0b746e5SOllivier Robert break; 594c0b746e5SOllivier Robert 595c0b746e5SOllivier Robert case RESTRICT_REMOVE: 596ea906c41SOllivier Robert case RESTRICT_REMOVEIF: 597c0b746e5SOllivier Robert /* 5989c2daa00SOllivier Robert * Remove an entry from the table entirely if we 5999c2daa00SOllivier Robert * found one. Don't remove the default entry and 6009c2daa00SOllivier Robert * don't remove an interface entry. 601c0b746e5SOllivier Robert */ 6022b15cb3dSCy Schubert if (res != NULL 6032b15cb3dSCy Schubert && (RESTRICT_REMOVEIF == op 6042b15cb3dSCy Schubert || !(RESM_INTERFACE & res->mflags)) 6052b15cb3dSCy Schubert && res != &restrict_def4 6062b15cb3dSCy Schubert && res != &restrict_def6) 6072b15cb3dSCy Schubert free_res(res, v6); 608c0b746e5SOllivier Robert break; 609c0b746e5SOllivier Robert 6102b15cb3dSCy Schubert default: /* unknown op */ 611*9034852cSGleb Smirnoff INSIST(0); 612c0b746e5SOllivier Robert break; 613c0b746e5SOllivier Robert } 6142b15cb3dSCy Schubert 6152b15cb3dSCy Schubert } 6162b15cb3dSCy Schubert 6172b15cb3dSCy Schubert 6189c2daa00SOllivier Robert /* 6192b15cb3dSCy Schubert * restrict_source - maintains dynamic "restrict source ..." entries as 6202b15cb3dSCy Schubert * peers come and go. 6219c2daa00SOllivier Robert */ 6222b15cb3dSCy Schubert void 6232b15cb3dSCy Schubert restrict_source( 6242b15cb3dSCy Schubert sockaddr_u * addr, 6252b15cb3dSCy Schubert int farewell, /* 0 to add, 1 to remove */ 6262b15cb3dSCy Schubert u_long expire /* 0 is infinite, valid until */ 6272b15cb3dSCy Schubert ) 6282b15cb3dSCy Schubert { 6292b15cb3dSCy Schubert sockaddr_u onesmask; 6302b15cb3dSCy Schubert restrict_u * res; 6312b15cb3dSCy Schubert int found_specific; 632c0b746e5SOllivier Robert 6332b15cb3dSCy Schubert if (!restrict_source_enabled || SOCK_UNSPEC(addr) || 6342b15cb3dSCy Schubert IS_MCAST(addr) || ISREFCLOCKADR(addr)) 6352b15cb3dSCy Schubert return; 6369c2daa00SOllivier Robert 637*9034852cSGleb Smirnoff REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr)); 6382b15cb3dSCy Schubert 6392b15cb3dSCy Schubert SET_HOSTMASK(&onesmask, AF(addr)); 6402b15cb3dSCy Schubert if (farewell) { 6412b15cb3dSCy Schubert hack_restrict(RESTRICT_REMOVE, addr, &onesmask, 6422b15cb3dSCy Schubert 0, 0, 0); 6432b15cb3dSCy Schubert DPRINTF(1, ("restrict_source: %s removed", stoa(addr))); 6442b15cb3dSCy Schubert return; 6452b15cb3dSCy Schubert } 6462b15cb3dSCy Schubert 6479c2daa00SOllivier Robert /* 6482b15cb3dSCy Schubert * If there is a specific entry for this address, hands 6492b15cb3dSCy Schubert * off, as it is condidered more specific than "restrict 6502b15cb3dSCy Schubert * server ...". 6512b15cb3dSCy Schubert * However, if the specific entry found is a fleeting one 6522b15cb3dSCy Schubert * added by pool_xmit() before soliciting, replace it 6532b15cb3dSCy Schubert * immediately regardless of the expire value to make way 6542b15cb3dSCy Schubert * for the more persistent entry. 6559c2daa00SOllivier Robert */ 6562b15cb3dSCy Schubert if (IS_IPV4(addr)) { 6572b15cb3dSCy Schubert res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr)); 658*9034852cSGleb Smirnoff INSIST(res != NULL); 6592b15cb3dSCy Schubert found_specific = (SRCADR(&onesmask) == res->u.v4.mask); 660ea906c41SOllivier Robert } else { 6612b15cb3dSCy Schubert res = match_restrict6_addr(&SOCK_ADDR6(addr), 6622b15cb3dSCy Schubert SRCPORT(addr)); 663*9034852cSGleb Smirnoff INSIST(res != NULL); 6642b15cb3dSCy Schubert found_specific = ADDR6_EQ(&res->u.v6.mask, 6652b15cb3dSCy Schubert &SOCK_ADDR6(&onesmask)); 666ea906c41SOllivier Robert } 6672b15cb3dSCy Schubert if (!expire && found_specific && res->expire) { 6682b15cb3dSCy Schubert found_specific = 0; 6692b15cb3dSCy Schubert free_res(res, IS_IPV6(addr)); 6709c2daa00SOllivier Robert } 6712b15cb3dSCy Schubert if (found_specific) 6722b15cb3dSCy Schubert return; 6739c2daa00SOllivier Robert 6742b15cb3dSCy Schubert hack_restrict(RESTRICT_FLAGS, addr, &onesmask, 6752b15cb3dSCy Schubert restrict_source_mflags, restrict_source_flags, 6762b15cb3dSCy Schubert expire); 6772b15cb3dSCy Schubert DPRINTF(1, ("restrict_source: %s host restriction added\n", 6782b15cb3dSCy Schubert stoa(addr))); 679c0b746e5SOllivier Robert } 680