1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 
11 
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);
15 static ngx_int_t ngx_inet_add_addr(ngx_pool_t *pool, ngx_url_t *u,
16     struct sockaddr *sockaddr, socklen_t socklen, ngx_uint_t total);
17 
18 
19 in_addr_t
ngx_inet_addr(u_char * text,size_t len)20 ngx_inet_addr(u_char *text, size_t len)
21 {
22     u_char      *p, c;
23     in_addr_t    addr;
24     ngx_uint_t   octet, n;
25 
26     addr = 0;
27     octet = 0;
28     n = 0;
29 
30     for (p = text; p < text + len; p++) {
31         c = *p;
32 
33         if (c >= '0' && c <= '9') {
34             octet = octet * 10 + (c - '0');
35 
36             if (octet > 255) {
37                 return INADDR_NONE;
38             }
39 
40             continue;
41         }
42 
43         if (c == '.') {
44             addr = (addr << 8) + octet;
45             octet = 0;
46             n++;
47             continue;
48         }
49 
50         return INADDR_NONE;
51     }
52 
53     if (n == 3) {
54         addr = (addr << 8) + octet;
55         return htonl(addr);
56     }
57 
58     return INADDR_NONE;
59 }
60 
61 
62 #if (NGX_HAVE_INET6)
63 
64 ngx_int_t
ngx_inet6_addr(u_char * p,size_t len,u_char * addr)65 ngx_inet6_addr(u_char *p, size_t len, u_char *addr)
66 {
67     u_char      c, *zero, *digit, *s, *d;
68     size_t      len4;
69     ngx_uint_t  n, nibbles, word;
70 
71     if (len == 0) {
72         return NGX_ERROR;
73     }
74 
75     zero = NULL;
76     digit = NULL;
77     len4 = 0;
78     nibbles = 0;
79     word = 0;
80     n = 8;
81 
82     if (p[0] == ':') {
83         p++;
84         len--;
85     }
86 
87     for (/* void */; len; len--) {
88         c = *p++;
89 
90         if (c == ':') {
91             if (nibbles) {
92                 digit = p;
93                 len4 = len;
94                 *addr++ = (u_char) (word >> 8);
95                 *addr++ = (u_char) (word & 0xff);
96 
97                 if (--n) {
98                     nibbles = 0;
99                     word = 0;
100                     continue;
101                 }
102 
103             } else {
104                 if (zero == NULL) {
105                     digit = p;
106                     len4 = len;
107                     zero = addr;
108                     continue;
109                 }
110             }
111 
112             return NGX_ERROR;
113         }
114 
115         if (c == '.' && nibbles) {
116             if (n < 2 || digit == NULL) {
117                 return NGX_ERROR;
118             }
119 
120             word = ngx_inet_addr(digit, len4 - 1);
121             if (word == INADDR_NONE) {
122                 return NGX_ERROR;
123             }
124 
125             word = ntohl(word);
126             *addr++ = (u_char) ((word >> 24) & 0xff);
127             *addr++ = (u_char) ((word >> 16) & 0xff);
128             n--;
129             break;
130         }
131 
132         if (++nibbles > 4) {
133             return NGX_ERROR;
134         }
135 
136         if (c >= '0' && c <= '9') {
137             word = word * 16 + (c - '0');
138             continue;
139         }
140 
141         c |= 0x20;
142 
143         if (c >= 'a' && c <= 'f') {
144             word = word * 16 + (c - 'a') + 10;
145             continue;
146         }
147 
148         return NGX_ERROR;
149     }
150 
151     if (nibbles == 0 && zero == NULL) {
152         return NGX_ERROR;
153     }
154 
155     *addr++ = (u_char) (word >> 8);
156     *addr++ = (u_char) (word & 0xff);
157 
158     if (--n) {
159         if (zero) {
160             n *= 2;
161             s = addr - 1;
162             d = s + n;
163             while (s >= zero) {
164                 *d-- = *s--;
165             }
166             ngx_memzero(zero, n);
167             return NGX_OK;
168         }
169 
170     } else {
171         if (zero == NULL) {
172             return NGX_OK;
173         }
174     }
175 
176     return NGX_ERROR;
177 }
178 
179 #endif
180 
181 
182 size_t
ngx_sock_ntop(struct sockaddr * sa,socklen_t socklen,u_char * text,size_t len,ngx_uint_t port)183 ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len,
184     ngx_uint_t port)
185 {
186     u_char               *p;
187 #if (NGX_HAVE_INET6 || NGX_HAVE_UNIX_DOMAIN)
188     size_t                n;
189 #endif
190     struct sockaddr_in   *sin;
191 #if (NGX_HAVE_INET6)
192     struct sockaddr_in6  *sin6;
193 #endif
194 #if (NGX_HAVE_UNIX_DOMAIN)
195     struct sockaddr_un   *saun;
196 #endif
197 
198     switch (sa->sa_family) {
199 
200     case AF_INET:
201 
202         sin = (struct sockaddr_in *) sa;
203         p = (u_char *) &sin->sin_addr;
204 
205         if (port) {
206             p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud:%d",
207                              p[0], p[1], p[2], p[3], ntohs(sin->sin_port));
208         } else {
209             p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
210                              p[0], p[1], p[2], p[3]);
211         }
212 
213         return (p - text);
214 
215 #if (NGX_HAVE_INET6)
216 
217     case AF_INET6:
218 
219         sin6 = (struct sockaddr_in6 *) sa;
220 
221         n = 0;
222 
223         if (port) {
224             text[n++] = '[';
225         }
226 
227         n = ngx_inet6_ntop(sin6->sin6_addr.s6_addr, &text[n], len);
228 
229         if (port) {
230             n = ngx_sprintf(&text[1 + n], "]:%d",
231                             ntohs(sin6->sin6_port)) - text;
232         }
233 
234         return n;
235 #endif
236 
237 #if (NGX_HAVE_UNIX_DOMAIN)
238 
239     case AF_UNIX:
240         saun = (struct sockaddr_un *) sa;
241 
242         /* on Linux sockaddr might not include sun_path at all */
243 
244         if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)) {
245             p = ngx_snprintf(text, len, "unix:%Z");
246 
247         } else {
248             n = ngx_strnlen((u_char *) saun->sun_path,
249                             socklen - offsetof(struct sockaddr_un, sun_path));
250             p = ngx_snprintf(text, len, "unix:%*s%Z", n, saun->sun_path);
251         }
252 
253         /* we do not include trailing zero in address length */
254 
255         return (p - text - 1);
256 
257 #endif
258 
259     default:
260         return 0;
261     }
262 }
263 
264 
265 size_t
ngx_inet_ntop(int family,void * addr,u_char * text,size_t len)266 ngx_inet_ntop(int family, void *addr, u_char *text, size_t len)
267 {
268     u_char  *p;
269 
270     switch (family) {
271 
272     case AF_INET:
273 
274         p = addr;
275 
276         return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
277                             p[0], p[1], p[2], p[3])
278                - text;
279 
280 #if (NGX_HAVE_INET6)
281 
282     case AF_INET6:
283         return ngx_inet6_ntop(addr, text, len);
284 
285 #endif
286 
287     default:
288         return 0;
289     }
290 }
291 
292 
293 #if (NGX_HAVE_INET6)
294 
295 size_t
ngx_inet6_ntop(u_char * p,u_char * text,size_t len)296 ngx_inet6_ntop(u_char *p, u_char *text, size_t len)
297 {
298     u_char      *dst;
299     size_t       max, n;
300     ngx_uint_t   i, zero, last;
301 
302     if (len < NGX_INET6_ADDRSTRLEN) {
303         return 0;
304     }
305 
306     zero = (ngx_uint_t) -1;
307     last = (ngx_uint_t) -1;
308     max = 1;
309     n = 0;
310 
311     for (i = 0; i < 16; i += 2) {
312 
313         if (p[i] || p[i + 1]) {
314 
315             if (max < n) {
316                 zero = last;
317                 max = n;
318             }
319 
320             n = 0;
321             continue;
322         }
323 
324         if (n++ == 0) {
325             last = i;
326         }
327     }
328 
329     if (max < n) {
330         zero = last;
331         max = n;
332     }
333 
334     dst = text;
335     n = 16;
336 
337     if (zero == 0) {
338 
339         if ((max == 5 && p[10] == 0xff && p[11] == 0xff)
340             || (max == 6)
341             || (max == 7 && p[14] != 0 && p[15] != 1))
342         {
343             n = 12;
344         }
345 
346         *dst++ = ':';
347     }
348 
349     for (i = 0; i < n; i += 2) {
350 
351         if (i == zero) {
352             *dst++ = ':';
353             i += (max - 1) * 2;
354             continue;
355         }
356 
357         dst = ngx_sprintf(dst, "%xd", p[i] * 256 + p[i + 1]);
358 
359         if (i < 14) {
360             *dst++ = ':';
361         }
362     }
363 
364     if (n == 12) {
365         dst = ngx_sprintf(dst, "%ud.%ud.%ud.%ud", p[12], p[13], p[14], p[15]);
366     }
367 
368     return dst - text;
369 }
370 
371 #endif
372 
373 
374 ngx_int_t
ngx_ptocidr(ngx_str_t * text,ngx_cidr_t * cidr)375 ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr)
376 {
377     u_char      *addr, *mask, *last;
378     size_t       len;
379     ngx_int_t    shift;
380 #if (NGX_HAVE_INET6)
381     ngx_int_t    rc;
382     ngx_uint_t   s, i;
383 #endif
384 
385     addr = text->data;
386     last = addr + text->len;
387 
388     mask = ngx_strlchr(addr, last, '/');
389     len = (mask ? mask : last) - addr;
390 
391     cidr->u.in.addr = ngx_inet_addr(addr, len);
392 
393     if (cidr->u.in.addr != INADDR_NONE) {
394         cidr->family = AF_INET;
395 
396         if (mask == NULL) {
397             cidr->u.in.mask = 0xffffffff;
398             return NGX_OK;
399         }
400 
401 #if (NGX_HAVE_INET6)
402     } else if (ngx_inet6_addr(addr, len, cidr->u.in6.addr.s6_addr) == NGX_OK) {
403         cidr->family = AF_INET6;
404 
405         if (mask == NULL) {
406             ngx_memset(cidr->u.in6.mask.s6_addr, 0xff, 16);
407             return NGX_OK;
408         }
409 
410 #endif
411     } else {
412         return NGX_ERROR;
413     }
414 
415     mask++;
416 
417     shift = ngx_atoi(mask, last - mask);
418     if (shift == NGX_ERROR) {
419         return NGX_ERROR;
420     }
421 
422     switch (cidr->family) {
423 
424 #if (NGX_HAVE_INET6)
425     case AF_INET6:
426         if (shift > 128) {
427             return NGX_ERROR;
428         }
429 
430         addr = cidr->u.in6.addr.s6_addr;
431         mask = cidr->u.in6.mask.s6_addr;
432         rc = NGX_OK;
433 
434         for (i = 0; i < 16; i++) {
435 
436             s = (shift > 8) ? 8 : shift;
437             shift -= s;
438 
439             mask[i] = (u_char) (0xffu << (8 - s));
440 
441             if (addr[i] != (addr[i] & mask[i])) {
442                 rc = NGX_DONE;
443                 addr[i] &= mask[i];
444             }
445         }
446 
447         return rc;
448 #endif
449 
450     default: /* AF_INET */
451         if (shift > 32) {
452             return NGX_ERROR;
453         }
454 
455         if (shift) {
456             cidr->u.in.mask = htonl((uint32_t) (0xffffffffu << (32 - shift)));
457 
458         } else {
459             /* x86 compilers use a shl instruction that shifts by modulo 32 */
460             cidr->u.in.mask = 0;
461         }
462 
463         if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) {
464             return NGX_OK;
465         }
466 
467         cidr->u.in.addr &= cidr->u.in.mask;
468 
469         return NGX_DONE;
470     }
471 }
472 
473 
474 ngx_int_t
ngx_cidr_match(struct sockaddr * sa,ngx_array_t * cidrs)475 ngx_cidr_match(struct sockaddr *sa, ngx_array_t *cidrs)
476 {
477 #if (NGX_HAVE_INET6)
478     u_char           *p;
479 #endif
480     in_addr_t         inaddr;
481     ngx_cidr_t       *cidr;
482     ngx_uint_t        family, i;
483 #if (NGX_HAVE_INET6)
484     ngx_uint_t        n;
485     struct in6_addr  *inaddr6;
486 #endif
487 
488 #if (NGX_SUPPRESS_WARN)
489     inaddr = 0;
490 #if (NGX_HAVE_INET6)
491     inaddr6 = NULL;
492 #endif
493 #endif
494 
495     family = sa->sa_family;
496 
497     if (family == AF_INET) {
498         inaddr = ((struct sockaddr_in *) sa)->sin_addr.s_addr;
499     }
500 
501 #if (NGX_HAVE_INET6)
502     else if (family == AF_INET6) {
503         inaddr6 = &((struct sockaddr_in6 *) sa)->sin6_addr;
504 
505         if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
506             family = AF_INET;
507 
508             p = inaddr6->s6_addr;
509 
510             inaddr = p[12] << 24;
511             inaddr += p[13] << 16;
512             inaddr += p[14] << 8;
513             inaddr += p[15];
514 
515             inaddr = htonl(inaddr);
516         }
517     }
518 #endif
519 
520     for (cidr = cidrs->elts, i = 0; i < cidrs->nelts; i++) {
521         if (cidr[i].family != family) {
522             goto next;
523         }
524 
525         switch (family) {
526 
527 #if (NGX_HAVE_INET6)
528         case AF_INET6:
529             for (n = 0; n < 16; n++) {
530                 if ((inaddr6->s6_addr[n] & cidr[i].u.in6.mask.s6_addr[n])
531                     != cidr[i].u.in6.addr.s6_addr[n])
532                 {
533                     goto next;
534                 }
535             }
536             break;
537 #endif
538 
539 #if (NGX_HAVE_UNIX_DOMAIN)
540         case AF_UNIX:
541             break;
542 #endif
543 
544         default: /* AF_INET */
545             if ((inaddr & cidr[i].u.in.mask) != cidr[i].u.in.addr) {
546                 goto next;
547             }
548             break;
549         }
550 
551         return NGX_OK;
552 
553     next:
554         continue;
555     }
556 
557     return NGX_DECLINED;
558 }
559 
560 
561 ngx_int_t
ngx_parse_addr(ngx_pool_t * pool,ngx_addr_t * addr,u_char * text,size_t len)562 ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len)
563 {
564     in_addr_t             inaddr;
565     ngx_uint_t            family;
566     struct sockaddr_in   *sin;
567 #if (NGX_HAVE_INET6)
568     struct in6_addr       inaddr6;
569     struct sockaddr_in6  *sin6;
570 
571     /*
572      * prevent MSVC8 warning:
573      *    potentially uninitialized local variable 'inaddr6' used
574      */
575     ngx_memzero(&inaddr6, sizeof(struct in6_addr));
576 #endif
577 
578     inaddr = ngx_inet_addr(text, len);
579 
580     if (inaddr != INADDR_NONE) {
581         family = AF_INET;
582         len = sizeof(struct sockaddr_in);
583 
584 #if (NGX_HAVE_INET6)
585     } else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) {
586         family = AF_INET6;
587         len = sizeof(struct sockaddr_in6);
588 
589 #endif
590     } else {
591         return NGX_DECLINED;
592     }
593 
594     addr->sockaddr = ngx_pcalloc(pool, len);
595     if (addr->sockaddr == NULL) {
596         return NGX_ERROR;
597     }
598 
599     addr->sockaddr->sa_family = (u_char) family;
600     addr->socklen = len;
601 
602     switch (family) {
603 
604 #if (NGX_HAVE_INET6)
605     case AF_INET6:
606         sin6 = (struct sockaddr_in6 *) addr->sockaddr;
607         ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16);
608         break;
609 #endif
610 
611     default: /* AF_INET */
612         sin = (struct sockaddr_in *) addr->sockaddr;
613         sin->sin_addr.s_addr = inaddr;
614         break;
615     }
616 
617     return NGX_OK;
618 }
619 
620 
621 ngx_int_t
ngx_parse_addr_port(ngx_pool_t * pool,ngx_addr_t * addr,u_char * text,size_t len)622 ngx_parse_addr_port(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text,
623     size_t len)
624 {
625     u_char     *p, *last;
626     size_t      plen;
627     ngx_int_t   rc, port;
628 
629     rc = ngx_parse_addr(pool, addr, text, len);
630 
631     if (rc != NGX_DECLINED) {
632         return rc;
633     }
634 
635     last = text + len;
636 
637 #if (NGX_HAVE_INET6)
638     if (len && text[0] == '[') {
639 
640         p = ngx_strlchr(text, last, ']');
641 
642         if (p == NULL || p == last - 1 || *++p != ':') {
643             return NGX_DECLINED;
644         }
645 
646         text++;
647         len -= 2;
648 
649     } else
650 #endif
651 
652     {
653         p = ngx_strlchr(text, last, ':');
654 
655         if (p == NULL) {
656             return NGX_DECLINED;
657         }
658     }
659 
660     p++;
661     plen = last - p;
662 
663     port = ngx_atoi(p, plen);
664 
665     if (port < 1 || port > 65535) {
666         return NGX_DECLINED;
667     }
668 
669     len -= plen + 1;
670 
671     rc = ngx_parse_addr(pool, addr, text, len);
672 
673     if (rc != NGX_OK) {
674         return rc;
675     }
676 
677     ngx_inet_set_port(addr->sockaddr, (in_port_t) port);
678 
679     return NGX_OK;
680 }
681 
682 
683 ngx_int_t
ngx_parse_url(ngx_pool_t * pool,ngx_url_t * u)684 ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u)
685 {
686     u_char  *p;
687     size_t   len;
688 
689     p = u->url.data;
690     len = u->url.len;
691 
692     if (len >= 5 && ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
693         return ngx_parse_unix_domain_url(pool, u);
694     }
695 
696     if (len && p[0] == '[') {
697         return ngx_parse_inet6_url(pool, u);
698     }
699 
700     return ngx_parse_inet_url(pool, u);
701 }
702 
703 
704 static ngx_int_t
ngx_parse_unix_domain_url(ngx_pool_t * pool,ngx_url_t * u)705 ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u)
706 {
707 #if (NGX_HAVE_UNIX_DOMAIN)
708     u_char              *path, *uri, *last;
709     size_t               len;
710     struct sockaddr_un  *saun;
711 
712     len = u->url.len;
713     path = u->url.data;
714 
715     path += 5;
716     len -= 5;
717 
718     if (u->uri_part) {
719 
720         last = path + len;
721         uri = ngx_strlchr(path, last, ':');
722 
723         if (uri) {
724             len = uri - path;
725             uri++;
726             u->uri.len = last - uri;
727             u->uri.data = uri;
728         }
729     }
730 
731     if (len == 0) {
732         u->err = "no path in the unix domain socket";
733         return NGX_ERROR;
734     }
735 
736     u->host.len = len++;
737     u->host.data = path;
738 
739     if (len > sizeof(saun->sun_path)) {
740         u->err = "too long path in the unix domain socket";
741         return NGX_ERROR;
742     }
743 
744     u->socklen = sizeof(struct sockaddr_un);
745     saun = (struct sockaddr_un *) &u->sockaddr;
746     saun->sun_family = AF_UNIX;
747     (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
748 
749     u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
750     if (u->addrs == NULL) {
751         return NGX_ERROR;
752     }
753 
754     saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un));
755     if (saun == NULL) {
756         return NGX_ERROR;
757     }
758 
759     u->family = AF_UNIX;
760     u->naddrs = 1;
761 
762     saun->sun_family = AF_UNIX;
763     (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
764 
765     u->addrs[0].sockaddr = (struct sockaddr *) saun;
766     u->addrs[0].socklen = sizeof(struct sockaddr_un);
767     u->addrs[0].name.len = len + 4;
768     u->addrs[0].name.data = u->url.data;
769 
770     return NGX_OK;
771 
772 #else
773 
774     u->err = "the unix domain sockets are not supported on this platform";
775 
776     return NGX_ERROR;
777 
778 #endif
779 }
780 
781 
782 static ngx_int_t
ngx_parse_inet_url(ngx_pool_t * pool,ngx_url_t * u)783 ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
784 {
785     u_char              *host, *port, *last, *uri, *args, *dash;
786     size_t               len;
787     ngx_int_t            n;
788     struct sockaddr_in  *sin;
789 
790     u->socklen = sizeof(struct sockaddr_in);
791     sin = (struct sockaddr_in *) &u->sockaddr;
792     sin->sin_family = AF_INET;
793 
794     u->family = AF_INET;
795 
796     host = u->url.data;
797 
798     last = host + u->url.len;
799 
800     port = ngx_strlchr(host, last, ':');
801 
802     uri = ngx_strlchr(host, last, '/');
803 
804     args = ngx_strlchr(host, last, '?');
805 
806     if (args) {
807         if (uri == NULL || args < uri) {
808             uri = args;
809         }
810     }
811 
812     if (uri) {
813         if (u->listen || !u->uri_part) {
814             u->err = "invalid host";
815             return NGX_ERROR;
816         }
817 
818         u->uri.len = last - uri;
819         u->uri.data = uri;
820 
821         last = uri;
822 
823         if (uri < port) {
824             port = NULL;
825         }
826     }
827 
828     if (port) {
829         port++;
830 
831         len = last - port;
832 
833         if (u->listen) {
834             dash = ngx_strlchr(port, last, '-');
835 
836             if (dash) {
837                 dash++;
838 
839                 n = ngx_atoi(dash, last - dash);
840 
841                 if (n < 1 || n > 65535) {
842                     u->err = "invalid port";
843                     return NGX_ERROR;
844                 }
845 
846                 u->last_port = (in_port_t) n;
847 
848                 len = dash - port - 1;
849             }
850         }
851 
852         n = ngx_atoi(port, len);
853 
854         if (n < 1 || n > 65535) {
855             u->err = "invalid port";
856             return NGX_ERROR;
857         }
858 
859         if (u->last_port && n > u->last_port) {
860             u->err = "invalid port range";
861             return NGX_ERROR;
862         }
863 
864         u->port = (in_port_t) n;
865         sin->sin_port = htons((in_port_t) n);
866 
867         u->port_text.len = last - port;
868         u->port_text.data = port;
869 
870         last = port - 1;
871 
872     } else {
873         if (uri == NULL) {
874 
875             if (u->listen) {
876 
877                 /* test value as port only */
878 
879                 len = last - host;
880 
881                 dash = ngx_strlchr(host, last, '-');
882 
883                 if (dash) {
884                     dash++;
885 
886                     n = ngx_atoi(dash, last - dash);
887 
888                     if (n == NGX_ERROR) {
889                         goto no_port;
890                     }
891 
892                     if (n < 1 || n > 65535) {
893                         u->err = "invalid port";
894 
895                     } else {
896                         u->last_port = (in_port_t) n;
897                     }
898 
899                     len = dash - host - 1;
900                 }
901 
902                 n = ngx_atoi(host, len);
903 
904                 if (n != NGX_ERROR) {
905 
906                     if (u->err) {
907                         return NGX_ERROR;
908                     }
909 
910                     if (n < 1 || n > 65535) {
911                         u->err = "invalid port";
912                         return NGX_ERROR;
913                     }
914 
915                     if (u->last_port && n > u->last_port) {
916                         u->err = "invalid port range";
917                         return NGX_ERROR;
918                     }
919 
920                     u->port = (in_port_t) n;
921                     sin->sin_port = htons((in_port_t) n);
922                     sin->sin_addr.s_addr = INADDR_ANY;
923 
924                     u->port_text.len = last - host;
925                     u->port_text.data = host;
926 
927                     u->wildcard = 1;
928 
929                     return ngx_inet_add_addr(pool, u, &u->sockaddr.sockaddr,
930                                              u->socklen, 1);
931                 }
932             }
933         }
934 
935 no_port:
936 
937         u->err = NULL;
938         u->no_port = 1;
939         u->port = u->default_port;
940         sin->sin_port = htons(u->default_port);
941         u->last_port = 0;
942     }
943 
944     len = last - host;
945 
946     if (len == 0) {
947         u->err = "no host";
948         return NGX_ERROR;
949     }
950 
951     u->host.len = len;
952     u->host.data = host;
953 
954     if (u->listen && len == 1 && *host == '*') {
955         sin->sin_addr.s_addr = INADDR_ANY;
956         u->wildcard = 1;
957         return ngx_inet_add_addr(pool, u, &u->sockaddr.sockaddr, u->socklen, 1);
958     }
959 
960     sin->sin_addr.s_addr = ngx_inet_addr(host, len);
961 
962     if (sin->sin_addr.s_addr != INADDR_NONE) {
963 
964         if (sin->sin_addr.s_addr == INADDR_ANY) {
965             u->wildcard = 1;
966         }
967 
968         return ngx_inet_add_addr(pool, u, &u->sockaddr.sockaddr, u->socklen, 1);
969     }
970 
971     if (u->no_resolve) {
972         return NGX_OK;
973     }
974 
975     if (ngx_inet_resolve_host(pool, u) != NGX_OK) {
976         return NGX_ERROR;
977     }
978 
979     u->family = u->addrs[0].sockaddr->sa_family;
980     u->socklen = u->addrs[0].socklen;
981     ngx_memcpy(&u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen);
982     u->wildcard = ngx_inet_wildcard(&u->sockaddr.sockaddr);
983 
984     return NGX_OK;
985 }
986 
987 
988 static ngx_int_t
ngx_parse_inet6_url(ngx_pool_t * pool,ngx_url_t * u)989 ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u)
990 {
991 #if (NGX_HAVE_INET6)
992     u_char               *p, *host, *port, *last, *uri, *dash;
993     size_t                len;
994     ngx_int_t             n;
995     struct sockaddr_in6  *sin6;
996 
997     u->socklen = sizeof(struct sockaddr_in6);
998     sin6 = (struct sockaddr_in6 *) &u->sockaddr;
999     sin6->sin6_family = AF_INET6;
1000 
1001     host = u->url.data + 1;
1002 
1003     last = u->url.data + u->url.len;
1004 
1005     p = ngx_strlchr(host, last, ']');
1006 
1007     if (p == NULL) {
1008         u->err = "invalid host";
1009         return NGX_ERROR;
1010     }
1011 
1012     port = p + 1;
1013 
1014     uri = ngx_strlchr(port, last, '/');
1015 
1016     if (uri) {
1017         if (u->listen || !u->uri_part) {
1018             u->err = "invalid host";
1019             return NGX_ERROR;
1020         }
1021 
1022         u->uri.len = last - uri;
1023         u->uri.data = uri;
1024 
1025         last = uri;
1026     }
1027 
1028     if (port < last) {
1029         if (*port != ':') {
1030             u->err = "invalid host";
1031             return NGX_ERROR;
1032         }
1033 
1034         port++;
1035 
1036         len = last - port;
1037 
1038         if (u->listen) {
1039             dash = ngx_strlchr(port, last, '-');
1040 
1041             if (dash) {
1042                 dash++;
1043 
1044                 n = ngx_atoi(dash, last - dash);
1045 
1046                 if (n < 1 || n > 65535) {
1047                     u->err = "invalid port";
1048                     return NGX_ERROR;
1049                 }
1050 
1051                 u->last_port = (in_port_t) n;
1052 
1053                 len = dash - port - 1;
1054             }
1055         }
1056 
1057         n = ngx_atoi(port, len);
1058 
1059         if (n < 1 || n > 65535) {
1060             u->err = "invalid port";
1061             return NGX_ERROR;
1062         }
1063 
1064         if (u->last_port && n > u->last_port) {
1065             u->err = "invalid port range";
1066             return NGX_ERROR;
1067         }
1068 
1069         u->port = (in_port_t) n;
1070         sin6->sin6_port = htons((in_port_t) n);
1071 
1072         u->port_text.len = last - port;
1073         u->port_text.data = port;
1074 
1075     } else {
1076         u->no_port = 1;
1077         u->port = u->default_port;
1078         sin6->sin6_port = htons(u->default_port);
1079     }
1080 
1081     len = p - host;
1082 
1083     if (len == 0) {
1084         u->err = "no host";
1085         return NGX_ERROR;
1086     }
1087 
1088     u->host.len = len + 2;
1089     u->host.data = host - 1;
1090 
1091     if (ngx_inet6_addr(host, len, sin6->sin6_addr.s6_addr) != NGX_OK) {
1092         u->err = "invalid IPv6 address";
1093         return NGX_ERROR;
1094     }
1095 
1096     if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1097         u->wildcard = 1;
1098     }
1099 
1100     u->family = AF_INET6;
1101 
1102     return ngx_inet_add_addr(pool, u, &u->sockaddr.sockaddr, u->socklen, 1);
1103 
1104 #else
1105 
1106     u->err = "the INET6 sockets are not supported on this platform";
1107 
1108     return NGX_ERROR;
1109 
1110 #endif
1111 }
1112 
1113 
1114 #if (NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6)
1115 
1116 ngx_int_t
ngx_inet_resolve_host(ngx_pool_t * pool,ngx_url_t * u)1117 ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
1118 {
1119     u_char           *host;
1120     ngx_uint_t        n;
1121     struct addrinfo   hints, *res, *rp;
1122 
1123     host = ngx_alloc(u->host.len + 1, pool->log);
1124     if (host == NULL) {
1125         return NGX_ERROR;
1126     }
1127 
1128     (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
1129 
1130     ngx_memzero(&hints, sizeof(struct addrinfo));
1131     hints.ai_family = AF_UNSPEC;
1132     hints.ai_socktype = SOCK_STREAM;
1133 #ifdef AI_ADDRCONFIG
1134     hints.ai_flags = AI_ADDRCONFIG;
1135 #endif
1136 
1137     if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) {
1138         u->err = "host not found";
1139         ngx_free(host);
1140         return NGX_ERROR;
1141     }
1142 
1143     ngx_free(host);
1144 
1145     for (n = 0, rp = res; rp != NULL; rp = rp->ai_next) {
1146 
1147         switch (rp->ai_family) {
1148 
1149         case AF_INET:
1150         case AF_INET6:
1151             break;
1152 
1153         default:
1154             continue;
1155         }
1156 
1157         n++;
1158     }
1159 
1160     if (n == 0) {
1161         u->err = "host not found";
1162         goto failed;
1163     }
1164 
1165     /* MP: ngx_shared_palloc() */
1166 
1167     for (rp = res; rp != NULL; rp = rp->ai_next) {
1168 
1169         switch (rp->ai_family) {
1170 
1171         case AF_INET:
1172         case AF_INET6:
1173             break;
1174 
1175         default:
1176             continue;
1177         }
1178 
1179         if (ngx_inet_add_addr(pool, u, rp->ai_addr, rp->ai_addrlen, n)
1180             != NGX_OK)
1181         {
1182             goto failed;
1183         }
1184     }
1185 
1186     freeaddrinfo(res);
1187     return NGX_OK;
1188 
1189 failed:
1190 
1191     freeaddrinfo(res);
1192     return NGX_ERROR;
1193 }
1194 
1195 #else /* !NGX_HAVE_GETADDRINFO || !NGX_HAVE_INET6 */
1196 
1197 ngx_int_t
ngx_inet_resolve_host(ngx_pool_t * pool,ngx_url_t * u)1198 ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
1199 {
1200     u_char              *host;
1201     ngx_uint_t           i, n;
1202     struct hostent      *h;
1203     struct sockaddr_in   sin;
1204 
1205     /* AF_INET only */
1206 
1207     ngx_memzero(&sin, sizeof(struct sockaddr_in));
1208 
1209     sin.sin_family = AF_INET;
1210     sin.sin_addr.s_addr = ngx_inet_addr(u->host.data, u->host.len);
1211 
1212     if (sin.sin_addr.s_addr == INADDR_NONE) {
1213         host = ngx_alloc(u->host.len + 1, pool->log);
1214         if (host == NULL) {
1215             return NGX_ERROR;
1216         }
1217 
1218         (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
1219 
1220         h = gethostbyname((char *) host);
1221 
1222         ngx_free(host);
1223 
1224         if (h == NULL || h->h_addr_list[0] == NULL) {
1225             u->err = "host not found";
1226             return NGX_ERROR;
1227         }
1228 
1229         for (n = 0; h->h_addr_list[n] != NULL; n++) { /* void */ }
1230 
1231         /* MP: ngx_shared_palloc() */
1232 
1233         for (i = 0; i < n; i++) {
1234             sin.sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]);
1235 
1236             if (ngx_inet_add_addr(pool, u, (struct sockaddr *) &sin,
1237                                   sizeof(struct sockaddr_in), n)
1238                 != NGX_OK)
1239             {
1240                 return NGX_ERROR;
1241             }
1242         }
1243 
1244     } else {
1245 
1246         /* MP: ngx_shared_palloc() */
1247 
1248         if (ngx_inet_add_addr(pool, u, (struct sockaddr *) &sin,
1249                               sizeof(struct sockaddr_in), 1)
1250             != NGX_OK)
1251         {
1252             return NGX_ERROR;
1253         }
1254     }
1255 
1256     return NGX_OK;
1257 }
1258 
1259 #endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */
1260 
1261 
1262 static ngx_int_t
ngx_inet_add_addr(ngx_pool_t * pool,ngx_url_t * u,struct sockaddr * sockaddr,socklen_t socklen,ngx_uint_t total)1263 ngx_inet_add_addr(ngx_pool_t *pool, ngx_url_t *u, struct sockaddr *sockaddr,
1264     socklen_t socklen, ngx_uint_t total)
1265 {
1266     u_char           *p;
1267     size_t            len;
1268     ngx_uint_t        i, nports;
1269     ngx_addr_t       *addr;
1270     struct sockaddr  *sa;
1271 
1272     nports = u->last_port ? u->last_port - u->port + 1 : 1;
1273 
1274     if (u->addrs == NULL) {
1275         u->addrs = ngx_palloc(pool, total * nports * sizeof(ngx_addr_t));
1276         if (u->addrs == NULL) {
1277             return NGX_ERROR;
1278         }
1279     }
1280 
1281     for (i = 0; i < nports; i++) {
1282         sa = ngx_pcalloc(pool, socklen);
1283         if (sa == NULL) {
1284             return NGX_ERROR;
1285         }
1286 
1287         ngx_memcpy(sa, sockaddr, socklen);
1288 
1289         ngx_inet_set_port(sa, u->port + i);
1290 
1291         switch (sa->sa_family) {
1292 
1293 #if (NGX_HAVE_INET6)
1294         case AF_INET6:
1295             len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65536") - 1;
1296             break;
1297 #endif
1298 
1299         default: /* AF_INET */
1300             len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
1301         }
1302 
1303         p = ngx_pnalloc(pool, len);
1304         if (p == NULL) {
1305             return NGX_ERROR;
1306         }
1307 
1308         len = ngx_sock_ntop(sa, socklen, p, len, 1);
1309 
1310         addr = &u->addrs[u->naddrs++];
1311 
1312         addr->sockaddr = sa;
1313         addr->socklen = socklen;
1314 
1315         addr->name.len = len;
1316         addr->name.data = p;
1317     }
1318 
1319     return NGX_OK;
1320 }
1321 
1322 
1323 ngx_int_t
ngx_cmp_sockaddr(struct sockaddr * sa1,socklen_t slen1,struct sockaddr * sa2,socklen_t slen2,ngx_uint_t cmp_port)1324 ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1,
1325     struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port)
1326 {
1327     struct sockaddr_in   *sin1, *sin2;
1328 #if (NGX_HAVE_INET6)
1329     struct sockaddr_in6  *sin61, *sin62;
1330 #endif
1331 #if (NGX_HAVE_UNIX_DOMAIN)
1332     size_t                len;
1333     struct sockaddr_un   *saun1, *saun2;
1334 #endif
1335 
1336     if (sa1->sa_family != sa2->sa_family) {
1337         return NGX_DECLINED;
1338     }
1339 
1340     switch (sa1->sa_family) {
1341 
1342 #if (NGX_HAVE_INET6)
1343     case AF_INET6:
1344 
1345         sin61 = (struct sockaddr_in6 *) sa1;
1346         sin62 = (struct sockaddr_in6 *) sa2;
1347 
1348         if (cmp_port && sin61->sin6_port != sin62->sin6_port) {
1349             return NGX_DECLINED;
1350         }
1351 
1352         if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) {
1353             return NGX_DECLINED;
1354         }
1355 
1356         break;
1357 #endif
1358 
1359 #if (NGX_HAVE_UNIX_DOMAIN)
1360     case AF_UNIX:
1361 
1362         saun1 = (struct sockaddr_un *) sa1;
1363         saun2 = (struct sockaddr_un *) sa2;
1364 
1365         if (slen1 < slen2) {
1366             len = slen1 - offsetof(struct sockaddr_un, sun_path);
1367 
1368         } else {
1369             len = slen2 - offsetof(struct sockaddr_un, sun_path);
1370         }
1371 
1372         if (len > sizeof(saun1->sun_path)) {
1373             len = sizeof(saun1->sun_path);
1374         }
1375 
1376         if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, len) != 0) {
1377             return NGX_DECLINED;
1378         }
1379 
1380         break;
1381 #endif
1382 
1383     default: /* AF_INET */
1384 
1385         sin1 = (struct sockaddr_in *) sa1;
1386         sin2 = (struct sockaddr_in *) sa2;
1387 
1388         if (cmp_port && sin1->sin_port != sin2->sin_port) {
1389             return NGX_DECLINED;
1390         }
1391 
1392         if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
1393             return NGX_DECLINED;
1394         }
1395 
1396         break;
1397     }
1398 
1399     return NGX_OK;
1400 }
1401 
1402 
1403 in_port_t
ngx_inet_get_port(struct sockaddr * sa)1404 ngx_inet_get_port(struct sockaddr *sa)
1405 {
1406     struct sockaddr_in   *sin;
1407 #if (NGX_HAVE_INET6)
1408     struct sockaddr_in6  *sin6;
1409 #endif
1410 
1411     switch (sa->sa_family) {
1412 
1413 #if (NGX_HAVE_INET6)
1414     case AF_INET6:
1415         sin6 = (struct sockaddr_in6 *) sa;
1416         return ntohs(sin6->sin6_port);
1417 #endif
1418 
1419 #if (NGX_HAVE_UNIX_DOMAIN)
1420     case AF_UNIX:
1421         return 0;
1422 #endif
1423 
1424     default: /* AF_INET */
1425         sin = (struct sockaddr_in *) sa;
1426         return ntohs(sin->sin_port);
1427     }
1428 }
1429 
1430 
1431 void
ngx_inet_set_port(struct sockaddr * sa,in_port_t port)1432 ngx_inet_set_port(struct sockaddr *sa, in_port_t port)
1433 {
1434     struct sockaddr_in   *sin;
1435 #if (NGX_HAVE_INET6)
1436     struct sockaddr_in6  *sin6;
1437 #endif
1438 
1439     switch (sa->sa_family) {
1440 
1441 #if (NGX_HAVE_INET6)
1442     case AF_INET6:
1443         sin6 = (struct sockaddr_in6 *) sa;
1444         sin6->sin6_port = htons(port);
1445         break;
1446 #endif
1447 
1448 #if (NGX_HAVE_UNIX_DOMAIN)
1449     case AF_UNIX:
1450         break;
1451 #endif
1452 
1453     default: /* AF_INET */
1454         sin = (struct sockaddr_in *) sa;
1455         sin->sin_port = htons(port);
1456         break;
1457     }
1458 }
1459 
1460 
1461 ngx_uint_t
ngx_inet_wildcard(struct sockaddr * sa)1462 ngx_inet_wildcard(struct sockaddr *sa)
1463 {
1464     struct sockaddr_in   *sin;
1465 #if (NGX_HAVE_INET6)
1466     struct sockaddr_in6  *sin6;
1467 #endif
1468 
1469     switch (sa->sa_family) {
1470 
1471     case AF_INET:
1472         sin = (struct sockaddr_in *) sa;
1473 
1474         if (sin->sin_addr.s_addr == INADDR_ANY) {
1475             return 1;
1476         }
1477 
1478         break;
1479 
1480 #if (NGX_HAVE_INET6)
1481 
1482     case AF_INET6:
1483         sin6 = (struct sockaddr_in6 *) sa;
1484 
1485         if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1486             return 1;
1487         }
1488 
1489         break;
1490 
1491 #endif
1492     }
1493 
1494     return 0;
1495 }
1496