Coverage Report

Created: 2023-09-25 07:18

/src/unit/src/nxt_sockaddr.c
Line
Count
Source (jump to first uncovered line)
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) NGINX, Inc.
5
 */
6
7
#include <nxt_main.h>
8
9
10
#if (NXT_INET6)
11
static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end);
12
#endif
13
14
static nxt_sockaddr_t *nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr);
15
static nxt_sockaddr_t *nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr);
16
static nxt_sockaddr_t *nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr);
17
18
19
nxt_sockaddr_t *
20
nxt_sockaddr_cache_alloc(nxt_event_engine_t *engine, nxt_listen_socket_t *ls)
21
0
{
22
0
    size_t          size;
23
0
    uint8_t         hint;
24
0
    nxt_sockaddr_t  *sa;
25
26
0
    hint = NXT_EVENT_ENGINE_NO_MEM_HINT;
27
0
    size = offsetof(nxt_sockaddr_t, u) + ls->socklen + ls->address_length;
28
29
0
    sa = nxt_event_engine_mem_alloc(engine, &hint, size);
30
31
0
    if (nxt_fast_path(sa != NULL)) {
32
        /* Zero only beginning of structure up to sockaddr_un.sun_path[1]. */
33
0
        nxt_memzero(sa, offsetof(nxt_sockaddr_t, u.sockaddr.sa_data[1]));
34
35
0
        sa->cache_hint = hint;
36
0
        sa->socklen = ls->socklen;
37
0
        sa->length = ls->address_length;
38
39
0
        sa->type = ls->sockaddr->type;
40
        /*
41
         * Set address family for unspecified Unix domain socket,
42
         * because these sockaddr's are not updated by old BSD systems,
43
         * see comment in nxt_conn_io_accept().
44
         */
45
0
        sa->u.sockaddr.sa_family = ls->sockaddr->u.sockaddr.sa_family;
46
0
    }
47
48
0
    return sa;
49
0
}
50
51
52
void
53
nxt_sockaddr_cache_free(nxt_event_engine_t *engine, nxt_conn_t *c)
54
0
{
55
0
    nxt_sockaddr_t  *sa;
56
57
0
    sa = c->remote;
58
59
0
    nxt_event_engine_mem_free(engine, sa->cache_hint, sa, 0);
60
0
}
61
62
63
nxt_sockaddr_t *
64
nxt_sockaddr_alloc(nxt_mp_t *mp, socklen_t socklen, size_t address_length)
65
0
{
66
0
    size_t          size;
67
0
    nxt_sockaddr_t  *sa;
68
69
0
    size = offsetof(nxt_sockaddr_t, u) + socklen + address_length;
70
71
    /*
72
     * The current struct sockaddr's define 32-bit fields at maximum
73
     * and may define 64-bit AF_INET6 fields in the future.  Alignment
74
     * of memory allocated by nxt_mp_zalloc() is enough for these fields.
75
     * If 128-bit alignment will be required then nxt_mem_malloc() and
76
     * nxt_memzero() should be used instead.
77
     */
78
79
0
    sa = nxt_mp_zalloc(mp, size);
80
81
0
    if (nxt_fast_path(sa != NULL)) {
82
0
        sa->socklen = socklen;
83
0
        sa->length = address_length;
84
0
    }
85
86
0
    return sa;
87
0
}
88
89
90
nxt_sockaddr_t *
91
nxt_sockaddr_create(nxt_mp_t *mp, struct sockaddr *sockaddr, socklen_t length,
92
    size_t address_length)
93
0
{
94
0
    size_t          size, copy;
95
0
    nxt_sockaddr_t  *sa;
96
97
0
    size = length;
98
0
    copy = length;
99
100
0
#if (NXT_HAVE_UNIX_DOMAIN)
101
102
    /*
103
     * Unspecified Unix domain sockaddr_un form and length are very
104
     * platform depended (see comment in nxt_socket.h).  Here they are
105
     * normalized to the sockaddr_un with single zero byte sun_path[].
106
     */
107
108
0
    if (size <= offsetof(struct sockaddr_un, sun_path)) {
109
        /*
110
         * Small socket length means a short unspecified Unix domain
111
         * socket address:
112
         *
113
         *   getsockname() and getpeername() on OpenBSD prior to 5.3
114
         *   return zero length and does not update a passed sockaddr
115
         *   buffer at all.
116
         *
117
         *   Linux returns length equal to 2, i.e. sockaddr_un without
118
         *   sun_path[], unix(7):
119
         *
120
         *     unnamed: A stream socket that has not been bound
121
         *     to a pathname using bind(2) has no name.  Likewise,
122
         *     the two sockets created by socketpair(2) are unnamed.
123
         *     When the address of an unnamed socket is returned by
124
         *     getsockname(2), getpeername(2), and accept(2), its
125
         *     length is sizeof(sa_family_t), and sun_path should
126
         *     not be inspected.
127
         */
128
0
        size = offsetof(struct sockaddr_un, sun_path) + 1;
129
130
#if !(NXT_LINUX)
131
132
    } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') {
133
        /*
134
         * Omit nonsignificant zeros of the unspecified Unix domain socket
135
         * address.  This test is disabled for Linux since Linux abstract
136
         * socket address also starts with zero.  However Linux unspecified
137
         * Unix domain socket address is short and is handled above.
138
         */
139
        size = offsetof(struct sockaddr_un, sun_path) + 1;
140
        copy = size;
141
142
#endif
143
0
    }
144
145
0
#endif  /* NXT_HAVE_UNIX_DOMAIN */
146
147
0
    sa = nxt_sockaddr_alloc(mp, size, address_length);
148
149
0
    if (nxt_fast_path(sa != NULL)) {
150
0
        nxt_memcpy(&sa->u.sockaddr, sockaddr, copy);
151
152
#if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD)
153
154
        if (length == 0) {
155
            sa->u.sockaddr.sa_family = AF_UNIX;
156
        }
157
158
#endif
159
0
    }
160
161
0
    return sa;
162
0
}
163
164
165
nxt_sockaddr_t *
166
nxt_sockaddr_copy(nxt_mp_t *mp, nxt_sockaddr_t *src)
167
0
{
168
0
    size_t          length;
169
0
    nxt_sockaddr_t  *dst;
170
171
0
    length = offsetof(nxt_sockaddr_t, u) + src->socklen;
172
173
0
    dst = nxt_mp_alloc(mp, length);
174
175
0
    if (nxt_fast_path(dst != NULL)) {
176
0
        nxt_memcpy(dst, src, length);
177
0
    }
178
179
0
    return dst;
180
0
}
181
182
183
nxt_sockaddr_t *
184
nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s)
185
0
{
186
0
    int                 ret;
187
0
    size_t              length;
188
0
    socklen_t           socklen;
189
0
    nxt_sockaddr_buf_t  sockaddr;
190
191
0
    socklen = NXT_SOCKADDR_LEN;
192
193
0
    ret = getsockname(s, &sockaddr.buf, &socklen);
194
195
0
    if (nxt_fast_path(ret == 0)) {
196
197
0
        switch (sockaddr.buf.sa_family) {
198
0
#if (NXT_INET6)
199
0
        case AF_INET6:
200
0
            length = NXT_INET6_ADDR_STR_LEN;
201
0
            break;
202
0
#endif
203
204
0
#if (NXT_HAVE_UNIX_DOMAIN)
205
0
        case AF_UNIX:
206
0
            length = nxt_length("unix:") + socklen;
207
0
            break;
208
0
#endif
209
210
0
        case AF_INET:
211
0
            length = NXT_INET_ADDR_STR_LEN;
212
0
            break;
213
214
0
        default:
215
0
            length = 0;
216
0
            break;
217
0
        }
218
219
0
        return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length);
220
0
    }
221
222
0
    nxt_log(task, NXT_LOG_ERR, "getsockname(%d) failed %E", s, nxt_errno);
223
224
0
    return NULL;
225
0
}
226
227
228
void
229
nxt_sockaddr_text(nxt_sockaddr_t *sa)
230
0
{
231
0
    size_t    offset;
232
0
    u_char    *p, *start, *end, *octet;
233
0
    uint32_t  port;
234
235
0
    offset = offsetof(nxt_sockaddr_t, u) + sa->socklen;
236
0
    sa->start = offset;
237
0
    sa->port_start = offset;
238
239
0
    start = nxt_pointer_to(sa, offset);
240
0
    end = start + sa->length;
241
242
0
    switch (sa->u.sockaddr.sa_family) {
243
244
0
    case AF_INET:
245
0
        sa->address_start = offset;
246
247
0
        octet = (u_char *) &sa->u.sockaddr_in.sin_addr;
248
249
0
        p = nxt_sprintf(start, end, "%ud.%ud.%ud.%ud",
250
0
                        octet[0], octet[1], octet[2], octet[3]);
251
252
0
        sa->address_length = p - start;
253
0
        sa->port_start += sa->address_length + 1;
254
255
0
        port = sa->u.sockaddr_in.sin_port;
256
257
0
        break;
258
259
0
#if (NXT_INET6)
260
261
0
    case AF_INET6:
262
0
        sa->address_start = offset + 1;
263
264
0
        p = start;
265
0
        *p++ = '[';
266
267
0
        p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end);
268
269
0
        sa->address_length = p - (start + 1);
270
0
        sa->port_start += sa->address_length + 3;
271
272
0
        *p++ = ']';
273
274
0
        port = sa->u.sockaddr_in6.sin6_port;
275
276
0
        break;
277
278
0
#endif
279
280
0
#if (NXT_HAVE_UNIX_DOMAIN)
281
282
0
    case AF_UNIX:
283
0
        sa->address_start = offset;
284
285
0
        p = (u_char *) sa->u.sockaddr_un.sun_path;
286
287
0
#if (NXT_LINUX)
288
289
0
        if (p[0] == '\0') {
290
0
            size_t  length;
291
292
            /* Linux abstract socket address has no trailing zero. */
293
0
            length = sa->socklen - offsetof(struct sockaddr_un, sun_path);
294
295
0
            p = nxt_sprintf(start, end, "unix:@%*s", length - 1, p + 1);
296
297
0
        } else {
298
0
            p = nxt_sprintf(start, end, "unix:%s", p);
299
0
        }
300
301
#else  /* !(NXT_LINUX) */
302
303
        p = nxt_sprintf(start, end, "unix:%s", p);
304
305
#endif
306
307
0
        sa->address_length = p - start;
308
0
        sa->port_start += sa->address_length;
309
0
        sa->length = p - start;
310
311
0
        return;
312
313
0
#endif  /* NXT_HAVE_UNIX_DOMAIN */
314
315
0
    default:
316
0
        return;
317
0
    }
318
319
0
    p = nxt_sprintf(p, end, ":%d", ntohs(port));
320
321
0
    sa->length = p - start;
322
0
}
323
324
325
uint32_t
326
nxt_sockaddr_port_number(nxt_sockaddr_t *sa)
327
0
{
328
0
    uint32_t  port;
329
330
0
    switch (sa->u.sockaddr.sa_family) {
331
332
0
#if (NXT_INET6)
333
334
0
    case AF_INET6:
335
0
        port = sa->u.sockaddr_in6.sin6_port;
336
0
        break;
337
338
0
#endif
339
340
0
#if (NXT_HAVE_UNIX_DOMAIN)
341
342
0
    case AF_UNIX:
343
0
        return 0;
344
345
0
#endif
346
347
0
    default:
348
0
        port = sa->u.sockaddr_in.sin_port;
349
0
        break;
350
0
    }
351
352
0
    return ntohs((uint16_t) port);
353
0
}
354
355
356
nxt_bool_t
357
nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2)
358
0
{
359
0
    if (sa1->socklen != sa2->socklen) {
360
0
        return 0;
361
0
    }
362
363
0
    if (sa1->type != sa2->type) {
364
0
        return 0;
365
0
    }
366
367
0
    if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) {
368
0
        return 0;
369
0
    }
370
371
    /*
372
     * sockaddr struct's cannot be compared in whole since kernel
373
     * may fill some fields in inherited sockaddr struct's.
374
     */
375
376
0
    switch (sa1->u.sockaddr.sa_family) {
377
378
0
#if (NXT_INET6)
379
380
0
    case AF_INET6:
381
0
        if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) {
382
0
            return 0;
383
0
        }
384
385
0
        if (memcmp(&sa1->u.sockaddr_in6.sin6_addr,
386
0
                       &sa2->u.sockaddr_in6.sin6_addr, 16)
387
0
            != 0)
388
0
        {
389
0
            return 0;
390
0
        }
391
392
0
        return 1;
393
394
0
#endif
395
396
0
#if (NXT_HAVE_UNIX_DOMAIN)
397
398
0
    case AF_UNIX:
399
0
        {
400
0
            size_t  length;
401
402
0
            length = sa1->socklen - offsetof(struct sockaddr_un, sun_path);
403
404
0
            if (memcmp(&sa1->u.sockaddr_un.sun_path,
405
0
                           &sa2->u.sockaddr_un.sun_path, length)
406
0
                != 0)
407
0
            {
408
0
                return 0;
409
0
            }
410
411
0
            return 1;
412
0
        }
413
414
0
#endif
415
416
0
    default: /* AF_INET */
417
0
        if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) {
418
0
            return 0;
419
0
        }
420
421
0
        if (sa1->u.sockaddr_in.sin_addr.s_addr
422
0
            != sa2->u.sockaddr_in.sin_addr.s_addr)
423
0
        {
424
0
            return 0;
425
0
        }
426
427
0
        return 1;
428
0
    }
429
0
}
430
431
432
#if (NXT_INET6)
433
434
static u_char *
435
nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end)
436
0
{
437
0
    u_char       *p;
438
0
    size_t       zero_groups, last_zero_groups, ipv6_bytes;
439
0
    nxt_uint_t   i, zero_start, last_zero_start;
440
441
0
    const size_t  max_inet6_length =
442
0
                        nxt_length("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
443
444
0
    if (buf + max_inet6_length > end) {
445
0
        return buf;
446
0
    }
447
448
0
    zero_start = 16;
449
0
    zero_groups = 0;
450
0
    last_zero_start = 16;
451
0
    last_zero_groups = 0;
452
453
0
    for (i = 0; i < 16; i += 2) {
454
455
0
        if (addr[i] == 0 && addr[i + 1] == 0) {
456
457
0
            if (last_zero_groups == 0) {
458
0
                last_zero_start = i;
459
0
            }
460
461
0
            last_zero_groups++;
462
463
0
        } else {
464
0
            if (zero_groups < last_zero_groups) {
465
0
                zero_groups = last_zero_groups;
466
0
                zero_start = last_zero_start;
467
0
            }
468
469
0
            last_zero_groups = 0;
470
0
        }
471
0
    }
472
473
0
    if (zero_groups < last_zero_groups) {
474
0
        zero_groups = last_zero_groups;
475
0
        zero_start = last_zero_start;
476
0
    }
477
478
0
    ipv6_bytes = 16;
479
0
    p = buf;
480
481
0
    if (zero_start == 0) {
482
483
               /* IPv4-mapped address */
484
0
        if ((zero_groups == 5 && addr[10] == 0xFF && addr[11] == 0xFF)
485
               /* IPv4-compatible address */
486
0
            || (zero_groups == 6)
487
               /* not IPv6 loopback address */
488
0
            || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1))
489
0
        {
490
0
            ipv6_bytes = 12;
491
0
        }
492
493
0
        *p++ = ':';
494
0
    }
495
496
0
    for (i = 0; i < ipv6_bytes; i += 2) {
497
498
0
        if (i == zero_start) {
499
            /* Output maximum number of consecutive zero groups as "::". */
500
0
            i += (zero_groups - 1) * 2;
501
0
            *p++ = ':';
502
0
            continue;
503
0
        }
504
505
0
        p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]);
506
507
0
        if (i < 14) {
508
0
            *p++ = ':';
509
0
        }
510
0
    }
511
512
0
    if (ipv6_bytes == 12) {
513
0
        p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud",
514
0
                        addr[12], addr[13], addr[14], addr[15]);
515
0
    }
516
517
0
    return p;
518
0
}
519
520
#endif
521
522
523
nxt_sockaddr_t *
524
nxt_sockaddr_parse(nxt_mp_t *mp, nxt_str_t *addr)
525
0
{
526
0
    nxt_sockaddr_t  *sa;
527
528
0
    sa = nxt_sockaddr_parse_optport(mp, addr);
529
530
0
    if (sa != NULL
531
0
        && sa->u.sockaddr.sa_family != AF_UNIX
532
0
        && nxt_sockaddr_port_number(sa) == 0)
533
0
    {
534
0
        nxt_thread_log_error(NXT_LOG_ERR,
535
0
                             "The address \"%V\" must specify a port.", addr);
536
0
        return NULL;
537
0
    }
538
539
0
    return sa;
540
0
}
541
542
543
nxt_sockaddr_t *
544
nxt_sockaddr_parse_optport(nxt_mp_t *mp, nxt_str_t *addr)
545
0
{
546
0
    nxt_sockaddr_t  *sa;
547
548
0
    if (addr->length == 0) {
549
0
        nxt_thread_log_error(NXT_LOG_ERR, "socket address cannot be empty");
550
0
        return NULL;
551
0
    }
552
553
0
    if (addr->length > 6 && memcmp(addr->start, "unix:", 5) == 0) {
554
0
        sa = nxt_sockaddr_unix_parse(mp, addr);
555
556
0
    } else if (addr->start[0] == '[' || nxt_inet6_probe(addr)) {
557
0
        sa = nxt_sockaddr_inet6_parse(mp, addr);
558
559
0
    } else {
560
0
        sa = nxt_sockaddr_inet_parse(mp, addr);
561
0
    }
562
563
0
    if (nxt_fast_path(sa != NULL)) {
564
0
        nxt_sockaddr_text(sa);
565
0
    }
566
567
0
    return sa;
568
0
}
569
570
571
static nxt_sockaddr_t *
572
nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr)
573
0
{
574
0
#if (NXT_HAVE_UNIX_DOMAIN)
575
0
    size_t          length, socklen;
576
0
    u_char          *path;
577
0
    nxt_sockaddr_t  *sa;
578
579
    /*
580
     * Actual sockaddr_un length can be lesser or even larger than defined
581
     * struct sockaddr_un length (see comment in nxt_socket.h).  So
582
     * limit maximum Unix domain socket address length by defined sun_path[]
583
     * length because some OSes accept addresses twice larger than defined
584
     * struct sockaddr_un.  Also reserve space for a trailing zero to avoid
585
     * ambiguity, since many OSes accept Unix domain socket addresses
586
     * without a trailing zero.
587
     */
588
0
    const size_t max_len = sizeof(struct sockaddr_un)
589
0
                           - offsetof(struct sockaddr_un, sun_path) - 1;
590
591
    /* Cutting "unix:". */
592
0
    length = addr->length - 5;
593
0
    path = addr->start + 5;
594
595
0
    if (length > max_len) {
596
0
        nxt_thread_log_error(NXT_LOG_ERR,
597
0
                             "unix domain socket \"%V\" name is too long",
598
0
                             addr);
599
0
        return NULL;
600
0
    }
601
602
0
    socklen = offsetof(struct sockaddr_un, sun_path) + length + 1;
603
604
    /*
605
     * Linux unix(7):
606
     *
607
     *   abstract: an abstract socket address is distinguished by the fact
608
     *   that sun_path[0] is a null byte ('\0').  The socket's address in
609
     *   this namespace is given by the additional bytes in sun_path that
610
     *   are covered by the specified length of the address structure.
611
     *   (Null bytes in the name have no special significance.)
612
     */
613
0
    if (path[0] == '@') {
614
0
        path[0] = '\0';
615
0
        socklen--;
616
#if !(NXT_LINUX)
617
        nxt_thread_log_error(NXT_LOG_ERR,
618
                             "abstract unix domain sockets are not supported");
619
        return NULL;
620
#endif
621
0
    }
622
623
0
    sa = nxt_sockaddr_alloc(mp, socklen, addr->length);
624
625
0
    if (nxt_fast_path(sa != NULL)) {
626
0
        sa->u.sockaddr_un.sun_family = AF_UNIX;
627
0
        nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length);
628
0
    }
629
630
0
    return sa;
631
632
#else  /* !(NXT_HAVE_UNIX_DOMAIN) */
633
634
    nxt_thread_log_error(NXT_LOG_ERR,
635
                         "unix domain socket \"%V\" is not supported", addr);
636
637
    return NULL;
638
639
#endif
640
0
}
641
642
643
static nxt_sockaddr_t *
644
nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr)
645
0
{
646
0
#if (NXT_INET6)
647
0
    u_char          *p, *start, *end;
648
0
    size_t          length;
649
0
    nxt_int_t       ret, port;
650
0
    nxt_sockaddr_t  *sa;
651
652
0
    if (addr->start[0] == '[') {
653
0
        length = addr->length - 1;
654
0
        start = addr->start + 1;
655
656
0
        end = memchr(start, ']', length);
657
0
        if (nxt_slow_path(end == NULL)) {
658
0
            return NULL;
659
0
        }
660
661
0
        p = end + 1;
662
663
0
    } else {
664
0
        length = addr->length;
665
0
        start = addr->start;
666
0
        end = addr->start + addr->length;
667
0
        p = NULL;
668
0
    }
669
670
0
    port = 0;
671
672
0
    if (p != NULL) {
673
0
        length = (start + length) - p;
674
675
0
        if (length < 2 || *p != ':') {
676
0
            nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"",
677
0
                                 addr);
678
0
            return NULL;
679
0
        }
680
681
0
        port = nxt_int_parse(p + 1, length - 1);
682
683
0
        if (port < 1 || port > 65535) {
684
0
            nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr);
685
0
            return NULL;
686
0
        }
687
0
    }
688
689
0
    sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6),
690
0
                            NXT_INET6_ADDR_STR_LEN);
691
0
    if (nxt_slow_path(sa == NULL)) {
692
0
        return NULL;
693
0
    }
694
695
0
    ret = nxt_inet6_addr(&sa->u.sockaddr_in6.sin6_addr, start, end - start);
696
0
    if (nxt_slow_path(ret != NXT_OK)) {
697
0
        nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"",
698
0
                             addr);
699
0
        return NULL;
700
0
    }
701
702
0
    sa->u.sockaddr_in6.sin6_family = AF_INET6;
703
0
    sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port);
704
705
0
    return sa;
706
707
#else  /* !(NXT_INET6) */
708
709
    nxt_thread_log_error(NXT_LOG_ERR, "IPv6 socket \"%V\" is not supported",
710
                         addr);
711
    return NULL;
712
713
#endif
714
0
}
715
716
717
static nxt_sockaddr_t *
718
nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr)
719
0
{
720
0
    u_char          *p;
721
0
    size_t          length;
722
0
    nxt_int_t       port;
723
0
    in_addr_t       inaddr;
724
0
    nxt_sockaddr_t  *sa;
725
726
0
    p = memchr(addr->start, ':', addr->length);
727
728
0
    if (p == NULL) {
729
0
        length = addr->length;
730
731
0
    } else {
732
0
        length = p - addr->start;
733
0
    }
734
735
0
    inaddr = INADDR_ANY;
736
737
0
    if (length != 1 || addr->start[0] != '*') {
738
0
        inaddr = nxt_inet_addr(addr->start, length);
739
0
        if (nxt_slow_path(inaddr == INADDR_NONE)) {
740
0
            nxt_thread_log_error(NXT_LOG_ERR, "invalid address \"%V\"", addr);
741
0
            return NULL;
742
0
        }
743
0
    }
744
745
0
    port = 0;
746
747
0
    if (p != NULL) {
748
0
        p++;
749
0
        length = (addr->start + addr->length) - p;
750
751
0
        port = nxt_int_parse(p, length);
752
753
0
        if (port < 1 || port > 65535) {
754
0
            nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr);
755
0
            return NULL;
756
0
        }
757
0
    }
758
759
0
    sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
760
0
                            NXT_INET_ADDR_STR_LEN);
761
0
    if (nxt_slow_path(sa == NULL)) {
762
0
        return NULL;
763
0
    }
764
765
0
    sa->u.sockaddr_in.sin_family = AF_INET;
766
0
    sa->u.sockaddr_in.sin_addr.s_addr = inaddr;
767
0
    sa->u.sockaddr_in.sin_port = htons((in_port_t) port);
768
769
0
    return sa;
770
0
}
771
772
773
in_addr_t
774
nxt_inet_addr(u_char *buf, size_t length)
775
0
{
776
0
    u_char      c, *end;
777
0
    in_addr_t   addr;
778
0
    nxt_uint_t  digit, octet, dots;
779
780
0
    if (nxt_slow_path(*(buf + length - 1) == '.')) {
781
0
        return INADDR_NONE;
782
0
    }
783
784
0
    addr = 0;
785
0
    octet = 0;
786
0
    dots = 0;
787
788
0
    end = buf + length;
789
790
0
    while (buf < end) {
791
792
0
        c = *buf++;
793
794
0
        digit = c - '0';
795
        /* values below '0' become large unsigned integers */
796
797
0
        if (digit < 10) {
798
0
            octet = octet * 10 + digit;
799
0
            continue;
800
0
        }
801
802
0
        if (c == '.' && octet < 256) {
803
0
            addr = (addr << 8) + octet;
804
0
            octet = 0;
805
0
            dots++;
806
0
            continue;
807
0
        }
808
809
0
        return INADDR_NONE;
810
0
    }
811
812
0
    if (dots == 3 && octet < 256) {
813
0
        addr = (addr << 8) + octet;
814
0
        return htonl(addr);
815
0
    }
816
817
0
    return INADDR_NONE;
818
0
}
819
820
821
#if (NXT_INET6)
822
823
nxt_int_t
824
nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t length)
825
0
{
826
0
    u_char      c, *addr, *zero_start, *ipv4, *dst, *src, *end;
827
0
    nxt_uint_t  digit, group, nibbles, groups_left;
828
829
0
    if (length == 0) {
830
0
        return NXT_ERROR;
831
0
    }
832
833
0
    end = buf + length;
834
835
0
    if (buf[0] == ':') {
836
0
        buf++;
837
0
    }
838
839
0
    addr = in6_addr->s6_addr;
840
0
    zero_start = NULL;
841
0
    groups_left = 8;
842
0
    nibbles = 0;
843
0
    group = 0;
844
0
    ipv4 = NULL;
845
846
0
    while (buf < end) {
847
0
        c = *buf++;
848
849
0
        if (c == ':') {
850
0
            if (nibbles != 0) {
851
0
                ipv4 = buf;
852
853
0
                *addr++ = (u_char) (group >> 8);
854
0
                *addr++ = (u_char) (group & 0xFF);
855
0
                groups_left--;
856
857
0
                if (groups_left != 0) {
858
0
                    nibbles = 0;
859
0
                    group = 0;
860
0
                    continue;
861
0
                }
862
863
0
            } else {
864
0
                if (zero_start == NULL) {
865
0
                    ipv4 = buf;
866
0
                    zero_start = addr;
867
0
                    continue;
868
0
                }
869
0
            }
870
871
0
            return NXT_ERROR;
872
0
        }
873
874
0
        if (c == '.' && nibbles != 0) {
875
876
0
            if (groups_left < 2 || ipv4 == NULL) {
877
0
                return NXT_ERROR;
878
0
            }
879
880
0
            group = nxt_inet_addr(ipv4, end - ipv4);
881
0
            if (group == INADDR_NONE) {
882
0
                return NXT_ERROR;
883
0
            }
884
885
0
            group = ntohl(group);
886
887
0
            *addr++ = (u_char) ((group >> 24) & 0xFF);
888
0
            *addr++ = (u_char) ((group >> 16) & 0xFF);
889
0
            groups_left--;
890
891
            /* the low 16-bit are copied below */
892
0
            break;
893
0
        }
894
895
0
        nibbles++;
896
897
0
        if (nibbles > 4) {
898
0
            return NXT_ERROR;
899
0
        }
900
901
0
        group <<= 4;
902
903
0
        digit = c - '0';
904
        /* values below '0' become large unsigned integers */
905
906
0
        if (digit < 10) {
907
0
            group += digit;
908
0
            continue;
909
0
        }
910
911
0
        c |= 0x20;
912
0
        digit = c - 'a';
913
        /* values below 'a' become large unsigned integers */
914
915
0
        if (digit < 6) {
916
0
            group += 10 + digit;
917
0
            continue;
918
0
        }
919
920
0
        return NXT_ERROR;
921
0
    }
922
923
0
    if (nibbles == 0 && zero_start == NULL) {
924
0
        return NXT_ERROR;
925
0
    }
926
927
0
    *addr++ = (u_char) (group >> 8);
928
0
    *addr++ = (u_char) (group & 0xFF);
929
0
    groups_left--;
930
931
0
    if (groups_left != 0) {
932
933
0
        if (zero_start != NULL) {
934
935
            /* moving part before consecutive zero groups to the end */
936
937
0
            groups_left *= 2;
938
0
            src = addr - 1;
939
0
            dst = src + groups_left;
940
941
0
            while (src >= zero_start) {
942
0
                *dst-- = *src--;
943
0
            }
944
945
0
            nxt_memzero(zero_start, groups_left);
946
947
0
            return NXT_OK;
948
0
        }
949
950
0
    } else {
951
0
        if (zero_start == NULL) {
952
0
            return NXT_OK;
953
0
        }
954
0
    }
955
956
0
    return NXT_ERROR;
957
0
}
958
959
#endif
960
961
962
nxt_bool_t
963
nxt_inet6_probe(nxt_str_t *str)
964
0
{
965
0
    u_char  *colon, *end;
966
967
0
    colon = memchr(str->start, ':', str->length);
968
969
0
    if (colon != NULL) {
970
0
        end = str->start + str->length;
971
0
        colon = memchr(colon + 1, ':', end - (colon + 1));
972
0
    }
973
974
0
    return (colon != NULL);
975
0
}