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     size_t          ext;
0021     u_char         *pos;
0022     u_char         *dst;
0023     u_char          buf[4];
0024     ngx_str_t       host;
0025     ngx_str_t       alpn;
0026     ngx_log_t      *log;
0027     ngx_pool_t     *pool;
0028     ngx_uint_t      state;
0029 } ngx_stream_ssl_preread_ctx_t;
0030 
0031 
0032 static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s);
0033 static ngx_int_t ngx_stream_ssl_preread_parse_record(
0034     ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last);
0035 static ngx_int_t ngx_stream_ssl_preread_server_name_variable(
0036     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
0037 static ngx_int_t ngx_stream_ssl_preread_alpn_protocols_variable(
0038     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
0039 static ngx_int_t ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf);
0040 static void *ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf);
0041 static char *ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent,
0042     void *child);
0043 static ngx_int_t ngx_stream_ssl_preread_init(ngx_conf_t *cf);
0044 
0045 
0046 static ngx_command_t  ngx_stream_ssl_preread_commands[] = {
0047 
0048     { ngx_string("ssl_preread"),
0049       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
0050       ngx_conf_set_flag_slot,
0051       NGX_STREAM_SRV_CONF_OFFSET,
0052       offsetof(ngx_stream_ssl_preread_srv_conf_t, enabled),
0053       NULL },
0054 
0055       ngx_null_command
0056 };
0057 
0058 
0059 static ngx_stream_module_t  ngx_stream_ssl_preread_module_ctx = {
0060     ngx_stream_ssl_preread_add_variables,   /* preconfiguration */
0061     ngx_stream_ssl_preread_init,            /* postconfiguration */
0062 
0063     NULL,                                   /* create main configuration */
0064     NULL,                                   /* init main configuration */
0065 
0066     ngx_stream_ssl_preread_create_srv_conf, /* create server configuration */
0067     ngx_stream_ssl_preread_merge_srv_conf   /* merge server configuration */
0068 };
0069 
0070 
0071 ngx_module_t  ngx_stream_ssl_preread_module = {
0072     NGX_MODULE_V1,
0073     &ngx_stream_ssl_preread_module_ctx,     /* module context */
0074     ngx_stream_ssl_preread_commands,        /* module directives */
0075     NGX_STREAM_MODULE,                      /* module type */
0076     NULL,                                   /* init master */
0077     NULL,                                   /* init module */
0078     NULL,                                   /* init process */
0079     NULL,                                   /* init thread */
0080     NULL,                                   /* exit thread */
0081     NULL,                                   /* exit process */
0082     NULL,                                   /* exit master */
0083     NGX_MODULE_V1_PADDING
0084 };
0085 
0086 
0087 static ngx_stream_variable_t  ngx_stream_ssl_preread_vars[] = {
0088 
0089     { ngx_string("ssl_preread_server_name"), NULL,
0090       ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 },
0091 
0092     { ngx_string("ssl_preread_alpn_protocols"), NULL,
0093       ngx_stream_ssl_preread_alpn_protocols_variable, 0, 0, 0 },
0094 
0095       ngx_stream_null_variable
0096 };
0097 
0098 
0099 static ngx_int_t
0100 ngx_stream_ssl_preread_handler(ngx_stream_session_t *s)
0101 {
0102     u_char                             *last, *p;
0103     size_t                              len;
0104     ngx_int_t                           rc;
0105     ngx_connection_t                   *c;
0106     ngx_stream_ssl_preread_ctx_t       *ctx;
0107     ngx_stream_ssl_preread_srv_conf_t  *sscf;
0108 
0109     c = s->connection;
0110 
0111     ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "ssl preread handler");
0112 
0113     sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_preread_module);
0114 
0115     if (!sscf->enabled) {
0116         return NGX_DECLINED;
0117     }
0118 
0119     if (c->type != SOCK_STREAM) {
0120         return NGX_DECLINED;
0121     }
0122 
0123     if (c->buffer == NULL) {
0124         return NGX_AGAIN;
0125     }
0126 
0127     ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);
0128     if (ctx == NULL) {
0129         ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_ssl_preread_ctx_t));
0130         if (ctx == NULL) {
0131             return NGX_ERROR;
0132         }
0133 
0134         ngx_stream_set_ctx(s, ctx, ngx_stream_ssl_preread_module);
0135 
0136         ctx->pool = c->pool;
0137         ctx->log = c->log;
0138         ctx->pos = c->buffer->pos;
0139     }
0140 
0141     p = ctx->pos;
0142     last = c->buffer->last;
0143 
0144     while (last - p >= 5) {
0145 
0146         if (p[0] != 0x16) {
0147             ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0148                            "ssl preread: not a handshake");
0149             ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
0150             return NGX_DECLINED;
0151         }
0152 
0153         if (p[1] != 3) {
0154             ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0155                            "ssl preread: unsupported SSL version");
0156             ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
0157             return NGX_DECLINED;
0158         }
0159 
0160         len = (p[3] << 8) + p[4];
0161 
0162         /* read the whole record before parsing */
0163         if ((size_t) (last - p) < len + 5) {
0164             break;
0165         }
0166 
0167         p += 5;
0168 
0169         rc = ngx_stream_ssl_preread_parse_record(ctx, p, p + len);
0170 
0171         if (rc == NGX_DECLINED) {
0172             ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
0173             return NGX_DECLINED;
0174         }
0175 
0176         if (rc != NGX_AGAIN) {
0177             return rc;
0178         }
0179 
0180         p += len;
0181     }
0182 
0183     ctx->pos = p;
0184 
0185     return NGX_AGAIN;
0186 }
0187 
0188 
0189 static ngx_int_t
0190 ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx,
0191     u_char *pos, u_char *last)
0192 {
0193     size_t   left, n, size, ext;
0194     u_char  *dst, *p;
0195 
0196     enum {
0197         sw_start = 0,
0198         sw_header,          /* handshake msg_type, length */
0199         sw_head_tail,       /* version, random */
0200         sw_sid_len,         /* session_id length */
0201         sw_sid,             /* session_id */
0202         sw_cs_len,          /* cipher_suites length */
0203         sw_cs,              /* cipher_suites */
0204         sw_cm_len,          /* compression_methods length */
0205         sw_cm,              /* compression_methods */
0206         sw_ext,             /* extension */
0207         sw_ext_header,      /* extension_type, extension_data length */
0208         sw_sni_len,         /* SNI length */
0209         sw_sni_host_head,   /* SNI name_type, host_name length */
0210         sw_sni_host,        /* SNI host_name */
0211         sw_alpn_len,        /* ALPN length */
0212         sw_alpn_proto_len,  /* ALPN protocol_name length */
0213         sw_alpn_proto_data  /* ALPN protocol_name */
0214     } state;
0215 
0216     ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0217                    "ssl preread: state %ui left %z", ctx->state, ctx->left);
0218 
0219     state = ctx->state;
0220     size = ctx->size;
0221     left = ctx->left;
0222     ext = ctx->ext;
0223     dst = ctx->dst;
0224     p = ctx->buf;
0225 
0226     for ( ;; ) {
0227         n = ngx_min((size_t) (last - pos), size);
0228 
0229         if (dst) {
0230             dst = ngx_cpymem(dst, pos, n);
0231         }
0232 
0233         pos += n;
0234         size -= n;
0235         left -= n;
0236 
0237         if (size != 0) {
0238             break;
0239         }
0240 
0241         switch (state) {
0242 
0243         case sw_start:
0244             state = sw_header;
0245             dst = p;
0246             size = 4;
0247             left = size;
0248             break;
0249 
0250         case sw_header:
0251             if (p[0] != 1) {
0252                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0253                                "ssl preread: not a client hello");
0254                 return NGX_DECLINED;
0255             }
0256 
0257             state = sw_head_tail;
0258             dst = NULL;
0259             size = 34;
0260             left = (p[1] << 16) + (p[2] << 8) + p[3];
0261             break;
0262 
0263         case sw_head_tail:
0264             state = sw_sid_len;
0265             dst = p;
0266             size = 1;
0267             break;
0268 
0269         case sw_sid_len:
0270             state = sw_sid;
0271             dst = NULL;
0272             size = p[0];
0273             break;
0274 
0275         case sw_sid:
0276             state = sw_cs_len;
0277             dst = p;
0278             size = 2;
0279             break;
0280 
0281         case sw_cs_len:
0282             state = sw_cs;
0283             dst = NULL;
0284             size = (p[0] << 8) + p[1];
0285             break;
0286 
0287         case sw_cs:
0288             state = sw_cm_len;
0289             dst = p;
0290             size = 1;
0291             break;
0292 
0293         case sw_cm_len:
0294             state = sw_cm;
0295             dst = NULL;
0296             size = p[0];
0297             break;
0298 
0299         case sw_cm:
0300             if (left == 0) {
0301                 /* no extensions */
0302                 return NGX_OK;
0303             }
0304 
0305             state = sw_ext;
0306             dst = p;
0307             size = 2;
0308             break;
0309 
0310         case sw_ext:
0311             if (left == 0) {
0312                 return NGX_OK;
0313             }
0314 
0315             state = sw_ext_header;
0316             dst = p;
0317             size = 4;
0318             break;
0319 
0320         case sw_ext_header:
0321             if (p[0] == 0 && p[1] == 0 && ctx->host.data == NULL) {
0322                 /* SNI extension */
0323                 state = sw_sni_len;
0324                 dst = p;
0325                 size = 2;
0326                 break;
0327             }
0328 
0329             if (p[0] == 0 && p[1] == 16 && ctx->alpn.data == NULL) {
0330                 /* ALPN extension */
0331                 state = sw_alpn_len;
0332                 dst = p;
0333                 size = 2;
0334                 break;
0335             }
0336 
0337             state = sw_ext;
0338             dst = NULL;
0339             size = (p[2] << 8) + p[3];
0340             break;
0341 
0342         case sw_sni_len:
0343             ext = (p[0] << 8) + p[1];
0344             state = sw_sni_host_head;
0345             dst = p;
0346             size = 3;
0347             break;
0348 
0349         case sw_sni_host_head:
0350             if (p[0] != 0) {
0351                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0352                                "ssl preread: SNI hostname type is not DNS");
0353                 return NGX_DECLINED;
0354             }
0355 
0356             size = (p[1] << 8) + p[2];
0357 
0358             if (ext < 3 + size) {
0359                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0360                                "ssl preread: SNI format error");
0361                 return NGX_DECLINED;
0362             }
0363             ext -= 3 + size;
0364 
0365             ctx->host.data = ngx_pnalloc(ctx->pool, size);
0366             if (ctx->host.data == NULL) {
0367                 return NGX_ERROR;
0368             }
0369 
0370             state = sw_sni_host;
0371             dst = ctx->host.data;
0372             break;
0373 
0374         case sw_sni_host:
0375             ctx->host.len = (p[1] << 8) + p[2];
0376 
0377             ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0378                            "ssl preread: SNI hostname \"%V\"", &ctx->host);
0379 
0380             state = sw_ext;
0381             dst = NULL;
0382             size = ext;
0383             break;
0384 
0385         case sw_alpn_len:
0386             ext = (p[0] << 8) + p[1];
0387 
0388             ctx->alpn.data = ngx_pnalloc(ctx->pool, ext);
0389             if (ctx->alpn.data == NULL) {
0390                 return NGX_ERROR;
0391             }
0392 
0393             state = sw_alpn_proto_len;
0394             dst = p;
0395             size = 1;
0396             break;
0397 
0398         case sw_alpn_proto_len:
0399             size = p[0];
0400 
0401             if (size == 0) {
0402                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0403                                "ssl preread: ALPN empty protocol");
0404                 return NGX_DECLINED;
0405             }
0406 
0407             if (ext < 1 + size) {
0408                 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0409                                "ssl preread: ALPN format error");
0410                 return NGX_DECLINED;
0411             }
0412             ext -= 1 + size;
0413 
0414             state = sw_alpn_proto_data;
0415             dst = ctx->alpn.data + ctx->alpn.len;
0416             break;
0417 
0418         case sw_alpn_proto_data:
0419             ctx->alpn.len += p[0];
0420 
0421             ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0422                            "ssl preread: ALPN protocols \"%V\"", &ctx->alpn);
0423 
0424             if (ext) {
0425                 ctx->alpn.data[ctx->alpn.len++] = ',';
0426 
0427                 state = sw_alpn_proto_len;
0428                 dst = p;
0429                 size = 1;
0430                 break;
0431             }
0432 
0433             state = sw_ext;
0434             dst = NULL;
0435             size = 0;
0436             break;
0437         }
0438 
0439         if (left < size) {
0440             ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
0441                            "ssl preread: failed to parse handshake");
0442             return NGX_DECLINED;
0443         }
0444     }
0445 
0446     ctx->state = state;
0447     ctx->size = size;
0448     ctx->left = left;
0449     ctx->ext = ext;
0450     ctx->dst = dst;
0451 
0452     return NGX_AGAIN;
0453 }
0454 
0455 
0456 static ngx_int_t
0457 ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s,
0458     ngx_variable_value_t *v, uintptr_t data)
0459 {
0460     ngx_stream_ssl_preread_ctx_t  *ctx;
0461 
0462     ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);
0463 
0464     if (ctx == NULL) {
0465         v->not_found = 1;
0466         return NGX_OK;
0467     }
0468 
0469     v->valid = 1;
0470     v->no_cacheable = 0;
0471     v->not_found = 0;
0472     v->len = ctx->host.len;
0473     v->data = ctx->host.data;
0474 
0475     return NGX_OK;
0476 }
0477 
0478 
0479 static ngx_int_t
0480 ngx_stream_ssl_preread_alpn_protocols_variable(ngx_stream_session_t *s,
0481     ngx_variable_value_t *v, uintptr_t data)
0482 {
0483     ngx_stream_ssl_preread_ctx_t  *ctx;
0484 
0485     ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);
0486 
0487     if (ctx == NULL) {
0488         v->not_found = 1;
0489         return NGX_OK;
0490     }
0491 
0492     v->valid = 1;
0493     v->no_cacheable = 0;
0494     v->not_found = 0;
0495     v->len = ctx->alpn.len;
0496     v->data = ctx->alpn.data;
0497 
0498     return NGX_OK;
0499 }
0500 
0501 
0502 static ngx_int_t
0503 ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf)
0504 {
0505     ngx_stream_variable_t  *var, *v;
0506 
0507     for (v = ngx_stream_ssl_preread_vars; v->name.len; v++) {
0508         var = ngx_stream_add_variable(cf, &v->name, v->flags);
0509         if (var == NULL) {
0510             return NGX_ERROR;
0511         }
0512 
0513         var->get_handler = v->get_handler;
0514         var->data = v->data;
0515     }
0516 
0517     return NGX_OK;
0518 }
0519 
0520 
0521 static void *
0522 ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf)
0523 {
0524     ngx_stream_ssl_preread_srv_conf_t  *conf;
0525 
0526     conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_ssl_preread_srv_conf_t));
0527     if (conf == NULL) {
0528         return NULL;
0529     }
0530 
0531     conf->enabled = NGX_CONF_UNSET;
0532 
0533     return conf;
0534 }
0535 
0536 
0537 static char *
0538 ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
0539 {
0540     ngx_stream_ssl_preread_srv_conf_t *prev = parent;
0541     ngx_stream_ssl_preread_srv_conf_t *conf = child;
0542 
0543     ngx_conf_merge_value(conf->enabled, prev->enabled, 0);
0544 
0545     return NGX_CONF_OK;
0546 }
0547 
0548 
0549 static ngx_int_t
0550 ngx_stream_ssl_preread_init(ngx_conf_t *cf)
0551 {
0552     ngx_stream_handler_pt        *h;
0553     ngx_stream_core_main_conf_t  *cmcf;
0554 
0555     cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
0556 
0557     h = ngx_array_push(&cmcf->phases[NGX_STREAM_PREREAD_PHASE].handlers);
0558     if (h == NULL) {
0559         return NGX_ERROR;
0560     }
0561 
0562     *h = ngx_stream_ssl_preread_handler;
0563 
0564     return NGX_OK;
0565 }