1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
10 #include <ngx_mail.h>
11
12
13 static char *ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
14 static ngx_int_t ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
15 ngx_mail_listen_t *listen);
16 static char *ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports);
17 static ngx_int_t ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
18 ngx_mail_conf_addr_t *addr);
19 #if (NGX_HAVE_INET6)
20 static ngx_int_t ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
21 ngx_mail_conf_addr_t *addr);
22 #endif
23 static ngx_int_t ngx_mail_cmp_conf_addrs(const void *one, const void *two);
24
25
26 ngx_uint_t ngx_mail_max_module;
27
28
29 static ngx_command_t ngx_mail_commands[] = {
30
31 { ngx_string("mail"),
32 NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
33 ngx_mail_block,
34 0,
35 0,
36 NULL },
37
38 { ngx_string("imap"),
39 NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
40 ngx_mail_block,
41 0,
42 0,
43 NULL },
44
45 ngx_null_command
46 };
47
48
49 static ngx_core_module_t ngx_mail_module_ctx = {
50 ngx_string("mail"),
51 NULL,
52 NULL
53 };
54
55
56 ngx_module_t ngx_mail_module = {
57 NGX_MODULE_V1,
58 &ngx_mail_module_ctx, /* module context */
59 ngx_mail_commands, /* module directives */
60 NGX_CORE_MODULE, /* module type */
61 NULL, /* init master */
62 NULL, /* init module */
63 NULL, /* init process */
64 NULL, /* init thread */
65 NULL, /* exit thread */
66 NULL, /* exit process */
67 NULL, /* exit master */
68 NGX_MODULE_V1_PADDING
69 };
70
71
72 static char *
73 ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
74 {
75 char *rv;
76 ngx_uint_t i, m, mi, s;
77 ngx_conf_t pcf;
78 ngx_array_t ports;
79 ngx_mail_listen_t *listen;
80 ngx_mail_module_t *module;
81 ngx_mail_conf_ctx_t *ctx;
82 ngx_mail_core_srv_conf_t **cscfp;
83 ngx_mail_core_main_conf_t *cmcf;
84
85 if (cmd->name.data[0] == 'i') {
86 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
87 "the \"imap\" directive is deprecated, "
88 "use the \"mail\" directive instead");
89 }
90
91 /* the main mail context */
92
93 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
94 if (ctx == NULL) {
95 return NGX_CONF_ERROR;
96 }
97
98 *(ngx_mail_conf_ctx_t **) conf = ctx;
99
100 /* count the number of the http modules and set up their indices */
101
102 ngx_mail_max_module = 0;
103 for (m = 0; ngx_modules[m]; m++) {
104 if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
105 continue;
106 }
107
108 ngx_modules[m]->ctx_index = ngx_mail_max_module++;
109 }
110
111
112 /* the mail main_conf context, it is the same in the all mail contexts */
113
114 ctx->main_conf = ngx_pcalloc(cf->pool,
115 sizeof(void *) * ngx_mail_max_module);
116 if (ctx->main_conf == NULL) {
117 return NGX_CONF_ERROR;
118 }
119
120
121 /*
122 * the mail null srv_conf context, it is used to merge
123 * the server{}s' srv_conf's
124 */
125
126 ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
127 if (ctx->srv_conf == NULL) {
128 return NGX_CONF_ERROR;
129 }
130
131
132 /*
133 * create the main_conf's, the null srv_conf's, and the null loc_conf's
134 * of the all mail modules
135 */
136
137 for (m = 0; ngx_modules[m]; m++) {
138 if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
139 continue;
140 }
141
142 module = ngx_modules[m]->ctx;
143 mi = ngx_modules[m]->ctx_index;
144
145 if (module->create_main_conf) {
146 ctx->main_conf[mi] = module->create_main_conf(cf);
147 if (ctx->main_conf[mi] == NULL) {
148 return NGX_CONF_ERROR;
149 }
150 }
151
152 if (module->create_srv_conf) {
153 ctx->srv_conf[mi] = module->create_srv_conf(cf);
154 if (ctx->srv_conf[mi] == NULL) {
155 return NGX_CONF_ERROR;
156 }
157 }
158 }
159
160
161 /* parse inside the mail{} block */
162
163 pcf = *cf;
164 cf->ctx = ctx;
165
166 cf->module_type = NGX_MAIL_MODULE;
167 cf->cmd_type = NGX_MAIL_MAIN_CONF;
168 rv = ngx_conf_parse(cf, NULL);
169
170 if (rv != NGX_CONF_OK) {
171 *cf = pcf;
172 return rv;
173 }
174
175
176 /* init mail{} main_conf's, merge the server{}s' srv_conf's */
177
178 cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
179 cscfp = cmcf->servers.elts;
180
181 for (m = 0; ngx_modules[m]; m++) {
182 if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
183 continue;
184 }
185
186 module = ngx_modules[m]->ctx;
187 mi = ngx_modules[m]->ctx_index;
188
189 /* init mail{} main_conf's */
190
191 cf->ctx = ctx;
192
193 if (module->init_main_conf) {
194 rv = module->init_main_conf(cf, ctx->main_conf[mi]);
195 if (rv != NGX_CONF_OK) {
196 *cf = pcf;
197 return rv;
198 }
199 }
200
201 for (s = 0; s < cmcf->servers.nelts; s++) {
202
203 /* merge the server{}s' srv_conf's */
204
205 cf->ctx = cscfp[s]->ctx;
206
207 if (module->merge_srv_conf) {
208 rv = module->merge_srv_conf(cf,
209 ctx->srv_conf[mi],
210 cscfp[s]->ctx->srv_conf[mi]);
211 if (rv != NGX_CONF_OK) {
212 *cf = pcf;
213 return rv;
214 }
215 }
216 }
217 }
218
219 *cf = pcf;
220
221
222 if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_mail_conf_port_t))
223 != NGX_OK)
224 {
225 return NGX_CONF_ERROR;
226 }
227
228 listen = cmcf->listen.elts;
229
230 for (i = 0; i < cmcf->listen.nelts; i++) {
231 if (ngx_mail_add_ports(cf, &ports, &listen[i]) != NGX_OK) {
232 return NGX_CONF_ERROR;
233 }
234 }
235
236 return ngx_mail_optimize_servers(cf, &ports);
237 }
238
239
240 static ngx_int_t
241 ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
242 ngx_mail_listen_t *listen)
243 {
244 in_port_t p;
245 ngx_uint_t i;
246 struct sockaddr *sa;
247 struct sockaddr_in *sin;
248 ngx_mail_conf_port_t *port;
249 ngx_mail_conf_addr_t *addr;
250 #if (NGX_HAVE_INET6)
251 struct sockaddr_in6 *sin6;
252 #endif
253
254 sa = (struct sockaddr *) &listen->sockaddr;
255
256 switch (sa->sa_family) {
257
258 #if (NGX_HAVE_INET6)
259 case AF_INET6:
260 sin6 = (struct sockaddr_in6 *) sa;
261 p = sin6->sin6_port;
262 break;
263 #endif
264
265 default: /* AF_INET */
266 sin = (struct sockaddr_in *) sa;
267 p = sin->sin_port;
268 break;
269 }
270
271 port = ports->elts;
272 for (i = 0; i < ports->nelts; i++) {
273 if (p == port[i].port && sa->sa_family == port[i].family) {
274
275 /* a port is already in the port list */
276
277 port = &port[i];
278 goto found;
279 }
280 }
281
282 /* add a port to the port list */
283
284 port = ngx_array_push(ports);
285 if (port == NULL) {
286 return NGX_ERROR;
287 }
288
289 port->family = sa->sa_family;
290 port->port = p;
291
292 if (ngx_array_init(&port->addrs, cf->temp_pool, 2,
293 sizeof(ngx_mail_conf_addr_t))
294 != NGX_OK)
295 {
296 return NGX_ERROR;
297 }
298
299 found:
300
301 addr = ngx_array_push(&port->addrs);
302 if (addr == NULL) {
303 return NGX_ERROR;
304 }
305
306 addr->sockaddr = (struct sockaddr *) &listen->sockaddr;
307 addr->socklen = listen->socklen;
308 addr->ctx = listen->ctx;
309 addr->bind = listen->bind;
310 addr->wildcard = listen->wildcard;
311 #if (NGX_MAIL_SSL)
312 addr->ssl = listen->ssl;
313 #endif
314 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
315 addr->ipv6only = listen->ipv6only;
316 #endif
317
318 return NGX_OK;
319 }
320
321
322 static char *
323 ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
324 {
325 ngx_uint_t i, p, last, bind_wildcard;
326 ngx_listening_t *ls;
327 ngx_mail_port_t *mport;
328 ngx_mail_conf_port_t *port;
329 ngx_mail_conf_addr_t *addr;
330
331 port = ports->elts;
332 for (p = 0; p < ports->nelts; p++) {
333
334 ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,
335 sizeof(ngx_mail_conf_addr_t), ngx_mail_cmp_conf_addrs);
336
337 addr = port[p].addrs.elts;
338 last = port[p].addrs.nelts;
339
340 /*
341 * if there is the binding to the "*:port" then we need to bind()
342 * to the "*:port" only and ignore the other bindings
343 */
344
345 if (addr[last - 1].wildcard) {
346 addr[last - 1].bind = 1;
347 bind_wildcard = 1;
348
349 } else {
350 bind_wildcard = 0;
351 }
352
353 i = 0;
354
355 while (i < last) {
356
357 if (bind_wildcard && !addr[i].bind) {
358 i++;
359 continue;
360 }
361
362 ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen);
363 if (ls == NULL) {
364 return NGX_CONF_ERROR;
365 }
366
367 ls->addr_ntop = 1;
368 ls->handler = ngx_mail_init_connection;
369 ls->pool_size = 256;
370
371 /* TODO: error_log directive */
372 ls->logp = &cf->cycle->new_log;
373 ls->log.data = &ls->addr_text;
374 ls->log.handler = ngx_accept_log_error;
375
376 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
377 ls->ipv6only = addr[i].ipv6only;
378 #endif
379
380 mport = ngx_palloc(cf->pool, sizeof(ngx_mail_port_t));
381 if (mport == NULL) {
382 return NGX_CONF_ERROR;
383 }
384
385 ls->servers = mport;
386
387 if (i == last - 1) {
388 mport->naddrs = last;
389
390 } else {
391 mport->naddrs = 1;
392 i = 0;
393 }
394
395 switch (ls->sockaddr->sa_family) {
396 #if (NGX_HAVE_INET6)
397 case AF_INET6:
398 if (ngx_mail_add_addrs6(cf, mport, addr) != NGX_OK) {
399 return NGX_CONF_ERROR;
400 }
401 break;
402 #endif
403 default: /* AF_INET */
404 if (ngx_mail_add_addrs(cf, mport, addr) != NGX_OK) {
405 return NGX_CONF_ERROR;
406 }
407 break;
408 }
409
410 addr++;
411 last--;
412 }
413 }
414
415 return NGX_CONF_OK;
416 }
417
418
419 static ngx_int_t
420 ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
421 ngx_mail_conf_addr_t *addr)
422 {
423 u_char *p;
424 size_t len;
425 ngx_uint_t i;
426 ngx_mail_in_addr_t *addrs;
427 struct sockaddr_in *sin;
428 u_char buf[NGX_SOCKADDR_STRLEN];
429
430 mport->addrs = ngx_pcalloc(cf->pool,
431 mport->naddrs * sizeof(ngx_mail_in_addr_t));
432 if (mport->addrs == NULL) {
433 return NGX_ERROR;
434 }
435
436 addrs = mport->addrs;
437
438 for (i = 0; i < mport->naddrs; i++) {
439
440 sin = (struct sockaddr_in *) addr[i].sockaddr;
441 addrs[i].addr = sin->sin_addr.s_addr;
442
443 addrs[i].conf.ctx = addr[i].ctx;
444 #if (NGX_MAIL_SSL)
445 addrs[i].conf.ssl = addr[i].ssl;
446 #endif
447
448 len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1);
449
450 p = ngx_pnalloc(cf->pool, len);
451 if (p == NULL) {
452 return NGX_ERROR;
453 }
454
455 ngx_memcpy(p, buf, len);
456
457 addrs[i].conf.addr_text.len = len;
458 addrs[i].conf.addr_text.data = p;
459 }
460
461 return NGX_OK;
462 }
463
464
465 #if (NGX_HAVE_INET6)
466
467 static ngx_int_t
468 ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
469 ngx_mail_conf_addr_t *addr)
470 {
471 u_char *p;
472 size_t len;
473 ngx_uint_t i;
474 ngx_mail_in6_addr_t *addrs6;
475 struct sockaddr_in6 *sin6;
476 u_char buf[NGX_SOCKADDR_STRLEN];
477
478 mport->addrs = ngx_pcalloc(cf->pool,
479 mport->naddrs * sizeof(ngx_mail_in6_addr_t));
480 if (mport->addrs == NULL) {
481 return NGX_ERROR;
482 }
483
484 addrs6 = mport->addrs;
485
486 for (i = 0; i < mport->naddrs; i++) {
487
488 sin6 = (struct sockaddr_in6 *) addr[i].sockaddr;
489 addrs6[i].addr6 = sin6->sin6_addr;
490
491 addrs6[i].conf.ctx = addr[i].ctx;
492 #if (NGX_MAIL_SSL)
493 addrs6[i].conf.ssl = addr[i].ssl;
494 #endif
495
496 len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1);
497
498 p = ngx_pnalloc(cf->pool, len);
499 if (p == NULL) {
500 return NGX_ERROR;
501 }
502
503 ngx_memcpy(p, buf, len);
504
505 addrs6[i].conf.addr_text.len = len;
506 addrs6[i].conf.addr_text.data = p;
507 }
508
509 return NGX_OK;
510 }
511
512 #endif
513
514
515 static ngx_int_t
516 ngx_mail_cmp_conf_addrs(const void *one, const void *two)
517 {
518 ngx_mail_conf_addr_t *first, *second;
519
520 first = (ngx_mail_conf_addr_t *) one;
521 second = (ngx_mail_conf_addr_t *) two;
522
523 if (first->wildcard) {
524 /* a wildcard must be the last resort, shift it to the end */
525 return 1;
526 }
527
528 if (first->bind && !second->bind) {
529 /* shift explicit bind()ed addresses to the start */
530 return -1;
531 }
532
533 if (!first->bind && second->bind) {
534 /* shift explicit bind()ed addresses to the start */
535 return 1;
536 }
537
538 /* do not sort by default */
539
540 return 0;
541 }
542
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.