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