Coverage Report

Created: 2024-02-11 06:05

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