Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.11 ]​[ nginx-1.14.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
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 char *ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
0015 static ngx_int_t ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
0016     ngx_mail_listen_t *listen);
0017 static char *ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports);
0018 static ngx_int_t ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
0019     ngx_mail_conf_addr_t *addr);
0020 #if (NGX_HAVE_INET6)
0021 static ngx_int_t ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
0022     ngx_mail_conf_addr_t *addr);
0023 #endif
0024 static ngx_int_t ngx_mail_cmp_conf_addrs(const void *one, const void *two);
0025 
0026 
0027 ngx_uint_t  ngx_mail_max_module;
0028 
0029 
0030 static ngx_command_t  ngx_mail_commands[] = {
0031 
0032     { ngx_string("mail"),
0033       NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
0034       ngx_mail_block,
0035       0,
0036       0,
0037       NULL },
0038 
0039       ngx_null_command
0040 };
0041 
0042 
0043 static ngx_core_module_t  ngx_mail_module_ctx = {
0044     ngx_string("mail"),
0045     NULL,
0046     NULL
0047 };
0048 
0049 
0050 ngx_module_t  ngx_mail_module = {
0051     NGX_MODULE_V1,
0052     &ngx_mail_module_ctx,                  /* module context */
0053     ngx_mail_commands,                     /* module directives */
0054     NGX_CORE_MODULE,                       /* module type */
0055     NULL,                                  /* init master */
0056     NULL,                                  /* init module */
0057     NULL,                                  /* init process */
0058     NULL,                                  /* init thread */
0059     NULL,                                  /* exit thread */
0060     NULL,                                  /* exit process */
0061     NULL,                                  /* exit master */
0062     NGX_MODULE_V1_PADDING
0063 };
0064 
0065 
0066 static char *
0067 ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0068 {
0069     char                        *rv;
0070     ngx_uint_t                   i, m, mi, s;
0071     ngx_conf_t                   pcf;
0072     ngx_array_t                  ports;
0073     ngx_mail_listen_t           *listen;
0074     ngx_mail_module_t           *module;
0075     ngx_mail_conf_ctx_t         *ctx;
0076     ngx_mail_core_srv_conf_t   **cscfp;
0077     ngx_mail_core_main_conf_t   *cmcf;
0078 
0079     if (*(ngx_mail_conf_ctx_t **) conf) {
0080         return "is duplicate";
0081     }
0082 
0083     /* the main mail context */
0084 
0085     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
0086     if (ctx == NULL) {
0087         return NGX_CONF_ERROR;
0088     }
0089 
0090     *(ngx_mail_conf_ctx_t **) conf = ctx;
0091 
0092     /* count the number of the mail modules and set up their indices */
0093 
0094     ngx_mail_max_module = ngx_count_modules(cf->cycle, NGX_MAIL_MODULE);
0095 
0096 
0097     /* the mail main_conf context, it is the same in the all mail contexts */
0098 
0099     ctx->main_conf = ngx_pcalloc(cf->pool,
0100                                  sizeof(void *) * ngx_mail_max_module);
0101     if (ctx->main_conf == NULL) {
0102         return NGX_CONF_ERROR;
0103     }
0104 
0105 
0106     /*
0107      * the mail null srv_conf context, it is used to merge
0108      * the server{}s' srv_conf's
0109      */
0110 
0111     ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
0112     if (ctx->srv_conf == NULL) {
0113         return NGX_CONF_ERROR;
0114     }
0115 
0116 
0117     /*
0118      * create the main_conf's and the null srv_conf's of the all mail modules
0119      */
0120 
0121     for (m = 0; cf->cycle->modules[m]; m++) {
0122         if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
0123             continue;
0124         }
0125 
0126         module = cf->cycle->modules[m]->ctx;
0127         mi = cf->cycle->modules[m]->ctx_index;
0128 
0129         if (module->create_main_conf) {
0130             ctx->main_conf[mi] = module->create_main_conf(cf);
0131             if (ctx->main_conf[mi] == NULL) {
0132                 return NGX_CONF_ERROR;
0133             }
0134         }
0135 
0136         if (module->create_srv_conf) {
0137             ctx->srv_conf[mi] = module->create_srv_conf(cf);
0138             if (ctx->srv_conf[mi] == NULL) {
0139                 return NGX_CONF_ERROR;
0140             }
0141         }
0142     }
0143 
0144 
0145     /* parse inside the mail{} block */
0146 
0147     pcf = *cf;
0148     cf->ctx = ctx;
0149 
0150     cf->module_type = NGX_MAIL_MODULE;
0151     cf->cmd_type = NGX_MAIL_MAIN_CONF;
0152     rv = ngx_conf_parse(cf, NULL);
0153 
0154     if (rv != NGX_CONF_OK) {
0155         *cf = pcf;
0156         return rv;
0157     }
0158 
0159 
0160     /* init mail{} main_conf's, merge the server{}s' srv_conf's */
0161 
0162     cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
0163     cscfp = cmcf->servers.elts;
0164 
0165     for (m = 0; cf->cycle->modules[m]; m++) {
0166         if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
0167             continue;
0168         }
0169 
0170         module = cf->cycle->modules[m]->ctx;
0171         mi = cf->cycle->modules[m]->ctx_index;
0172 
0173         /* init mail{} main_conf's */
0174 
0175         cf->ctx = ctx;
0176 
0177         if (module->init_main_conf) {
0178             rv = module->init_main_conf(cf, ctx->main_conf[mi]);
0179             if (rv != NGX_CONF_OK) {
0180                 *cf = pcf;
0181                 return rv;
0182             }
0183         }
0184 
0185         for (s = 0; s < cmcf->servers.nelts; s++) {
0186 
0187             /* merge the server{}s' srv_conf's */
0188 
0189             cf->ctx = cscfp[s]->ctx;
0190 
0191             if (module->merge_srv_conf) {
0192                 rv = module->merge_srv_conf(cf,
0193                                             ctx->srv_conf[mi],
0194                                             cscfp[s]->ctx->srv_conf[mi]);
0195                 if (rv != NGX_CONF_OK) {
0196                     *cf = pcf;
0197                     return rv;
0198                 }
0199             }
0200         }
0201     }
0202 
0203     *cf = pcf;
0204 
0205 
0206     if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_mail_conf_port_t))
0207         != NGX_OK)
0208     {
0209         return NGX_CONF_ERROR;
0210     }
0211 
0212     listen = cmcf->listen.elts;
0213 
0214     for (i = 0; i < cmcf->listen.nelts; i++) {
0215         if (ngx_mail_add_ports(cf, &ports, &listen[i]) != NGX_OK) {
0216             return NGX_CONF_ERROR;
0217         }
0218     }
0219 
0220     return ngx_mail_optimize_servers(cf, &ports);
0221 }
0222 
0223 
0224 static ngx_int_t
0225 ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
0226     ngx_mail_listen_t *listen)
0227 {
0228     in_port_t              p;
0229     ngx_uint_t             i;
0230     struct sockaddr       *sa;
0231     ngx_mail_conf_port_t  *port;
0232     ngx_mail_conf_addr_t  *addr;
0233 
0234     sa = listen->sockaddr;
0235     p = ngx_inet_get_port(sa);
0236 
0237     port = ports->elts;
0238     for (i = 0; i < ports->nelts; i++) {
0239         if (p == port[i].port && sa->sa_family == port[i].family) {
0240 
0241             /* a port is already in the port list */
0242 
0243             port = &port[i];
0244             goto found;
0245         }
0246     }
0247 
0248     /* add a port to the port list */
0249 
0250     port = ngx_array_push(ports);
0251     if (port == NULL) {
0252         return NGX_ERROR;
0253     }
0254 
0255     port->family = sa->sa_family;
0256     port->port = p;
0257 
0258     if (ngx_array_init(&port->addrs, cf->temp_pool, 2,
0259                        sizeof(ngx_mail_conf_addr_t))
0260         != NGX_OK)
0261     {
0262         return NGX_ERROR;
0263     }
0264 
0265 found:
0266 
0267     addr = ngx_array_push(&port->addrs);
0268     if (addr == NULL) {
0269         return NGX_ERROR;
0270     }
0271 
0272     addr->opt = *listen;
0273 
0274     return NGX_OK;
0275 }
0276 
0277 
0278 static char *
0279 ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
0280 {
0281     ngx_uint_t                 i, p, last, bind_wildcard;
0282     ngx_listening_t           *ls;
0283     ngx_mail_port_t           *mport;
0284     ngx_mail_conf_port_t      *port;
0285     ngx_mail_conf_addr_t      *addr;
0286     ngx_mail_core_srv_conf_t  *cscf;
0287 
0288     port = ports->elts;
0289     for (p = 0; p < ports->nelts; p++) {
0290 
0291         ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,
0292                  sizeof(ngx_mail_conf_addr_t), ngx_mail_cmp_conf_addrs);
0293 
0294         addr = port[p].addrs.elts;
0295         last = port[p].addrs.nelts;
0296 
0297         /*
0298          * if there is the binding to the "*:port" then we need to bind()
0299          * to the "*:port" only and ignore the other bindings
0300          */
0301 
0302         if (addr[last - 1].opt.wildcard) {
0303             addr[last - 1].opt.bind = 1;
0304             bind_wildcard = 1;
0305 
0306         } else {
0307             bind_wildcard = 0;
0308         }
0309 
0310         i = 0;
0311 
0312         while (i < last) {
0313 
0314             if (bind_wildcard && !addr[i].opt.bind) {
0315                 i++;
0316                 continue;
0317             }
0318 
0319             ls = ngx_create_listening(cf, addr[i].opt.sockaddr,
0320                                       addr[i].opt.socklen);
0321             if (ls == NULL) {
0322                 return NGX_CONF_ERROR;
0323             }
0324 
0325             ls->addr_ntop = 1;
0326             ls->handler = ngx_mail_init_connection;
0327             ls->pool_size = 256;
0328 
0329             cscf = addr->opt.ctx->srv_conf[ngx_mail_core_module.ctx_index];
0330 
0331             ls->logp = cscf->error_log;
0332             ls->log.data = &ls->addr_text;
0333             ls->log.handler = ngx_accept_log_error;
0334 
0335             ls->backlog = addr[i].opt.backlog;
0336             ls->rcvbuf = addr[i].opt.rcvbuf;
0337             ls->sndbuf = addr[i].opt.sndbuf;
0338 
0339             ls->keepalive = addr[i].opt.so_keepalive;
0340 #if (NGX_HAVE_KEEPALIVE_TUNABLE)
0341             ls->keepidle = addr[i].opt.tcp_keepidle;
0342             ls->keepintvl = addr[i].opt.tcp_keepintvl;
0343             ls->keepcnt = addr[i].opt.tcp_keepcnt;
0344 #endif
0345 
0346 #if (NGX_HAVE_INET6)
0347             ls->ipv6only = addr[i].opt.ipv6only;
0348 #endif
0349 
0350             mport = ngx_palloc(cf->pool, sizeof(ngx_mail_port_t));
0351             if (mport == NULL) {
0352                 return NGX_CONF_ERROR;
0353             }
0354 
0355             ls->servers = mport;
0356 
0357             mport->naddrs = i + 1;
0358 
0359             switch (ls->sockaddr->sa_family) {
0360 #if (NGX_HAVE_INET6)
0361             case AF_INET6:
0362                 if (ngx_mail_add_addrs6(cf, mport, addr) != NGX_OK) {
0363                     return NGX_CONF_ERROR;
0364                 }
0365                 break;
0366 #endif
0367             default: /* AF_INET */
0368                 if (ngx_mail_add_addrs(cf, mport, addr) != NGX_OK) {
0369                     return NGX_CONF_ERROR;
0370                 }
0371                 break;
0372             }
0373 
0374             addr++;
0375             last--;
0376         }
0377     }
0378 
0379     return NGX_CONF_OK;
0380 }
0381 
0382 
0383 static ngx_int_t
0384 ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
0385     ngx_mail_conf_addr_t *addr)
0386 {
0387     ngx_uint_t           i;
0388     ngx_mail_in_addr_t  *addrs;
0389     struct sockaddr_in  *sin;
0390 
0391     mport->addrs = ngx_pcalloc(cf->pool,
0392                                mport->naddrs * sizeof(ngx_mail_in_addr_t));
0393     if (mport->addrs == NULL) {
0394         return NGX_ERROR;
0395     }
0396 
0397     addrs = mport->addrs;
0398 
0399     for (i = 0; i < mport->naddrs; i++) {
0400 
0401         sin = (struct sockaddr_in *) addr[i].opt.sockaddr;
0402         addrs[i].addr = sin->sin_addr.s_addr;
0403 
0404         addrs[i].conf.ctx = addr[i].opt.ctx;
0405 #if (NGX_MAIL_SSL)
0406         addrs[i].conf.ssl = addr[i].opt.ssl;
0407 #endif
0408         addrs[i].conf.addr_text = addr[i].opt.addr_text;
0409     }
0410 
0411     return NGX_OK;
0412 }
0413 
0414 
0415 #if (NGX_HAVE_INET6)
0416 
0417 static ngx_int_t
0418 ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
0419     ngx_mail_conf_addr_t *addr)
0420 {
0421     ngx_uint_t            i;
0422     ngx_mail_in6_addr_t  *addrs6;
0423     struct sockaddr_in6  *sin6;
0424 
0425     mport->addrs = ngx_pcalloc(cf->pool,
0426                                mport->naddrs * sizeof(ngx_mail_in6_addr_t));
0427     if (mport->addrs == NULL) {
0428         return NGX_ERROR;
0429     }
0430 
0431     addrs6 = mport->addrs;
0432 
0433     for (i = 0; i < mport->naddrs; i++) {
0434 
0435         sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr;
0436         addrs6[i].addr6 = sin6->sin6_addr;
0437 
0438         addrs6[i].conf.ctx = addr[i].opt.ctx;
0439 #if (NGX_MAIL_SSL)
0440         addrs6[i].conf.ssl = addr[i].opt.ssl;
0441 #endif
0442         addrs6[i].conf.addr_text = addr[i].opt.addr_text;
0443     }
0444 
0445     return NGX_OK;
0446 }
0447 
0448 #endif
0449 
0450 
0451 static ngx_int_t
0452 ngx_mail_cmp_conf_addrs(const void *one, const void *two)
0453 {
0454     ngx_mail_conf_addr_t  *first, *second;
0455 
0456     first = (ngx_mail_conf_addr_t *) one;
0457     second = (ngx_mail_conf_addr_t *) two;
0458 
0459     if (first->opt.wildcard) {
0460         /* a wildcard must be the last resort, shift it to the end */
0461         return 1;
0462     }
0463 
0464     if (second->opt.wildcard) {
0465         /* a wildcard must be the last resort, shift it to the end */
0466         return -1;
0467     }
0468 
0469     if (first->opt.bind && !second->opt.bind) {
0470         /* shift explicit bind()ed addresses to the start */
0471         return -1;
0472     }
0473 
0474     if (!first->opt.bind && second->opt.bind) {
0475         /* shift explicit bind()ed addresses to the start */
0476         return 1;
0477     }
0478 
0479     /* do not sort by default */
0480 
0481     return 0;
0482 }