37 38struct addr_operations { 39 int af; 40 krb5_address_type atype; 41 size_t max_sockaddr_size; 42 krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *); 43 krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *); 44 void (*addr2sockaddr)(const krb5_address *, struct sockaddr *, 45 int *sa_size, int port); 46 void (*h_addr2sockaddr)(const char *, struct sockaddr *, int *, int); 47 krb5_error_code (*h_addr2addr)(const char *, krb5_address *); 48 krb5_boolean (*uninteresting)(const struct sockaddr *); 49 void (*anyaddr)(struct sockaddr *, int *, int); 50 int (*print_addr)(const krb5_address *, char *, size_t); 51 int (*parse_addr)(const char*, krb5_address *); 52}; 53 54/* 55 * AF_INET - aka IPv4 implementation 56 */ 57 58static krb5_error_code 59ipv4_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) 60{ 61 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; 62 unsigned char buf[4]; 63 64 a->addr_type = KRB5_ADDRESS_INET; 65 memcpy (buf, &sin->sin_addr, 4); 66 return krb5_data_copy(&a->address, buf, 4); 67} 68 69static krb5_error_code 70ipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port) 71{ 72 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; 73 74 *port = sin->sin_port; 75 return 0; 76} 77 78static void 79ipv4_addr2sockaddr (const krb5_address *a, 80 struct sockaddr *sa, 81 int *sa_size, 82 int port) 83{ 84 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 85 86 memset (sin, 0, sizeof(*sin)); 87 sin->sin_family = AF_INET; 88 memcpy (&sin->sin_addr, a->address.data, 4); 89 sin->sin_port = port; 90 *sa_size = sizeof(*sin); 91} 92 93static void 94ipv4_h_addr2sockaddr(const char *addr, 95 struct sockaddr *sa, int *sa_size, int port) 96{ 97 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 98 99 memset (sin, 0, sizeof(*sin)); 100 *sa_size = sizeof(*sin); 101 sin->sin_family = AF_INET; 102 sin->sin_port = port; 103 sin->sin_addr = *((const struct in_addr *)addr); 104} 105 106static krb5_error_code 107ipv4_h_addr2addr (const char *addr, 108 krb5_address *a) 109{ 110 unsigned char buf[4]; 111 112 a->addr_type = KRB5_ADDRESS_INET; 113 memcpy(buf, addr, 4); 114 return krb5_data_copy(&a->address, buf, 4); 115} 116 117/* 118 * Are there any addresses that should be considered `uninteresting'? 119 */ 120 121static krb5_boolean 122ipv4_uninteresting (const struct sockaddr *sa) 123{ 124 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; 125 126 if (sin->sin_addr.s_addr == INADDR_ANY) 127 return TRUE; 128 129 return FALSE; 130} 131 132static void 133ipv4_anyaddr (struct sockaddr *sa, int *sa_size, int port) 134{ 135 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 136 137 memset (sin, 0, sizeof(*sin)); 138 *sa_size = sizeof(*sin); 139 sin->sin_family = AF_INET; 140 sin->sin_port = port; 141 sin->sin_addr.s_addr = INADDR_ANY; 142} 143 144static int 145ipv4_print_addr (const krb5_address *addr, char *str, size_t len) 146{ 147 struct in_addr ia; 148 149 memcpy (&ia, addr->address.data, 4); 150 151 return snprintf (str, len, "IPv4:%s", inet_ntoa(ia)); 152} 153 154static int 155ipv4_parse_addr (const char *address, krb5_address *addr) 156{ 157 const char *p; 158 struct in_addr a; 159 160 p = strchr(address, ':'); 161 if(p) { 162 p++; 163 if(strncasecmp(address, "ip:", p - address) != 0 && 164 strncasecmp(address, "ip4:", p - address) != 0 && 165 strncasecmp(address, "ipv4:", p - address) != 0 && 166 strncasecmp(address, "inet:", p - address) != 0) 167 return -1; 168 } else 169 p = address; 170#ifdef HAVE_INET_ATON 171 if(inet_aton(p, &a) == 0) 172 return -1; 173#elif defined(HAVE_INET_ADDR) 174 a.s_addr = inet_addr(p); 175 if(a.s_addr == INADDR_NONE) 176 return -1; 177#else 178 return -1; 179#endif 180 addr->addr_type = KRB5_ADDRESS_INET; 181 if(krb5_data_alloc(&addr->address, 4) != 0) 182 return -1; 183 _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length); 184 return 0; 185} 186 187/* 188 * AF_INET6 - aka IPv6 implementation 189 */ 190 191#ifdef HAVE_IPV6 192 193static krb5_error_code 194ipv6_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) 195{ 196 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 197 198 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 199 unsigned char buf[4]; 200 201 a->addr_type = KRB5_ADDRESS_INET; 202#ifndef IN6_ADDR_V6_TO_V4 203#ifdef IN6_EXTRACT_V4ADDR 204#define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x)) 205#else 206#define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12]) 207#endif 208#endif 209 memcpy (buf, IN6_ADDR_V6_TO_V4(&sin6->sin6_addr), 4); 210 return krb5_data_copy(&a->address, buf, 4); 211 } else { 212 a->addr_type = KRB5_ADDRESS_INET6; 213 return krb5_data_copy(&a->address, 214 &sin6->sin6_addr, 215 sizeof(sin6->sin6_addr)); 216 } 217} 218 219static krb5_error_code 220ipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port) 221{ 222 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 223 224 *port = sin6->sin6_port; 225 return 0; 226} 227 228static void 229ipv6_addr2sockaddr (const krb5_address *a, 230 struct sockaddr *sa, 231 int *sa_size, 232 int port) 233{ 234 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 235 236 memset (sin6, 0, sizeof(*sin6)); 237 sin6->sin6_family = AF_INET6; 238 memcpy (&sin6->sin6_addr, a->address.data, sizeof(sin6->sin6_addr)); 239 sin6->sin6_port = port; 240 *sa_size = sizeof(*sin6); 241} 242 243static void 244ipv6_h_addr2sockaddr(const char *addr, 245 struct sockaddr *sa, 246 int *sa_size, 247 int port) 248{ 249 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 250 251 memset (sin6, 0, sizeof(*sin6)); 252 *sa_size = sizeof(*sin6); 253 sin6->sin6_family = AF_INET6; 254 sin6->sin6_port = port; 255 sin6->sin6_addr = *((const struct in6_addr *)addr); 256} 257 258static krb5_error_code 259ipv6_h_addr2addr (const char *addr, 260 krb5_address *a) 261{ 262 a->addr_type = KRB5_ADDRESS_INET6; 263 return krb5_data_copy(&a->address, addr, sizeof(struct in6_addr)); 264} 265 266/* 267 * 268 */ 269 270static krb5_boolean 271ipv6_uninteresting (const struct sockaddr *sa) 272{ 273 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 274 const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr; 275 276 return 277 IN6_IS_ADDR_LINKLOCAL(in6) 278 || IN6_IS_ADDR_V4COMPAT(in6); 279} 280 281static void 282ipv6_anyaddr (struct sockaddr *sa, int *sa_size, int port) 283{ 284 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 285 286 memset (sin6, 0, sizeof(*sin6)); 287 *sa_size = sizeof(*sin6); 288 sin6->sin6_family = AF_INET6; 289 sin6->sin6_port = port; 290 sin6->sin6_addr = in6addr_any; 291} 292 293static int 294ipv6_print_addr (const krb5_address *addr, char *str, size_t len) 295{ 296 char buf[128], buf2[3]; 297#ifdef HAVE_INET_NTOP 298 if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL) 299#endif 300 { 301 /* XXX this is pretty ugly, but better than abort() */ 302 int i; 303 unsigned char *p = addr->address.data; 304 buf[0] = '\0'; 305 for(i = 0; i < addr->address.length; i++) { 306 snprintf(buf2, sizeof(buf2), "%02x", p[i]); 307 if(i > 0 && (i & 1) == 0) 308 strlcat(buf, ":", sizeof(buf)); 309 strlcat(buf, buf2, sizeof(buf)); 310 } 311 } 312 return snprintf(str, len, "IPv6:%s", buf); 313} 314 315static int 316ipv6_parse_addr (const char *address, krb5_address *addr) 317{ 318 int ret; 319 struct in6_addr in6; 320 321 ret = inet_pton(AF_INET6, address, &in6.s6_addr); 322 if(ret == 1) { 323 addr->addr_type = KRB5_ADDRESS_INET6; 324 ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr)); 325 if (ret) 326 return -1; 327 memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr)); 328 return 0; 329 } 330 return -1; 331} 332 333#endif /* IPv6 */ 334 335/* 336 * table 337 */ 338 339static struct addr_operations at[] = { 340 {AF_INET, KRB5_ADDRESS_INET, sizeof(struct sockaddr_in), 341 ipv4_sockaddr2addr, 342 ipv4_sockaddr2port, 343 ipv4_addr2sockaddr, 344 ipv4_h_addr2sockaddr, 345 ipv4_h_addr2addr, 346 ipv4_uninteresting, ipv4_anyaddr, ipv4_print_addr, ipv4_parse_addr}, 347#ifdef HAVE_IPV6 348 {AF_INET6, KRB5_ADDRESS_INET6, sizeof(struct sockaddr_in6), 349 ipv6_sockaddr2addr, 350 ipv6_sockaddr2port, 351 ipv6_addr2sockaddr, 352 ipv6_h_addr2sockaddr, 353 ipv6_h_addr2addr, 354 ipv6_uninteresting, ipv6_anyaddr, ipv6_print_addr, ipv6_parse_addr} 355#endif 356}; 357 358static int num_addrs = sizeof(at) / sizeof(at[0]); 359 360static size_t max_sockaddr_size = 0; 361 362/* 363 * generic functions 364 */ 365 366static struct addr_operations * 367find_af(int af) 368{ 369 struct addr_operations *a; 370 371 for (a = at; a < at + num_addrs; ++a) 372 if (af == a->af) 373 return a; 374 return NULL; 375} 376 377static struct addr_operations * 378find_atype(int atype) 379{ 380 struct addr_operations *a; 381 382 for (a = at; a < at + num_addrs; ++a) 383 if (atype == a->atype) 384 return a; 385 return NULL; 386} 387 388krb5_error_code 389krb5_sockaddr2address (const struct sockaddr *sa, krb5_address *addr) 390{ 391 struct addr_operations *a = find_af(sa->sa_family); 392 if (a == NULL) 393 return KRB5_PROG_ATYPE_NOSUPP; 394 return (*a->sockaddr2addr)(sa, addr); 395} 396 397krb5_error_code 398krb5_sockaddr2port (const struct sockaddr *sa, int16_t *port) 399{ 400 struct addr_operations *a = find_af(sa->sa_family); 401 if (a == NULL) 402 return KRB5_PROG_ATYPE_NOSUPP; 403 return (*a->sockaddr2port)(sa, port); 404} 405 406krb5_error_code 407krb5_addr2sockaddr (const krb5_address *addr, 408 struct sockaddr *sa, 409 int *sa_size, 410 int port) 411{ 412 struct addr_operations *a = find_atype(addr->addr_type); 413 414 if (a == NULL) 415 return KRB5_PROG_ATYPE_NOSUPP; 416 (*a->addr2sockaddr)(addr, sa, sa_size, port); 417 return 0; 418} 419 420size_t 421krb5_max_sockaddr_size (void) 422{ 423 if (max_sockaddr_size == 0) { 424 struct addr_operations *a; 425 426 for(a = at; a < at + num_addrs; ++a) 427 max_sockaddr_size = max(max_sockaddr_size, a->max_sockaddr_size); 428 } 429 return max_sockaddr_size; 430} 431 432krb5_boolean 433krb5_sockaddr_uninteresting(const struct sockaddr *sa) 434{ 435 struct addr_operations *a = find_af(sa->sa_family); 436 if (a == NULL) 437 return TRUE; 438 return (*a->uninteresting)(sa); 439} 440 441krb5_error_code 442krb5_h_addr2sockaddr (int af, 443 const char *addr, struct sockaddr *sa, int *sa_size, 444 int port) 445{ 446 struct addr_operations *a = find_af(af); 447 if (a == NULL) 448 return KRB5_PROG_ATYPE_NOSUPP; 449 (*a->h_addr2sockaddr)(addr, sa, sa_size, port); 450 return 0; 451} 452 453krb5_error_code 454krb5_h_addr2addr (int af, 455 const char *haddr, krb5_address *addr) 456{ 457 struct addr_operations *a = find_af(af); 458 if (a == NULL) 459 return KRB5_PROG_ATYPE_NOSUPP; 460 return (*a->h_addr2addr)(haddr, addr); 461} 462 463krb5_error_code 464krb5_anyaddr (int af, 465 struct sockaddr *sa, 466 int *sa_size, 467 int port) 468{ 469 struct addr_operations *a = find_af (af); 470 471 if (a == NULL) 472 return KRB5_PROG_ATYPE_NOSUPP; 473 474 (*a->anyaddr)(sa, sa_size, port); 475 return 0; 476} 477 478krb5_error_code 479krb5_print_address (const krb5_address *addr, 480 char *str, size_t len, size_t *ret_len) 481{ 482 struct addr_operations *a = find_atype(addr->addr_type); 483 484 if (a == NULL) { 485 char *s; 486 size_t l; 487 int i; 488 s = str; 489 l = snprintf(s, len, "TYPE_%d:", addr->addr_type); 490 s += l; 491 len -= len; 492 for(i = 0; i < addr->address.length; i++) { 493 l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]); 494 len -= l; 495 s += l; 496 } 497 *ret_len = s - str; 498 return 0; 499 } 500 *ret_len = (*a->print_addr)(addr, str, len); 501 return 0; 502} 503 504krb5_error_code 505krb5_parse_address(krb5_context context, 506 const char *string, 507 krb5_addresses *addresses) 508{ 509 int i, n; 510 struct addrinfo *ai, *a; 511 int error; 512 513 for(i = 0; i < num_addrs; i++) { 514 if(at[i].parse_addr) { 515 krb5_address a; 516 if((*at[i].parse_addr)(string, &a) == 0) { 517 ALLOC_SEQ(addresses, 1); 518 addresses->val[0] = a; 519 return 0; 520 } 521 } 522 } 523 524 error = getaddrinfo (string, NULL, NULL, &ai); 525 if (error) 526 return -1; 527 528 n = 0; 529 for (a = ai; a != NULL; a = a->ai_next) 530 ++n; 531 532 ALLOC_SEQ(addresses, n); 533 534 for (a = ai, i = 0; a != NULL; a = a->ai_next, ++i) {
| 37 38struct addr_operations { 39 int af; 40 krb5_address_type atype; 41 size_t max_sockaddr_size; 42 krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *); 43 krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *); 44 void (*addr2sockaddr)(const krb5_address *, struct sockaddr *, 45 int *sa_size, int port); 46 void (*h_addr2sockaddr)(const char *, struct sockaddr *, int *, int); 47 krb5_error_code (*h_addr2addr)(const char *, krb5_address *); 48 krb5_boolean (*uninteresting)(const struct sockaddr *); 49 void (*anyaddr)(struct sockaddr *, int *, int); 50 int (*print_addr)(const krb5_address *, char *, size_t); 51 int (*parse_addr)(const char*, krb5_address *); 52}; 53 54/* 55 * AF_INET - aka IPv4 implementation 56 */ 57 58static krb5_error_code 59ipv4_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) 60{ 61 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; 62 unsigned char buf[4]; 63 64 a->addr_type = KRB5_ADDRESS_INET; 65 memcpy (buf, &sin->sin_addr, 4); 66 return krb5_data_copy(&a->address, buf, 4); 67} 68 69static krb5_error_code 70ipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port) 71{ 72 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; 73 74 *port = sin->sin_port; 75 return 0; 76} 77 78static void 79ipv4_addr2sockaddr (const krb5_address *a, 80 struct sockaddr *sa, 81 int *sa_size, 82 int port) 83{ 84 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 85 86 memset (sin, 0, sizeof(*sin)); 87 sin->sin_family = AF_INET; 88 memcpy (&sin->sin_addr, a->address.data, 4); 89 sin->sin_port = port; 90 *sa_size = sizeof(*sin); 91} 92 93static void 94ipv4_h_addr2sockaddr(const char *addr, 95 struct sockaddr *sa, int *sa_size, int port) 96{ 97 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 98 99 memset (sin, 0, sizeof(*sin)); 100 *sa_size = sizeof(*sin); 101 sin->sin_family = AF_INET; 102 sin->sin_port = port; 103 sin->sin_addr = *((const struct in_addr *)addr); 104} 105 106static krb5_error_code 107ipv4_h_addr2addr (const char *addr, 108 krb5_address *a) 109{ 110 unsigned char buf[4]; 111 112 a->addr_type = KRB5_ADDRESS_INET; 113 memcpy(buf, addr, 4); 114 return krb5_data_copy(&a->address, buf, 4); 115} 116 117/* 118 * Are there any addresses that should be considered `uninteresting'? 119 */ 120 121static krb5_boolean 122ipv4_uninteresting (const struct sockaddr *sa) 123{ 124 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; 125 126 if (sin->sin_addr.s_addr == INADDR_ANY) 127 return TRUE; 128 129 return FALSE; 130} 131 132static void 133ipv4_anyaddr (struct sockaddr *sa, int *sa_size, int port) 134{ 135 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 136 137 memset (sin, 0, sizeof(*sin)); 138 *sa_size = sizeof(*sin); 139 sin->sin_family = AF_INET; 140 sin->sin_port = port; 141 sin->sin_addr.s_addr = INADDR_ANY; 142} 143 144static int 145ipv4_print_addr (const krb5_address *addr, char *str, size_t len) 146{ 147 struct in_addr ia; 148 149 memcpy (&ia, addr->address.data, 4); 150 151 return snprintf (str, len, "IPv4:%s", inet_ntoa(ia)); 152} 153 154static int 155ipv4_parse_addr (const char *address, krb5_address *addr) 156{ 157 const char *p; 158 struct in_addr a; 159 160 p = strchr(address, ':'); 161 if(p) { 162 p++; 163 if(strncasecmp(address, "ip:", p - address) != 0 && 164 strncasecmp(address, "ip4:", p - address) != 0 && 165 strncasecmp(address, "ipv4:", p - address) != 0 && 166 strncasecmp(address, "inet:", p - address) != 0) 167 return -1; 168 } else 169 p = address; 170#ifdef HAVE_INET_ATON 171 if(inet_aton(p, &a) == 0) 172 return -1; 173#elif defined(HAVE_INET_ADDR) 174 a.s_addr = inet_addr(p); 175 if(a.s_addr == INADDR_NONE) 176 return -1; 177#else 178 return -1; 179#endif 180 addr->addr_type = KRB5_ADDRESS_INET; 181 if(krb5_data_alloc(&addr->address, 4) != 0) 182 return -1; 183 _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length); 184 return 0; 185} 186 187/* 188 * AF_INET6 - aka IPv6 implementation 189 */ 190 191#ifdef HAVE_IPV6 192 193static krb5_error_code 194ipv6_sockaddr2addr (const struct sockaddr *sa, krb5_address *a) 195{ 196 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 197 198 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 199 unsigned char buf[4]; 200 201 a->addr_type = KRB5_ADDRESS_INET; 202#ifndef IN6_ADDR_V6_TO_V4 203#ifdef IN6_EXTRACT_V4ADDR 204#define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x)) 205#else 206#define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12]) 207#endif 208#endif 209 memcpy (buf, IN6_ADDR_V6_TO_V4(&sin6->sin6_addr), 4); 210 return krb5_data_copy(&a->address, buf, 4); 211 } else { 212 a->addr_type = KRB5_ADDRESS_INET6; 213 return krb5_data_copy(&a->address, 214 &sin6->sin6_addr, 215 sizeof(sin6->sin6_addr)); 216 } 217} 218 219static krb5_error_code 220ipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port) 221{ 222 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 223 224 *port = sin6->sin6_port; 225 return 0; 226} 227 228static void 229ipv6_addr2sockaddr (const krb5_address *a, 230 struct sockaddr *sa, 231 int *sa_size, 232 int port) 233{ 234 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 235 236 memset (sin6, 0, sizeof(*sin6)); 237 sin6->sin6_family = AF_INET6; 238 memcpy (&sin6->sin6_addr, a->address.data, sizeof(sin6->sin6_addr)); 239 sin6->sin6_port = port; 240 *sa_size = sizeof(*sin6); 241} 242 243static void 244ipv6_h_addr2sockaddr(const char *addr, 245 struct sockaddr *sa, 246 int *sa_size, 247 int port) 248{ 249 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 250 251 memset (sin6, 0, sizeof(*sin6)); 252 *sa_size = sizeof(*sin6); 253 sin6->sin6_family = AF_INET6; 254 sin6->sin6_port = port; 255 sin6->sin6_addr = *((const struct in6_addr *)addr); 256} 257 258static krb5_error_code 259ipv6_h_addr2addr (const char *addr, 260 krb5_address *a) 261{ 262 a->addr_type = KRB5_ADDRESS_INET6; 263 return krb5_data_copy(&a->address, addr, sizeof(struct in6_addr)); 264} 265 266/* 267 * 268 */ 269 270static krb5_boolean 271ipv6_uninteresting (const struct sockaddr *sa) 272{ 273 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa; 274 const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr; 275 276 return 277 IN6_IS_ADDR_LINKLOCAL(in6) 278 || IN6_IS_ADDR_V4COMPAT(in6); 279} 280 281static void 282ipv6_anyaddr (struct sockaddr *sa, int *sa_size, int port) 283{ 284 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 285 286 memset (sin6, 0, sizeof(*sin6)); 287 *sa_size = sizeof(*sin6); 288 sin6->sin6_family = AF_INET6; 289 sin6->sin6_port = port; 290 sin6->sin6_addr = in6addr_any; 291} 292 293static int 294ipv6_print_addr (const krb5_address *addr, char *str, size_t len) 295{ 296 char buf[128], buf2[3]; 297#ifdef HAVE_INET_NTOP 298 if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL) 299#endif 300 { 301 /* XXX this is pretty ugly, but better than abort() */ 302 int i; 303 unsigned char *p = addr->address.data; 304 buf[0] = '\0'; 305 for(i = 0; i < addr->address.length; i++) { 306 snprintf(buf2, sizeof(buf2), "%02x", p[i]); 307 if(i > 0 && (i & 1) == 0) 308 strlcat(buf, ":", sizeof(buf)); 309 strlcat(buf, buf2, sizeof(buf)); 310 } 311 } 312 return snprintf(str, len, "IPv6:%s", buf); 313} 314 315static int 316ipv6_parse_addr (const char *address, krb5_address *addr) 317{ 318 int ret; 319 struct in6_addr in6; 320 321 ret = inet_pton(AF_INET6, address, &in6.s6_addr); 322 if(ret == 1) { 323 addr->addr_type = KRB5_ADDRESS_INET6; 324 ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr)); 325 if (ret) 326 return -1; 327 memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr)); 328 return 0; 329 } 330 return -1; 331} 332 333#endif /* IPv6 */ 334 335/* 336 * table 337 */ 338 339static struct addr_operations at[] = { 340 {AF_INET, KRB5_ADDRESS_INET, sizeof(struct sockaddr_in), 341 ipv4_sockaddr2addr, 342 ipv4_sockaddr2port, 343 ipv4_addr2sockaddr, 344 ipv4_h_addr2sockaddr, 345 ipv4_h_addr2addr, 346 ipv4_uninteresting, ipv4_anyaddr, ipv4_print_addr, ipv4_parse_addr}, 347#ifdef HAVE_IPV6 348 {AF_INET6, KRB5_ADDRESS_INET6, sizeof(struct sockaddr_in6), 349 ipv6_sockaddr2addr, 350 ipv6_sockaddr2port, 351 ipv6_addr2sockaddr, 352 ipv6_h_addr2sockaddr, 353 ipv6_h_addr2addr, 354 ipv6_uninteresting, ipv6_anyaddr, ipv6_print_addr, ipv6_parse_addr} 355#endif 356}; 357 358static int num_addrs = sizeof(at) / sizeof(at[0]); 359 360static size_t max_sockaddr_size = 0; 361 362/* 363 * generic functions 364 */ 365 366static struct addr_operations * 367find_af(int af) 368{ 369 struct addr_operations *a; 370 371 for (a = at; a < at + num_addrs; ++a) 372 if (af == a->af) 373 return a; 374 return NULL; 375} 376 377static struct addr_operations * 378find_atype(int atype) 379{ 380 struct addr_operations *a; 381 382 for (a = at; a < at + num_addrs; ++a) 383 if (atype == a->atype) 384 return a; 385 return NULL; 386} 387 388krb5_error_code 389krb5_sockaddr2address (const struct sockaddr *sa, krb5_address *addr) 390{ 391 struct addr_operations *a = find_af(sa->sa_family); 392 if (a == NULL) 393 return KRB5_PROG_ATYPE_NOSUPP; 394 return (*a->sockaddr2addr)(sa, addr); 395} 396 397krb5_error_code 398krb5_sockaddr2port (const struct sockaddr *sa, int16_t *port) 399{ 400 struct addr_operations *a = find_af(sa->sa_family); 401 if (a == NULL) 402 return KRB5_PROG_ATYPE_NOSUPP; 403 return (*a->sockaddr2port)(sa, port); 404} 405 406krb5_error_code 407krb5_addr2sockaddr (const krb5_address *addr, 408 struct sockaddr *sa, 409 int *sa_size, 410 int port) 411{ 412 struct addr_operations *a = find_atype(addr->addr_type); 413 414 if (a == NULL) 415 return KRB5_PROG_ATYPE_NOSUPP; 416 (*a->addr2sockaddr)(addr, sa, sa_size, port); 417 return 0; 418} 419 420size_t 421krb5_max_sockaddr_size (void) 422{ 423 if (max_sockaddr_size == 0) { 424 struct addr_operations *a; 425 426 for(a = at; a < at + num_addrs; ++a) 427 max_sockaddr_size = max(max_sockaddr_size, a->max_sockaddr_size); 428 } 429 return max_sockaddr_size; 430} 431 432krb5_boolean 433krb5_sockaddr_uninteresting(const struct sockaddr *sa) 434{ 435 struct addr_operations *a = find_af(sa->sa_family); 436 if (a == NULL) 437 return TRUE; 438 return (*a->uninteresting)(sa); 439} 440 441krb5_error_code 442krb5_h_addr2sockaddr (int af, 443 const char *addr, struct sockaddr *sa, int *sa_size, 444 int port) 445{ 446 struct addr_operations *a = find_af(af); 447 if (a == NULL) 448 return KRB5_PROG_ATYPE_NOSUPP; 449 (*a->h_addr2sockaddr)(addr, sa, sa_size, port); 450 return 0; 451} 452 453krb5_error_code 454krb5_h_addr2addr (int af, 455 const char *haddr, krb5_address *addr) 456{ 457 struct addr_operations *a = find_af(af); 458 if (a == NULL) 459 return KRB5_PROG_ATYPE_NOSUPP; 460 return (*a->h_addr2addr)(haddr, addr); 461} 462 463krb5_error_code 464krb5_anyaddr (int af, 465 struct sockaddr *sa, 466 int *sa_size, 467 int port) 468{ 469 struct addr_operations *a = find_af (af); 470 471 if (a == NULL) 472 return KRB5_PROG_ATYPE_NOSUPP; 473 474 (*a->anyaddr)(sa, sa_size, port); 475 return 0; 476} 477 478krb5_error_code 479krb5_print_address (const krb5_address *addr, 480 char *str, size_t len, size_t *ret_len) 481{ 482 struct addr_operations *a = find_atype(addr->addr_type); 483 484 if (a == NULL) { 485 char *s; 486 size_t l; 487 int i; 488 s = str; 489 l = snprintf(s, len, "TYPE_%d:", addr->addr_type); 490 s += l; 491 len -= len; 492 for(i = 0; i < addr->address.length; i++) { 493 l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]); 494 len -= l; 495 s += l; 496 } 497 *ret_len = s - str; 498 return 0; 499 } 500 *ret_len = (*a->print_addr)(addr, str, len); 501 return 0; 502} 503 504krb5_error_code 505krb5_parse_address(krb5_context context, 506 const char *string, 507 krb5_addresses *addresses) 508{ 509 int i, n; 510 struct addrinfo *ai, *a; 511 int error; 512 513 for(i = 0; i < num_addrs; i++) { 514 if(at[i].parse_addr) { 515 krb5_address a; 516 if((*at[i].parse_addr)(string, &a) == 0) { 517 ALLOC_SEQ(addresses, 1); 518 addresses->val[0] = a; 519 return 0; 520 } 521 } 522 } 523 524 error = getaddrinfo (string, NULL, NULL, &ai); 525 if (error) 526 return -1; 527 528 n = 0; 529 for (a = ai; a != NULL; a = a->ai_next) 530 ++n; 531 532 ALLOC_SEQ(addresses, n); 533 534 for (a = ai, i = 0; a != NULL; a = a->ai_next, ++i) {
|