1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 #include <ngx_mail.h>
12
13
14 static void *ngx_mail_core_create_main_conf(ngx_conf_t *cf);
15 static void *ngx_mail_core_create_srv_conf(ngx_conf_t *cf);
16 static char *ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
17 void *child);
18 static char *ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
19 void *conf);
20 static char *ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
21 void *conf);
22 static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd,
23 void *conf);
24 static char *ngx_mail_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
25 void *conf);
26 static char *ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
27 void *conf);
28
29
30 static ngx_command_t ngx_mail_core_commands[] = {
31
32 { ngx_string("server"),
33 NGX_MAIL_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
34 ngx_mail_core_server,
35 0,
36 0,
37 NULL },
38
39 { ngx_string("listen"),
40 NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
41 ngx_mail_core_listen,
42 NGX_MAIL_SRV_CONF_OFFSET,
43 0,
44 NULL },
45
46 { ngx_string("protocol"),
47 NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
48 ngx_mail_core_protocol,
49 NGX_MAIL_SRV_CONF_OFFSET,
50 0,
51 NULL },
52
53 { ngx_string("timeout"),
54 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
55 ngx_conf_set_msec_slot,
56 NGX_MAIL_SRV_CONF_OFFSET,
57 offsetof(ngx_mail_core_srv_conf_t, timeout),
58 NULL },
59
60 { ngx_string("server_name"),
61 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
62 ngx_conf_set_str_slot,
63 NGX_MAIL_SRV_CONF_OFFSET,
64 offsetof(ngx_mail_core_srv_conf_t, server_name),
65 NULL },
66
67 #if (NGX_HAVE_FSTACK)
68 { ngx_string("kernel_network_stack"),
69 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
70 ngx_conf_set_flag_slot,
71 NGX_MAIL_SRV_CONF_OFFSET,
72 offsetof(ngx_mail_core_srv_conf_t, kernel_network_stack),
73 NULL },
74 #endif
75
76 { ngx_string("error_log"),
77 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
78 ngx_mail_core_error_log,
79 NGX_MAIL_SRV_CONF_OFFSET,
80 0,
81 NULL },
82
83 { ngx_string("resolver"),
84 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
85 ngx_mail_core_resolver,
86 NGX_MAIL_SRV_CONF_OFFSET,
87 0,
88 NULL },
89
90 { ngx_string("resolver_timeout"),
91 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
92 ngx_conf_set_msec_slot,
93 NGX_MAIL_SRV_CONF_OFFSET,
94 offsetof(ngx_mail_core_srv_conf_t, resolver_timeout),
95 NULL },
96
97 ngx_null_command
98 };
99
100
101 static ngx_mail_module_t ngx_mail_core_module_ctx = {
102 NULL, /* protocol */
103
104 ngx_mail_core_create_main_conf, /* create main configuration */
105 NULL, /* init main configuration */
106
107 ngx_mail_core_create_srv_conf, /* create server configuration */
108 ngx_mail_core_merge_srv_conf /* merge server configuration */
109 };
110
111
112 ngx_module_t ngx_mail_core_module = {
113 NGX_MODULE_V1,
114 &ngx_mail_core_module_ctx, /* module context */
115 ngx_mail_core_commands, /* module directives */
116 NGX_MAIL_MODULE, /* module type */
117 NULL, /* init master */
118 NULL, /* init module */
119 NULL, /* init process */
120 NULL, /* init thread */
121 NULL, /* exit thread */
122 NULL, /* exit process */
123 NULL, /* exit master */
124 NGX_MODULE_V1_PADDING
125 };
126
127
128 static void *
ngx_mail_core_create_main_conf(ngx_conf_t * cf)129 ngx_mail_core_create_main_conf(ngx_conf_t *cf)
130 {
131 ngx_mail_core_main_conf_t *cmcf;
132
133 cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t));
134 if (cmcf == NULL) {
135 return NULL;
136 }
137
138 if (ngx_array_init(&cmcf->servers, cf->pool, 4,
139 sizeof(ngx_mail_core_srv_conf_t *))
140 != NGX_OK)
141 {
142 return NULL;
143 }
144
145 if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t))
146 != NGX_OK)
147 {
148 return NULL;
149 }
150
151 return cmcf;
152 }
153
154
155 static void *
ngx_mail_core_create_srv_conf(ngx_conf_t * cf)156 ngx_mail_core_create_srv_conf(ngx_conf_t *cf)
157 {
158 ngx_mail_core_srv_conf_t *cscf;
159
160 cscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_srv_conf_t));
161 if (cscf == NULL) {
162 return NULL;
163 }
164
165 /*
166 * set by ngx_pcalloc():
167 *
168 * cscf->protocol = NULL;
169 * cscf->error_log = NULL;
170 */
171
172 cscf->timeout = NGX_CONF_UNSET_MSEC;
173 cscf->resolver_timeout = NGX_CONF_UNSET_MSEC;
174
175 cscf->resolver = NGX_CONF_UNSET_PTR;
176
177 cscf->file_name = cf->conf_file->file.name.data;
178 cscf->line = cf->conf_file->line;
179
180 #if (NGX_HAVE_FSTACK)
181 cscf->kernel_network_stack = NGX_CONF_UNSET;
182 #endif
183
184 return cscf;
185 }
186
187
188 static char *
ngx_mail_core_merge_srv_conf(ngx_conf_t * cf,void * parent,void * child)189 ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
190 {
191 ngx_mail_core_srv_conf_t *prev = parent;
192 ngx_mail_core_srv_conf_t *conf = child;
193
194 ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
195 ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout,
196 30000);
197
198
199 ngx_conf_merge_str_value(conf->server_name, prev->server_name, "");
200
201 if (conf->server_name.len == 0) {
202 conf->server_name = cf->cycle->hostname;
203 }
204
205 if (conf->protocol == NULL) {
206 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
207 "unknown mail protocol for server in %s:%ui",
208 conf->file_name, conf->line);
209 return NGX_CONF_ERROR;
210 }
211
212 if (conf->error_log == NULL) {
213 if (prev->error_log) {
214 conf->error_log = prev->error_log;
215 } else {
216 conf->error_log = &cf->cycle->new_log;
217 }
218 }
219
220 ngx_conf_merge_ptr_value(conf->resolver, prev->resolver, NULL);
221
222 #if (NGX_HAVE_FSTACK)
223 /* By default, we set up a server on fstack */
224 ngx_conf_merge_value(conf->kernel_network_stack,
225 prev->kernel_network_stack, 0);
226 #endif
227
228 return NGX_CONF_OK;
229 }
230
231
232 static char *
ngx_mail_core_server(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)233 ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
234 {
235 char *rv;
236 void *mconf;
237 ngx_uint_t m;
238 ngx_conf_t pcf;
239 ngx_mail_module_t *module;
240 ngx_mail_conf_ctx_t *ctx, *mail_ctx;
241 ngx_mail_core_srv_conf_t *cscf, **cscfp;
242 ngx_mail_core_main_conf_t *cmcf;
243
244 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
245 if (ctx == NULL) {
246 return NGX_CONF_ERROR;
247 }
248
249 mail_ctx = cf->ctx;
250 ctx->main_conf = mail_ctx->main_conf;
251
252 /* the server{}'s srv_conf */
253
254 ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
255 if (ctx->srv_conf == NULL) {
256 return NGX_CONF_ERROR;
257 }
258
259 for (m = 0; cf->cycle->modules[m]; m++) {
260 if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
261 continue;
262 }
263
264 module = cf->cycle->modules[m]->ctx;
265
266 if (module->create_srv_conf) {
267 mconf = module->create_srv_conf(cf);
268 if (mconf == NULL) {
269 return NGX_CONF_ERROR;
270 }
271
272 ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf;
273 }
274 }
275
276 /* the server configuration context */
277
278 cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index];
279 cscf->ctx = ctx;
280
281 cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
282
283 cscfp = ngx_array_push(&cmcf->servers);
284 if (cscfp == NULL) {
285 return NGX_CONF_ERROR;
286 }
287
288 *cscfp = cscf;
289
290
291 /* parse inside server{} */
292
293 pcf = *cf;
294 cf->ctx = ctx;
295 cf->cmd_type = NGX_MAIL_SRV_CONF;
296
297 rv = ngx_conf_parse(cf, NULL);
298
299 *cf = pcf;
300
301 if (rv == NGX_CONF_OK && !cscf->listen) {
302 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
303 "no \"listen\" is defined for server in %s:%ui",
304 cscf->file_name, cscf->line);
305 return NGX_CONF_ERROR;
306 }
307
308 return rv;
309 }
310
311
312 static char *
ngx_mail_core_listen(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)313 ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
314 {
315 ngx_mail_core_srv_conf_t *cscf = conf;
316
317 ngx_str_t *value, size;
318 ngx_url_t u;
319 ngx_uint_t i, n, m;
320 ngx_mail_listen_t *ls, *als;
321 ngx_mail_module_t *module;
322 ngx_mail_core_main_conf_t *cmcf;
323
324 cscf->listen = 1;
325
326 value = cf->args->elts;
327
328 ngx_memzero(&u, sizeof(ngx_url_t));
329
330 u.url = value[1];
331 u.listen = 1;
332
333 if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
334 if (u.err) {
335 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
336 "%s in \"%V\" of the \"listen\" directive",
337 u.err, &u.url);
338 }
339
340 return NGX_CONF_ERROR;
341 }
342
343 cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);
344
345 ls = ngx_array_push_n(&cmcf->listen, u.naddrs);
346 if (ls == NULL) {
347 return NGX_CONF_ERROR;
348 }
349
350 ngx_memzero(ls, sizeof(ngx_mail_listen_t));
351
352 ls->backlog = NGX_LISTEN_BACKLOG;
353 ls->rcvbuf = -1;
354 ls->sndbuf = -1;
355 ls->ctx = cf->ctx;
356
357 #if (NGX_HAVE_INET6)
358 ls->ipv6only = 1;
359 #endif
360
361 if (cscf->protocol == NULL) {
362 for (m = 0; cf->cycle->modules[m]; m++) {
363 if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
364 continue;
365 }
366
367 module = cf->cycle->modules[m]->ctx;
368
369 if (module->protocol == NULL) {
370 continue;
371 }
372
373 for (i = 0; module->protocol->port[i]; i++) {
374 if (module->protocol->port[i] == u.port) {
375 cscf->protocol = module->protocol;
376 break;
377 }
378 }
379 }
380 }
381
382 for (i = 2; i < cf->args->nelts; i++) {
383
384 if (ngx_strcmp(value[i].data, "bind") == 0) {
385 ls->bind = 1;
386 continue;
387 }
388
389 if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
390 ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
391 ls->bind = 1;
392
393 if (ls->backlog == NGX_ERROR || ls->backlog == 0) {
394 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
395 "invalid backlog \"%V\"", &value[i]);
396 return NGX_CONF_ERROR;
397 }
398
399 continue;
400 }
401
402 if (ngx_strncmp(value[i].data, "rcvbuf=", 7) == 0) {
403 size.len = value[i].len - 7;
404 size.data = value[i].data + 7;
405
406 ls->rcvbuf = ngx_parse_size(&size);
407 ls->bind = 1;
408
409 if (ls->rcvbuf == NGX_ERROR) {
410 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
411 "invalid rcvbuf \"%V\"", &value[i]);
412 return NGX_CONF_ERROR;
413 }
414
415 continue;
416 }
417
418 if (ngx_strncmp(value[i].data, "sndbuf=", 7) == 0) {
419 size.len = value[i].len - 7;
420 size.data = value[i].data + 7;
421
422 ls->sndbuf = ngx_parse_size(&size);
423 ls->bind = 1;
424
425 if (ls->sndbuf == NGX_ERROR) {
426 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
427 "invalid sndbuf \"%V\"", &value[i]);
428 return NGX_CONF_ERROR;
429 }
430
431 continue;
432 }
433
434 if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
435 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
436 if (ngx_strcmp(&value[i].data[10], "n") == 0) {
437 ls->ipv6only = 1;
438
439 } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
440 ls->ipv6only = 0;
441
442 } else {
443 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
444 "invalid ipv6only flags \"%s\"",
445 &value[i].data[9]);
446 return NGX_CONF_ERROR;
447 }
448
449 ls->bind = 1;
450 continue;
451 #else
452 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
453 "bind ipv6only is not supported "
454 "on this platform");
455 return NGX_CONF_ERROR;
456 #endif
457 }
458
459 if (ngx_strcmp(value[i].data, "ssl") == 0) {
460 #if (NGX_MAIL_SSL)
461 ngx_mail_ssl_conf_t *sslcf;
462
463 sslcf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_ssl_module);
464
465 sslcf->listen = 1;
466 sslcf->file = cf->conf_file->file.name.data;
467 sslcf->line = cf->conf_file->line;
468
469 ls->ssl = 1;
470
471 continue;
472 #else
473 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
474 "the \"ssl\" parameter requires "
475 "ngx_mail_ssl_module");
476 return NGX_CONF_ERROR;
477 #endif
478 }
479
480 if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) {
481
482 if (ngx_strcmp(&value[i].data[13], "on") == 0) {
483 ls->so_keepalive = 1;
484
485 } else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
486 ls->so_keepalive = 2;
487
488 } else {
489
490 #if (NGX_HAVE_KEEPALIVE_TUNABLE)
491 u_char *p, *end;
492 ngx_str_t s;
493
494 end = value[i].data + value[i].len;
495 s.data = value[i].data + 13;
496
497 p = ngx_strlchr(s.data, end, ':');
498 if (p == NULL) {
499 p = end;
500 }
501
502 if (p > s.data) {
503 s.len = p - s.data;
504
505 ls->tcp_keepidle = ngx_parse_time(&s, 1);
506 if (ls->tcp_keepidle == (time_t) NGX_ERROR) {
507 goto invalid_so_keepalive;
508 }
509 }
510
511 s.data = (p < end) ? (p + 1) : end;
512
513 p = ngx_strlchr(s.data, end, ':');
514 if (p == NULL) {
515 p = end;
516 }
517
518 if (p > s.data) {
519 s.len = p - s.data;
520
521 ls->tcp_keepintvl = ngx_parse_time(&s, 1);
522 if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
523 goto invalid_so_keepalive;
524 }
525 }
526
527 s.data = (p < end) ? (p + 1) : end;
528
529 if (s.data < end) {
530 s.len = end - s.data;
531
532 ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
533 if (ls->tcp_keepcnt == NGX_ERROR) {
534 goto invalid_so_keepalive;
535 }
536 }
537
538 if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
539 && ls->tcp_keepcnt == 0)
540 {
541 goto invalid_so_keepalive;
542 }
543
544 ls->so_keepalive = 1;
545
546 #else
547
548 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
549 "the \"so_keepalive\" parameter accepts "
550 "only \"on\" or \"off\" on this platform");
551 return NGX_CONF_ERROR;
552
553 #endif
554 }
555
556 ls->bind = 1;
557
558 continue;
559
560 #if (NGX_HAVE_KEEPALIVE_TUNABLE)
561 invalid_so_keepalive:
562
563 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
564 "invalid so_keepalive value: \"%s\"",
565 &value[i].data[13]);
566 return NGX_CONF_ERROR;
567 #endif
568 }
569
570 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
571 "the invalid \"%V\" parameter", &value[i]);
572 return NGX_CONF_ERROR;
573 }
574
575 als = cmcf->listen.elts;
576
577 for (n = 0; n < u.naddrs; n++) {
578 ls[n] = ls[0];
579
580 ls[n].sockaddr = u.addrs[n].sockaddr;
581 ls[n].socklen = u.addrs[n].socklen;
582 ls[n].addr_text = u.addrs[n].name;
583 ls[n].wildcard = ngx_inet_wildcard(ls[n].sockaddr);
584
585 for (i = 0; i < cmcf->listen.nelts - u.naddrs + n; i++) {
586
587 if (ngx_cmp_sockaddr(als[i].sockaddr, als[i].socklen,
588 ls[n].sockaddr, ls[n].socklen, 1)
589 != NGX_OK)
590 {
591 continue;
592 }
593
594 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
595 "duplicate \"%V\" address and port pair",
596 &ls[n].addr_text);
597 return NGX_CONF_ERROR;
598 }
599 }
600
601 return NGX_CONF_OK;
602 }
603
604
605 static char *
ngx_mail_core_protocol(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)606 ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
607 {
608 ngx_mail_core_srv_conf_t *cscf = conf;
609
610 ngx_str_t *value;
611 ngx_uint_t m;
612 ngx_mail_module_t *module;
613
614 value = cf->args->elts;
615
616 for (m = 0; cf->cycle->modules[m]; m++) {
617 if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
618 continue;
619 }
620
621 module = cf->cycle->modules[m]->ctx;
622
623 if (module->protocol
624 && ngx_strcmp(module->protocol->name.data, value[1].data) == 0)
625 {
626 cscf->protocol = module->protocol;
627
628 return NGX_CONF_OK;
629 }
630 }
631
632 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
633 "unknown protocol \"%V\"", &value[1]);
634 return NGX_CONF_ERROR;
635 }
636
637
638 static char *
ngx_mail_core_error_log(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)639 ngx_mail_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
640 {
641 ngx_mail_core_srv_conf_t *cscf = conf;
642
643 return ngx_log_set_log(cf, &cscf->error_log);
644 }
645
646
647 static char *
ngx_mail_core_resolver(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)648 ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
649 {
650 ngx_mail_core_srv_conf_t *cscf = conf;
651
652 ngx_str_t *value;
653
654 value = cf->args->elts;
655
656 if (cscf->resolver != NGX_CONF_UNSET_PTR) {
657 return "is duplicate";
658 }
659
660 if (ngx_strcmp(value[1].data, "off") == 0) {
661 cscf->resolver = NULL;
662 return NGX_CONF_OK;
663 }
664
665 cscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1);
666 if (cscf->resolver == NULL) {
667 return NGX_CONF_ERROR;
668 }
669
670 return NGX_CONF_OK;
671 }
672
673
674 char *
ngx_mail_capabilities(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)675 ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
676 {
677 char *p = conf;
678
679 ngx_str_t *c, *value;
680 ngx_uint_t i;
681 ngx_array_t *a;
682
683 a = (ngx_array_t *) (p + cmd->offset);
684
685 value = cf->args->elts;
686
687 for (i = 1; i < cf->args->nelts; i++) {
688 c = ngx_array_push(a);
689 if (c == NULL) {
690 return NGX_CONF_ERROR;
691 }
692
693 *c = value[i];
694 }
695
696 return NGX_CONF_OK;
697 }
698