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