1 /* 2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* $Id: sockaddr.c,v 1.7 2020/02/25 05:00:43 jsg Exp $ */ 18 19 /*! \file */ 20 21 #include <stdio.h> 22 23 #include <isc/buffer.h> 24 #include <isc/netaddr.h> 25 26 #include <isc/region.h> 27 #include <isc/sockaddr.h> 28 #include <string.h> 29 #include <isc/util.h> 30 31 isc_boolean_t 32 isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) { 33 return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR| 34 ISC_SOCKADDR_CMPPORT| 35 ISC_SOCKADDR_CMPSCOPE)); 36 } 37 38 isc_boolean_t 39 isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) { 40 return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR| 41 ISC_SOCKADDR_CMPSCOPE)); 42 } 43 44 isc_boolean_t 45 isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b, 46 unsigned int flags) 47 { 48 REQUIRE(a != NULL && b != NULL); 49 50 if (a->length != b->length) 51 return (ISC_FALSE); 52 53 /* 54 * We don't just memcmp because the sin_zero field isn't always 55 * zero. 56 */ 57 58 if (a->type.sa.sa_family != b->type.sa.sa_family) 59 return (ISC_FALSE); 60 switch (a->type.sa.sa_family) { 61 case AF_INET: 62 if ((flags & ISC_SOCKADDR_CMPADDR) != 0 && 63 memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr, 64 sizeof(a->type.sin.sin_addr)) != 0) 65 return (ISC_FALSE); 66 if ((flags & ISC_SOCKADDR_CMPPORT) != 0 && 67 a->type.sin.sin_port != b->type.sin.sin_port) 68 return (ISC_FALSE); 69 break; 70 case AF_INET6: 71 if ((flags & ISC_SOCKADDR_CMPADDR) != 0 && 72 memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr, 73 sizeof(a->type.sin6.sin6_addr)) != 0) 74 return (ISC_FALSE); 75 /* 76 * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return 77 * ISC_FALSE if one of the scopes in zero. 78 */ 79 if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 && 80 a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id && 81 ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 || 82 (a->type.sin6.sin6_scope_id != 0 && 83 b->type.sin6.sin6_scope_id != 0))) 84 return (ISC_FALSE); 85 if ((flags & ISC_SOCKADDR_CMPPORT) != 0 && 86 a->type.sin6.sin6_port != b->type.sin6.sin6_port) 87 return (ISC_FALSE); 88 break; 89 default: 90 if (memcmp(&a->type, &b->type, a->length) != 0) 91 return (ISC_FALSE); 92 } 93 return (ISC_TRUE); 94 } 95 96 isc_result_t 97 isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) { 98 isc_result_t result; 99 isc_netaddr_t netaddr; 100 char pbuf[sizeof("65000")]; 101 unsigned int plen; 102 isc_region_t avail; 103 104 REQUIRE(sockaddr != NULL); 105 106 /* 107 * Do the port first, giving us the opportunity to check for 108 * unsupported address families before calling 109 * isc_netaddr_fromsockaddr(). 110 */ 111 switch (sockaddr->type.sa.sa_family) { 112 case AF_INET: 113 snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port)); 114 break; 115 case AF_INET6: 116 snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port)); 117 break; 118 default: 119 return (ISC_R_FAILURE); 120 } 121 122 plen = strlen(pbuf); 123 INSIST(plen < sizeof(pbuf)); 124 125 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 126 result = isc_netaddr_totext(&netaddr, target); 127 if (result != ISC_R_SUCCESS) 128 return (result); 129 130 if (1 + plen + 1 > isc_buffer_availablelength(target)) 131 return (ISC_R_NOSPACE); 132 133 isc_buffer_putmem(target, (const unsigned char *)"#", 1); 134 isc_buffer_putmem(target, (const unsigned char *)pbuf, plen); 135 136 /* 137 * Null terminate after used region. 138 */ 139 isc_buffer_availableregion(target, &avail); 140 INSIST(avail.length >= 1); 141 avail.base[0] = '\0'; 142 143 return (ISC_R_SUCCESS); 144 } 145 146 void 147 isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) { 148 isc_result_t result; 149 isc_buffer_t buf; 150 151 if (size == 0U) 152 return; 153 154 isc_buffer_init(&buf, array, size); 155 result = isc_sockaddr_totext(sa, &buf); 156 if (result != ISC_R_SUCCESS) { 157 /* 158 * The message is the same as in netaddr.c. 159 */ 160 snprintf(array, size, "<unknown address, family %u>", 161 sa->type.sa.sa_family); 162 array[size - 1] = '\0'; 163 } 164 } 165 166 void 167 isc_sockaddr_any(isc_sockaddr_t *sockaddr) 168 { 169 memset(sockaddr, 0, sizeof(*sockaddr)); 170 sockaddr->type.sin.sin_family = AF_INET; 171 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin); 172 sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY; 173 sockaddr->type.sin.sin_port = 0; 174 sockaddr->length = sizeof(sockaddr->type.sin); 175 ISC_LINK_INIT(sockaddr, link); 176 } 177 178 void 179 isc_sockaddr_any6(isc_sockaddr_t *sockaddr) 180 { 181 memset(sockaddr, 0, sizeof(*sockaddr)); 182 sockaddr->type.sin6.sin6_family = AF_INET6; 183 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6); 184 sockaddr->type.sin6.sin6_addr = in6addr_any; 185 sockaddr->type.sin6.sin6_port = 0; 186 sockaddr->length = sizeof(sockaddr->type.sin6); 187 ISC_LINK_INIT(sockaddr, link); 188 } 189 190 void 191 isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, 192 in_port_t port) 193 { 194 memset(sockaddr, 0, sizeof(*sockaddr)); 195 sockaddr->type.sin.sin_family = AF_INET; 196 sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin); 197 sockaddr->type.sin.sin_addr = *ina; 198 sockaddr->type.sin.sin_port = htons(port); 199 sockaddr->length = sizeof(sockaddr->type.sin); 200 ISC_LINK_INIT(sockaddr, link); 201 } 202 203 void 204 isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) { 205 switch (pf) { 206 case AF_INET: 207 isc_sockaddr_any(sockaddr); 208 break; 209 case AF_INET6: 210 isc_sockaddr_any6(sockaddr); 211 break; 212 default: 213 INSIST(0); 214 } 215 } 216 217 void 218 isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6, 219 in_port_t port) 220 { 221 memset(sockaddr, 0, sizeof(*sockaddr)); 222 sockaddr->type.sin6.sin6_family = AF_INET6; 223 sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6); 224 sockaddr->type.sin6.sin6_addr = *ina6; 225 sockaddr->type.sin6.sin6_port = htons(port); 226 sockaddr->length = sizeof(sockaddr->type.sin6); 227 ISC_LINK_INIT(sockaddr, link); 228 } 229 230 int 231 isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) { 232 233 /* 234 * Get the protocol family of 'sockaddr'. 235 */ 236 237 return (sockaddr->type.sa.sa_family); 238 } 239 240 in_port_t 241 isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) { 242 in_port_t port = 0; 243 244 switch (sockaddr->type.sa.sa_family) { 245 case AF_INET: 246 port = ntohs(sockaddr->type.sin.sin_port); 247 break; 248 case AF_INET6: 249 port = ntohs(sockaddr->type.sin6.sin6_port); 250 break; 251 default: 252 FATAL_ERROR(__FILE__, __LINE__, 253 "unknown address family: %d", 254 (int)sockaddr->type.sa.sa_family); 255 } 256 257 return (port); 258 } 259 260 isc_boolean_t 261 isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) { 262 isc_netaddr_t netaddr; 263 264 if (sockaddr->type.sa.sa_family == AF_INET || 265 sockaddr->type.sa.sa_family == AF_INET6) { 266 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 267 return (isc_netaddr_ismulticast(&netaddr)); 268 } 269 return (ISC_FALSE); 270 } 271 272 isc_boolean_t 273 isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) { 274 isc_netaddr_t netaddr; 275 276 if (sockaddr->type.sa.sa_family == AF_INET6) { 277 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 278 return (isc_netaddr_issitelocal(&netaddr)); 279 } 280 return (ISC_FALSE); 281 } 282 283 isc_boolean_t 284 isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) { 285 isc_netaddr_t netaddr; 286 287 if (sockaddr->type.sa.sa_family == AF_INET6) { 288 isc_netaddr_fromsockaddr(&netaddr, sockaddr); 289 return (isc_netaddr_islinklocal(&netaddr)); 290 } 291 return (ISC_FALSE); 292 } 293