Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Nginx, Inc.
0004  */
0005 
0006 
0007 #include <ngx_config.h>
0008 #include <ngx_core.h>
0009 #include <ngx_stream.h>
0010 
0011 
0012 typedef struct {
0013     ngx_flag_t      enabled;
0014 } ngx_stream_ssl_preread_srv_conf_t;
0015 
0016 
0017 typedef struct {
0018     size_t          left;
0019     size_t          size;
0020     u_char         *pos;
0021     u_char         *dst;
0022     u_char          buf[4];
0023     ngx_str_t       host;
0024     ngx_log_t      *log;
0025     ngx_pool_t     *pool;
0026     ngx_uint_t      state;
0027 } ngx_stream_ssl_preread_ctx_t;
0028 
0029 
0030 static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s);
0031 static ngx_int_t ngx_stream_ssl_preread_parse_record(
0032     ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last);
0033 static ngx_int_t ngx_stream_ssl_preread_server_name_variable(
0034     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
0035 static ngx_int_t ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf);
0036 static void *ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf);
0037 static char *ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent,
0038     void *child);
0039 static ngx_int_t ngx_stream_ssl_preread_init(ngx_conf_t *cf);
0040 
0041 
0042 static ngx_command_t  ngx_stream_ssl_preread_commands[] = {
0043 
0044     { ngx_string("ssl_preread"),
0045       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
0046       ngx_conf_set_flag_slot,
0047       NGX_STREAM_SRV_CONF_OFFSET,
0048       offsetof(ngx_stream_ssl_preread_srv_conf_t, enabled),
0049       NULL },
0050 
0051       ngx_null_command
0052 };
0053 
0054 
0055 static ngx_stream_module_t  ngx_stream_ssl_preread_module_ctx = {
0056     ngx_stream_ssl_preread_add_variables,   /* preconfiguration */
0057     ngx_stream_ssl_preread_init,            /* postconfiguration */
0058 
0059     NULL,                                   /* create main configuration */
0060     NULL,                                   /* init main configuration */
0061 
0062     ngx_stream_ssl_preread_create_srv_conf, /* create server configuration */
0063     ngx_stream_ssl_preread_merge_srv_conf   /* merge server configuration */
0064 };
0065 
0066 
0067 ngx_module_t  ngx_stream_ssl_preread_module = {
0068     NGX_MODULE_V1,
0069     &ngx_stream_ssl_preread_module_ctx,     /* module context */
0070     ngx_stream_ssl_preread_commands,        /* module directives */
0071     NGX_STREAM_MODULE,                      /* module type */
0072     NULL,                                   /* init master */
0073     NULL,                                   /* init module */
0074     NULL,                                   /* init process */
0075     NULL,                                   /* init thread */
0076     NULL,                                   /* exit thread */
0077     NULL,                                   /* exit process */
0078     NULL,                                   /* exit master */
0079     NGX_MODULE_V1_PADDING
0080 };
0081 
0082 
0083 static ngx_stream_variable_t  ngx_stream_ssl_preread_vars[] = {
0084 
0085     { ngx_string("ssl_preread_server_name"), NULL,
0086       ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 },
0087 
0088     { ngx_null_string, NULL, NULL, 0, 0, 0 }
0089 };
0090 
0091 
0092 static ngx_int_t
0093 ngx_stream_ssl_preread_handler(ngx_stream_session_t *s)
0094 {
0095     u_char                             *last, *p;
0096     size_t                              len;
0097     ngx_int_t                           rc;
0098     ngx_connection_t                   *c;
0099     ngx_stream_ssl_preread_ctx_t       *ctx;
0100     ngx_stream_ssl_preread_srv_conf_t  *sscf;
0101 
0102     c = s->connection;
0103 
0104     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "ssl preread handler");
0105 
0106     sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_preread_module);
0107 
0108     if (!sscf->enabled) {
0109         return NGX_DECLINED;
0110     }
0111 
0112     if (c->type != SOCK_STREAM) {
0113         return NGX_DECLINED;
0114     }
0115 
0116     if (c->buffer == NULL) {
0117         return NGX_AGAIN;
0118     }
0119 
0120     ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);
0121     if (ctx == NULL) {
0122         ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_ssl_preread_ctx_t));
0123         if (ctx == NULL) {
0124             return NGX_ERROR;
0125         }
0126 
0127         ngx_stream_set_ctx(s, ctx, ngx_stream_ssl_preread_module);
0128 
0129         ctx->pool = c->pool;
0130         ctx->log = c->log;
0131         ctx->pos = c->buffer->pos;
0132     }
0133 
0134     p = ctx->pos;
0135     last = c->buffer->last;
0136 
0137     while (last - p >= 5) {
0138 
0139         if (p[0] != 0x16) {
0140             ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0141                            "ssl preread: not a handshake");
0142             return NGX_DECLINED;
0143         }
0144 
0145         if (p[1] != 3) {
0146             ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0147                            "ssl preread: unsupported SSL version");
0148             return NGX_DECLINED;
0149         }
0150 
0151         len = (p[3] << 8) + p[4];
0152 
0153         /* read the whole record before parsing */
0154         if ((size_t) (last - p) < len + 5) {
0155             break;
0156         }
0157 
0158         p += 5;
0159 
0160         rc = ngx_stream_ssl_preread_parse_record(ctx, p, p + len);
0161         if (rc != NGX_AGAIN) {
0162             return rc;
0163         }
0164 
0165         p += len;
0166     }
0167 
0168     ctx->pos = p;
0169 
0170     return NGX_AGAIN;
0171 }
0172 
0173 
0174 static ngx_int_t
0175 ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx,
0176     u_char *pos, u_char *last)
0177 {
0178     size_t   left, n, size;
0179     u_char  *dst, *p;
0180 
0181     enum {
0182         sw_start = 0,
0183         sw_header,          /* handshake msg_type, length */
0184         sw_head_tail,       /* version, random */
0185         sw_sid_len,         /* session_id length */
0186         sw_sid,             /* session_id */
0187         sw_cs_len,          /* cipher_suites length */
0188         sw_cs,              /* cipher_suites */
0189         sw_cm_len,          /* compression_methods length */
0190         sw_cm,              /* compression_methods */
0191         sw_ext,             /* extension */
0192         sw_ext_header,      /* extension_type, extension_data length */
0193         sw_sni_len,         /* SNI length */
0194         sw_sni_host_head,   /* SNI name_type, host_name length */
0195         sw_sni_host         /* SNI host_name */
0196     } state;
0197 
0198     ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0199                    "ssl preread: state %ui left %z", ctx->state, ctx->left);
0200 
0201     state = ctx->state;
0202     size = ctx->size;
0203     left = ctx->left;
0204     dst = ctx->dst;
0205     p = ctx->buf;
0206 
0207     for ( ;; ) {
0208         n = ngx_min((size_t) (last - pos), size);
0209 
0210         if (dst) {
0211             dst = ngx_cpymem(dst, pos, n);
0212         }
0213 
0214         pos += n;
0215         size -= n;
0216         left -= n;
0217 
0218         if (size != 0) {
0219             break;
0220         }
0221 
0222         switch (state) {
0223 
0224         case sw_start:
0225             state = sw_header;
0226             dst = p;
0227             size = 4;
0228             left = size;
0229             break;
0230 
0231         case sw_header:
0232             if (p[0] != 1) {
0233                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0234                                "ssl preread: not a client hello");
0235                 return NGX_DECLINED;
0236             }
0237 
0238             state = sw_head_tail;
0239             dst = NULL;
0240             size = 34;
0241             left = (p[1] << 16) + (p[2] << 8) + p[3];
0242             break;
0243 
0244         case sw_head_tail:
0245             state = sw_sid_len;
0246             dst = p;
0247             size = 1;
0248             break;
0249 
0250         case sw_sid_len:
0251             state = sw_sid;
0252             dst = NULL;
0253             size = p[0];
0254             break;
0255 
0256         case sw_sid:
0257             state = sw_cs_len;
0258             dst = p;
0259             size = 2;
0260             break;
0261 
0262         case sw_cs_len:
0263             state = sw_cs;
0264             dst = NULL;
0265             size = (p[0] << 8) + p[1];
0266             break;
0267 
0268         case sw_cs:
0269             state = sw_cm_len;
0270             dst = p;
0271             size = 1;
0272             break;
0273 
0274         case sw_cm_len:
0275             state = sw_cm;
0276             dst = NULL;
0277             size = p[0];
0278             break;
0279 
0280         case sw_cm:
0281             if (left == 0) {
0282                 /* no extensions */
0283                 return NGX_OK;
0284             }
0285 
0286             state = sw_ext;
0287             dst = p;
0288             size = 2;
0289             break;
0290 
0291         case sw_ext:
0292             if (left == 0) {
0293                 return NGX_OK;
0294             }
0295 
0296             state = sw_ext_header;
0297             dst = p;
0298             size = 4;
0299             break;
0300 
0301         case sw_ext_header:
0302             if (p[0] == 0 && p[1] == 0) {
0303                 /* SNI extension */
0304                 state = sw_sni_len;
0305                 dst = NULL;
0306                 size = 2;
0307                 break;
0308             }
0309 
0310             state = sw_ext;
0311             dst = NULL;
0312             size = (p[2] << 8) + p[3];
0313             break;
0314 
0315         case sw_sni_len:
0316             state = sw_sni_host_head;
0317             dst = p;
0318             size = 3;
0319             break;
0320 
0321         case sw_sni_host_head:
0322             if (p[0] != 0) {
0323                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0324                                "ssl preread: SNI hostname type is not DNS");
0325                 return NGX_DECLINED;
0326             }
0327 
0328             state = sw_sni_host;
0329             size = (p[1] << 8) + p[2];
0330 
0331             ctx->host.data = ngx_pnalloc(ctx->pool, size);
0332             if (ctx->host.data == NULL) {
0333                 return NGX_ERROR;
0334             }
0335 
0336             dst = ctx->host.data;
0337             break;
0338 
0339         case sw_sni_host:
0340             ctx->host.len = (p[1] << 8) + p[2];
0341 
0342             ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0343                            "ssl preread: SNI hostname \"%V\"", &ctx->host);
0344             return NGX_OK;
0345         }
0346 
0347         if (left < size) {
0348            ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0349                           "ssl preread: failed to parse handshake");
0350            return NGX_DECLINED;
0351         }
0352     }
0353 
0354     ctx->state = state;
0355     ctx->size = size;
0356     ctx->left = left;
0357     ctx->dst = dst;
0358 
0359     return NGX_AGAIN;
0360 }
0361 
0362 
0363 static ngx_int_t
0364 ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s,
0365     ngx_variable_value_t *v, uintptr_t data)
0366 {
0367     ngx_stream_ssl_preread_ctx_t  *ctx;
0368 
0369     ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);
0370 
0371     if (ctx == NULL) {
0372         v->not_found = 1;
0373         return NGX_OK;
0374     }
0375 
0376     v->valid = 1;
0377     v->no_cacheable = 0;
0378     v->not_found = 0;
0379     v->len = ctx->host.len;
0380     v->data = ctx->host.data;
0381 
0382     return NGX_OK;
0383 }
0384 
0385 
0386 static ngx_int_t
0387 ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf)
0388 {
0389     ngx_stream_variable_t  *var, *v;
0390 
0391     for (v = ngx_stream_ssl_preread_vars; v->name.len; v++) {
0392         var = ngx_stream_add_variable(cf, &v->name, v->flags);
0393         if (var == NULL) {
0394             return NGX_ERROR;
0395         }
0396 
0397         var->get_handler = v->get_handler;
0398         var->data = v->data;
0399     }
0400 
0401     return NGX_OK;
0402 }
0403 
0404 
0405 static void *
0406 ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf)
0407 {
0408     ngx_stream_ssl_preread_srv_conf_t  *conf;
0409 
0410     conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_ssl_preread_srv_conf_t));
0411     if (conf == NULL) {
0412         return NULL;
0413     }
0414 
0415     conf->enabled = NGX_CONF_UNSET;
0416 
0417     return conf;
0418 }
0419 
0420 
0421 static char *
0422 ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
0423 {
0424     ngx_stream_ssl_preread_srv_conf_t *prev = parent;
0425     ngx_stream_ssl_preread_srv_conf_t *conf = child;
0426 
0427     ngx_conf_merge_value(conf->enabled, prev->enabled, 0);
0428 
0429     return NGX_CONF_OK;
0430 }
0431 
0432 
0433 static ngx_int_t
0434 ngx_stream_ssl_preread_init(ngx_conf_t *cf)
0435 {
0436     ngx_stream_handler_pt        *h;
0437     ngx_stream_core_main_conf_t  *cmcf;
0438 
0439     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
0440 
0441     h = ngx_array_push(&cmcf->phases[NGX_STREAM_PREREAD_PHASE].handlers);
0442     if (h == NULL) {
0443         return NGX_ERROR;
0444     }
0445 
0446     *h = ngx_stream_ssl_preread_handler;
0447 
0448     return NGX_OK;
0449 }