3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
12 static ngx_int_t
ngx_parse_unix_domain_url(ngx_pool_t
*pool
, ngx_url_t
*u
);
13 static ngx_int_t
ngx_parse_inet_url(ngx_pool_t
*pool
, ngx_url_t
*u
);
14 static ngx_int_t
ngx_parse_inet6_url(ngx_pool_t
*pool
, ngx_url_t
*u
);
18 ngx_inet_addr(u_char
*text
, size_t len
)
28 for (p
= text
; p
< text
+ len
; p
++) {
32 if (c
>= '0' && c
<= '9') {
33 octet
= octet
* 10 + (c
- '0');
37 if (c
== '.' && octet
< 256) {
38 addr
= (addr
<< 8) + octet
;
47 if (n
== 3 && octet
< 256) {
48 addr
= (addr
<< 8) + octet
;
59 ngx_inet6_addr(u_char
*p
, size_t len
, u_char
*addr
)
61 u_char c
, *zero
, *digit
, *s
, *d
;
63 ngx_uint_t n
, nibbles
, word
;
81 for (/* void */; len
; len
--) {
88 *addr
++ = (u_char
) (word
>> 8);
89 *addr
++ = (u_char
) (word
& 0xff);
109 if (c
== '.' && nibbles
) {
110 if (n
< 2 || digit
== NULL
) {
114 word
= ngx_inet_addr(digit
, len4
- 1);
115 if (word
== INADDR_NONE
) {
120 *addr
++ = (u_char
) ((word
>> 24) & 0xff);
121 *addr
++ = (u_char
) ((word
>> 16) & 0xff);
130 if (c
>= '0' && c
<= '9') {
131 word
= word
* 16 + (c
- '0');
137 if (c
>= 'a' && c
<= 'f') {
138 word
= word
* 16 + (c
- 'a') + 10;
145 if (nibbles
== 0 && zero
== NULL
) {
149 *addr
++ = (u_char
) (word
>> 8);
150 *addr
++ = (u_char
) (word
& 0xff);
160 ngx_memzero(zero
, n
);
177 ngx_sock_ntop(struct sockaddr
*sa
, u_char
*text
, size_t len
, ngx_uint_t port
)
180 struct sockaddr_in
*sin
;
183 struct sockaddr_in6
*sin6
;
185 #if (NGX_HAVE_UNIX_DOMAIN)
186 struct sockaddr_un
*saun
;
189 switch (sa
->sa_family
) {
193 sin
= (struct sockaddr_in
*) sa
;
194 p
= (u_char
*) &sin
->sin_addr
;
197 p
= ngx_snprintf(text
, len
, "%ud.%ud.%ud.%ud:%d",
198 p
[0], p
[1], p
[2], p
[3], ntohs(sin
->sin_port
));
200 p
= ngx_snprintf(text
, len
, "%ud.%ud.%ud.%ud",
201 p
[0], p
[1], p
[2], p
[3]);
210 sin6
= (struct sockaddr_in6
*) sa
;
218 n
= ngx_inet6_ntop(sin6
->sin6_addr
.s6_addr
, &text
[n
], len
);
221 n
= ngx_sprintf(&text
[1 + n
], "]:%d",
222 ntohs(sin6
->sin6_port
)) - text
;
228 #if (NGX_HAVE_UNIX_DOMAIN)
231 saun
= (struct sockaddr_un
*) sa
;
233 /* we do not include trailing zero in address length */
235 return ngx_snprintf(text
, len
, "unix:%s%Z", saun
->sun_path
) - text
- 1;
246 ngx_inet_ntop(int family
, void *addr
, u_char
*text
, size_t len
)
256 return ngx_snprintf(text
, len
, "%ud.%ud.%ud.%ud",
257 p
[0], p
[1], p
[2], p
[3])
263 return ngx_inet6_ntop(addr
, text
, len
);
276 ngx_inet6_ntop(u_char
*p
, u_char
*text
, size_t len
)
280 ngx_uint_t i
, zero
, last
;
282 if (len
< NGX_INET6_ADDRSTRLEN
) {
286 zero
= (ngx_uint_t
) -1;
287 last
= (ngx_uint_t
) -1;
291 for (i
= 0; i
< 16; i
+= 2) {
293 if (p
[i
] || p
[i
+ 1]) {
319 if ((max
== 5 && p
[10] == 0xff && p
[11] == 0xff)
321 || (max
== 7 && p
[14] != 0 && p
[15] != 1))
329 for (i
= 0; i
< n
; i
+= 2) {
337 dst
= ngx_sprintf(dst
, "%uxi", p
[i
] * 256 + p
[i
+ 1]);
345 dst
= ngx_sprintf(dst
, "%ud.%ud.%ud.%ud", p
[12], p
[13], p
[14], p
[15]);
355 ngx_ptocidr(ngx_str_t
*text
, ngx_cidr_t
*cidr
)
357 u_char
*addr
, *mask
, *last
;
366 last
= addr
+ text
->len
;
368 mask
= ngx_strlchr(addr
, last
, '/');
369 len
= (mask
? mask
: last
) - addr
;
371 cidr
->u
.in
.addr
= ngx_inet_addr(addr
, len
);
373 if (cidr
->u
.in
.addr
!= INADDR_NONE
) {
374 cidr
->family
= AF_INET
;
377 cidr
->u
.in
.mask
= 0xffffffff;
382 } else if (ngx_inet6_addr(addr
, len
, cidr
->u
.in6
.addr
.s6_addr
) == NGX_OK
) {
383 cidr
->family
= AF_INET6
;
386 ngx_memset(cidr
->u
.in6
.mask
.s6_addr
, 0xff, 16);
397 shift
= ngx_atoi(mask
, last
- mask
);
398 if (shift
== NGX_ERROR
) {
402 switch (cidr
->family
) {
410 addr
= cidr
->u
.in6
.addr
.s6_addr
;
411 mask
= cidr
->u
.in6
.mask
.s6_addr
;
414 for (i
= 0; i
< 16; i
++) {
416 s
= (shift
> 8) ? 8 : shift
;
419 mask
[i
] = (u_char
) (0xffu
<< (8 - s
));
421 if (addr
[i
] != (addr
[i
] & mask
[i
])) {
430 default: /* AF_INET */
436 cidr
->u
.in
.mask
= htonl((uint32_t) (0xffffffffu
<< (32 - shift
)));
439 /* x86 compilers use a shl instruction that shifts by modulo 32 */
443 if (cidr
->u
.in
.addr
== (cidr
->u
.in
.addr
& cidr
->u
.in
.mask
)) {
447 cidr
->u
.in
.addr
&= cidr
->u
.in
.mask
;
455 ngx_parse_addr(ngx_pool_t
*pool
, ngx_addr_t
*addr
, u_char
*text
, size_t len
)
459 struct sockaddr_in
*sin
;
461 struct in6_addr inaddr6
;
462 struct sockaddr_in6
*sin6
;
465 * prevent MSVC8 warning:
466 * potentially uninitialized local variable 'inaddr6' used
468 ngx_memzero(&inaddr6
, sizeof(struct in6_addr
));
471 inaddr
= ngx_inet_addr(text
, len
);
473 if (inaddr
!= INADDR_NONE
) {
475 len
= sizeof(struct sockaddr_in
);
478 } else if (ngx_inet6_addr(text
, len
, inaddr6
.s6_addr
) == NGX_OK
) {
480 len
= sizeof(struct sockaddr_in6
);
487 addr
->sockaddr
= ngx_pcalloc(pool
, len
);
488 if (addr
->sockaddr
== NULL
) {
492 addr
->sockaddr
->sa_family
= (u_char
) family
;
499 sin6
= (struct sockaddr_in6
*) addr
->sockaddr
;
500 ngx_memcpy(sin6
->sin6_addr
.s6_addr
, inaddr6
.s6_addr
, 16);
504 default: /* AF_INET */
505 sin
= (struct sockaddr_in
*) addr
->sockaddr
;
506 sin
->sin_addr
.s_addr
= inaddr
;
515 ngx_parse_url(ngx_pool_t
*pool
, ngx_url_t
*u
)
521 if (ngx_strncasecmp(p
, (u_char
*) "unix:", 5) == 0) {
522 return ngx_parse_unix_domain_url(pool
, u
);
526 return ngx_parse_inet6_url(pool
, u
);
529 return ngx_parse_inet_url(pool
, u
);
534 ngx_parse_unix_domain_url(ngx_pool_t
*pool
, ngx_url_t
*u
)
536 #if (NGX_HAVE_UNIX_DOMAIN)
537 u_char
*path
, *uri
, *last
;
539 struct sockaddr_un
*saun
;
550 uri
= ngx_strlchr(path
, last
, ':');
555 u
->uri
.len
= last
- uri
;
561 u
->err
= "no path in the unix domain socket";
568 if (len
> sizeof(saun
->sun_path
)) {
569 u
->err
= "too long path in the unix domain socket";
573 u
->socklen
= sizeof(struct sockaddr_un
);
574 saun
= (struct sockaddr_un
*) &u
->sockaddr
;
575 saun
->sun_family
= AF_UNIX
;
576 (void) ngx_cpystrn((u_char
*) saun
->sun_path
, path
, len
);
578 u
->addrs
= ngx_pcalloc(pool
, sizeof(ngx_addr_t
));
579 if (u
->addrs
== NULL
) {
583 saun
= ngx_pcalloc(pool
, sizeof(struct sockaddr_un
));
591 saun
->sun_family
= AF_UNIX
;
592 (void) ngx_cpystrn((u_char
*) saun
->sun_path
, path
, len
);
594 u
->addrs
[0].sockaddr
= (struct sockaddr
*) saun
;
595 u
->addrs
[0].socklen
= sizeof(struct sockaddr_un
);
596 u
->addrs
[0].name
.len
= len
+ 4;
597 u
->addrs
[0].name
.data
= u
->url
.data
;
603 u
->err
= "the unix domain sockets are not supported on this platform";
612 ngx_parse_inet_url(ngx_pool_t
*pool
, ngx_url_t
*u
)
614 u_char
*p
, *host
, *port
, *last
, *uri
, *args
;
617 struct sockaddr_in
*sin
;
619 struct sockaddr_in6
*sin6
;
622 u
->socklen
= sizeof(struct sockaddr_in
);
623 sin
= (struct sockaddr_in
*) &u
->sockaddr
;
624 sin
->sin_family
= AF_INET
;
630 last
= host
+ u
->url
.len
;
632 port
= ngx_strlchr(host
, last
, ':');
634 uri
= ngx_strlchr(host
, last
, '/');
636 args
= ngx_strlchr(host
, last
, '?');
639 if (uri
== NULL
|| args
< uri
) {
645 if (u
->listen
|| !u
->uri_part
) {
646 u
->err
= "invalid host";
650 u
->uri
.len
= last
- uri
;
665 n
= ngx_atoi(port
, len
);
667 if (n
< 1 || n
> 65535) {
668 u
->err
= "invalid port";
672 u
->port
= (in_port_t
) n
;
673 sin
->sin_port
= htons((in_port_t
) n
);
675 u
->port_text
.len
= len
;
676 u
->port_text
.data
= port
;
685 /* test value as port only */
687 n
= ngx_atoi(host
, last
- host
);
689 if (n
!= NGX_ERROR
) {
691 if (n
< 1 || n
> 65535) {
692 u
->err
= "invalid port";
696 u
->port
= (in_port_t
) n
;
697 sin
->sin_port
= htons((in_port_t
) n
);
699 u
->port_text
.len
= last
- host
;
700 u
->port_text
.data
= host
;
710 u
->port
= u
->default_port
;
711 sin
->sin_port
= htons(u
->default_port
);
724 if (u
->listen
&& len
== 1 && *host
== '*') {
725 sin
->sin_addr
.s_addr
= INADDR_ANY
;
730 sin
->sin_addr
.s_addr
= ngx_inet_addr(host
, len
);
732 if (sin
->sin_addr
.s_addr
!= INADDR_NONE
) {
734 if (sin
->sin_addr
.s_addr
== INADDR_ANY
) {
740 u
->addrs
= ngx_pcalloc(pool
, sizeof(ngx_addr_t
));
741 if (u
->addrs
== NULL
) {
745 sin
= ngx_pcalloc(pool
, sizeof(struct sockaddr_in
));
750 ngx_memcpy(sin
, u
->sockaddr
, sizeof(struct sockaddr_in
));
752 u
->addrs
[0].sockaddr
= (struct sockaddr
*) sin
;
753 u
->addrs
[0].socklen
= sizeof(struct sockaddr_in
);
755 p
= ngx_pnalloc(pool
, u
->host
.len
+ sizeof(":65535") - 1);
760 u
->addrs
[0].name
.len
= ngx_sprintf(p
, "%V:%d",
761 &u
->host
, u
->port
) - p
;
762 u
->addrs
[0].name
.data
= p
;
771 if (ngx_inet_resolve_host(pool
, u
) != NGX_OK
) {
775 u
->family
= u
->addrs
[0].sockaddr
->sa_family
;
776 u
->socklen
= u
->addrs
[0].socklen
;
777 ngx_memcpy(u
->sockaddr
, u
->addrs
[0].sockaddr
, u
->addrs
[0].socklen
);
783 sin6
= (struct sockaddr_in6
*) &u
->sockaddr
;
785 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
->sin6_addr
)) {
792 default: /* AF_INET */
793 sin
= (struct sockaddr_in
*) &u
->sockaddr
;
795 if (sin
->sin_addr
.s_addr
== INADDR_ANY
) {
807 ngx_parse_inet6_url(ngx_pool_t
*pool
, ngx_url_t
*u
)
810 u_char
*p
, *host
, *port
, *last
, *uri
;
813 struct sockaddr_in6
*sin6
;
815 u
->socklen
= sizeof(struct sockaddr_in6
);
816 sin6
= (struct sockaddr_in6
*) &u
->sockaddr
;
817 sin6
->sin6_family
= AF_INET6
;
819 host
= u
->url
.data
+ 1;
821 last
= u
->url
.data
+ u
->url
.len
;
823 p
= ngx_strlchr(host
, last
, ']');
826 u
->err
= "invalid host";
834 uri
= ngx_strlchr(port
, last
, '/');
837 if (u
->listen
|| !u
->uri_part
) {
838 u
->err
= "invalid host";
842 u
->uri
.len
= last
- uri
;
853 n
= ngx_atoi(port
, len
);
855 if (n
< 1 || n
> 65535) {
856 u
->err
= "invalid port";
860 u
->port
= (in_port_t
) n
;
861 sin6
->sin6_port
= htons((in_port_t
) n
);
863 u
->port_text
.len
= len
;
864 u
->port_text
.data
= port
;
868 u
->port
= u
->default_port
;
869 sin6
->sin6_port
= htons(u
->default_port
);
880 u
->host
.len
= len
+ 2;
881 u
->host
.data
= host
- 1;
883 if (ngx_inet6_addr(host
, len
, sin6
->sin6_addr
.s6_addr
) != NGX_OK
) {
884 u
->err
= "invalid IPv6 address";
888 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
->sin6_addr
)) {
892 u
->family
= AF_INET6
;
895 u
->addrs
= ngx_pcalloc(pool
, sizeof(ngx_addr_t
));
896 if (u
->addrs
== NULL
) {
900 sin6
= ngx_pcalloc(pool
, sizeof(struct sockaddr_in6
));
905 ngx_memcpy(sin6
, u
->sockaddr
, sizeof(struct sockaddr_in6
));
907 u
->addrs
[0].sockaddr
= (struct sockaddr
*) sin6
;
908 u
->addrs
[0].socklen
= sizeof(struct sockaddr_in6
);
910 p
= ngx_pnalloc(pool
, u
->host
.len
+ sizeof(":65535") - 1);
915 u
->addrs
[0].name
.len
= ngx_sprintf(p
, "%V:%d",
916 &u
->host
, u
->port
) - p
;
917 u
->addrs
[0].name
.data
= p
;
923 u
->err
= "the INET6 sockets are not supported on this platform";
931 #if (NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6)
934 ngx_inet_resolve_host(ngx_pool_t
*pool
, ngx_url_t
*u
)
940 struct addrinfo hints
, *res
, *rp
;
941 struct sockaddr_in
*sin
;
942 struct sockaddr_in6
*sin6
;
944 port
= htons(u
->port
);
946 host
= ngx_alloc(u
->host
.len
+ 1, pool
->log
);
951 (void) ngx_cpystrn(host
, u
->host
.data
, u
->host
.len
+ 1);
953 ngx_memzero(&hints
, sizeof(struct addrinfo
));
954 hints
.ai_family
= AF_UNSPEC
;
955 hints
.ai_socktype
= SOCK_STREAM
;
957 if (getaddrinfo((char *) host
, NULL
, &hints
, &res
) != 0) {
958 u
->err
= "host not found";
965 for (i
= 0, rp
= res
; rp
!= NULL
; rp
= rp
->ai_next
) {
967 switch (rp
->ai_family
) {
981 u
->err
= "host not found";
985 /* MP: ngx_shared_palloc() */
987 u
->addrs
= ngx_pcalloc(pool
, i
* sizeof(ngx_addr_t
));
988 if (u
->addrs
== NULL
) {
996 /* AF_INET addresses first */
998 for (rp
= res
; rp
!= NULL
; rp
= rp
->ai_next
) {
1000 if (rp
->ai_family
!= AF_INET
) {
1004 sin
= ngx_pcalloc(pool
, rp
->ai_addrlen
);
1009 ngx_memcpy(sin
, rp
->ai_addr
, rp
->ai_addrlen
);
1011 sin
->sin_port
= port
;
1013 u
->addrs
[i
].sockaddr
= (struct sockaddr
*) sin
;
1014 u
->addrs
[i
].socklen
= rp
->ai_addrlen
;
1016 len
= NGX_INET_ADDRSTRLEN
+ sizeof(":65535") - 1;
1018 p
= ngx_pnalloc(pool
, len
);
1023 len
= ngx_sock_ntop((struct sockaddr
*) sin
, p
, len
, 1);
1025 u
->addrs
[i
].name
.len
= len
;
1026 u
->addrs
[i
].name
.data
= p
;
1031 for (rp
= res
; rp
!= NULL
; rp
= rp
->ai_next
) {
1033 if (rp
->ai_family
!= AF_INET6
) {
1037 sin6
= ngx_pcalloc(pool
, rp
->ai_addrlen
);
1042 ngx_memcpy(sin6
, rp
->ai_addr
, rp
->ai_addrlen
);
1044 sin6
->sin6_port
= port
;
1046 u
->addrs
[i
].sockaddr
= (struct sockaddr
*) sin6
;
1047 u
->addrs
[i
].socklen
= rp
->ai_addrlen
;
1049 len
= NGX_INET6_ADDRSTRLEN
+ sizeof("[]:65535") - 1;
1051 p
= ngx_pnalloc(pool
, len
);
1056 len
= ngx_sock_ntop((struct sockaddr
*) sin6
, p
, len
, 1);
1058 u
->addrs
[i
].name
.len
= len
;
1059 u
->addrs
[i
].name
.data
= p
;
1073 #else /* !NGX_HAVE_GETADDRINFO || !NGX_HAVE_INET6 */
1076 ngx_inet_resolve_host(ngx_pool_t
*pool
, ngx_url_t
*u
)
1084 struct sockaddr_in
*sin
;
1088 port
= htons(u
->port
);
1090 in_addr
= ngx_inet_addr(u
->host
.data
, u
->host
.len
);
1092 if (in_addr
== INADDR_NONE
) {
1093 host
= ngx_alloc(u
->host
.len
+ 1, pool
->log
);
1098 (void) ngx_cpystrn(host
, u
->host
.data
, u
->host
.len
+ 1);
1100 h
= gethostbyname((char *) host
);
1104 if (h
== NULL
|| h
->h_addr_list
[0] == NULL
) {
1105 u
->err
= "host not found";
1109 for (i
= 0; h
->h_addr_list
[i
] != NULL
; i
++) { /* void */ }
1111 /* MP: ngx_shared_palloc() */
1113 u
->addrs
= ngx_pcalloc(pool
, i
* sizeof(ngx_addr_t
));
1114 if (u
->addrs
== NULL
) {
1120 for (i
= 0; i
< u
->naddrs
; i
++) {
1122 sin
= ngx_pcalloc(pool
, sizeof(struct sockaddr_in
));
1127 sin
->sin_family
= AF_INET
;
1128 sin
->sin_port
= port
;
1129 sin
->sin_addr
.s_addr
= *(in_addr_t
*) (h
->h_addr_list
[i
]);
1131 u
->addrs
[i
].sockaddr
= (struct sockaddr
*) sin
;
1132 u
->addrs
[i
].socklen
= sizeof(struct sockaddr_in
);
1134 len
= NGX_INET_ADDRSTRLEN
+ sizeof(":65535") - 1;
1136 p
= ngx_pnalloc(pool
, len
);
1141 len
= ngx_sock_ntop((struct sockaddr
*) sin
, p
, len
, 1);
1143 u
->addrs
[i
].name
.len
= len
;
1144 u
->addrs
[i
].name
.data
= p
;
1149 /* MP: ngx_shared_palloc() */
1151 u
->addrs
= ngx_pcalloc(pool
, sizeof(ngx_addr_t
));
1152 if (u
->addrs
== NULL
) {
1156 sin
= ngx_pcalloc(pool
, sizeof(struct sockaddr_in
));
1163 sin
->sin_family
= AF_INET
;
1164 sin
->sin_port
= port
;
1165 sin
->sin_addr
.s_addr
= in_addr
;
1167 u
->addrs
[0].sockaddr
= (struct sockaddr
*) sin
;
1168 u
->addrs
[0].socklen
= sizeof(struct sockaddr_in
);
1170 p
= ngx_pnalloc(pool
, u
->host
.len
+ sizeof(":65535") - 1);
1175 u
->addrs
[0].name
.len
= ngx_sprintf(p
, "%V:%d",
1176 &u
->host
, ntohs(port
)) - p
;
1177 u
->addrs
[0].name
.data
= p
;
1183 #endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */