blob: e051f7f0fa5c3de2a4d9adb5803cde1a6c9a28ab [file] [log] [blame]
Igor Sysoev42feecb2002-12-15 06:25:09 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Igor Sysoevd90282d2004-09-28 08:34:51 +00004 */
5
6
Igor Sysoev42feecb2002-12-15 06:25:09 +00007#include <ngx_config.h>
Igor Sysoev1c104622003-06-03 15:42:58 +00008#include <ngx_core.h>
Igor Sysoev42feecb2002-12-15 06:25:09 +00009
10
Igor Sysoeva35eacc2009-02-21 07:02:02 +000011#if (NGX_HAVE_INET6)
12static size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len);
13#endif
Igor Sysoev154013c2008-08-22 13:36:56 +000014static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u);
15static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u);
Igor Sysoeva35eacc2009-02-21 07:02:02 +000016static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u);
Igor Sysoev154013c2008-08-22 13:36:56 +000017
18
Igor Sysoev36b634c2007-11-23 16:59:24 +000019in_addr_t
20ngx_inet_addr(u_char *text, size_t len)
21{
22 u_char *p, c;
23 in_addr_t addr;
24 ngx_uint_t octet, n;
25
26 addr = 0;
27 octet = 0;
28 n = 0;
29
30 for (p = text; p < text + len; p++) {
31
32 c = *p;
33
34 if (c >= '0' && c <= '9') {
35 octet = octet * 10 + (c - '0');
36 continue;
37 }
38
39 if (c == '.' && octet < 256) {
40 addr = (addr << 8) + octet;
41 octet = 0;
42 n++;
43 continue;
44 }
45
46 return INADDR_NONE;
47 }
48
49 if (n != 3) {
50 return INADDR_NONE;
51 }
52
53 if (octet < 256) {
54 addr = (addr << 8) + octet;
55 return htonl(addr);
56 }
57
58 return INADDR_NONE;
59}
60
61
Igor Sysoev5a76cbb2009-11-02 12:50:00 +000062#if (NGX_HAVE_INET6)
63
64ngx_int_t
65ngx_inet6_addr(u_char *p, size_t len, u_char *addr)
66{
67 u_char c, *zero, *digit, *s, *d;
68 size_t len4;
69 ngx_uint_t n, nibbles, word;
70
71 if (len == 0) {
72 return NGX_ERROR;
73 }
74
75 zero = NULL;
76 digit = NULL;
77 len4 = 0;
78 nibbles = 0;
79 word = 0;
80 n = 8;
81
82 if (p[0] == ':') {
83 p++;
84 len--;
85 }
86
87 for (/* void */; len; len--) {
88 c = *p++;
89
90 if (c == ':') {
91 if (nibbles) {
92 digit = p;
93 len4 = len;
94 *addr++ = (u_char) (word >> 8);
95 *addr++ = (u_char) (word & 0xff);
96
97 if (--n) {
98 nibbles = 0;
99 word = 0;
100 continue;
101 }
102
103 } else {
104 if (zero == NULL) {
105 digit = p;
106 len4 = len;
107 zero = addr;
108 continue;
109 }
110 }
111
112 return NGX_ERROR;
113 }
114
115 if (c == '.' && nibbles) {
116 if (n < 2) {
117 return NGX_ERROR;
118 }
119
120 word = ngx_inet_addr(digit, len4 - 1);
121 if (word == INADDR_NONE) {
122 return NGX_ERROR;
123 }
124
125 word = ntohl(word);
126 *addr++ = (u_char) ((word >> 24) & 0xff);
127 *addr++ = (u_char) ((word >> 16) & 0xff);
128 n--;
129 break;
130 }
131
132 if (++nibbles > 4) {
133 return NGX_ERROR;
134 }
135
136 if (c >= '0' && c <= '9') {
137 word = word * 16 + (c - '0');
138 continue;
139 }
140
141 c |= 0x20;
142
143 if (c >= 'a' && c <= 'f') {
144 word = word * 16 + (c - 'a') + 10;
145 continue;
146 }
147
148 return NGX_ERROR;
149 }
150
151 if (nibbles == 0 && zero == NULL) {
152 return NGX_ERROR;
153 }
154
155 *addr++ = (u_char) (word >> 8);
156 *addr++ = (u_char) (word & 0xff);
157
158 if (--n) {
159 if (zero) {
160 n *= 2;
161 s = addr - 1;
162 d = s + n;
163 while (s >= zero) {
164 *d-- = *s--;
165 }
166 ngx_memzero(zero, n);
167 return NGX_OK;
168 }
169
170 } else {
171 if (zero == NULL) {
172 return NGX_OK;
173 }
174 }
175
176 return NGX_ERROR;
177}
178
179#endif
180
181
Igor Sysoev899b44e2005-05-12 14:58:06 +0000182size_t
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000183ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port)
Igor Sysoev86de4cb2003-01-30 07:28:09 +0000184{
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000185 u_char *p;
186 struct sockaddr_in *sin;
187#if (NGX_HAVE_INET6)
188 size_t n;
189 struct sockaddr_in6 *sin6;
190#endif
Igor Sysoevbaf8e402009-10-26 11:43:32 +0000191#if (NGX_HAVE_UNIX_DOMAIN)
192 struct sockaddr_un *saun;
193#endif
Igor Sysoev86de4cb2003-01-30 07:28:09 +0000194
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000195 switch (sa->sa_family) {
196
197 case AF_INET:
Igor Sysoev6a750192008-08-21 18:47:23 +0000198
199 sin = (struct sockaddr_in *) sa;
200 p = (u_char *) &sin->sin_addr;
201
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000202 if (port) {
203 p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud:%d",
204 p[0], p[1], p[2], p[3], ntohs(sin->sin_port));
205 } else {
206 p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
207 p[0], p[1], p[2], p[3]);
208 }
Igor Sysoev9c610952004-03-16 13:35:20 +0000209
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000210 return (p - text);
211
212#if (NGX_HAVE_INET6)
213
214 case AF_INET6:
215
216 sin6 = (struct sockaddr_in6 *) sa;
217
218 n = 0;
219
220 if (port) {
221 text[n++] = '[';
222 }
223
Igor Sysoev67765e82009-11-02 14:32:46 +0000224 n = ngx_inet6_ntop(sin6->sin6_addr.s6_addr, &text[n], len);
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000225
226 if (port) {
227 n = ngx_sprintf(&text[1 + n], "]:%d",
228 ntohs(sin6->sin6_port)) - text;
229 }
230
231 return n;
232#endif
233
Igor Sysoevbaf8e402009-10-26 11:43:32 +0000234#if (NGX_HAVE_UNIX_DOMAIN)
235
236 case AF_UNIX:
237 saun = (struct sockaddr_un *) sa;
238
239 /* we do not include trailing zero in address length */
240
241 return ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path) - text - 1;
242
243#endif
244
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000245 default:
246 return 0;
247 }
Igor Sysoev86de4cb2003-01-30 07:28:09 +0000248}
249
Igor Sysoev02729772008-01-04 11:54:55 +0000250
Igor Sysoev899b44e2005-05-12 14:58:06 +0000251size_t
252ngx_inet_ntop(int family, void *addr, u_char *text, size_t len)
Igor Sysoev42feecb2002-12-15 06:25:09 +0000253{
Igor Sysoev6a750192008-08-21 18:47:23 +0000254 u_char *p;
Igor Sysoev9c610952004-03-16 13:35:20 +0000255
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000256 switch (family) {
Igor Sysoev6a750192008-08-21 18:47:23 +0000257
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000258 case AF_INET:
259
260 p = addr;
Igor Sysoev6a750192008-08-21 18:47:23 +0000261
262 return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
263 p[0], p[1], p[2], p[3])
264 - text;
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000265
266#if (NGX_HAVE_INET6)
267
268 case AF_INET6:
269 return ngx_inet6_ntop(addr, text, len);
270
271#endif
272
273 default:
274 return 0;
275 }
276}
277
278
279#if (NGX_HAVE_INET6)
280
281static size_t
282ngx_inet6_ntop(u_char *p, u_char *text, size_t len)
283{
284 u_char *dst;
285 size_t max, n;
286 ngx_uint_t i, zero, last;
287
288 if (len < NGX_INET6_ADDRSTRLEN) {
289 return 0;
Igor Sysoev9c610952004-03-16 13:35:20 +0000290 }
291
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000292 zero = (ngx_uint_t) -1;
293 last = (ngx_uint_t) -1;
294 max = 1;
295 n = 0;
296
297 for (i = 0; i < 16; i += 2) {
298
299 if (p[i] || p[i + 1]) {
300
301 if (max < n) {
302 zero = last;
303 max = n;
304 }
305
306 n = 0;
307 continue;
308 }
309
310 if (n++ == 0) {
311 last = i;
312 }
313 }
314
315 if (max < n) {
316 zero = last;
317 max = n;
318 }
319
320 dst = text;
321 n = 16;
322
323 if (zero == 0) {
324
325 if ((max == 5 && p[10] == 0xff && p[11] == 0xff)
326 || (max == 6)
327 || (max == 7 && p[14] != 0 && p[15] != 1))
328 {
329 n = 12;
330 }
331
332 *dst++ = ':';
333 }
334
335 for (i = 0; i < n; i += 2) {
336
337 if (i == zero) {
338 *dst++ = ':';
339 i += (max - 1) * 2;
340 continue;
341 }
342
343 dst = ngx_sprintf(dst, "%uxi", p[i] * 256 + p[i + 1]);
344
345 if (i < 14) {
346 *dst++ = ':';
347 }
348 }
349
350 if (n == 12) {
351 dst = ngx_sprintf(dst, "%ud.%ud.%ud.%ud", p[12], p[13], p[14], p[15]);
352 }
353
354 return dst - text;
Igor Sysoev02729772008-01-04 11:54:55 +0000355}
356
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000357#endif
358
Igor Sysoev02729772008-01-04 11:54:55 +0000359
Igor Sysoev822834e2004-05-25 15:28:46 +0000360/* AF_INET only */
361
Igor Sysoev899b44e2005-05-12 14:58:06 +0000362ngx_int_t
Igor Sysoev36860102009-02-24 14:01:40 +0000363ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr)
Igor Sysoev822834e2004-05-25 15:28:46 +0000364{
Igor Sysoev36860102009-02-24 14:01:40 +0000365 u_char *addr, *mask, *last;
366 ngx_int_t shift;
Igor Sysoev822834e2004-05-25 15:28:46 +0000367
Igor Sysoev9c388c02008-08-26 14:19:37 +0000368 addr = text->data;
369 last = addr + text->len;
Igor Sysoev822834e2004-05-25 15:28:46 +0000370
Igor Sysoev9c388c02008-08-26 14:19:37 +0000371 mask = ngx_strlchr(addr, last, '/');
Igor Sysoev822834e2004-05-25 15:28:46 +0000372
Igor Sysoev36860102009-02-24 14:01:40 +0000373 cidr->u.in.addr = ngx_inet_addr(addr, (mask ? mask : last) - addr);
Igor Sysoev822834e2004-05-25 15:28:46 +0000374
Igor Sysoev36860102009-02-24 14:01:40 +0000375 if (cidr->u.in.addr == INADDR_NONE) {
Igor Sysoev822834e2004-05-25 15:28:46 +0000376 return NGX_ERROR;
377 }
378
Igor Sysoev9c388c02008-08-26 14:19:37 +0000379 if (mask == NULL) {
Igor Sysoev36860102009-02-24 14:01:40 +0000380 cidr->family = AF_INET;
381 cidr->u.in.mask = 0xffffffff;
Igor Sysoev9c388c02008-08-26 14:19:37 +0000382 return NGX_OK;
383 }
384
385 mask++;
386
387 shift = ngx_atoi(mask, last - mask);
388 if (shift == NGX_ERROR) {
Igor Sysoev822834e2004-05-25 15:28:46 +0000389 return NGX_ERROR;
390 }
391
Igor Sysoev36860102009-02-24 14:01:40 +0000392 cidr->family = AF_INET;
393
Igor Sysoev9c388c02008-08-26 14:19:37 +0000394 if (shift == 0) {
Igor Sysoev59f3aa32004-06-24 16:07:04 +0000395
396 /* the x86 compilers use the shl instruction that shifts by modulo 32 */
397
Igor Sysoev36860102009-02-24 14:01:40 +0000398 cidr->u.in.mask = 0;
Igor Sysoev9c388c02008-08-26 14:19:37 +0000399
Igor Sysoev36860102009-02-24 14:01:40 +0000400 if (cidr->u.in.addr == 0) {
Igor Sysoev9c388c02008-08-26 14:19:37 +0000401 return NGX_OK;
402 }
403
404 return NGX_DONE;
Igor Sysoev59f3aa32004-06-24 16:07:04 +0000405 }
406
Igor Sysoev36860102009-02-24 14:01:40 +0000407 cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift))));
Igor Sysoev59f3aa32004-06-24 16:07:04 +0000408
Igor Sysoev36860102009-02-24 14:01:40 +0000409 if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) {
Igor Sysoev845f6d52007-08-10 13:13:28 +0000410 return NGX_OK;
411 }
412
Igor Sysoev36860102009-02-24 14:01:40 +0000413 cidr->u.in.addr &= cidr->u.in.mask;
Igor Sysoev845f6d52007-08-10 13:13:28 +0000414
415 return NGX_DONE;
Igor Sysoev822834e2004-05-25 15:28:46 +0000416}
Igor Sysoeve2ff3ea2004-09-14 15:55:24 +0000417
418
Igor Sysoev1d52beb2009-11-02 15:20:42 +0000419ngx_addr_t *
420ngx_parse_addr(ngx_pool_t *pool, ngx_str_t *addr)
421{
422 size_t len;
423 in_addr_t inaddr;
424 ngx_uint_t family;
425 ngx_addr_t *a;
426 struct sockaddr_in *sin;
427#if (NGX_HAVE_INET6)
428 struct in6_addr inaddr6;
429 struct sockaddr_in6 *sin6;
430#endif
431
432 inaddr = ngx_inet_addr(addr->data, addr->len);
433
434 if (inaddr != INADDR_NONE) {
435 family = AF_INET;
436 len = sizeof(struct sockaddr_in);
437
438#if (NGX_HAVE_INET6)
439 } else if (ngx_inet6_addr(addr->data, addr->len, inaddr6.s6_addr) == NGX_OK)
440 {
441 family = AF_INET6;
442 len = sizeof(struct sockaddr_in6);
443
444#endif
445 } else {
446 return NULL;
447 }
448
449 a = ngx_palloc(pool, sizeof(ngx_addr_t));
450 if (a == NULL) {
451 return NULL;
452 }
453
454 a->sockaddr = ngx_pcalloc(pool, len);
455 if (a->sockaddr == NULL) {
456 return NULL;
457 }
458
459 a->sockaddr->sa_family = family;
460 a->socklen = len;
461 a->name = *addr;
462
463 switch (family) {
464
465#if (NGX_HAVE_INET6)
466 case AF_INET6:
467 sin6 = (struct sockaddr_in6 *) a->sockaddr;
468 ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16);
469 break;
470#endif
471
472 default: /* AF_INET */
473 sin = (struct sockaddr_in *) a->sockaddr;
474 sin->sin_addr.s_addr = inaddr;
475 break;
476 }
477
478 return a;
479}
480
481
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000482ngx_int_t
Igor Sysoev7ed63ee2007-10-08 08:55:12 +0000483ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u)
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000484{
Igor Sysoev154013c2008-08-22 13:36:56 +0000485 u_char *p;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000486
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000487 p = u->url.data;
488
Igor Sysoev722231f2007-02-14 18:51:19 +0000489 if (ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
Igor Sysoev154013c2008-08-22 13:36:56 +0000490 return ngx_parse_unix_domain_url(pool, u);
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000491 }
492
493 if ((p[0] == ':' || p[0] == '/') && !u->listen) {
494 u->err = "invalid host";
495 return NGX_ERROR;
496 }
497
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000498 if (p[0] == '[') {
499 return ngx_parse_inet6_url(pool, u);
500 }
501
Igor Sysoev154013c2008-08-22 13:36:56 +0000502 return ngx_parse_inet_url(pool, u);
503}
504
505
506static ngx_int_t
507ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u)
508{
509#if (NGX_HAVE_UNIX_DOMAIN)
Igor Sysoevc9491d12008-08-26 14:24:14 +0000510 u_char *path, *uri, *last;
Igor Sysoev154013c2008-08-22 13:36:56 +0000511 size_t len;
Igor Sysoev154013c2008-08-22 13:36:56 +0000512 struct sockaddr_un *saun;
513
514 len = u->url.len;
Igor Sysoevc9491d12008-08-26 14:24:14 +0000515 path = u->url.data;
Igor Sysoev154013c2008-08-22 13:36:56 +0000516
Igor Sysoevc9491d12008-08-26 14:24:14 +0000517 path += 5;
Igor Sysoev154013c2008-08-22 13:36:56 +0000518 len -= 5;
519
Igor Sysoev154013c2008-08-22 13:36:56 +0000520 if (u->uri_part) {
Igor Sysoev154013c2008-08-22 13:36:56 +0000521
Igor Sysoevc9491d12008-08-26 14:24:14 +0000522 last = path + len;
523 uri = ngx_strlchr(path, last, ':');
Igor Sysoev154013c2008-08-22 13:36:56 +0000524
Igor Sysoevc9491d12008-08-26 14:24:14 +0000525 if (uri) {
526 len = uri - path;
527 uri++;
528 u->uri.len = last - uri;
529 u->uri.data = uri;
Igor Sysoev154013c2008-08-22 13:36:56 +0000530 }
531 }
532
533 if (len == 0) {
534 u->err = "no path in the unix domain socket";
535 return NGX_ERROR;
536 }
537
Igor Sysoevc9491d12008-08-26 14:24:14 +0000538 u->host.len = len++;
539 u->host.data = path;
Igor Sysoevc9491d12008-08-26 14:24:14 +0000540
541 if (len > sizeof(saun->sun_path)) {
Igor Sysoev154013c2008-08-22 13:36:56 +0000542 u->err = "too long path in the unix domain socket";
543 return NGX_ERROR;
544 }
545
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000546 u->socklen = sizeof(struct sockaddr_un);
547 saun = (struct sockaddr_un *) &u->sockaddr;
548 saun->sun_family = AF_UNIX;
549 (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
550
Igor Sysoev0c189c52009-11-02 15:14:17 +0000551 u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
Igor Sysoev154013c2008-08-22 13:36:56 +0000552 if (u->addrs == NULL) {
553 return NGX_ERROR;
554 }
555
556 saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un));
557 if (saun == NULL) {
558 return NGX_ERROR;
559 }
560
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000561 u->family = AF_UNIX;
Igor Sysoev154013c2008-08-22 13:36:56 +0000562 u->naddrs = 1;
563
564 saun->sun_family = AF_UNIX;
Igor Sysoevc9491d12008-08-26 14:24:14 +0000565 (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
Igor Sysoev154013c2008-08-22 13:36:56 +0000566
567 u->addrs[0].sockaddr = (struct sockaddr *) saun;
568 u->addrs[0].socklen = sizeof(struct sockaddr_un);
Igor Sysoevc9491d12008-08-26 14:24:14 +0000569 u->addrs[0].name.len = len + 4;
Igor Sysoev154013c2008-08-22 13:36:56 +0000570 u->addrs[0].name.data = u->url.data;
571
Igor Sysoev154013c2008-08-22 13:36:56 +0000572 return NGX_OK;
573
574#else
575
576 u->err = "the unix domain sockets are not supported on this platform";
577
578 return NGX_ERROR;
579
580#endif
581}
582
583
584static ngx_int_t
585ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
586{
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000587 u_char *p, *host, *port, *last, *uri, *args;
588 size_t len;
589 ngx_int_t n;
590 struct hostent *h;
591 struct sockaddr_in *sin;
592
593 u->socklen = sizeof(struct sockaddr_in);
594 sin = (struct sockaddr_in *) &u->sockaddr;
595 sin->sin_family = AF_INET;
Igor Sysoev154013c2008-08-22 13:36:56 +0000596
Igor Sysoevd3bf7c12008-08-26 16:11:30 +0000597 u->family = AF_INET;
598
Igor Sysoevc9491d12008-08-26 14:24:14 +0000599 host = u->url.data;
Igor Sysoev154013c2008-08-22 13:36:56 +0000600
Igor Sysoevc9491d12008-08-26 14:24:14 +0000601 last = host + u->url.len;
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000602
Igor Sysoevc9491d12008-08-26 14:24:14 +0000603 port = ngx_strlchr(host, last, ':');
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000604
Igor Sysoevc239da52008-10-24 15:12:11 +0000605 uri = ngx_strlchr(host, last, '/');
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000606
Igor Sysoev164abfb2008-10-24 19:34:24 +0000607 args = ngx_strlchr(host, last, '?');
608
609 if (args) {
610 if (uri == NULL) {
611 uri = args;
612
613 } else if (args < uri) {
614 uri = args;
615 }
616 }
617
Igor Sysoevc9491d12008-08-26 14:24:14 +0000618 if (uri) {
619 if (u->listen || !u->uri_part) {
620 u->err = "invalid host";
621 return NGX_ERROR;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000622 }
623
Igor Sysoevc9491d12008-08-26 14:24:14 +0000624 u->uri.len = last - uri;
625 u->uri.data = uri;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000626
Igor Sysoevc9491d12008-08-26 14:24:14 +0000627 last = uri;
Igor Sysoevc239da52008-10-24 15:12:11 +0000628
629 if (uri < port) {
630 port = NULL;
Igor Sysoevead80912008-11-11 16:04:05 +0000631 }
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000632 }
633
Igor Sysoevc9491d12008-08-26 14:24:14 +0000634 if (port) {
635 port++;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000636
Igor Sysoevd3bf7c12008-08-26 16:11:30 +0000637 len = last - port;
638
639 if (len == 0) {
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000640 u->err = "invalid port";
641 return NGX_ERROR;
642 }
643
Igor Sysoevd3bf7c12008-08-26 16:11:30 +0000644 n = ngx_atoi(port, len);
645
646 if (n < 1 || n > 65536) {
647 u->err = "invalid port";
648 return NGX_ERROR;
649 }
650
651 u->port = (in_port_t) n;
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000652 sin->sin_port = htons((in_port_t) n);
Igor Sysoevd3bf7c12008-08-26 16:11:30 +0000653
654 u->port_text.len = len;
Igor Sysoevc9491d12008-08-26 14:24:14 +0000655 u->port_text.data = port;
656
657 last = port - 1;
Igor Sysoev00e03772007-11-28 19:55:31 +0000658
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000659 } else {
Igor Sysoevc9491d12008-08-26 14:24:14 +0000660 if (uri == NULL) {
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000661
Igor Sysoevc9491d12008-08-26 14:24:14 +0000662 if (u->listen) {
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000663
Igor Sysoevc9491d12008-08-26 14:24:14 +0000664 /* test value as port only */
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000665
Igor Sysoevc9491d12008-08-26 14:24:14 +0000666 n = ngx_atoi(host, last - host);
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000667
Igor Sysoevc9491d12008-08-26 14:24:14 +0000668 if (n != NGX_ERROR) {
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000669
Igor Sysoevc9491d12008-08-26 14:24:14 +0000670 if (n < 1 || n > 65536) {
671 u->err = "invalid port";
672 return NGX_ERROR;
673 }
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000674
Igor Sysoevc9491d12008-08-26 14:24:14 +0000675 u->port = (in_port_t) n;
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000676 sin->sin_port = htons((in_port_t) n);
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000677
Igor Sysoevc9491d12008-08-26 14:24:14 +0000678 u->port_text.len = last - host;
679 u->port_text.data = host;
Igor Sysoev20bf47b2006-10-24 13:06:55 +0000680
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000681 u->wildcard = 1;
682
Igor Sysoevc9491d12008-08-26 14:24:14 +0000683 return NGX_OK;
Igor Sysoev20bf47b2006-10-24 13:06:55 +0000684 }
Igor Sysoev20bf47b2006-10-24 13:06:55 +0000685 }
Igor Sysoev20bf47b2006-10-24 13:06:55 +0000686 }
687
Igor Sysoevc9491d12008-08-26 14:24:14 +0000688 u->no_port = 1;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000689 }
690
Igor Sysoevc9491d12008-08-26 14:24:14 +0000691 len = last - host;
692
693 if (len == 0) {
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000694 u->err = "no host";
695 return NGX_ERROR;
696 }
697
Igor Sysoevc9491d12008-08-26 14:24:14 +0000698 if (len == 1 && *host == '*') {
699 len = 0;
700 }
701
702 u->host.len = len;
703 u->host.data = host;
704
Igor Sysoevd3bf7c12008-08-26 16:11:30 +0000705 if (u->no_resolve) {
706 return NGX_OK;
707 }
708
Igor Sysoev0f25ed32009-11-02 13:51:10 +0000709 if (len) {
710 sin->sin_addr.s_addr = ngx_inet_addr(host, len);
Igor Sysoevc9491d12008-08-26 14:24:14 +0000711
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000712 if (sin->sin_addr.s_addr == INADDR_NONE) {
Igor Sysoev0f25ed32009-11-02 13:51:10 +0000713 p = ngx_alloc(++len, pool->log);
714 if (p == NULL) {
715 return NGX_ERROR;
716 }
717
718 (void) ngx_cpystrn(p, host, len);
719
Igor Sysoevc9491d12008-08-26 14:24:14 +0000720 h = gethostbyname((const char *) p);
721
Igor Sysoev0f25ed32009-11-02 13:51:10 +0000722 ngx_free(p);
723
Igor Sysoevc9491d12008-08-26 14:24:14 +0000724 if (h == NULL || h->h_addr_list[0] == NULL) {
725 ngx_free(p);
726 u->err = "host not found";
727 return NGX_ERROR;
728 }
729
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000730 sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[0]);
731 }
732
733 if (sin->sin_addr.s_addr == INADDR_ANY) {
734 u->wildcard = 1;
Igor Sysoevc9491d12008-08-26 14:24:14 +0000735 }
736
Igor Sysoevc9491d12008-08-26 14:24:14 +0000737 } else {
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000738 sin->sin_addr.s_addr = INADDR_ANY;
739 u->wildcard = 1;
Igor Sysoevc9491d12008-08-26 14:24:14 +0000740 }
741
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000742 if (u->no_port) {
743 u->port = u->default_port;
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000744 sin->sin_port = htons(u->default_port);
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000745 }
746
Igor Sysoevc9491d12008-08-26 14:24:14 +0000747 if (u->listen) {
748 return NGX_OK;
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000749 }
750
Igor Sysoev7ed63ee2007-10-08 08:55:12 +0000751 if (ngx_inet_resolve_host(pool, u) != NGX_OK) {
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000752 return NGX_ERROR;
753 }
754
755 return NGX_OK;
756}
757
758
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000759static ngx_int_t
760ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u)
761{
762#if (NGX_HAVE_INET6)
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000763 u_char *p, *host, *port, *last, *uri;
764 size_t len;
765 ngx_int_t n;
766 struct sockaddr_in6 *sin6;
767
768 u->socklen = sizeof(struct sockaddr_in6);
769 sin6 = (struct sockaddr_in6 *) &u->sockaddr;
770 sin6->sin6_family = AF_INET6;
771
772 host = u->url.data + 1;
773
774 last = u->url.data + u->url.len;
775
776 p = ngx_strlchr(host, last, ']');
777
778 if (p == NULL) {
779 u->err = "invalid host";
780 return NGX_ERROR;
781 }
782
783 if (last - p) {
784
785 port = p + 1;
786
787 uri = ngx_strlchr(port, last, '/');
788
789 if (uri) {
790 if (u->listen || !u->uri_part) {
791 u->err = "invalid host";
792 return NGX_ERROR;
793 }
794
795 u->uri.len = last - uri;
796 u->uri.data = uri;
797 }
798
799 if (*port == ':') {
800 port++;
801
802 len = last - port;
803
804 if (len == 0) {
805 u->err = "invalid port";
806 return NGX_ERROR;
807 }
808
809 n = ngx_atoi(port, len);
810
811 if (n < 1 || n > 65536) {
812 u->err = "invalid port";
813 return NGX_ERROR;
814 }
815
816 u->port = (in_port_t) n;
817 sin6->sin6_port = htons((in_port_t) n);
818
819 u->port_text.len = len;
820 u->port_text.data = port;
821
822 } else {
823 u->no_port = 1;
824 }
825 }
826
827 len = p - host;
828
829 if (len == 0) {
830 u->err = "no host";
831 return NGX_ERROR;
832 }
833
Igor Sysoev47c88462009-11-02 12:58:30 +0000834 u->host.len = len;
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000835 u->host.data = host;
836
Igor Sysoev67765e82009-11-02 14:32:46 +0000837 if (ngx_inet6_addr(host, len, sin6->sin6_addr.s6_addr) != NGX_OK) {
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000838 u->err = "invalid IPv6 address";
839 return NGX_ERROR;
840 }
841
842 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
843 u->wildcard = 1;
844 }
845
846 u->family = AF_INET6;
847
848 if (u->no_resolve) {
849 return NGX_OK;
850 }
851
852 if (u->no_port) {
853 u->port = u->default_port;
854 sin6->sin6_port = htons(u->default_port);
855 }
856
857 return NGX_OK;
858
859#else
860
861 u->err = "the INET6 sockets are not supported on this platform";
862
863 return NGX_ERROR;
864
865#endif
866}
867
868
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000869ngx_int_t
Igor Sysoev7ed63ee2007-10-08 08:55:12 +0000870ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000871{
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000872 u_char *p, *host;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000873 size_t len;
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000874 in_port_t port;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000875 in_addr_t in_addr;
876 ngx_uint_t i;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000877 struct hostent *h;
878 struct sockaddr_in *sin;
879
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000880 /* AF_INET only */
881
Igor Sysoev2bc44ea2009-02-21 14:34:32 +0000882 port = htons(u->port);
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000883
Igor Sysoev0f25ed32009-11-02 13:51:10 +0000884 in_addr = ngx_inet_addr(u->host.data, u->host.len);
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000885
886 if (in_addr == INADDR_NONE) {
Igor Sysoev0f25ed32009-11-02 13:51:10 +0000887 host = ngx_alloc(u->host.len + 1, pool->log);
888 if (host == NULL) {
889 return NGX_ERROR;
890 }
891
892 (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
893
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000894 h = gethostbyname((char *) host);
895
Igor Sysoev7ed63ee2007-10-08 08:55:12 +0000896 ngx_free(host);
897
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000898 if (h == NULL || h->h_addr_list[0] == NULL) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000899 u->err = "host not found";
900 return NGX_ERROR;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000901 }
902
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000903 if (u->one_addr == 0) {
904 for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
905
906 } else {
907 i = 1;
908 }
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000909
910 /* MP: ngx_shared_palloc() */
911
Igor Sysoev0c189c52009-11-02 15:14:17 +0000912 u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000913 if (u->addrs == NULL) {
914 return NGX_ERROR;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000915 }
916
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000917 u->naddrs = i;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000918
919 for (i = 0; h->h_addr_list[i] != NULL; i++) {
920
Igor Sysoev7ed63ee2007-10-08 08:55:12 +0000921 sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000922 if (sin == NULL) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000923 return NGX_ERROR;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000924 }
925
926 sin->sin_family = AF_INET;
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000927 sin->sin_port = port;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000928 sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]);
929
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000930 u->addrs[i].sockaddr = (struct sockaddr *) sin;
931 u->addrs[i].socklen = sizeof(struct sockaddr_in);
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000932
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000933 len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000934
Igor Sysoev7f6b2ff2008-06-17 15:00:30 +0000935 p = ngx_pnalloc(pool, len);
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000936 if (p == NULL) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000937 return NGX_ERROR;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000938 }
939
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000940 len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000941
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000942 u->addrs[i].name.len = len;
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000943 u->addrs[i].name.data = p;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000944 }
945
946 } else {
947
948 /* MP: ngx_shared_palloc() */
949
Igor Sysoev0c189c52009-11-02 15:14:17 +0000950 u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000951 if (u->addrs == NULL) {
952 return NGX_ERROR;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000953 }
954
Igor Sysoev7ed63ee2007-10-08 08:55:12 +0000955 sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000956 if (sin == NULL) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000957 return NGX_ERROR;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000958 }
959
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000960 u->naddrs = 1;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000961
962 sin->sin_family = AF_INET;
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000963 sin->sin_port = port;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000964 sin->sin_addr.s_addr = in_addr;
965
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000966 u->addrs[0].sockaddr = (struct sockaddr *) sin;
967 u->addrs[0].socklen = sizeof(struct sockaddr_in);
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000968
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000969 p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000970 if (p == NULL) {
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000971 return NGX_ERROR;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000972 }
973
Igor Sysoeva35eacc2009-02-21 07:02:02 +0000974 u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
975 &u->host, ntohs(port)) - p;
Igor Sysoevbf3aaac2006-12-12 16:46:16 +0000976 u->addrs[0].name.data = p;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000977 }
978
Igor Sysoev3d2fd182006-12-04 16:46:13 +0000979 return NGX_OK;
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000980}