5c88a9d9de4c2128f4ec6eb411a9b4c38443e6c8
[nginx.git] / nginx / src / core / ngx_inet.c
1
2 /*
3  * Copyright (C) Igor Sysoev
4  */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9
10
11 static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u);
12 static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u);
13
14
15 /* AF_INET only */
16
17 in_addr_t
18 ngx_inet_addr(u_char *text, size_t len)
19 {
20     u_char      *p, c;
21     in_addr_t    addr;
22     ngx_uint_t   octet, n;
23
24     addr = 0;
25     octet = 0;
26     n = 0;
27
28     for (p = text; p < text + len; p++) {
29
30         c = *p;
31
32         if (c >= '0' && c <= '9') {
33             octet = octet * 10 + (c - '0');
34             continue;
35         }
36
37         if (c == '.' && octet < 256) {
38             addr = (addr << 8) + octet;
39             octet = 0;
40             n++;
41             continue;
42         }
43
44         return INADDR_NONE;
45     }
46
47     if (n != 3) {
48         return INADDR_NONE;
49     }
50
51     if (octet < 256) {
52         addr = (addr << 8) + octet;
53         return htonl(addr);
54     }
55
56     return INADDR_NONE;
57 }
58
59
60 /* AF_INET only */
61
62 size_t
63 ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len)
64 {
65     u_char              *p;
66     struct sockaddr_in  *sin;
67
68     if (sa->sa_family == AF_INET) {
69
70         sin = (struct sockaddr_in *) sa;
71         p = (u_char *) &sin->sin_addr;
72
73         return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
74                             p[0], p[1], p[2], p[3])
75                - text;
76     }
77
78     return 0;
79 }
80
81
82 size_t
83 ngx_inet_ntop(int family, void *addr, u_char *text, size_t len)
84 {
85     u_char  *p;
86
87     if (family == AF_INET) {
88
89         p = (u_char *) addr;
90
91         return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
92                             p[0], p[1], p[2], p[3])
93                - text;
94     }
95
96     return 0;
97 }
98
99
100 /* AF_INET only */
101
102 ngx_int_t
103 ngx_ptocidr(ngx_str_t *text, void *cidr)
104 {
105     u_char           *addr, *mask, *last;
106     ngx_int_t         shift;
107     ngx_inet_cidr_t  *in_cidr;
108
109     in_cidr = cidr;
110     addr = text->data;
111     last = addr + text->len;
112
113     mask = ngx_strlchr(addr, last, '/');
114
115     in_cidr->addr = ngx_inet_addr(addr, (mask ? mask : last) - addr);
116
117     if (in_cidr->addr == INADDR_NONE) {
118         return NGX_ERROR;
119     }
120
121     if (mask == NULL) {
122         in_cidr->mask = 0xffffffff;
123         return NGX_OK;
124     }
125
126     mask++;
127
128     shift = ngx_atoi(mask, last - mask);
129     if (shift == NGX_ERROR) {
130         return NGX_ERROR;
131     }
132
133     if (shift == 0) {
134
135         /* the x86 compilers use the shl instruction that shifts by modulo 32 */
136
137         in_cidr->mask = 0;
138
139         if (in_cidr->addr == 0) {
140             return NGX_OK;
141         }
142
143         return NGX_DONE;
144     }
145
146     in_cidr->mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift))));
147
148     if (in_cidr->addr == (in_cidr->addr & in_cidr->mask)) {
149         return NGX_OK;
150     }
151
152     in_cidr->addr &= in_cidr->mask;
153
154     return NGX_DONE;
155 }
156
157
158 ngx_int_t
159 ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u)
160 {
161     u_char  *p;
162
163     p = u->url.data;
164
165     if (ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
166         return ngx_parse_unix_domain_url(pool, u);
167     }
168
169     if ((p[0] == ':' || p[0] == '/') && !u->listen) {
170         u->err = "invalid host";
171         return NGX_ERROR;
172     }
173
174     return ngx_parse_inet_url(pool, u);
175 }
176
177
178 static ngx_int_t
179 ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u)
180 {
181 #if (NGX_HAVE_UNIX_DOMAIN)
182     u_char              *path, *uri, *last;
183     size_t               len;
184     struct sockaddr_un  *saun;
185
186     len = u->url.len;
187     path = u->url.data;
188
189     path += 5;
190     len -= 5;
191
192     if (u->uri_part) {
193
194         last = path + len;
195         uri = ngx_strlchr(path, last, ':');
196
197         if (uri) {
198             len = uri - path;
199             uri++;
200             u->uri.len = last - uri;
201             u->uri.data = uri;
202         }
203     }
204
205     if (len == 0) {
206         u->err = "no path in the unix domain socket";
207         return NGX_ERROR;
208     }
209
210     u->host.len = len++;
211     u->host.data = path;
212     u->family = AF_UNIX;
213
214     if (len > sizeof(saun->sun_path)) {
215         u->err = "too long path in the unix domain socket";
216         return NGX_ERROR;
217     }
218
219     u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t));
220     if (u->addrs == NULL) {
221         return NGX_ERROR;
222     }
223
224     saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un));
225     if (saun == NULL) {
226         return NGX_ERROR;
227     }
228
229     u->naddrs = 1;
230
231     saun->sun_family = AF_UNIX;
232     (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
233
234     u->addrs[0].sockaddr = (struct sockaddr *) saun;
235     u->addrs[0].socklen = sizeof(struct sockaddr_un);
236     u->addrs[0].name.len = len + 4;
237     u->addrs[0].name.data = u->url.data;
238
239     return NGX_OK;
240
241 #else
242
243     u->err = "the unix domain sockets are not supported on this platform";
244
245     return NGX_ERROR;
246
247 #endif
248 }
249
250
251 static ngx_int_t
252 ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
253 {
254     u_char          *p, *host, *port, *last, *uri, *args;
255     size_t           len;
256     ngx_int_t        n;
257     struct hostent  *h;
258
259     u->family = AF_INET;
260
261     host = u->url.data;
262
263     last = host + u->url.len;
264
265     port = ngx_strlchr(host, last, ':');
266
267     uri = ngx_strlchr(host, last, '/');
268
269     args = ngx_strlchr(host, last, '?');
270
271     if (args) {
272         if (uri == NULL) {
273             uri = args;
274
275         } else if (args < uri) {
276             uri = args;
277         }
278     }
279
280     if (uri) {
281         if (u->listen || !u->uri_part) {
282             u->err = "invalid host";
283             return NGX_ERROR;
284         }
285
286         u->uri.len = last - uri;
287         u->uri.data = uri;
288
289         last = uri;
290
291         if (uri < port) {
292             port = NULL;
293         }
294     }
295
296     if (port) {
297         port++;
298
299         len = last - port;
300
301         if (len == 0) {
302             u->err = "invalid port";
303             return NGX_ERROR;
304         }
305
306         n = ngx_atoi(port, len);
307
308         if (n < 1 || n > 65536) {
309             u->err = "invalid port";
310             return NGX_ERROR;
311         }
312
313         u->port = (in_port_t) n;
314
315         u->port_text.len = len;
316         u->port_text.data = port;
317
318         last = port - 1;
319
320     } else {
321         if (uri == NULL) {
322
323             if (u->listen) {
324
325                 /* test value as port only */
326
327                 n = ngx_atoi(host, last - host);
328
329                 if (n != NGX_ERROR) {
330
331                     if (n < 1 || n > 65536) {
332                         u->err = "invalid port";
333                         return NGX_ERROR;
334                     }
335
336                     u->port = (in_port_t) n;
337
338                     u->port_text.len = last - host;
339                     u->port_text.data = host;
340
341                     return NGX_OK;
342                 }
343             }
344         }
345
346         u->no_port = 1;
347     }
348
349     len = last - host;
350
351     if (len == 0) {
352         u->err = "no host";
353         return NGX_ERROR;
354     }
355
356     if (len == 1 && *host == '*') {
357         len = 0;
358     }
359
360     u->host.len = len;
361     u->host.data = host;
362
363     if (u->no_resolve) {
364         return NGX_OK;
365     }
366
367     if (len++) {
368
369         p = ngx_alloc(len, pool->log);
370         if (p == NULL) {
371             return NGX_ERROR;
372         }
373
374         (void) ngx_cpystrn(p, host, len);
375
376         u->addr.in_addr = inet_addr((const char *) p);
377
378         if (u->addr.in_addr == INADDR_NONE) {
379             h = gethostbyname((const char *) p);
380
381             if (h == NULL || h->h_addr_list[0] == NULL) {
382                 ngx_free(p);
383                 u->err = "host not found";
384                 return NGX_ERROR;
385             }
386
387             u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]);
388         }
389
390         ngx_free(p);
391
392     } else {
393         u->addr.in_addr = INADDR_ANY;
394     }
395
396     if (u->no_port) {
397         u->port = u->default_port;
398     }
399
400     if (u->listen) {
401         return NGX_OK;
402     }
403
404     if (ngx_inet_resolve_host(pool, u) != NGX_OK) {
405         return NGX_ERROR;
406     }
407
408     return NGX_OK;
409 }
410
411
412 ngx_int_t
413 ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
414 {
415     u_char              *p, *host;
416     size_t               len;
417     in_addr_t            in_addr;
418     ngx_uint_t           i;
419     struct hostent      *h;
420     struct sockaddr_in  *sin;
421
422     host = ngx_alloc(u->host.len + 1, pool->log);
423     if (host == NULL) {
424         return NGX_ERROR;
425     }
426
427     (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
428
429     /* AF_INET only */
430
431     in_addr = inet_addr((char *) host);
432
433     if (in_addr == INADDR_NONE) {
434         h = gethostbyname((char *) host);
435
436         ngx_free(host);
437
438         if (h == NULL || h->h_addr_list[0] == NULL) {
439             u->err = "host not found";
440             return NGX_ERROR;
441         }
442
443         if (u->one_addr == 0) {
444             for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
445
446         } else {
447             i = 1;
448         }
449
450         /* MP: ngx_shared_palloc() */
451
452         u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_peer_addr_t));
453         if (u->addrs == NULL) {
454             return NGX_ERROR;
455         }
456
457         u->naddrs = i;
458
459         for (i = 0; h->h_addr_list[i] != NULL; i++) {
460
461             sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
462             if (sin == NULL) {
463                 return NGX_ERROR;
464             }
465
466             sin->sin_family = AF_INET;
467             sin->sin_port = htons(u->port);
468             sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]);
469
470             u->addrs[i].sockaddr = (struct sockaddr *) sin;
471             u->addrs[i].socklen = sizeof(struct sockaddr_in);
472
473             len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
474
475             p = ngx_pnalloc(pool, len);
476             if (p == NULL) {
477                 return NGX_ERROR;
478             }
479
480             len = ngx_sock_ntop((struct sockaddr *) sin, p, len);
481
482             u->addrs[i].name.len = ngx_sprintf(&p[len], ":%d", u->port) - p;
483             u->addrs[i].name.data = p;
484         }
485
486     } else {
487
488         ngx_free(host);
489
490         /* MP: ngx_shared_palloc() */
491
492         u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t));
493         if (u->addrs == NULL) {
494             return NGX_ERROR;
495         }
496
497         sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
498         if (sin == NULL) {
499             return NGX_ERROR;
500         }
501
502         u->naddrs = 1;
503
504         sin->sin_family = AF_INET;
505         sin->sin_port = htons(u->port);
506         sin->sin_addr.s_addr = in_addr;
507
508         u->addrs[0].sockaddr = (struct sockaddr *) sin;
509         u->addrs[0].socklen = sizeof(struct sockaddr_in);
510
511         p = ngx_pnalloc(pool, u->host.len + sizeof(":65536") - 1);
512         if (p == NULL) {
513             return NGX_ERROR;
514         }
515
516         u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", &u->host, u->port) - p;
517         u->addrs[0].name.data = p;
518     }
519
520     return NGX_OK;
521 }