src/http/v3/ngx_http_v3_module.c - nginx source code

Global variables defined

Functions defined

Source code


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


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


  8. static ngx_int_t ngx_http_v3_variable(ngx_http_request_t *r,
  9.     ngx_http_variable_value_t *v, uintptr_t data);
  10. static ngx_int_t ngx_http_v3_add_variables(ngx_conf_t *cf);
  11. static void *ngx_http_v3_create_srv_conf(ngx_conf_t *cf);
  12. static char *ngx_http_v3_merge_srv_conf(ngx_conf_t *cf, void *parent,
  13.     void *child);
  14. static char *ngx_http_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd,
  15.     void *conf);


  16. static ngx_command_t  ngx_http_v3_commands[] = {

  17.     { ngx_string("http3"),
  18.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
  19.       ngx_conf_set_flag_slot,
  20.       NGX_HTTP_SRV_CONF_OFFSET,
  21.       offsetof(ngx_http_v3_srv_conf_t, enable),
  22.       NULL },

  23.     { ngx_string("http3_hq"),
  24.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
  25.       ngx_conf_set_flag_slot,
  26.       NGX_HTTP_SRV_CONF_OFFSET,
  27.       offsetof(ngx_http_v3_srv_conf_t, enable_hq),
  28.       NULL },

  29.     { ngx_string("http3_max_concurrent_streams"),
  30.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
  31.       ngx_conf_set_num_slot,
  32.       NGX_HTTP_SRV_CONF_OFFSET,
  33.       offsetof(ngx_http_v3_srv_conf_t, max_concurrent_streams),
  34.       NULL },

  35.     { ngx_string("http3_stream_buffer_size"),
  36.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
  37.       ngx_conf_set_size_slot,
  38.       NGX_HTTP_SRV_CONF_OFFSET,
  39.       offsetof(ngx_http_v3_srv_conf_t, quic.stream_buffer_size),
  40.       NULL },

  41.     { ngx_string("quic_retry"),
  42.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
  43.       ngx_conf_set_flag_slot,
  44.       NGX_HTTP_SRV_CONF_OFFSET,
  45.       offsetof(ngx_http_v3_srv_conf_t, quic.retry),
  46.       NULL },

  47.     { ngx_string("quic_gso"),
  48.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
  49.       ngx_conf_set_flag_slot,
  50.       NGX_HTTP_SRV_CONF_OFFSET,
  51.       offsetof(ngx_http_v3_srv_conf_t, quic.gso_enabled),
  52.       NULL },

  53.     { ngx_string("quic_host_key"),
  54.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
  55.       ngx_http_quic_host_key,
  56.       NGX_HTTP_SRV_CONF_OFFSET,
  57.       0,
  58.       NULL },

  59.     { ngx_string("quic_active_connection_id_limit"),
  60.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
  61.       ngx_conf_set_num_slot,
  62.       NGX_HTTP_SRV_CONF_OFFSET,
  63.       offsetof(ngx_http_v3_srv_conf_t, quic.active_connection_id_limit),
  64.       NULL },

  65.       ngx_null_command
  66. };


  67. static ngx_http_module_t  ngx_http_v3_module_ctx = {
  68.     ngx_http_v3_add_variables,             /* preconfiguration */
  69.     NULL,                                  /* postconfiguration */

  70.     NULL,                                  /* create main configuration */
  71.     NULL,                                  /* init main configuration */

  72.     ngx_http_v3_create_srv_conf,           /* create server configuration */
  73.     ngx_http_v3_merge_srv_conf,            /* merge server configuration */

  74.     NULL,                                  /* create location configuration */
  75.     NULL                                   /* merge location configuration */
  76. };


  77. ngx_module_t  ngx_http_v3_module = {
  78.     NGX_MODULE_V1,
  79.     &ngx_http_v3_module_ctx,               /* module context */
  80.     ngx_http_v3_commands,                  /* module directives */
  81.     NGX_HTTP_MODULE,                       /* module type */
  82.     NULL,                                  /* init master */
  83.     NULL,                                  /* init module */
  84.     NULL,                                  /* init process */
  85.     NULL,                                  /* init thread */
  86.     NULL,                                  /* exit thread */
  87.     NULL,                                  /* exit process */
  88.     NULL,                                  /* exit master */
  89.     NGX_MODULE_V1_PADDING
  90. };


  91. static ngx_http_variable_t  ngx_http_v3_vars[] = {

  92.     { ngx_string("http3"), NULL, ngx_http_v3_variable, 0, 0, 0 },

  93.       ngx_http_null_variable
  94. };

  95. static ngx_str_t  ngx_http_quic_salt = ngx_string("ngx_quic");


  96. static ngx_int_t
  97. ngx_http_v3_variable(ngx_http_request_t *r,
  98.     ngx_http_variable_value_t *v, uintptr_t data)
  99. {
  100.     ngx_http_v3_session_t  *h3c;

  101.     if (r->connection->quic) {
  102.         h3c = ngx_http_v3_get_session(r->connection);

  103.         if (h3c->hq) {
  104.             v->len = sizeof("hq") - 1;
  105.             v->valid = 1;
  106.             v->no_cacheable = 0;
  107.             v->not_found = 0;
  108.             v->data = (u_char *) "hq";

  109.             return NGX_OK;
  110.         }

  111.         v->len = sizeof("h3") - 1;
  112.         v->valid = 1;
  113.         v->no_cacheable = 0;
  114.         v->not_found = 0;
  115.         v->data = (u_char *) "h3";

  116.         return NGX_OK;
  117.     }

  118.     *v = ngx_http_variable_null_value;

  119.     return NGX_OK;
  120. }


  121. static ngx_int_t
  122. ngx_http_v3_add_variables(ngx_conf_t *cf)
  123. {
  124.     ngx_http_variable_t  *var, *v;

  125.     for (v = ngx_http_v3_vars; v->name.len; v++) {
  126.         var = ngx_http_add_variable(cf, &v->name, v->flags);
  127.         if (var == NULL) {
  128.             return NGX_ERROR;
  129.         }

  130.         var->get_handler = v->get_handler;
  131.         var->data = v->data;
  132.     }

  133.     return NGX_OK;
  134. }


  135. static void *
  136. ngx_http_v3_create_srv_conf(ngx_conf_t *cf)
  137. {
  138.     ngx_http_v3_srv_conf_t  *h3scf;

  139.     h3scf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v3_srv_conf_t));
  140.     if (h3scf == NULL) {
  141.         return NULL;
  142.     }

  143.     /*
  144.      * set by ngx_pcalloc():
  145.      *
  146.      *     h3scf->quic.host_key = { 0, NULL }
  147.      *     h3scf->quic.stream_reject_code_uni = 0;
  148.      *     h3scf->quic.disable_active_migration = 0;
  149.      *     h3scf->quic.idle_timeout = 0;
  150.      *     h3scf->max_blocked_streams = 0;
  151.      */

  152.     h3scf->enable = NGX_CONF_UNSET;
  153.     h3scf->enable_hq = NGX_CONF_UNSET;
  154.     h3scf->max_table_capacity = NGX_HTTP_V3_MAX_TABLE_CAPACITY;
  155.     h3scf->max_concurrent_streams = NGX_CONF_UNSET_UINT;

  156.     h3scf->quic.stream_buffer_size = NGX_CONF_UNSET_SIZE;
  157.     h3scf->quic.max_concurrent_streams_bidi = NGX_CONF_UNSET_UINT;
  158.     h3scf->quic.max_concurrent_streams_uni = NGX_HTTP_V3_MAX_UNI_STREAMS;
  159.     h3scf->quic.retry = NGX_CONF_UNSET;
  160.     h3scf->quic.gso_enabled = NGX_CONF_UNSET;
  161.     h3scf->quic.stream_close_code = NGX_HTTP_V3_ERR_NO_ERROR;
  162.     h3scf->quic.stream_reject_code_bidi = NGX_HTTP_V3_ERR_REQUEST_REJECTED;
  163.     h3scf->quic.active_connection_id_limit = NGX_CONF_UNSET_UINT;

  164.     h3scf->quic.init = ngx_http_v3_init;
  165.     h3scf->quic.shutdown = ngx_http_v3_shutdown;

  166.     return h3scf;
  167. }


  168. static char *
  169. ngx_http_v3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
  170. {
  171.     ngx_http_v3_srv_conf_t *prev = parent;
  172.     ngx_http_v3_srv_conf_t *conf = child;

  173.     ngx_http_ssl_srv_conf_t   *sscf;
  174.     ngx_http_core_srv_conf_t  *cscf;

  175.     ngx_conf_merge_value(conf->enable, prev->enable, 1);

  176.     ngx_conf_merge_value(conf->enable_hq, prev->enable_hq, 0);

  177.     ngx_conf_merge_uint_value(conf->max_concurrent_streams,
  178.                               prev->max_concurrent_streams, 128);

  179.     conf->max_blocked_streams = conf->max_concurrent_streams;

  180.     ngx_conf_merge_size_value(conf->quic.stream_buffer_size,
  181.                               prev->quic.stream_buffer_size,
  182.                               65536);

  183.     conf->quic.max_concurrent_streams_bidi = conf->max_concurrent_streams;

  184.     ngx_conf_merge_value(conf->quic.retry, prev->quic.retry, 0);
  185.     ngx_conf_merge_value(conf->quic.gso_enabled, prev->quic.gso_enabled, 0);

  186.     ngx_conf_merge_str_value(conf->quic.host_key, prev->quic.host_key, "");

  187.     ngx_conf_merge_uint_value(conf->quic.active_connection_id_limit,
  188.                               prev->quic.active_connection_id_limit,
  189.                               2);

  190.     if (conf->quic.host_key.len == 0) {

  191.         conf->quic.host_key.len = NGX_QUIC_DEFAULT_HOST_KEY_LEN;
  192.         conf->quic.host_key.data = ngx_palloc(cf->pool,
  193.                                               conf->quic.host_key.len);
  194.         if (conf->quic.host_key.data == NULL) {
  195.             return NGX_CONF_ERROR;
  196.         }

  197.         if (RAND_bytes(conf->quic.host_key.data, NGX_QUIC_DEFAULT_HOST_KEY_LEN)
  198.             <= 0)
  199.         {
  200.             return NGX_CONF_ERROR;
  201.         }
  202.     }

  203.     if (ngx_quic_derive_key(cf->log, "av_token_key",
  204.                             &conf->quic.host_key, &ngx_http_quic_salt,
  205.                             conf->quic.av_token_key, NGX_QUIC_AV_KEY_LEN)
  206.         != NGX_OK)
  207.     {
  208.         return NGX_CONF_ERROR;
  209.     }

  210.     if (ngx_quic_derive_key(cf->log, "sr_token_key",
  211.                             &conf->quic.host_key, &ngx_http_quic_salt,
  212.                             conf->quic.sr_token_key, NGX_QUIC_SR_KEY_LEN)
  213.         != NGX_OK)
  214.     {
  215.         return NGX_CONF_ERROR;
  216.     }

  217.     cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);
  218.     conf->quic.handshake_timeout = cscf->client_header_timeout;

  219.     sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module);
  220.     conf->quic.ssl = &sscf->ssl;

  221.     return NGX_CONF_OK;
  222. }


  223. static char *
  224. ngx_http_quic_host_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  225. {
  226.     ngx_http_v3_srv_conf_t  *h3scf = conf;

  227.     u_char           *buf;
  228.     size_t            size;
  229.     ssize_t           n;
  230.     ngx_str_t        *value;
  231.     ngx_file_t        file;
  232.     ngx_file_info_t   fi;
  233.     ngx_quic_conf_t  *qcf;

  234.     qcf = &h3scf->quic;

  235.     if (qcf->host_key.len) {
  236.         return "is duplicate";
  237.     }

  238.     buf = NULL;
  239. #if (NGX_SUPPRESS_WARN)
  240.     size = 0;
  241. #endif

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

  243.     if (ngx_conf_full_name(cf->cycle, &value[1], 1) != NGX_OK) {
  244.         return NGX_CONF_ERROR;
  245.     }

  246.     ngx_memzero(&file, sizeof(ngx_file_t));
  247.     file.name = value[1];
  248.     file.log = cf->log;

  249.     file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);

  250.     if (file.fd == NGX_INVALID_FILE) {
  251.         ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
  252.                            ngx_open_file_n " \"%V\" failed", &file.name);
  253.         return NGX_CONF_ERROR;
  254.     }

  255.     if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
  256.         ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
  257.                            ngx_fd_info_n " \"%V\" failed", &file.name);
  258.         goto failed;
  259.     }

  260.     size = ngx_file_size(&fi);

  261.     if (size == 0) {
  262.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  263.                            "\"%V\" zero key size", &file.name);
  264.         goto failed;
  265.     }

  266.     buf = ngx_pnalloc(cf->pool, size);
  267.     if (buf == NULL) {
  268.         goto failed;
  269.     }

  270.     n = ngx_read_file(&file, buf, size, 0);

  271.     if (n == NGX_ERROR) {
  272.         ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
  273.                            ngx_read_file_n " \"%V\" failed", &file.name);
  274.         goto failed;
  275.     }

  276.     if ((size_t) n != size) {
  277.         ngx_conf_log_error(NGX_LOG_CRIT, cf, 0,
  278.                            ngx_read_file_n " \"%V\" returned only "
  279.                            "%z bytes instead of %uz", &file.name, n, size);
  280.         goto failed;
  281.     }

  282.     qcf->host_key.data = buf;
  283.     qcf->host_key.len = n;

  284.     if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
  285.         ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
  286.                       ngx_close_file_n " \"%V\" failed", &file.name);
  287.     }

  288.     return NGX_CONF_OK;

  289. failed:

  290.     if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
  291.         ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
  292.                       ngx_close_file_n " \"%V\" failed", &file.name);
  293.     }

  294.     if (buf) {
  295.         ngx_explicit_memzero(buf, size);
  296.     }

  297.     return NGX_CONF_ERROR;
  298. }