大量word发布wordpress,深圳seo云哥,手机网站开发和pc网站的区别,精准营销算法1 缘起 前面的《nginx upstream server主动健康检测模块ngx_http_upstream_check_module 使用和源码分析》系列已经分析了ngx_http_upstream_check_module的实现原理#xff0c;并且在借助这个模块的框架实现了一个udp健康检测的新功能。 但是ngx_http_upstream_check_mod…1 缘起 前面的《nginx upstream server主动健康检测模块ngx_http_upstream_check_module 使用和源码分析》系列已经分析了ngx_http_upstream_check_module的实现原理并且在借助这个模块的框架实现了一个udp健康检测的新功能。 但是ngx_http_upstream_check_module还缺乏基于https监测上游服务器健康状况的能力始终是一个缺憾因此本文基于《nginx upstream server主动健康检测模块ngx_http_upstream_check_module 使用和源码分析》和《nginx stream proxy 模块的ssl连接源码分析》两篇博文的分析成果来实现一个基于https的上游服务器健康检测的能力。
1.1 功能定义 本次支持的功能
支持向上游服务器发起https请求功能请求的报文复用原有的http检测的请求报文定义响应的状态码检测复用原有的http检测的响应码的定义支持ssl握手过程中添加sni扩展信息支持ssl握手协议类型的配置支持ssl握手协议加密套件的配置 暂时不支持的功能
不支持ssl会话复用会话复用可以降低上游服务器的ssl握手压力不支持ssl证书双向验证不支持服务器端证书有效性验证
ems; 由于本次主要是检验https的链接握手流程对一些不是特别关键的ssl握手特性暂时不支持主要是为了简化代码逻辑但是不影响业务流程这样也便于在本文中将整个实现流程进行阐述。后续可以参照ngx_stream_proxy_module中的实现继续将这些特性进行完善以臻于完美。
2. 实现后的效果 首先来看一下实现后的效果有一些感性的认识。
2.1 配置文件 #user nobody;
worker_processes 1;
daemon off;
master_process off;error_log logs/error.log;
pid logs/nginx.pid;load_module objs/ngx_http_upstream_check_module.so;events {worker_connections 1024;
}http {include mime.types;default_type application/octet-stream;log_format main $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for;access_log logs/access.log main;sendfile on;keepalive_timeout 65;upstream backend {check typehttps interval3000 rise2 fall5 timeout1000 port443;check_http_send GET / HTTP/1.1\r\nHost: www.test.com\r\n\r\n;check_http_expect_alive http_2xx http_3xx;check_ssl_server_name www.test.com;server 192.168.0.1:443;}server {listen 9080;server_name localhost;# 开启本模块的状态查询接口 location /status {check_status html;}location / {proxy_pass http://backend;}#error_page 404 /404.html;# redirect server error pages to the static page /50x.html#error_page 500 502 503 504 /50x.html;location /50x.html {root html;}}
}以上配置文件中的upstream块中定义了一个https的健康检测类型 check_http_send复用了http的定义而check_ssl_server_name是新增的指令用来配置ssl握手设置sni扩展主机host信息。
2.2 运行效果
查看nginx的error.log日志 可以看到如下信息
2024/02/16 09:31:33 [error] 23638#0: https check failed with return code: 403
2024/02/16 09:31:33 [error] 23638#0: check protocol https error with peer: 192.168.0.1:443
2024/02/16 09:31:45 [info] 23663#0: enable check peer: 192.168.0.1:443error.log中的前面两条因为服务器响应403报了错误对应在配置了“check_http_expect_alive http_2xx http_3xx;”的情况。如果配置改成“check_http_expect_alive http_2xx http_3xx http_4xx;” 则报后面那条上游服务器enable的信息。证明https的检测功能已经可用了。
3. 代码实现
3.1 配置指令
3.1.1 配置指令定义
支持的配置指令如下
check_ssl_ciphers: 配置加密套件格式参考proxy_ssl_cipherscheck_ssl_protocols: 和服务器交互采用的ssl协议版本如TLSv1.1 TLSv1.2等格式参考proxy_ssl_protocols。check_ssl_server_name: 和服务器进行ssl握手时候采用的sni扩展host名字如果不设置并且upstream块中的server是用域名设置的那么默认就采用设置的服务器名字。check_ssl_verify[on/off] 是否校验服务器的证书有效性。待后续实现check_ssl_session_reuse: [on/off] 和上游服务器进行ssl握手的时候是否复用ssl会话信息。
3.1.2 配置指令结构体 struct ngx_http_upstream_check_srv_conf_s {ngx_uint_t port;ngx_uint_t fall_count;ngx_uint_t rise_count;ngx_msec_t check_interval;ngx_msec_t check_timeout;ngx_uint_t check_keepalive_requests;ngx_check_conf_t *check_type_conf;ngx_str_t send;union {ngx_uint_t return_code;ngx_uint_t status_alive;} code;ngx_array_t *fastcgi_params;ngx_uint_t default_down;ngx_uint_t unique;ngx_uint_t udp : 1; /* 是否udp socket */ngx_int_t match_part : 1; /* 是否只要部分匹配就可以了 */ngx_int_t match_offset; /* udp响应期望的内容从哪个字节开始匹配 */ngx_str_t expect; /* udp响应的期望内容 */#if (NGX_HTTP_SSL)ngx_ssl_t *ssl; /* ssl 配置上下文 */ngx_str_t ssl_ciphers; /* ssl 加密套件 */ngx_uint_t ssl_protocols; /* 采用的ssl协议 */ngx_str_t ssl_server_name; /* ssl握手的sni扩展hostname */
#endif
};以上添加的ssl_protocols参数在ngx_http_upstream_check_create_srv_conf函数中需要将其设置为NGX_CONF_UNSET_UINT,避免nginx在解析配置文件的时候出现参数重复的报错。
3.1.3 配置指令源码定义
#if (NGX_HTTP_SSL){ ngx_string(check_ssl_ciphers),NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1,ngx_conf_set_str_slot,NGX_HTTP_SRV_CONF_OFFSET,offsetof(ngx_http_upstream_check_srv_conf_t, ssl_ciphers),NULL },{ ngx_string(check_ssl_protocols),NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,ngx_conf_set_bitmask_slot,NGX_HTTP_SRV_CONF_OFFSET,offsetof(ngx_http_upstream_check_srv_conf_t, ssl_protocols),ngx_upstream_check_ssl_protocols },{ ngx_string(check_ssl_server_name),NGX_HTTP_UPS_CONF|NGX_CONF_FLAG,ngx_conf_set_str_slot,NGX_HTTP_SRV_CONF_OFFSET,offsetof(ngx_http_upstream_check_srv_conf_t, ssl_server_name),NULL },
#endif通过以上配置指令可以将解析到的参数设置到ngx_http_upstream_check_srv_conf_s结构体对应的字段中。其中ngx_upstream_check_ssl_protocols是一个可选协议的列表定义如下
#if (NGX_HTTP_SSL)static ngx_conf_bitmask_t ngx_upstream_check_ssl_protocols[] {{ ngx_string(SSLv2), NGX_SSL_SSLv2 },{ ngx_string(SSLv3), NGX_SSL_SSLv3 },{ ngx_string(TLSv1), NGX_SSL_TLSv1 },{ ngx_string(TLSv1.1), NGX_SSL_TLSv1_1 },{ ngx_string(TLSv1.2), NGX_SSL_TLSv1_2 },{ ngx_string(TLSv1.3), NGX_SSL_TLSv1_3 },{ ngx_null_string, 0 }
};#endif3.2 模块的初始化
static ngx_http_module_t ngx_http_upstream_check_module_ctx {NULL, /* preconfiguration */ngx_http_upstream_check_init, /* postconfiguration */ngx_http_upstream_check_create_main_conf,/* create main configuration */ngx_http_upstream_check_init_main_conf, /* init main configuration */ngx_http_upstream_check_create_srv_conf, /* create server configuration */NULL, /* merge server configuration */ngx_http_upstream_check_create_loc_conf, /* create location configuration */ngx_http_upstream_check_merge_loc_conf /* merge location configuration */
};在以上代码中ngx_http_upstream_check_module_ctx结构体的初始化定义中ngx_http_upstream_check_init_main_conf函数将在配置文件的http块解析完成后进行初始化因此我们通过修改这个函数来实现ssl上下文的初始化即ngx_http_upstream_check_srv_conf_s的ssl指针的初始化。ssl是一个指向ngx_ssl_t的指针用来对ssl协议的相关参数进行设定并初始化ssl上下文。 以下是ngx_http_upstream_check_init_main_conf函数的代码
static char *
ngx_http_upstream_check_init_main_conf(ngx_conf_t *cf, void *conf)
{ngx_buf_t *b;ngx_uint_t i;ngx_http_upstream_srv_conf_t **uscfp;ngx_http_upstream_main_conf_t *umcf;umcf ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);b ngx_http_upstream_check_create_fastcgi_request(cf-pool,fastcgi_default_params,sizeof(fastcgi_default_params) / sizeof(ngx_str_t) / 2);if (b NULL) {return NGX_CONF_ERROR;}fastcgi_default_request.data b-pos;fastcgi_default_request.len b-last - b-pos;uscfp umcf-upstreams.elts;for (i 0; i umcf-upstreams.nelts; i) {if (ngx_http_upstream_check_init_srv_conf(cf, uscfp[i]) ! NGX_OK) {return NGX_CONF_ERROR;}}return ngx_http_upstream_check_init_shm(cf, conf);
}在以上代码中 for (i 0; i umcf-upstreams.nelts; i) {if (ngx_http_upstream_check_init_srv_conf(cf, uscfp[i]) ! NGX_OK) {return NGX_CONF_ERROR;}}这段代码是对所有配置的http upstream进行遍历然后对它进行初始化因为我们的ssl上下文信息每个upstream对应一个因此正好在ngx_http_upstream_check_init_srv_conf函数里面可以进行初始化。 在函数ngx_http_upstream_check_init_srv_conf的最后返回前我们添加ssl的初始化代码如下
static char *
ngx_http_upstream_check_init_srv_conf(ngx_conf_t *cf, void *conf)
{
......
#if (NGX_HTTP_SSL)/* 如果当前的监测类型是https才需要进行ssl的初始化设置 */if (check-type NGX_HTTP_CHECK_HTTPS) {/* 如果ssl_protocols没有设置那么默认开启NGX_SSL_TLSv1,NGX_SSL_TLSv1_1和NGX_SSL_TLSv1_2 */if (ucscf-ssl_protocols NGX_CONF_UNSET_UINT) {ucscf-ssl_protocols NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1|NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2;}/* 如果没有设置ssl_ciphers那么设置默认值为DEFAULT */if (ucscf-ssl_ciphers.len 0) {ngx_str_set(ucscf-ssl_ciphers,DEFAULT);}/* 为ssl分配内存 */ucscf-ssl ngx_pcalloc(cf-pool, sizeof(ngx_ssl_t));if (ucscf-ssl NULL) {return NGX_CONF_ERROR;}ucscf-ssl-log cf-log;/* 创建ssl上下文 */if (ngx_ssl_create(ucscf-ssl, ucscf-ssl_protocols, NULL) ! NGX_OK) {return NGX_CONF_ERROR;}/* 设置ssl上下文回收回调函数 */cln ngx_pool_cleanup_add(cf-pool, 0);if (cln NULL) {return NGX_CONF_ERROR;}cln-handler ngx_ssl_cleanup_ctx;cln-data ucscf-ssl;/* 设置可以支持的加密套件 */if (ngx_ssl_ciphers(cf, ucscf-ssl, ucscf-ssl_ciphers, 0) ! NGX_OK) {return NGX_CONF_ERROR;}}#endifreturn NGX_CONF_OK;
}【未完待续】