3
* Copyright (C) Igor Sysoev
7
#include <ngx_config.h>
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);
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);
23
static ngx_int_t ngx_mail_cmp_conf_addrs(const void *one, const void *two);
26
ngx_uint_t ngx_mail_max_module;
29
static ngx_command_t ngx_mail_commands[] = {
32
NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
39
NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
49
static ngx_core_module_t ngx_mail_module_ctx = {
56
ngx_module_t ngx_mail_module = {
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 */
73
ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
76
ngx_uint_t i, m, mi, s;
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;
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");
91
/* the main mail context */
93
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
95
return NGX_CONF_ERROR;
98
*(ngx_mail_conf_ctx_t **) conf = ctx;
100
/* count the number of the http modules and set up their indices */
102
ngx_mail_max_module = 0;
103
for (m = 0; ngx_modules[m]; m++) {
104
if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
108
ngx_modules[m]->ctx_index = ngx_mail_max_module++;
112
/* the mail main_conf context, it is the same in the all mail contexts */
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;
122
* the mail null srv_conf context, it is used to merge
123
* the server{}s' srv_conf's
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;
133
* create the main_conf's, the null srv_conf's, and the null loc_conf's
134
* of the all mail modules
137
for (m = 0; ngx_modules[m]; m++) {
138
if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
142
module = ngx_modules[m]->ctx;
143
mi = ngx_modules[m]->ctx_index;
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;
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;
161
/* parse inside the mail{} block */
166
cf->module_type = NGX_MAIL_MODULE;
167
cf->cmd_type = NGX_MAIL_MAIN_CONF;
168
rv = ngx_conf_parse(cf, NULL);
170
if (rv != NGX_CONF_OK) {
176
/* init mail{} main_conf's, merge the server{}s' srv_conf's */
178
cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
179
cscfp = cmcf->servers.elts;
181
for (m = 0; ngx_modules[m]; m++) {
182
if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
186
module = ngx_modules[m]->ctx;
187
mi = ngx_modules[m]->ctx_index;
189
/* init mail{} main_conf's */
193
if (module->init_main_conf) {
194
rv = module->init_main_conf(cf, ctx->main_conf[mi]);
195
if (rv != NGX_CONF_OK) {
201
for (s = 0; s < cmcf->servers.nelts; s++) {
203
/* merge the server{}s' srv_conf's */
205
cf->ctx = cscfp[s]->ctx;
207
if (module->merge_srv_conf) {
208
rv = module->merge_srv_conf(cf,
210
cscfp[s]->ctx->srv_conf[mi]);
211
if (rv != NGX_CONF_OK) {
222
if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_mail_conf_port_t))
225
return NGX_CONF_ERROR;
228
listen = cmcf->listen.elts;
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;
236
return ngx_mail_optimize_servers(cf, &ports);
241
ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
242
ngx_mail_listen_t *listen)
247
struct sockaddr_in *sin;
248
ngx_mail_conf_port_t *port;
249
ngx_mail_conf_addr_t *addr;
251
struct sockaddr_in6 *sin6;
254
sa = (struct sockaddr *) &listen->sockaddr;
256
switch (sa->sa_family) {
260
sin6 = (struct sockaddr_in6 *) sa;
265
default: /* AF_INET */
266
sin = (struct sockaddr_in *) sa;
272
for (i = 0; i < ports->nelts; i++) {
273
if (p == port[i].port && sa->sa_family == port[i].family) {
275
/* a port is already in the port list */
282
/* add a port to the port list */
284
port = ngx_array_push(ports);
289
port->family = sa->sa_family;
292
if (ngx_array_init(&port->addrs, cf->temp_pool, 2,
293
sizeof(ngx_mail_conf_addr_t))
301
addr = ngx_array_push(&port->addrs);
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;
312
addr->ssl = listen->ssl;
314
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
315
addr->ipv6only = listen->ipv6only;
323
ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
325
ngx_uint_t i, p, last, bind_wildcard;
327
ngx_mail_port_t *mport;
328
ngx_mail_conf_port_t *port;
329
ngx_mail_conf_addr_t *addr;
332
for (p = 0; p < ports->nelts; p++) {
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);
337
addr = port[p].addrs.elts;
338
last = port[p].addrs.nelts;
341
* if there is the binding to the "*:port" then we need to bind()
342
* to the "*:port" only and ignore the other bindings
345
if (addr[last - 1].wildcard) {
346
addr[last - 1].bind = 1;
357
if (bind_wildcard && !addr[i].bind) {
362
ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen);
364
return NGX_CONF_ERROR;
368
ls->handler = ngx_mail_init_connection;
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;
376
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
377
ls->ipv6only = addr[i].ipv6only;
380
mport = ngx_palloc(cf->pool, sizeof(ngx_mail_port_t));
382
return NGX_CONF_ERROR;
388
mport->naddrs = last;
395
switch (ls->sockaddr->sa_family) {
398
if (ngx_mail_add_addrs6(cf, mport, addr) != NGX_OK) {
399
return NGX_CONF_ERROR;
403
default: /* AF_INET */
404
if (ngx_mail_add_addrs(cf, mport, addr) != NGX_OK) {
405
return NGX_CONF_ERROR;
420
ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
421
ngx_mail_conf_addr_t *addr)
426
ngx_mail_in_addr_t *addrs;
427
struct sockaddr_in *sin;
428
u_char buf[NGX_SOCKADDR_STRLEN];
430
mport->addrs = ngx_pcalloc(cf->pool,
431
mport->naddrs * sizeof(ngx_mail_in_addr_t));
432
if (mport->addrs == NULL) {
436
addrs = mport->addrs;
438
for (i = 0; i < mport->naddrs; i++) {
440
sin = (struct sockaddr_in *) addr[i].sockaddr;
441
addrs[i].addr = sin->sin_addr.s_addr;
443
addrs[i].conf.ctx = addr[i].ctx;
445
addrs[i].conf.ssl = addr[i].ssl;
448
len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1);
450
p = ngx_pnalloc(cf->pool, len);
455
ngx_memcpy(p, buf, len);
457
addrs[i].conf.addr_text.len = len;
458
addrs[i].conf.addr_text.data = p;
468
ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
469
ngx_mail_conf_addr_t *addr)
474
ngx_mail_in6_addr_t *addrs6;
475
struct sockaddr_in6 *sin6;
476
u_char buf[NGX_SOCKADDR_STRLEN];
478
mport->addrs = ngx_pcalloc(cf->pool,
479
mport->naddrs * sizeof(ngx_mail_in6_addr_t));
480
if (mport->addrs == NULL) {
484
addrs6 = mport->addrs;
486
for (i = 0; i < mport->naddrs; i++) {
488
sin6 = (struct sockaddr_in6 *) addr[i].sockaddr;
489
addrs6[i].addr6 = sin6->sin6_addr;
491
addrs6[i].conf.ctx = addr[i].ctx;
493
addrs6[i].conf.ssl = addr[i].ssl;
496
len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1);
498
p = ngx_pnalloc(cf->pool, len);
503
ngx_memcpy(p, buf, len);
505
addrs6[i].conf.addr_text.len = len;
506
addrs6[i].conf.addr_text.data = p;
516
ngx_mail_cmp_conf_addrs(const void *one, const void *two)
518
ngx_mail_conf_addr_t *first, *second;
520
first = (ngx_mail_conf_addr_t *) one;
521
second = (ngx_mail_conf_addr_t *) two;
523
if (first->wildcard) {
524
/* a wildcard must be the last resort, shift it to the end */
528
if (first->bind && !second->bind) {
529
/* shift explicit bind()ed addresses to the start */
533
if (!first->bind && second->bind) {
534
/* shift explicit bind()ed addresses to the start */
538
/* do not sort by default */