src/stream/ngx_stream_pass_module.c - nginx source code

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Roman Arutyunyan
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_stream.h>


  8. #define NGX_STREAM_PASS_MAX_PASSES  10


  9. typedef struct {
  10.     ngx_addr_t                  *addr;
  11.     ngx_stream_complex_value_t  *addr_value;
  12. } ngx_stream_pass_srv_conf_t;


  13. static void ngx_stream_pass_handler(ngx_stream_session_t *s);
  14. static ngx_int_t ngx_stream_pass_check_cycle(ngx_connection_t *c);
  15. static void ngx_stream_pass_cleanup(void *data);
  16. static ngx_int_t ngx_stream_pass_match(ngx_listening_t *ls, ngx_addr_t *addr);
  17. static void *ngx_stream_pass_create_srv_conf(ngx_conf_t *cf);
  18. static char *ngx_stream_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);


  19. static ngx_command_t  ngx_stream_pass_commands[] = {

  20.     { ngx_string("pass"),
  21.       NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
  22.       ngx_stream_pass,
  23.       NGX_STREAM_SRV_CONF_OFFSET,
  24.       0,
  25.       NULL },

  26.       ngx_null_command
  27. };


  28. static ngx_stream_module_t  ngx_stream_pass_module_ctx = {
  29.     NULL,                                  /* preconfiguration */
  30.     NULL,                                  /* postconfiguration */

  31.     NULL,                                  /* create main configuration */
  32.     NULL,                                  /* init main configuration */

  33.     ngx_stream_pass_create_srv_conf,       /* create server configuration */
  34.     NULL                                   /* merge server configuration */
  35. };


  36. ngx_module_t  ngx_stream_pass_module = {
  37.     NGX_MODULE_V1,
  38.     &ngx_stream_pass_module_ctx,           /* module context */
  39.     ngx_stream_pass_commands,              /* module directives */
  40.     NGX_STREAM_MODULE,                     /* module type */
  41.     NULL,                                  /* init master */
  42.     NULL,                                  /* init module */
  43.     NULL,                                  /* init process */
  44.     NULL,                                  /* init thread */
  45.     NULL,                                  /* exit thread */
  46.     NULL,                                  /* exit process */
  47.     NULL,                                  /* exit master */
  48.     NGX_MODULE_V1_PADDING
  49. };


  50. static void
  51. ngx_stream_pass_handler(ngx_stream_session_t *s)
  52. {
  53.     ngx_url_t                    u;
  54.     ngx_str_t                    url;
  55.     ngx_addr_t                  *addr;
  56.     ngx_uint_t                   i;
  57.     ngx_listening_t             *ls;
  58.     ngx_connection_t            *c;
  59.     ngx_stream_pass_srv_conf_t  *pscf;

  60.     c = s->connection;

  61.     c->log->action = "passing connection to port";

  62.     if (c->type == SOCK_DGRAM) {
  63.         ngx_log_error(NGX_LOG_ERR, c->log, 0, "cannot pass udp connection");
  64.         goto failed;
  65.     }

  66.     if (c->buffer && c->buffer->pos != c->buffer->last) {
  67.         ngx_log_error(NGX_LOG_ERR, c->log, 0,
  68.                       "cannot pass connection with preread data");
  69.         goto failed;
  70.     }

  71.     pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_pass_module);

  72.     addr = pscf->addr;

  73.     if (addr == NULL) {
  74.         if (ngx_stream_complex_value(s, pscf->addr_value, &url) != NGX_OK) {
  75.             goto failed;
  76.         }

  77.         ngx_memzero(&u, sizeof(ngx_url_t));

  78.         u.url = url;
  79.         u.no_resolve = 1;

  80.         if (ngx_parse_url(c->pool, &u) != NGX_OK) {
  81.             if (u.err) {
  82.                 ngx_log_error(NGX_LOG_ERR, c->log, 0,
  83.                               "%s in pass \"%V\"", u.err, &u.url);
  84.             }

  85.             goto failed;
  86.         }

  87.         if (u.naddrs == 0) {
  88.             ngx_log_error(NGX_LOG_ERR, c->log, 0,
  89.                           "no addresses in pass \"%V\"", &u.url);
  90.             goto failed;
  91.         }

  92.         if (u.no_port) {
  93.             ngx_log_error(NGX_LOG_ERR, c->log, 0,
  94.                           "no port in pass \"%V\"", &u.url);
  95.             goto failed;
  96.         }

  97.         addr = &u.addrs[0];
  98.     }

  99.     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
  100.                    "stream pass addr: \"%V\"", &addr->name);

  101.     if (ngx_stream_pass_check_cycle(c) != NGX_OK) {
  102.         goto failed;
  103.     }

  104.     ls = ngx_cycle->listening.elts;

  105.     for (i = 0; i < ngx_cycle->listening.nelts; i++) {

  106.         if (ngx_stream_pass_match(&ls[i], addr) != NGX_OK) {
  107.             continue;
  108.         }

  109.         c->listening = &ls[i];

  110.         c->data = NULL;
  111.         c->buffer = NULL;

  112.         *c->log = c->listening->log;
  113.         c->log->handler = NULL;
  114.         c->log->data = NULL;

  115.         c->local_sockaddr = addr->sockaddr;
  116.         c->local_socklen = addr->socklen;

  117.         c->listening->handler(c);

  118.         return;
  119.     }

  120.     ngx_log_error(NGX_LOG_ERR, c->log, 0,
  121.                   "port not found for \"%V\"", &addr->name);

  122.     ngx_stream_finalize_session(s, NGX_STREAM_OK);

  123.     return;

  124. failed:

  125.     ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
  126. }


  127. static ngx_int_t
  128. ngx_stream_pass_check_cycle(ngx_connection_t *c)
  129. {
  130.     ngx_uint_t          *num;
  131.     ngx_pool_cleanup_t  *cln;

  132.     for (cln = c->pool->cleanup; cln; cln = cln->next) {
  133.         if (cln->handler != ngx_stream_pass_cleanup) {
  134.             continue;
  135.         }

  136.         num = cln->data;

  137.         if (++(*num) > NGX_STREAM_PASS_MAX_PASSES) {
  138.             ngx_log_error(NGX_LOG_ERR, c->log, 0, "stream pass cycle");
  139.             return NGX_ERROR;
  140.         }

  141.         return NGX_OK;
  142.     }

  143.     cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_uint_t));
  144.     if (cln == NULL) {
  145.         return NGX_ERROR;
  146.     }

  147.     cln->handler = ngx_stream_pass_cleanup;

  148.     num = cln->data;
  149.     *num = 1;

  150.     return NGX_OK;
  151. }


  152. static void
  153. ngx_stream_pass_cleanup(void *data)
  154. {
  155.     return;
  156. }


  157. static ngx_int_t
  158. ngx_stream_pass_match(ngx_listening_t *ls, ngx_addr_t *addr)
  159. {
  160.     if (ls->type == SOCK_DGRAM) {
  161.         return NGX_DECLINED;
  162.     }

  163.     if (!ls->wildcard) {
  164.         return ngx_cmp_sockaddr(ls->sockaddr, ls->socklen,
  165.                                 addr->sockaddr, addr->socklen, 1);
  166.     }

  167.     if (ls->sockaddr->sa_family == addr->sockaddr->sa_family
  168.         && ngx_inet_get_port(ls->sockaddr) == ngx_inet_get_port(addr->sockaddr))
  169.     {
  170.         return NGX_OK;
  171.     }

  172.     return NGX_DECLINED;
  173. }


  174. static void *
  175. ngx_stream_pass_create_srv_conf(ngx_conf_t *cf)
  176. {
  177.     ngx_stream_pass_srv_conf_t  *conf;

  178.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_pass_srv_conf_t));
  179.     if (conf == NULL) {
  180.         return NULL;
  181.     }

  182.     /*
  183.      * set by ngx_pcalloc():
  184.      *
  185.      *     conf->addr = NULL;
  186.      *     conf->addr_value = NULL;
  187.      */

  188.     return conf;
  189. }


  190. static char *
  191. ngx_stream_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  192. {
  193.     ngx_stream_pass_srv_conf_t *pscf = conf;

  194.     ngx_url_t                            u;
  195.     ngx_str_t                           *value, *url;
  196.     ngx_stream_complex_value_t           cv;
  197.     ngx_stream_core_srv_conf_t          *cscf;
  198.     ngx_stream_compile_complex_value_t   ccv;

  199.     if (pscf->addr || pscf->addr_value) {
  200.         return "is duplicate";
  201.     }

  202.     cscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_core_module);

  203.     cscf->handler = ngx_stream_pass_handler;

  204.     value = cf->args->elts;

  205.     url = &value[1];

  206.     ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));

  207.     ccv.cf = cf;
  208.     ccv.value = url;
  209.     ccv.complex_value = &cv;

  210.     if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
  211.         return NGX_CONF_ERROR;
  212.     }

  213.     if (cv.lengths) {
  214.         pscf->addr_value = ngx_palloc(cf->pool,
  215.                                       sizeof(ngx_stream_complex_value_t));
  216.         if (pscf->addr_value == NULL) {
  217.             return NGX_CONF_ERROR;
  218.         }

  219.         *pscf->addr_value = cv;

  220.         return NGX_CONF_OK;
  221.     }

  222.     ngx_memzero(&u, sizeof(ngx_url_t));

  223.     u.url = *url;
  224.     u.no_resolve = 1;

  225.     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
  226.         if (u.err) {
  227.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  228.                                "%s in \"%V\" of the \"pass\" directive",
  229.                                u.err, &u.url);
  230.         }

  231.         return NGX_CONF_ERROR;
  232.     }

  233.     if (u.naddrs == 0) {
  234.         return "has no addresses";
  235.     }

  236.     if (u.no_port) {
  237.         return "has no port";
  238.     }

  239.     pscf->addr = &u.addrs[0];

  240.     return NGX_CONF_OK;
  241. }