src/stream/ngx_stream_ssl_preread_module.c - nginx source code

Global variables defined

Data types defined

Functions defined

Source code


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


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


  7. typedef struct {
  8.     ngx_flag_t      enabled;
  9. } ngx_stream_ssl_preread_srv_conf_t;


  10. typedef struct {
  11.     size_t          left;
  12.     size_t          size;
  13.     size_t          ext;
  14.     u_char         *pos;
  15.     u_char         *dst;
  16.     u_char          buf[4];
  17.     u_char          version[2];
  18.     ngx_str_t       host;
  19.     ngx_str_t       alpn;
  20.     ngx_log_t      *log;
  21.     ngx_pool_t     *pool;
  22.     ngx_uint_t      state;
  23. } ngx_stream_ssl_preread_ctx_t;


  24. static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s);
  25. static ngx_int_t ngx_stream_ssl_preread_parse_record(
  26.     ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last);
  27. static ngx_int_t ngx_stream_ssl_preread_servername(ngx_stream_session_t *s,
  28.     ngx_str_t *servername);
  29. static ngx_int_t ngx_stream_ssl_preread_protocol_variable(
  30.     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
  31. static ngx_int_t ngx_stream_ssl_preread_server_name_variable(
  32.     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
  33. static ngx_int_t ngx_stream_ssl_preread_alpn_protocols_variable(
  34.     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
  35. static ngx_int_t ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf);
  36. static void *ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf);
  37. static char *ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent,
  38.     void *child);
  39. static ngx_int_t ngx_stream_ssl_preread_init(ngx_conf_t *cf);


  40. static ngx_command_t  ngx_stream_ssl_preread_commands[] = {

  41.     { ngx_string("ssl_preread"),
  42.       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
  43.       ngx_conf_set_flag_slot,
  44.       NGX_STREAM_SRV_CONF_OFFSET,
  45.       offsetof(ngx_stream_ssl_preread_srv_conf_t, enabled),
  46.       NULL },

  47.       ngx_null_command
  48. };


  49. static ngx_stream_module_t  ngx_stream_ssl_preread_module_ctx = {
  50.     ngx_stream_ssl_preread_add_variables,   /* preconfiguration */
  51.     ngx_stream_ssl_preread_init,            /* postconfiguration */

  52.     NULL,                                   /* create main configuration */
  53.     NULL,                                   /* init main configuration */

  54.     ngx_stream_ssl_preread_create_srv_conf, /* create server configuration */
  55.     ngx_stream_ssl_preread_merge_srv_conf   /* merge server configuration */
  56. };


  57. ngx_module_t  ngx_stream_ssl_preread_module = {
  58.     NGX_MODULE_V1,
  59.     &ngx_stream_ssl_preread_module_ctx,     /* module context */
  60.     ngx_stream_ssl_preread_commands,        /* module directives */
  61.     NGX_STREAM_MODULE,                      /* module type */
  62.     NULL,                                   /* init master */
  63.     NULL,                                   /* init module */
  64.     NULL,                                   /* init process */
  65.     NULL,                                   /* init thread */
  66.     NULL,                                   /* exit thread */
  67.     NULL,                                   /* exit process */
  68.     NULL,                                   /* exit master */
  69.     NGX_MODULE_V1_PADDING
  70. };


  71. static ngx_stream_variable_t  ngx_stream_ssl_preread_vars[] = {

  72.     { ngx_string("ssl_preread_protocol"), NULL,
  73.       ngx_stream_ssl_preread_protocol_variable, 0, 0, 0 },

  74.     { ngx_string("ssl_preread_server_name"), NULL,
  75.       ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 },

  76.     { ngx_string("ssl_preread_alpn_protocols"), NULL,
  77.       ngx_stream_ssl_preread_alpn_protocols_variable, 0, 0, 0 },

  78.       ngx_stream_null_variable
  79. };


  80. static ngx_int_t
  81. ngx_stream_ssl_preread_handler(ngx_stream_session_t *s)
  82. {
  83.     u_char                             *last, *p;
  84.     size_t                              len;
  85.     ngx_int_t                           rc;
  86.     ngx_connection_t                   *c;
  87.     ngx_stream_ssl_preread_ctx_t       *ctx;
  88.     ngx_stream_ssl_preread_srv_conf_t  *sscf;

  89.     c = s->connection;

  90.     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "ssl preread handler");

  91.     sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_preread_module);

  92.     if (!sscf->enabled) {
  93.         return NGX_DECLINED;
  94.     }

  95.     if (c->type != SOCK_STREAM) {
  96.         return NGX_DECLINED;
  97.     }

  98.     if (c->buffer == NULL) {
  99.         return NGX_AGAIN;
  100.     }

  101.     ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);
  102.     if (ctx == NULL) {
  103.         ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_ssl_preread_ctx_t));
  104.         if (ctx == NULL) {
  105.             return NGX_ERROR;
  106.         }

  107.         ngx_stream_set_ctx(s, ctx, ngx_stream_ssl_preread_module);

  108.         ctx->pool = c->pool;
  109.         ctx->log = c->log;
  110.         ctx->pos = c->buffer->pos;
  111.     }

  112.     p = ctx->pos;
  113.     last = c->buffer->last;

  114.     while (last - p >= 5) {

  115.         if ((p[0] & 0x80) && p[2] == 1 && (p[3] == 0 || p[3] == 3)) {
  116.             ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  117.                            "ssl preread: version 2 ClientHello");
  118.             ctx->version[0] = p[3];
  119.             ctx->version[1] = p[4];
  120.             return NGX_OK;
  121.         }

  122.         if (p[0] != 0x16) {
  123.             ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  124.                            "ssl preread: not a handshake");
  125.             ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
  126.             return NGX_DECLINED;
  127.         }

  128.         if (p[1] != 3) {
  129.             ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  130.                            "ssl preread: unsupported SSL version");
  131.             ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
  132.             return NGX_DECLINED;
  133.         }

  134.         len = (p[3] << 8) + p[4];

  135.         /* read the whole record before parsing */
  136.         if ((size_t) (last - p) < len + 5) {
  137.             break;
  138.         }

  139.         p += 5;

  140.         rc = ngx_stream_ssl_preread_parse_record(ctx, p, p + len);

  141.         if (rc == NGX_DECLINED) {
  142.             ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
  143.             return NGX_DECLINED;
  144.         }

  145.         if (rc == NGX_OK) {
  146.             return ngx_stream_ssl_preread_servername(s, &ctx->host);
  147.         }

  148.         if (rc != NGX_AGAIN) {
  149.             return rc;
  150.         }

  151.         p += len;
  152.     }

  153.     ctx->pos = p;

  154.     return NGX_AGAIN;
  155. }


  156. static ngx_int_t
  157. ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx,
  158.     u_char *pos, u_char *last)
  159. {
  160.     size_t   left, n, size, ext;
  161.     u_char  *dst, *p;

  162.     enum {
  163.         sw_start = 0,
  164.         sw_header,          /* handshake msg_type, length */
  165.         sw_version,         /* client_version */
  166.         sw_random,          /* random */
  167.         sw_sid_len,         /* session_id length */
  168.         sw_sid,             /* session_id */
  169.         sw_cs_len,          /* cipher_suites length */
  170.         sw_cs,              /* cipher_suites */
  171.         sw_cm_len,          /* compression_methods length */
  172.         sw_cm,              /* compression_methods */
  173.         sw_ext,             /* extension */
  174.         sw_ext_header,      /* extension_type, extension_data length */
  175.         sw_sni_len,         /* SNI length */
  176.         sw_sni_host_head,   /* SNI name_type, host_name length */
  177.         sw_sni_host,        /* SNI host_name */
  178.         sw_alpn_len,        /* ALPN length */
  179.         sw_alpn_proto_len,  /* ALPN protocol_name length */
  180.         sw_alpn_proto_data, /* ALPN protocol_name */
  181.         sw_supver_len       /* supported_versions length */
  182.     } state;

  183.     ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  184.                    "ssl preread: state %ui left %z", ctx->state, ctx->left);

  185.     state = ctx->state;
  186.     size = ctx->size;
  187.     left = ctx->left;
  188.     ext = ctx->ext;
  189.     dst = ctx->dst;
  190.     p = ctx->buf;

  191.     for ( ;; ) {
  192.         n = ngx_min((size_t) (last - pos), size);

  193.         if (dst) {
  194.             dst = ngx_cpymem(dst, pos, n);
  195.         }

  196.         pos += n;
  197.         size -= n;
  198.         left -= n;

  199.         if (size != 0) {
  200.             break;
  201.         }

  202.         switch (state) {

  203.         case sw_start:
  204.             state = sw_header;
  205.             dst = p;
  206.             size = 4;
  207.             left = size;
  208.             break;

  209.         case sw_header:
  210.             if (p[0] != 1) {
  211.                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  212.                                "ssl preread: not a client hello");
  213.                 return NGX_DECLINED;
  214.             }

  215.             state = sw_version;
  216.             dst = ctx->version;
  217.             size = 2;
  218.             left = (p[1] << 16) + (p[2] << 8) + p[3];
  219.             break;

  220.         case sw_version:
  221.             state = sw_random;
  222.             dst = NULL;
  223.             size = 32;
  224.             break;

  225.         case sw_random:
  226.             state = sw_sid_len;
  227.             dst = p;
  228.             size = 1;
  229.             break;

  230.         case sw_sid_len:
  231.             state = sw_sid;
  232.             dst = NULL;
  233.             size = p[0];
  234.             break;

  235.         case sw_sid:
  236.             state = sw_cs_len;
  237.             dst = p;
  238.             size = 2;
  239.             break;

  240.         case sw_cs_len:
  241.             state = sw_cs;
  242.             dst = NULL;
  243.             size = (p[0] << 8) + p[1];
  244.             break;

  245.         case sw_cs:
  246.             state = sw_cm_len;
  247.             dst = p;
  248.             size = 1;
  249.             break;

  250.         case sw_cm_len:
  251.             state = sw_cm;
  252.             dst = NULL;
  253.             size = p[0];
  254.             break;

  255.         case sw_cm:
  256.             if (left == 0) {
  257.                 /* no extensions */
  258.                 return NGX_OK;
  259.             }

  260.             state = sw_ext;
  261.             dst = p;
  262.             size = 2;
  263.             break;

  264.         case sw_ext:
  265.             if (left == 0) {
  266.                 return NGX_OK;
  267.             }

  268.             state = sw_ext_header;
  269.             dst = p;
  270.             size = 4;
  271.             break;

  272.         case sw_ext_header:
  273.             if (p[0] == 0 && p[1] == 0 && ctx->host.data == NULL) {
  274.                 /* SNI extension */
  275.                 state = sw_sni_len;
  276.                 dst = p;
  277.                 size = 2;
  278.                 break;
  279.             }

  280.             if (p[0] == 0 && p[1] == 16 && ctx->alpn.data == NULL) {
  281.                 /* ALPN extension */
  282.                 state = sw_alpn_len;
  283.                 dst = p;
  284.                 size = 2;
  285.                 break;
  286.             }

  287.             if (p[0] == 0 && p[1] == 43) {
  288.                 /* supported_versions extension */
  289.                 state = sw_supver_len;
  290.                 dst = p;
  291.                 size = 1;
  292.                 break;
  293.             }

  294.             state = sw_ext;
  295.             dst = NULL;
  296.             size = (p[2] << 8) + p[3];
  297.             break;

  298.         case sw_sni_len:
  299.             ext = (p[0] << 8) + p[1];
  300.             state = sw_sni_host_head;
  301.             dst = p;
  302.             size = 3;
  303.             break;

  304.         case sw_sni_host_head:
  305.             if (p[0] != 0) {
  306.                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  307.                                "ssl preread: SNI hostname type is not DNS");
  308.                 return NGX_DECLINED;
  309.             }

  310.             size = (p[1] << 8) + p[2];

  311.             if (ext < 3 + size) {
  312.                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  313.                                "ssl preread: SNI format error");
  314.                 return NGX_DECLINED;
  315.             }
  316.             ext -= 3 + size;

  317.             ctx->host.data = ngx_pnalloc(ctx->pool, size);
  318.             if (ctx->host.data == NULL) {
  319.                 return NGX_ERROR;
  320.             }

  321.             state = sw_sni_host;
  322.             dst = ctx->host.data;
  323.             break;

  324.         case sw_sni_host:
  325.             ctx->host.len = (p[1] << 8) + p[2];

  326.             state = sw_ext;
  327.             dst = NULL;
  328.             size = ext;
  329.             break;

  330.         case sw_alpn_len:
  331.             ext = (p[0] << 8) + p[1];

  332.             ctx->alpn.data = ngx_pnalloc(ctx->pool, ext);
  333.             if (ctx->alpn.data == NULL) {
  334.                 return NGX_ERROR;
  335.             }

  336.             state = sw_alpn_proto_len;
  337.             dst = p;
  338.             size = 1;
  339.             break;

  340.         case sw_alpn_proto_len:
  341.             size = p[0];

  342.             if (size == 0) {
  343.                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  344.                                "ssl preread: ALPN empty protocol");
  345.                 return NGX_DECLINED;
  346.             }

  347.             if (ext < 1 + size) {
  348.                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  349.                                "ssl preread: ALPN format error");
  350.                 return NGX_DECLINED;
  351.             }
  352.             ext -= 1 + size;

  353.             state = sw_alpn_proto_data;
  354.             dst = ctx->alpn.data + ctx->alpn.len;
  355.             break;

  356.         case sw_alpn_proto_data:
  357.             ctx->alpn.len += p[0];

  358.             ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  359.                            "ssl preread: ALPN protocols \"%V\"", &ctx->alpn);

  360.             if (ext) {
  361.                 ctx->alpn.data[ctx->alpn.len++] = ',';

  362.                 state = sw_alpn_proto_len;
  363.                 dst = p;
  364.                 size = 1;
  365.                 break;
  366.             }

  367.             state = sw_ext;
  368.             dst = NULL;
  369.             size = 0;
  370.             break;

  371.         case sw_supver_len:
  372.             ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  373.                            "ssl preread: supported_versions");

  374.             /* set TLSv1.3 */
  375.             ctx->version[0] = 3;
  376.             ctx->version[1] = 4;

  377.             state = sw_ext;
  378.             dst = NULL;
  379.             size = p[0];
  380.             break;
  381.         }

  382.         if (left < size) {
  383.             ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
  384.                            "ssl preread: failed to parse handshake");
  385.             return NGX_DECLINED;
  386.         }
  387.     }

  388.     ctx->state = state;
  389.     ctx->size = size;
  390.     ctx->left = left;
  391.     ctx->ext = ext;
  392.     ctx->dst = dst;

  393.     return NGX_AGAIN;
  394. }


  395. static ngx_int_t
  396. ngx_stream_ssl_preread_servername(ngx_stream_session_t *s,
  397.     ngx_str_t *servername)
  398. {
  399.     ngx_int_t                    rc;
  400.     ngx_str_t                    host;
  401.     ngx_connection_t            *c;
  402.     ngx_stream_core_srv_conf_t  *cscf;

  403.     c = s->connection;

  404.     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
  405.                    "SSL preread server name: \"%V\"", servername);

  406.     if (servername->len == 0) {
  407.         return NGX_OK;
  408.     }

  409.     host = *servername;

  410.     rc = ngx_stream_validate_host(&host, c->pool, 0);

  411.     if (rc == NGX_ERROR) {
  412.         return NGX_ERROR;
  413.     }

  414.     if (rc == NGX_DECLINED) {
  415.         return NGX_OK;
  416.     }

  417.     rc = ngx_stream_find_virtual_server(s, &host, &cscf);

  418.     if (rc == NGX_ERROR) {
  419.         return NGX_ERROR;
  420.     }

  421.     if (rc == NGX_DECLINED) {
  422.         return NGX_OK;
  423.     }

  424.     s->srv_conf = cscf->ctx->srv_conf;

  425.     ngx_set_connection_log(c, cscf->error_log);

  426.     return NGX_OK;
  427. }


  428. static ngx_int_t
  429. ngx_stream_ssl_preread_protocol_variable(ngx_stream_session_t *s,
  430.     ngx_variable_value_t *v, uintptr_t data)
  431. {
  432.     ngx_str_t                      version;
  433.     ngx_stream_ssl_preread_ctx_t  *ctx;

  434.     ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);

  435.     if (ctx == NULL) {
  436.         v->not_found = 1;
  437.         return NGX_OK;
  438.     }

  439.     /* SSL_get_version() format */

  440.     ngx_str_null(&version);

  441.     switch (ctx->version[0]) {
  442.     case 0:
  443.         switch (ctx->version[1]) {
  444.         case 2:
  445.             ngx_str_set(&version, "SSLv2");
  446.             break;
  447.         }
  448.         break;
  449.     case 3:
  450.         switch (ctx->version[1]) {
  451.         case 0:
  452.             ngx_str_set(&version, "SSLv3");
  453.             break;
  454.         case 1:
  455.             ngx_str_set(&version, "TLSv1");
  456.             break;
  457.         case 2:
  458.             ngx_str_set(&version, "TLSv1.1");
  459.             break;
  460.         case 3:
  461.             ngx_str_set(&version, "TLSv1.2");
  462.             break;
  463.         case 4:
  464.             ngx_str_set(&version, "TLSv1.3");
  465.             break;
  466.         }
  467.     }

  468.     v->valid = 1;
  469.     v->no_cacheable = 0;
  470.     v->not_found = 0;
  471.     v->len = version.len;
  472.     v->data = version.data;

  473.     return NGX_OK;
  474. }


  475. static ngx_int_t
  476. ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s,
  477.     ngx_variable_value_t *v, uintptr_t data)
  478. {
  479.     ngx_stream_ssl_preread_ctx_t  *ctx;

  480.     ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);

  481.     if (ctx == NULL) {
  482.         v->not_found = 1;
  483.         return NGX_OK;
  484.     }

  485.     v->valid = 1;
  486.     v->no_cacheable = 0;
  487.     v->not_found = 0;
  488.     v->len = ctx->host.len;
  489.     v->data = ctx->host.data;

  490.     return NGX_OK;
  491. }


  492. static ngx_int_t
  493. ngx_stream_ssl_preread_alpn_protocols_variable(ngx_stream_session_t *s,
  494.     ngx_variable_value_t *v, uintptr_t data)
  495. {
  496.     ngx_stream_ssl_preread_ctx_t  *ctx;

  497.     ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);

  498.     if (ctx == NULL) {
  499.         v->not_found = 1;
  500.         return NGX_OK;
  501.     }

  502.     v->valid = 1;
  503.     v->no_cacheable = 0;
  504.     v->not_found = 0;
  505.     v->len = ctx->alpn.len;
  506.     v->data = ctx->alpn.data;

  507.     return NGX_OK;
  508. }


  509. static ngx_int_t
  510. ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf)
  511. {
  512.     ngx_stream_variable_t  *var, *v;

  513.     for (v = ngx_stream_ssl_preread_vars; v->name.len; v++) {
  514.         var = ngx_stream_add_variable(cf, &v->name, v->flags);
  515.         if (var == NULL) {
  516.             return NGX_ERROR;
  517.         }

  518.         var->get_handler = v->get_handler;
  519.         var->data = v->data;
  520.     }

  521.     return NGX_OK;
  522. }


  523. static void *
  524. ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf)
  525. {
  526.     ngx_stream_ssl_preread_srv_conf_t  *conf;

  527.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_ssl_preread_srv_conf_t));
  528.     if (conf == NULL) {
  529.         return NULL;
  530.     }

  531.     conf->enabled = NGX_CONF_UNSET;

  532.     return conf;
  533. }


  534. static char *
  535. ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
  536. {
  537.     ngx_stream_ssl_preread_srv_conf_t *prev = parent;
  538.     ngx_stream_ssl_preread_srv_conf_t *conf = child;

  539.     ngx_conf_merge_value(conf->enabled, prev->enabled, 0);

  540.     return NGX_CONF_OK;
  541. }


  542. static ngx_int_t
  543. ngx_stream_ssl_preread_init(ngx_conf_t *cf)
  544. {
  545.     ngx_stream_handler_pt        *h;
  546.     ngx_stream_core_main_conf_t  *cmcf;

  547.     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);

  548.     h = ngx_array_push(&cmcf->phases[NGX_STREAM_PREREAD_PHASE].handlers);
  549.     if (h == NULL) {
  550.         return NGX_ERROR;
  551.     }

  552.     *h = ngx_stream_ssl_preread_handler;

  553.     return NGX_OK;
  554. }