comparison src/core/ngx_inet.c @ 4971:eaf95350d75c

Implemented IPv6 support for URLs specified using domain names. This includes "debug_connection", upstreams, "proxy_pass", etc. (ticket #92) To preserve compatibility, "listen" specified with a domain name selects the first IPv4 address, if available. If not available, the first IPv6 address will be used (ticket #186).
author Ruslan Ermilov <ru@nginx.com>
date Mon, 17 Dec 2012 12:08:53 +0000
parents ed2219d58518
children 2677c561127b
comparison
equal deleted inserted replaced
4970:ed2219d58518 4971:eaf95350d75c
609 609
610 610
611 static ngx_int_t 611 static ngx_int_t
612 ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) 612 ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
613 { 613 {
614 u_char *p, *host, *port, *last, *uri, *args; 614 u_char *p, *host, *port, *last, *uri, *args;
615 size_t len; 615 size_t len;
616 ngx_int_t n; 616 ngx_int_t n;
617 struct hostent *h; 617 struct sockaddr_in *sin;
618 struct sockaddr_in *sin; 618 #if (NGX_HAVE_INET6)
619 struct sockaddr_in6 *sin6;
620 #endif
619 621
620 u->socklen = sizeof(struct sockaddr_in); 622 u->socklen = sizeof(struct sockaddr_in);
621 sin = (struct sockaddr_in *) &u->sockaddr; 623 sin = (struct sockaddr_in *) &u->sockaddr;
622 sin->sin_family = AF_INET; 624 sin->sin_family = AF_INET;
623 625
726 sin->sin_addr.s_addr = INADDR_ANY; 728 sin->sin_addr.s_addr = INADDR_ANY;
727 u->wildcard = 1; 729 u->wildcard = 1;
728 return NGX_OK; 730 return NGX_OK;
729 } 731 }
730 732
733 sin->sin_addr.s_addr = ngx_inet_addr(host, len);
734
735 if (sin->sin_addr.s_addr != INADDR_NONE) {
736
737 if (sin->sin_addr.s_addr == INADDR_ANY) {
738 u->wildcard = 1;
739 }
740
741 u->naddrs = 1;
742
743 u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
744 if (u->addrs == NULL) {
745 return NGX_ERROR;
746 }
747
748 sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
749 if (sin == NULL) {
750 return NGX_ERROR;
751 }
752
753 ngx_memcpy(sin, u->sockaddr, sizeof(struct sockaddr_in));
754
755 u->addrs[0].sockaddr = (struct sockaddr *) sin;
756 u->addrs[0].socklen = sizeof(struct sockaddr_in);
757
758 p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
759 if (p == NULL) {
760 return NGX_ERROR;
761 }
762
763 u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
764 &u->host, u->port) - p;
765 u->addrs[0].name.data = p;
766
767 return NGX_OK;
768 }
769
731 if (u->no_resolve) { 770 if (u->no_resolve) {
732 return NGX_OK; 771 return NGX_OK;
733 } 772 }
734 773
735 sin->sin_addr.s_addr = ngx_inet_addr(host, len); 774 if (ngx_inet_resolve_host(pool, u) != NGX_OK) {
736 775 return NGX_ERROR;
737 if (sin->sin_addr.s_addr == INADDR_NONE) { 776 }
738 p = ngx_alloc(++len, pool->log); 777
739 if (p == NULL) { 778 u->family = u->addrs[0].sockaddr->sa_family;
740 return NGX_ERROR; 779 u->socklen = u->addrs[0].socklen;
741 } 780 ngx_memcpy(u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen);
742 781
743 (void) ngx_cpystrn(p, host, len); 782 switch (u->family) {
744 783
745 h = gethostbyname((const char *) p); 784 #if (NGX_HAVE_INET6)
746 785 case AF_INET6:
747 ngx_free(p); 786 sin6 = (struct sockaddr_in6 *) &u->sockaddr;
748 787
749 if (h == NULL || h->h_addr_list[0] == NULL) { 788 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
750 u->err = "host not found"; 789 u->wildcard = 1;
751 return NGX_ERROR; 790 }
752 } 791
753 792 break;
754 sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[0]); 793 #endif
755 } 794
756 795 default: /* AF_INET */
757 if (sin->sin_addr.s_addr == INADDR_ANY) { 796 sin = (struct sockaddr_in *) &u->sockaddr;
758 u->wildcard = 1; 797
759 } 798 if (sin->sin_addr.s_addr == INADDR_ANY) {
760 799 u->wildcard = 1;
761 if (u->listen) { 800 }
762 return NGX_OK; 801
763 } 802 break;
764 803 }
765 return ngx_inet_resolve_host(pool, u); 804
805 return NGX_OK;
766 } 806 }
767 807
768 808
769 static ngx_int_t 809 static ngx_int_t
770 ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) 810 ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u)
891 return NGX_ERROR; 931 return NGX_ERROR;
892 932
893 #endif 933 #endif
894 } 934 }
895 935
936
937 #if (NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6)
938
939 ngx_int_t
940 ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
941 {
942 u_char *p, *host;
943 size_t len;
944 in_port_t port;
945 ngx_uint_t i;
946 struct addrinfo hints, *res, *rp;
947 struct sockaddr_in *sin;
948 struct sockaddr_in6 *sin6;
949
950 port = htons(u->port);
951
952 host = ngx_alloc(u->host.len + 1, pool->log);
953 if (host == NULL) {
954 return NGX_ERROR;
955 }
956
957 (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
958
959 ngx_memzero(&hints, sizeof(struct addrinfo));
960 hints.ai_family = AF_UNSPEC;
961 hints.ai_socktype = SOCK_STREAM;
962
963 if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) {
964 u->err = "host not found";
965 ngx_free(host);
966 return NGX_ERROR;
967 }
968
969 ngx_free(host);
970
971 for (i = 0, rp = res; rp != NULL; rp = rp->ai_next) {
972
973 switch (rp->ai_family) {
974
975 case AF_INET:
976 case AF_INET6:
977 break;
978
979 default:
980 continue;
981 }
982
983 i++;
984 }
985
986 if (i == 0) {
987 u->err = "host not found";
988 goto failed;
989 }
990
991 /* MP: ngx_shared_palloc() */
992
993 u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
994 if (u->addrs == NULL) {
995 goto failed;
996 }
997
998 u->naddrs = i;
999
1000 i = 0;
1001
1002 /* AF_INET addresses first */
1003
1004 for (rp = res; rp != NULL; rp = rp->ai_next) {
1005
1006 if (rp->ai_family != AF_INET) {
1007 continue;
1008 }
1009
1010 sin = ngx_pcalloc(pool, rp->ai_addrlen);
1011 if (sin == NULL) {
1012 goto failed;
1013 }
1014
1015 ngx_memcpy(sin, rp->ai_addr, rp->ai_addrlen);
1016
1017 sin->sin_port = port;
1018
1019 u->addrs[i].sockaddr = (struct sockaddr *) sin;
1020 u->addrs[i].socklen = rp->ai_addrlen;
1021
1022 len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
1023
1024 p = ngx_pnalloc(pool, len);
1025 if (p == NULL) {
1026 goto failed;
1027 }
1028
1029 len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
1030
1031 u->addrs[i].name.len = len;
1032 u->addrs[i].name.data = p;
1033
1034 i++;
1035 }
1036
1037 for (rp = res; rp != NULL; rp = rp->ai_next) {
1038
1039 if (rp->ai_family != AF_INET6) {
1040 continue;
1041 }
1042
1043 sin6 = ngx_pcalloc(pool, rp->ai_addrlen);
1044 if (sin6 == NULL) {
1045 goto failed;
1046 }
1047
1048 ngx_memcpy(sin6, rp->ai_addr, rp->ai_addrlen);
1049
1050 sin6->sin6_port = port;
1051
1052 u->addrs[i].sockaddr = (struct sockaddr *) sin6;
1053 u->addrs[i].socklen = rp->ai_addrlen;
1054
1055 len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1;
1056
1057 p = ngx_pnalloc(pool, len);
1058 if (p == NULL) {
1059 goto failed;
1060 }
1061
1062 len = ngx_sock_ntop((struct sockaddr *) sin6, p, len, 1);
1063
1064 u->addrs[i].name.len = len;
1065 u->addrs[i].name.data = p;
1066
1067 i++;
1068 }
1069
1070 freeaddrinfo(res);
1071 return NGX_OK;
1072
1073 failed:
1074
1075 freeaddrinfo(res);
1076 return NGX_ERROR;
1077 }
1078
1079 #else /* !NGX_HAVE_GETADDRINFO || !NGX_HAVE_INET6 */
896 1080
897 ngx_int_t 1081 ngx_int_t
898 ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) 1082 ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
899 { 1083 {
900 u_char *p, *host; 1084 u_char *p, *host;
926 if (h == NULL || h->h_addr_list[0] == NULL) { 1110 if (h == NULL || h->h_addr_list[0] == NULL) {
927 u->err = "host not found"; 1111 u->err = "host not found";
928 return NGX_ERROR; 1112 return NGX_ERROR;
929 } 1113 }
930 1114
931 if (u->one_addr == 0) { 1115 for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
932 for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
933
934 } else {
935 i = 1;
936 }
937 1116
938 /* MP: ngx_shared_palloc() */ 1117 /* MP: ngx_shared_palloc() */
939 1118
940 u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t)); 1119 u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
941 if (u->addrs == NULL) { 1120 if (u->addrs == NULL) {
1004 u->addrs[0].name.data = p; 1183 u->addrs[0].name.data = p;
1005 } 1184 }
1006 1185
1007 return NGX_OK; 1186 return NGX_OK;
1008 } 1187 }
1188
1189 #endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */