/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 | } |