1/* Socket union related function. 2 * Copyright (c) 1997, 98 Kunihiro Ishiguro 3 * 4 * This file is part of GNU Zebra. 5 * 6 * GNU Zebra is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2, or (at your option) any 9 * later version. 10 * 11 * GNU Zebra is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with GNU Zebra; see the file COPYING. If not, write to the Free 18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19 * 02111-1307, USA. 20 */ 21 22#include <zebra.h> 23 24#include "prefix.h" 25#include "vty.h" 26#include "sockunion.h" 27#include "memory.h" 28#include "str.h" 29#include "log.h" 30 31#ifndef HAVE_INET_ATON 32int 33inet_aton (const char *cp, struct in_addr *inaddr) 34{ 35 int dots = 0; 36 register u_long addr = 0; 37 register u_long val = 0, base = 10; 38 39 do 40 { 41 register char c = *cp; 42 43 switch (c) 44 { 45 case '0': case '1': case '2': case '3': case '4': case '5': 46 case '6': case '7': case '8': case '9': 47 val = (val * base) + (c - '0'); 48 break; 49 case '.': 50 if (++dots > 3) 51 return 0; 52 case '\0': 53 if (val > 255) 54 return 0; 55 addr = addr << 8 | val; 56 val = 0; 57 break; 58 default: 59 return 0; 60 } 61 } while (*cp++) ; 62 63 if (dots < 3) 64 addr <<= 8 * (3 - dots); 65 if (inaddr) 66 inaddr->s_addr = htonl (addr); 67 return 1; 68} 69#endif /* ! HAVE_INET_ATON */ 70 71 72#ifndef HAVE_INET_PTON 73int 74inet_pton (int family, const char *strptr, void *addrptr) 75{ 76 if (family == AF_INET) 77 { 78 struct in_addr in_val; 79 80 if (inet_aton (strptr, &in_val)) 81 { 82 memcpy (addrptr, &in_val, sizeof (struct in_addr)); 83 return 1; 84 } 85 return 0; 86 } 87 errno = EAFNOSUPPORT; 88 return -1; 89} 90#endif /* ! HAVE_INET_PTON */ 91 92#ifndef HAVE_INET_NTOP 93const char * 94inet_ntop (int family, const void *addrptr, char *strptr, size_t len) 95{ 96 unsigned char *p = (unsigned char *) addrptr; 97 98 if (family == AF_INET) 99 { 100 char temp[INET_ADDRSTRLEN]; 101 102 snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); 103 104 if (strlen(temp) >= len) 105 { 106 errno = ENOSPC; 107 return NULL; 108 } 109 strcpy(strptr, temp); 110 return strptr; 111 } 112 113 errno = EAFNOSUPPORT; 114 return NULL; 115} 116#endif /* ! HAVE_INET_NTOP */ 117 118const char * 119inet_sutop (union sockunion *su, char *str) 120{ 121 switch (su->sa.sa_family) 122 { 123 case AF_INET: 124 inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN); 125 break; 126#ifdef HAVE_IPV6 127 case AF_INET6: 128 inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN); 129 break; 130#endif /* HAVE_IPV6 */ 131 } 132 return str; 133} 134 135int 136str2sockunion (const char *str, union sockunion *su) 137{ 138 int ret; 139 140 memset (su, 0, sizeof (union sockunion)); 141 142 ret = inet_pton (AF_INET, str, &su->sin.sin_addr); 143 if (ret > 0) /* Valid IPv4 address format. */ 144 { 145 su->sin.sin_family = AF_INET; 146#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 147 su->sin.sin_len = sizeof(struct sockaddr_in); 148#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ 149 return 0; 150 } 151#ifdef HAVE_IPV6 152 ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr); 153 if (ret > 0) /* Valid IPv6 address format. */ 154 { 155 su->sin6.sin6_family = AF_INET6; 156#ifdef SIN6_LEN 157 su->sin6.sin6_len = sizeof(struct sockaddr_in6); 158#endif /* SIN6_LEN */ 159 return 0; 160 } 161#endif /* HAVE_IPV6 */ 162 return -1; 163} 164 165const char * 166sockunion2str (union sockunion *su, char *buf, size_t len) 167{ 168 if (su->sa.sa_family == AF_INET) 169 return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len); 170#ifdef HAVE_IPV6 171 else if (su->sa.sa_family == AF_INET6) 172 return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len); 173#endif /* HAVE_IPV6 */ 174 return NULL; 175} 176 177union sockunion * 178sockunion_str2su (const char *str) 179{ 180 union sockunion *su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); 181 182 if (!str2sockunion (str, su)) 183 return su; 184 185 XFREE (MTYPE_SOCKUNION, su); 186 return NULL; 187} 188 189/* Convert IPv4 compatible IPv6 address to IPv4 address. */ 190static void 191sockunion_normalise_mapped (union sockunion *su) 192{ 193 struct sockaddr_in sin; 194 195#ifdef HAVE_IPV6 196 if (su->sa.sa_family == AF_INET6 197 && IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr)) 198 { 199 memset (&sin, 0, sizeof (struct sockaddr_in)); 200 sin.sin_family = AF_INET; 201 sin.sin_port = su->sin6.sin6_port; 202 memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4); 203 memcpy (su, &sin, sizeof (struct sockaddr_in)); 204 } 205#endif /* HAVE_IPV6 */ 206} 207 208/* Return socket of sockunion. */ 209int 210sockunion_socket (union sockunion *su) 211{ 212 int sock; 213 214 sock = socket (su->sa.sa_family, SOCK_STREAM, 0); 215 if (sock < 0) 216 { 217 zlog (NULL, LOG_WARNING, "Can't make socket : %s", safe_strerror (errno)); 218 return -1; 219 } 220 221 return sock; 222} 223 224/* Return accepted new socket file descriptor. */ 225int 226sockunion_accept (int sock, union sockunion *su) 227{ 228 socklen_t len; 229 int client_sock; 230 231 len = sizeof (union sockunion); 232 client_sock = accept (sock, (struct sockaddr *) su, &len); 233 234 sockunion_normalise_mapped (su); 235 return client_sock; 236} 237 238/* Return sizeof union sockunion. */ 239static int 240sockunion_sizeof (union sockunion *su) 241{ 242 int ret; 243 244 ret = 0; 245 switch (su->sa.sa_family) 246 { 247 case AF_INET: 248 ret = sizeof (struct sockaddr_in); 249 break; 250#ifdef HAVE_IPV6 251 case AF_INET6: 252 ret = sizeof (struct sockaddr_in6); 253 break; 254#endif /* AF_INET6 */ 255 } 256 return ret; 257} 258 259/* return sockunion structure : this function should be revised. */ 260static const char * 261sockunion_log (union sockunion *su, char *buf, size_t len) 262{ 263 switch (su->sa.sa_family) 264 { 265 case AF_INET: 266 return inet_ntop(AF_INET, &su->sin.sin_addr, buf, len); 267 268#ifdef HAVE_IPV6 269 case AF_INET6: 270 return inet_ntop(AF_INET6, &(su->sin6.sin6_addr), buf, len); 271 break; 272#endif /* HAVE_IPV6 */ 273 274 default: 275 snprintf (buf, len, "af_unknown %d ", su->sa.sa_family); 276 return buf; 277 } 278} 279 280/* sockunion_connect returns 281 -1 : error occured 282 0 : connect success 283 1 : connect is in progress */ 284enum connect_result 285sockunion_connect (int fd, union sockunion *peersu, unsigned short port, 286 unsigned int ifindex) 287{ 288 int ret; 289 int val; 290 union sockunion su; 291 292 memcpy (&su, peersu, sizeof (union sockunion)); 293 294 switch (su.sa.sa_family) 295 { 296 case AF_INET: 297 su.sin.sin_port = port; 298 break; 299#ifdef HAVE_IPV6 300 case AF_INET6: 301 su.sin6.sin6_port = port; 302#ifdef KAME 303 if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex) 304 { 305#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 306 /* su.sin6.sin6_scope_id = ifindex; */ 307#endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */ 308 SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex); 309 } 310#endif /* KAME */ 311 break; 312#endif /* HAVE_IPV6 */ 313 } 314 315 /* Make socket non-block. */ 316 val = fcntl (fd, F_GETFL, 0); 317 fcntl (fd, F_SETFL, val|O_NONBLOCK); 318 319 /* Call connect function. */ 320 ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su)); 321 322 /* Immediate success */ 323 if (ret == 0) 324 { 325 fcntl (fd, F_SETFL, val); 326 return connect_success; 327 } 328 329 /* If connect is in progress then return 1 else it's real error. */ 330 if (ret < 0) 331 { 332 if (errno != EINPROGRESS) 333 { 334 char str[SU_ADDRSTRLEN]; 335 zlog_info ("can't connect to %s fd %d : %s", 336 sockunion_log (&su, str, sizeof str), 337 fd, safe_strerror (errno)); 338 return connect_error; 339 } 340 } 341 342 fcntl (fd, F_SETFL, val); 343 344 return connect_in_progress; 345} 346 347/* Make socket from sockunion union. */ 348int 349sockunion_stream_socket (union sockunion *su) 350{ 351 int sock; 352 353 if (su->sa.sa_family == 0) 354 su->sa.sa_family = AF_INET_UNION; 355 356 sock = socket (su->sa.sa_family, SOCK_STREAM, 0); 357 358 if (sock < 0) 359 zlog (NULL, LOG_WARNING, "can't make socket sockunion_stream_socket"); 360 361 return sock; 362} 363 364/* Bind socket to specified address. */ 365int 366sockunion_bind (int sock, union sockunion *su, unsigned short port, 367 union sockunion *su_addr) 368{ 369 int size = 0; 370 int ret; 371 372 if (su->sa.sa_family == AF_INET) 373 { 374 size = sizeof (struct sockaddr_in); 375 su->sin.sin_port = htons (port); 376#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 377 su->sin.sin_len = size; 378#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ 379 if (su_addr == NULL) 380 sockunion2ip (su) = htonl (INADDR_ANY); 381 } 382#ifdef HAVE_IPV6 383 else if (su->sa.sa_family == AF_INET6) 384 { 385 size = sizeof (struct sockaddr_in6); 386 su->sin6.sin6_port = htons (port); 387#ifdef SIN6_LEN 388 su->sin6.sin6_len = size; 389#endif /* SIN6_LEN */ 390 if (su_addr == NULL) 391 { 392#ifdef LINUX_IPV6 393 memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr)); 394#else 395 su->sin6.sin6_addr = in6addr_any; 396#endif /* LINUX_IPV6 */ 397 } 398 } 399#endif /* HAVE_IPV6 */ 400 401 402 ret = bind (sock, (struct sockaddr *)su, size); 403 if (ret < 0) 404 zlog (NULL, LOG_WARNING, "can't bind socket : %s", safe_strerror (errno)); 405 406 return ret; 407} 408 409int 410sockopt_reuseaddr (int sock) 411{ 412 int ret; 413 int on = 1; 414 415 ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, 416 (void *) &on, sizeof (on)); 417 if (ret < 0) 418 { 419 zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock); 420 return -1; 421 } 422 return 0; 423} 424 425#ifdef SO_REUSEPORT 426int 427sockopt_reuseport (int sock) 428{ 429 int ret; 430 int on = 1; 431 432 ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, 433 (void *) &on, sizeof (on)); 434 if (ret < 0) 435 { 436 zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEPORT to socket %d", sock); 437 return -1; 438 } 439 return 0; 440} 441#else 442int 443sockopt_reuseport (int sock) 444{ 445 return 0; 446} 447#endif /* 0 */ 448 449int 450sockopt_ttl (int family, int sock, int ttl) 451{ 452 int ret; 453 454#ifdef IP_TTL 455 if (family == AF_INET) 456 { 457 ret = setsockopt (sock, IPPROTO_IP, IP_TTL, 458 (void *) &ttl, sizeof (int)); 459 if (ret < 0) 460 { 461 zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock); 462 return -1; 463 } 464 return 0; 465 } 466#endif /* IP_TTL */ 467#ifdef HAVE_IPV6 468 if (family == AF_INET6) 469 { 470 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 471 (void *) &ttl, sizeof (int)); 472 if (ret < 0) 473 { 474 zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d", 475 ttl, sock); 476 return -1; 477 } 478 return 0; 479 } 480#endif /* HAVE_IPV6 */ 481 return 0; 482} 483 484int 485sockopt_cork (int sock, int onoff) 486{ 487#ifdef TCP_CORK 488 return setsockopt (sock, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff)); 489#else 490 return 0; 491#endif 492} 493 494int 495sockopt_minttl (int family, int sock, int minttl) 496{ 497#ifdef IP_MINTTL 498 if (family == AF_INET) 499 { 500 int ret = setsockopt (sock, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl)); 501 if (ret < 0) 502 zlog (NULL, LOG_WARNING, 503 "can't set sockopt IP_MINTTL to %d on socket %d: %s", 504 minttl, sock, safe_strerror (errno)); 505 return ret; 506 } 507#endif /* IP_MINTTL */ 508#ifdef IPV6_MINHOPCNT 509 if (family == AF_INET6) 510 { 511 int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCNT, &minttl, sizeof(minttl)); 512 if (ret < 0) 513 zlog (NULL, LOG_WARNING, 514 "can't set sockopt IPV6_MINHOPCNT to %d on socket %d: %s", 515 minttl, sock, safe_strerror (errno)); 516 return ret; 517 } 518#endif 519 520 errno = EOPNOTSUPP; 521 return -1; 522} 523 524int 525sockopt_v6only (int family, int sock) 526{ 527 int ret, on = 1; 528 529#ifdef HAVE_IPV6 530#ifdef IPV6_V6ONLY 531 if (family == AF_INET6) 532 { 533 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, 534 (void *) &on, sizeof (int)); 535 if (ret < 0) 536 { 537 zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_V6ONLY " 538 "to socket %d", sock); 539 return -1; 540 } 541 return 0; 542 } 543#endif /* IPV6_V6ONLY */ 544#endif /* HAVE_IPV6 */ 545 return 0; 546} 547 548/* If same family and same prefix return 1. */ 549int 550sockunion_same (union sockunion *su1, union sockunion *su2) 551{ 552 int ret = 0; 553 554 if (su1->sa.sa_family != su2->sa.sa_family) 555 return 0; 556 557 switch (su1->sa.sa_family) 558 { 559 case AF_INET: 560 ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr, 561 sizeof (struct in_addr)); 562 break; 563#ifdef HAVE_IPV6 564 case AF_INET6: 565 ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr, 566 sizeof (struct in6_addr)); 567 break; 568#endif /* HAVE_IPV6 */ 569 } 570 if (ret == 0) 571 return 1; 572 else 573 return 0; 574} 575 576/* After TCP connection is established. Get local address and port. */ 577union sockunion * 578sockunion_getsockname (int fd) 579{ 580 int ret; 581 socklen_t len; 582 union 583 { 584 struct sockaddr sa; 585 struct sockaddr_in sin; 586#ifdef HAVE_IPV6 587 struct sockaddr_in6 sin6; 588#endif /* HAVE_IPV6 */ 589 char tmp_buffer[128]; 590 } name; 591 union sockunion *su; 592 593 memset (&name, 0, sizeof name); 594 len = sizeof name; 595 596 ret = getsockname (fd, (struct sockaddr *)&name, &len); 597 if (ret < 0) 598 { 599 zlog_warn ("Can't get local address and port by getsockname: %s", 600 safe_strerror (errno)); 601 return NULL; 602 } 603 604 if (name.sa.sa_family == AF_INET) 605 { 606 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); 607 memcpy (su, &name, sizeof (struct sockaddr_in)); 608 return su; 609 } 610#ifdef HAVE_IPV6 611 if (name.sa.sa_family == AF_INET6) 612 { 613 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); 614 memcpy (su, &name, sizeof (struct sockaddr_in6)); 615 sockunion_normalise_mapped (su); 616 return su; 617 } 618#endif /* HAVE_IPV6 */ 619 return NULL; 620} 621 622/* After TCP connection is established. Get remote address and port. */ 623union sockunion * 624sockunion_getpeername (int fd) 625{ 626 int ret; 627 socklen_t len; 628 union 629 { 630 struct sockaddr sa; 631 struct sockaddr_in sin; 632#ifdef HAVE_IPV6 633 struct sockaddr_in6 sin6; 634#endif /* HAVE_IPV6 */ 635 char tmp_buffer[128]; 636 } name; 637 union sockunion *su; 638 639 memset (&name, 0, sizeof name); 640 len = sizeof name; 641 ret = getpeername (fd, (struct sockaddr *)&name, &len); 642 if (ret < 0) 643 { 644 zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s", 645 safe_strerror (errno)); 646 return NULL; 647 } 648 649 if (name.sa.sa_family == AF_INET) 650 { 651 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); 652 memcpy (su, &name, sizeof (struct sockaddr_in)); 653 return su; 654 } 655#ifdef HAVE_IPV6 656 if (name.sa.sa_family == AF_INET6) 657 { 658 su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); 659 memcpy (su, &name, sizeof (struct sockaddr_in6)); 660 sockunion_normalise_mapped (su); 661 return su; 662 } 663#endif /* HAVE_IPV6 */ 664 return NULL; 665} 666 667/* Print sockunion structure */ 668static void __attribute__ ((unused)) 669sockunion_print (union sockunion *su) 670{ 671 if (su == NULL) 672 return; 673 674 switch (su->sa.sa_family) 675 { 676 case AF_INET: 677 printf ("%s\n", inet_ntoa (su->sin.sin_addr)); 678 break; 679#ifdef HAVE_IPV6 680 case AF_INET6: 681 { 682 char buf [SU_ADDRSTRLEN]; 683 684 printf ("%s\n", inet_ntop (AF_INET6, &(su->sin6.sin6_addr), 685 buf, sizeof (buf))); 686 } 687 break; 688#endif /* HAVE_IPV6 */ 689 690#ifdef AF_LINK 691 case AF_LINK: 692 { 693 struct sockaddr_dl *sdl; 694 695 sdl = (struct sockaddr_dl *)&(su->sa); 696 printf ("link#%d\n", sdl->sdl_index); 697 } 698 break; 699#endif /* AF_LINK */ 700 default: 701 printf ("af_unknown %d\n", su->sa.sa_family); 702 break; 703 } 704} 705 706#ifdef HAVE_IPV6 707static int 708in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2) 709{ 710 unsigned int i; 711 u_char *p1, *p2; 712 713 p1 = (u_char *)addr1; 714 p2 = (u_char *)addr2; 715 716 for (i = 0; i < sizeof (struct in6_addr); i++) 717 { 718 if (p1[i] > p2[i]) 719 return 1; 720 else if (p1[i] < p2[i]) 721 return -1; 722 } 723 return 0; 724} 725#endif /* HAVE_IPV6 */ 726 727int 728sockunion_cmp (union sockunion *su1, union sockunion *su2) 729{ 730 if (su1->sa.sa_family > su2->sa.sa_family) 731 return 1; 732 if (su1->sa.sa_family < su2->sa.sa_family) 733 return -1; 734 735 if (su1->sa.sa_family == AF_INET) 736 { 737 if (ntohl (sockunion2ip (su1)) == ntohl (sockunion2ip (su2))) 738 return 0; 739 if (ntohl (sockunion2ip (su1)) > ntohl (sockunion2ip (su2))) 740 return 1; 741 else 742 return -1; 743 } 744#ifdef HAVE_IPV6 745 if (su1->sa.sa_family == AF_INET6) 746 return in6addr_cmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr); 747#endif /* HAVE_IPV6 */ 748 return 0; 749} 750 751/* Duplicate sockunion. */ 752union sockunion * 753sockunion_dup (union sockunion *su) 754{ 755 union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion)); 756 memcpy (dup, su, sizeof (union sockunion)); 757 return dup; 758} 759 760void 761sockunion_free (union sockunion *su) 762{ 763 XFREE (MTYPE_SOCKUNION, su); 764} 765