0001
0002
0003
0004
0005
0006
0007
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_event.h>
0011 #include <ngx_mail.h>
0012
0013
0014 static void *ngx_mail_core_create_main_conf(ngx_conf_t *cf);
0015 static void *ngx_mail_core_create_srv_conf(ngx_conf_t *cf);
0016 static char *ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
0017 void *child);
0018 static char *ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
0019 void *conf);
0020 static char *ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
0021 void *conf);
0022 static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd,
0023 void *conf);
0024 static char *ngx_mail_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
0025 void *conf);
0026 static char *ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
0027 void *conf);
0028
0029
0030 static ngx_command_t ngx_mail_core_commands[] = {
0031
0032 { ngx_string("server"),
0033 NGX_MAIL_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
0034 ngx_mail_core_server,
0035 0,
0036 0,
0037 NULL },
0038
0039 { ngx_string("listen"),
0040 NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
0041 ngx_mail_core_listen,
0042 NGX_MAIL_SRV_CONF_OFFSET,
0043 0,
0044 NULL },
0045
0046 { ngx_string("protocol"),
0047 NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
0048 ngx_mail_core_protocol,
0049 NGX_MAIL_SRV_CONF_OFFSET,
0050 0,
0051 NULL },
0052
0053 { ngx_string("timeout"),
0054 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
0055 ngx_conf_set_msec_slot,
0056 NGX_MAIL_SRV_CONF_OFFSET,
0057 offsetof(ngx_mail_core_srv_conf_t, timeout),
0058 NULL },
0059
0060 { ngx_string("server_name"),
0061 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
0062 ngx_conf_set_str_slot,
0063 NGX_MAIL_SRV_CONF_OFFSET,
0064 offsetof(ngx_mail_core_srv_conf_t, server_name),
0065 NULL },
0066
0067 { ngx_string("error_log"),
0068 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
0069 ngx_mail_core_error_log,
0070 NGX_MAIL_SRV_CONF_OFFSET,
0071 0,
0072 NULL },
0073
0074 { ngx_string("resolver"),
0075 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
0076 ngx_mail_core_resolver,
0077 NGX_MAIL_SRV_CONF_OFFSET,
0078 0,
0079 NULL },
0080
0081 { ngx_string("resolver_timeout"),
0082 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
0083 ngx_conf_set_msec_slot,
0084 NGX_MAIL_SRV_CONF_OFFSET,
0085 offsetof(ngx_mail_core_srv_conf_t, resolver_timeout),
0086 NULL },
0087
0088 ngx_null_command
0089 };
0090
0091
0092 static ngx_mail_module_t ngx_mail_core_module_ctx = {
0093 NULL,
0094
0095 ngx_mail_core_create_main_conf,
0096 NULL,
0097
0098 ngx_mail_core_create_srv_conf,
0099 ngx_mail_core_merge_srv_conf
0100 };
0101
0102
0103 ngx_module_t ngx_mail_core_module = {
0104 NGX_MODULE_V1,
0105 &ngx_mail_core_module_ctx,
0106 ngx_mail_core_commands,
0107 NGX_MAIL_MODULE,
0108 NULL,
0109 NULL,
0110 NULL,
0111 NULL,
0112 NULL,
0113 NULL,
0114 NULL,
0115 NGX_MODULE_V1_PADDING
0116 };
0117
0118
0119 static void *
0120 ngx_mail_core_create_main_conf(ngx_conf_t *cf)
0121 {
0122 ngx_mail_core_main_conf_t *cmcf;
0123
0124 cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t));
0125 if (cmcf == NULL) {
0126 return NULL;
0127 }
0128
0129 if (ngx_array_init(&cmcf->servers, cf->pool, 4,
0130 sizeof(ngx_mail_core_srv_conf_t *))
0131 != NGX_OK)
0132 {
0133 return NULL;
0134 }
0135
0136 if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t))
0137 != NGX_OK)
0138 {
0139 return NULL;
0140 }
0141
0142 return cmcf;
0143 }
0144
0145
0146 static void *
0147 ngx_mail_core_create_srv_conf(ngx_conf_t *cf)
0148 {
0149 ngx_mail_core_srv_conf_t *cscf;
0150
0151 cscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_srv_conf_t));
0152 if (cscf == NULL) {
0153 return NULL;
0154 }
0155
0156
0157
0158
0159
0160
0161
0162
0163 cscf->timeout = NGX_CONF_UNSET_MSEC;
0164 cscf->resolver_timeout = NGX_CONF_UNSET_MSEC;
0165
0166 cscf->resolver = NGX_CONF_UNSET_PTR;
0167
0168 cscf->file_name = cf->conf_file->file.name.data;
0169 cscf->line = cf->conf_file->line;
0170
0171 return cscf;
0172 }
0173
0174
0175 static char *
0176 ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
0177 {
0178 ngx_mail_core_srv_conf_t *prev = parent;
0179 ngx_mail_core_srv_conf_t *conf = child;
0180
0181 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
0182 ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout,
0183 30000);
0184
0185
0186 ngx_conf_merge_str_value(conf->server_name, prev->server_name, "");
0187
0188 if (conf->server_name.len == 0) {
0189 conf->server_name = cf->cycle->hostname;
0190 }
0191
0192 if (conf->protocol == NULL) {
0193 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
0194 "unknown mail protocol for server in %s:%ui",
0195 conf->file_name, conf->line);
0196 return NGX_CONF_ERROR;
0197 }
0198
0199 if (conf->error_log == NULL) {
0200 if (prev->error_log) {
0201 conf->error_log = prev->error_log;
0202 } else {
0203 conf->error_log = &cf->cycle->new_log;
0204 }
0205 }
0206
0207 ngx_conf_merge_ptr_value(conf->resolver, prev->resolver, NULL);
0208
0209 return NGX_CONF_OK;
0210 }
0211
0212
0213 static char *
0214 ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0215 {
0216 char *rv;
0217 void *mconf;
0218 ngx_uint_t m;
0219 ngx_conf_t pcf;
0220 ngx_mail_module_t *module;
0221 ngx_mail_conf_ctx_t *ctx, *mail_ctx;
0222 ngx_mail_core_srv_conf_t *cscf, **cscfp;
0223 ngx_mail_core_main_conf_t *cmcf;
0224
0225 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
0226 if (ctx == NULL) {
0227 return NGX_CONF_ERROR;
0228 }
0229
0230 mail_ctx = cf->ctx;
0231 ctx->main_conf = mail_ctx->main_conf;
0232
0233
0234
0235 ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
0236 if (ctx->srv_conf == NULL) {
0237 return NGX_CONF_ERROR;
0238 }
0239
0240 for (m = 0; cf->cycle->modules[m]; m++) {
0241 if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
0242 continue;
0243 }
0244
0245 module = cf->cycle->modules[m]->ctx;
0246
0247 if (module->create_srv_conf) {
0248 mconf = module->create_srv_conf(cf);
0249 if (mconf == NULL) {
0250 return NGX_CONF_ERROR;
0251 }
0252
0253 ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf;
0254 }
0255 }
0256
0257
0258
0259 cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index];
0260 cscf->ctx = ctx;
0261
0262 cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
0263
0264 cscfp = ngx_array_push(&cmcf->servers);
0265 if (cscfp == NULL) {
0266 return NGX_CONF_ERROR;
0267 }
0268
0269 *cscfp = cscf;
0270
0271
0272
0273
0274 pcf = *cf;
0275 cf->ctx = ctx;
0276 cf->cmd_type = NGX_MAIL_SRV_CONF;
0277
0278 rv = ngx_conf_parse(cf, NULL);
0279
0280 *cf = pcf;
0281
0282 if (rv == NGX_CONF_OK && !cscf->listen) {
0283 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
0284 "no \"listen\" is defined for server in %s:%ui",
0285 cscf->file_name, cscf->line);
0286 return NGX_CONF_ERROR;
0287 }
0288
0289 return rv;
0290 }
0291
0292
0293 static char *
0294 ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0295 {
0296 ngx_mail_core_srv_conf_t *cscf = conf;
0297
0298 ngx_str_t *value;
0299 ngx_url_t u;
0300 ngx_uint_t i, m;
0301 ngx_mail_listen_t *ls;
0302 ngx_mail_module_t *module;
0303 ngx_mail_core_main_conf_t *cmcf;
0304
0305 cscf->listen = 1;
0306
0307 value = cf->args->elts;
0308
0309 ngx_memzero(&u, sizeof(ngx_url_t));
0310
0311 u.url = value[1];
0312 u.listen = 1;
0313
0314 if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
0315 if (u.err) {
0316 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0317 "%s in \"%V\" of the \"listen\" directive",
0318 u.err, &u.url);
0319 }
0320
0321 return NGX_CONF_ERROR;
0322 }
0323
0324 cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);
0325
0326 ls = cmcf->listen.elts;
0327
0328 for (i = 0; i < cmcf->listen.nelts; i++) {
0329
0330 if (ngx_cmp_sockaddr(&ls[i].sockaddr.sockaddr, ls[i].socklen,
0331 (struct sockaddr *) &u.sockaddr, u.socklen, 1)
0332 != NGX_OK)
0333 {
0334 continue;
0335 }
0336
0337 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0338 "duplicate \"%V\" address and port pair", &u.url);
0339 return NGX_CONF_ERROR;
0340 }
0341
0342 ls = ngx_array_push(&cmcf->listen);
0343 if (ls == NULL) {
0344 return NGX_CONF_ERROR;
0345 }
0346
0347 ngx_memzero(ls, sizeof(ngx_mail_listen_t));
0348
0349 ngx_memcpy(&ls->sockaddr.sockaddr, &u.sockaddr, u.socklen);
0350
0351 ls->socklen = u.socklen;
0352 ls->backlog = NGX_LISTEN_BACKLOG;
0353 ls->wildcard = u.wildcard;
0354 ls->ctx = cf->ctx;
0355
0356 #if (NGX_HAVE_INET6)
0357 ls->ipv6only = 1;
0358 #endif
0359
0360 if (cscf->protocol == NULL) {
0361 for (m = 0; cf->cycle->modules[m]; m++) {
0362 if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
0363 continue;
0364 }
0365
0366 module = cf->cycle->modules[m]->ctx;
0367
0368 if (module->protocol == NULL) {
0369 continue;
0370 }
0371
0372 for (i = 0; module->protocol->port[i]; i++) {
0373 if (module->protocol->port[i] == u.port) {
0374 cscf->protocol = module->protocol;
0375 break;
0376 }
0377 }
0378 }
0379 }
0380
0381 for (i = 2; i < cf->args->nelts; i++) {
0382
0383 if (ngx_strcmp(value[i].data, "bind") == 0) {
0384 ls->bind = 1;
0385 continue;
0386 }
0387
0388 if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
0389 ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
0390 ls->bind = 1;
0391
0392 if (ls->backlog == NGX_ERROR || ls->backlog == 0) {
0393 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0394 "invalid backlog \"%V\"", &value[i]);
0395 return NGX_CONF_ERROR;
0396 }
0397
0398 continue;
0399 }
0400
0401 if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
0402 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
0403 size_t len;
0404 u_char buf[NGX_SOCKADDR_STRLEN];
0405
0406 if (ls->sockaddr.sockaddr.sa_family == AF_INET6) {
0407
0408 if (ngx_strcmp(&value[i].data[10], "n") == 0) {
0409 ls->ipv6only = 1;
0410
0411 } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
0412 ls->ipv6only = 0;
0413
0414 } else {
0415 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0416 "invalid ipv6only flags \"%s\"",
0417 &value[i].data[9]);
0418 return NGX_CONF_ERROR;
0419 }
0420
0421 ls->bind = 1;
0422
0423 } else {
0424 len = ngx_sock_ntop(&ls->sockaddr.sockaddr, ls->socklen, buf,
0425 NGX_SOCKADDR_STRLEN, 1);
0426
0427 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0428 "ipv6only is not supported "
0429 "on addr \"%*s\", ignored", len, buf);
0430 }
0431
0432 continue;
0433 #else
0434 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0435 "bind ipv6only is not supported "
0436 "on this platform");
0437 return NGX_CONF_ERROR;
0438 #endif
0439 }
0440
0441 if (ngx_strcmp(value[i].data, "ssl") == 0) {
0442 #if (NGX_MAIL_SSL)
0443 ls->ssl = 1;
0444 continue;
0445 #else
0446 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0447 "the \"ssl\" parameter requires "
0448 "ngx_mail_ssl_module");
0449 return NGX_CONF_ERROR;
0450 #endif
0451 }
0452
0453 if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) {
0454
0455 if (ngx_strcmp(&value[i].data[13], "on") == 0) {
0456 ls->so_keepalive = 1;
0457
0458 } else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
0459 ls->so_keepalive = 2;
0460
0461 } else {
0462
0463 #if (NGX_HAVE_KEEPALIVE_TUNABLE)
0464 u_char *p, *end;
0465 ngx_str_t s;
0466
0467 end = value[i].data + value[i].len;
0468 s.data = value[i].data + 13;
0469
0470 p = ngx_strlchr(s.data, end, ':');
0471 if (p == NULL) {
0472 p = end;
0473 }
0474
0475 if (p > s.data) {
0476 s.len = p - s.data;
0477
0478 ls->tcp_keepidle = ngx_parse_time(&s, 1);
0479 if (ls->tcp_keepidle == (time_t) NGX_ERROR) {
0480 goto invalid_so_keepalive;
0481 }
0482 }
0483
0484 s.data = (p < end) ? (p + 1) : end;
0485
0486 p = ngx_strlchr(s.data, end, ':');
0487 if (p == NULL) {
0488 p = end;
0489 }
0490
0491 if (p > s.data) {
0492 s.len = p - s.data;
0493
0494 ls->tcp_keepintvl = ngx_parse_time(&s, 1);
0495 if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
0496 goto invalid_so_keepalive;
0497 }
0498 }
0499
0500 s.data = (p < end) ? (p + 1) : end;
0501
0502 if (s.data < end) {
0503 s.len = end - s.data;
0504
0505 ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
0506 if (ls->tcp_keepcnt == NGX_ERROR) {
0507 goto invalid_so_keepalive;
0508 }
0509 }
0510
0511 if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
0512 && ls->tcp_keepcnt == 0)
0513 {
0514 goto invalid_so_keepalive;
0515 }
0516
0517 ls->so_keepalive = 1;
0518
0519 #else
0520
0521 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0522 "the \"so_keepalive\" parameter accepts "
0523 "only \"on\" or \"off\" on this platform");
0524 return NGX_CONF_ERROR;
0525
0526 #endif
0527 }
0528
0529 ls->bind = 1;
0530
0531 continue;
0532
0533 #if (NGX_HAVE_KEEPALIVE_TUNABLE)
0534 invalid_so_keepalive:
0535
0536 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0537 "invalid so_keepalive value: \"%s\"",
0538 &value[i].data[13]);
0539 return NGX_CONF_ERROR;
0540 #endif
0541 }
0542
0543 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0544 "the invalid \"%V\" parameter", &value[i]);
0545 return NGX_CONF_ERROR;
0546 }
0547
0548 return NGX_CONF_OK;
0549 }
0550
0551
0552 static char *
0553 ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0554 {
0555 ngx_mail_core_srv_conf_t *cscf = conf;
0556
0557 ngx_str_t *value;
0558 ngx_uint_t m;
0559 ngx_mail_module_t *module;
0560
0561 value = cf->args->elts;
0562
0563 for (m = 0; cf->cycle->modules[m]; m++) {
0564 if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
0565 continue;
0566 }
0567
0568 module = cf->cycle->modules[m]->ctx;
0569
0570 if (module->protocol
0571 && ngx_strcmp(module->protocol->name.data, value[1].data) == 0)
0572 {
0573 cscf->protocol = module->protocol;
0574
0575 return NGX_CONF_OK;
0576 }
0577 }
0578
0579 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0580 "unknown protocol \"%V\"", &value[1]);
0581 return NGX_CONF_ERROR;
0582 }
0583
0584
0585 static char *
0586 ngx_mail_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0587 {
0588 ngx_mail_core_srv_conf_t *cscf = conf;
0589
0590 return ngx_log_set_log(cf, &cscf->error_log);
0591 }
0592
0593
0594 static char *
0595 ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0596 {
0597 ngx_mail_core_srv_conf_t *cscf = conf;
0598
0599 ngx_str_t *value;
0600
0601 value = cf->args->elts;
0602
0603 if (cscf->resolver != NGX_CONF_UNSET_PTR) {
0604 return "is duplicate";
0605 }
0606
0607 if (ngx_strcmp(value[1].data, "off") == 0) {
0608 cscf->resolver = NULL;
0609 return NGX_CONF_OK;
0610 }
0611
0612 cscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1);
0613 if (cscf->resolver == NULL) {
0614 return NGX_CONF_ERROR;
0615 }
0616
0617 return NGX_CONF_OK;
0618 }
0619
0620
0621 char *
0622 ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0623 {
0624 char *p = conf;
0625
0626 ngx_str_t *c, *value;
0627 ngx_uint_t i;
0628 ngx_array_t *a;
0629
0630 a = (ngx_array_t *) (p + cmd->offset);
0631
0632 value = cf->args->elts;
0633
0634 for (i = 1; i < cf->args->nelts; i++) {
0635 c = ngx_array_push(a);
0636 if (c == NULL) {
0637 return NGX_CONF_ERROR;
0638 }
0639
0640 *c = value[i];
0641 }
0642
0643 return NGX_CONF_OK;
0644 }