说明:这里只是提供一种思路,提取代码数据之前的一个过程
nginx.conf配置
upstream tomcat_server {
server 127.0.0.1:8080;
}
server {
listen 443;
ssl on;
ssl_certificate /usr/local/nginx/conf/api.bz.crt;
ssl_certificate_key /usr/local/nginx/conf/api.bz_nopass.key;
server_name jueduiyingxiong.oicp.net;
index index.html index.htm index.jsp default.jsp index.do default.do;
root /data0/htdocs/www;
if (-d $request_filename)
{
rewrite ^/(.*)([^/])$ permanent;
}
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_pass
}
先总体了解吧:
一、ngx_event_openssl.c //事件模块
1、模块:
ngx_module_t ngx_openssl_module = {
NGX_MODULE_V1,
&ngx_openssl_module_ctx, /* module context */
ngx_openssl_commands, /* module directives */
NGX_CORE_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
ngx_openssl_exit, /* exit master */
NGX_MODULE_V1_PADDING
};
可以看出:
type 为 NGX_CORE_MODULE 为core模块
主进程退出的时候走ngx_openssl_exit:
static void ngx_openssl_exit(ngx_cycle_t *cycle)
{
EVP_cleanup();
ENGINE_cleanup();
}
对应的命令有:ngx_openssl_commands
static ngx_command_t ngx_openssl_commands[] = {
{ ngx_string("ssl_engine"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
ngx_openssl_engine,
0,
0,
NULL },
ngx_null_command
};
当调用set的时候,如果定义了“ssl_engine” 那么会调用:
static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_openssl_conf_t *oscf = conf;
ENGINE *engine;
ngx_str_t *value;
if (oscf->engine) {
return "is duplicate";
}
oscf->engine = 1;
value = cf->args->elts;
engine = ENGINE_by_id((const char *) value[1].data);
if (engine == NULL) {
ngx_ssl_error(NGX_LOG_WARN, cf->log, 0,
"ENGINE_by_id(\"%V\") failed", &value[1]);
return NGX_CONF_ERROR;
}
if (ENGINE_set_default(engine, ENGINE_METHOD_ALL) == 0) {
ngx_ssl_error(NGX_LOG_WARN, cf->log, 0,
"ENGINE_set_default(\"%V\", ENGINE_METHOD_ALL) failed",
&value[1]);
ENGINE_free(engine);
return NGX_CONF_ERROR;
}
ENGINE_free(engine);
return NGX_CONF_OK;
}
2、上下文信息:
static ngx_core_module_t ngx_openssl_module_ctx = {
ngx_string("openssl"),
ngx_openssl_create_conf,
NULL
};
说明:显然是核心模块,创建conf配置时走:
static void * ngx_openssl_create_conf(ngx_cycle_t *cycle)
{
ngx_openssl_conf_t *oscf;
oscf = ngx_pcalloc(cycle->pool, sizeof(ngx_openssl_conf_t));
if (oscf == NULL) {
return NULL;
}
/*
* set by ngx_pcalloc():
*
* oscf->engine = 0;
*/
return oscf;
}
3、只是分配这个结构的内存:
typedef struct {
ngx_uint_t engine; /* unsigned engine:1; */
} ngx_openssl_conf_t;
总结:
openssl 事件 支持配置:ssl_engine;其他函数使用于其他类内部
二、ngx_http_ssl_module.c //ssl模块
1、模块:
ngx_module_t ngx_http_ssl_module = {
NGX_MODULE_V1,
&ngx_http_ssl_module_ctx, /* module context */
ngx_http_ssl_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
可以看出:NGX_HTTP_MODULE 作为http模块集成;
二、上下文信息:
static ngx_http_module_t ngx_http_ssl_module_ctx = {
ngx_http_ssl_add_variables, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
ngx_http_ssl_create_srv_conf, /* create server configuration */
ngx_http_ssl_merge_srv_conf, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
11看出,在读取配置文件前: 保存对应的ngx_http_ssl_vars[] 处理方式(http里面的处理方式)
static ngx_int_t ngx_http_ssl_add_variables(ngx_conf_t *cf)
{
ngx_http_variable_t *var, *v;
for (v = ngx_http_ssl_vars; v->name.len; v++) {
var = ngx_http_add_variable(cf, &v->name, v->flags);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = v->get_handler;
var->data = v->data;
}
return NGX_OK;
}
22 create server 创建server配置的时候:设置配置的其他基本信息
static void * ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
{
ngx_http_ssl_srv_conf_t *sscf;
sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t));
if (sscf == NULL) {
return NULL;
}
sscf->enable = NGX_CONF_UNSET;
sscf->prefer_server_ciphers = NGX_CONF_UNSET;
sscf->verify = NGX_CONF_UNSET_UINT;
sscf->verify_depth = NGX_CONF_UNSET_UINT;
sscf->builtin_session_cache = NGX_CONF_UNSET;
sscf->session_timeout = NGX_CONF_UNSET;
return sscf;
}
33merge server 合并配置:
ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) //把多个配置合并为相应父的配置
2、指令 只是部分需要配置的保留,可以看出,只是字符的拷贝和设置而已
static ngx_command_t ngx_http_ssl_commands[] = {
{ ngx_string("ssl"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_http_ssl_enable,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, enable),
NULL },
{ ngx_string("ssl_certificate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, certificate),
NULL },
{ ngx_string("ssl_certificate_key"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, certificate_key),
NULL },
};
三、、、、下面来看实际调用流程(初始化的过程)
1、初始化调用(服务器启动):
ngx_int_t ngx_ssl_init(ngx_log_t *log)
2、在下面函数内部
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
调用配置信息所对应的函数
module->create_conf(cycle);
ngx_openssl_create_conf(ngx_cycle_t *cycle)
oscf = ngx_pcalloc(cycle->pool, sizeof(ngx_openssl_conf_t));
module->create_srv_conf(cf);
ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t));
if (module->preconfiguration(cf) != NGX_OK) { //调用先前配置
ngx_http_ssl_add_variables(ngx_conf_t *cf) //保存配置信息
for (v = ngx_http_ssl_vars; v->name.len; v++) {
3、指令调度
rv = cmd->set(cf, cmd, conf);// 调度指令的钩子 set
ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
//ups上会调用多次
mconf = module->create_srv_conf(cf);
ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
rv = cmd->set(cf, cmd, conf);// 调度指令的钩子 set
ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ssl
rv = module->merge_srv_conf(cf, saved.srv_conf[ctx_index],cscfp[s]->ctx->srv_conf[ctx_index]);
ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) 里面创建了ssl协议
ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
#if (NGX_HTTP_SSL) 为1
ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
prev->upstream.ssl_session_reuse, 1);
#endif
conf->upstream.ssl = prev->upstream.ssl;
4、监听的时候对服务器监听
ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t
ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port)
if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {
#if (NGX_HTTP_SSL)
addrs[i].conf.ssl = addr[i].opt.ssl;
#endif
四、接收 处理(尚未有证书)
events = epoll_wait(ep, event_list, (int) nevents, timer); events 1
rev->handler = 0x4958a8
s = accept4 lc->fd = 9 s = 10
events = epoll_wait events = 2
rev->handler = 0x4958a8
s = accept4(lc->fd s = 11
rev->handler = 0x439127
开始调用ssl
ngx_http_init_request(ngx_event_t *rev)
#if (NGX_HTTP_SSL)
{
ngx_http_ssl_srv_conf_t *sscf;
建立ssl的上下文套接口
if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER)
上面函数内部实现:
sc->connection = SSL_new(ssl->ctx);
if (SSL_set_fd(sc->connection, c->fd) == 0) {
SSL_set_accept_state(sc->connection);
if (SSL_set_ex_data(sc->connection, ngx_ssl_connection_index, c) == 0) {
rev->handler = ngx_http_ssl_handshake;
r->main_filter_need_in_memory = 1;
rev->handler = 0x439913
第一次读取数据做验证https 的加密版本
n = recv(c->fd, (char *) buf, 1, MSG_PEEK); c->fd = 10 n = 1
if (n == 1) {
if (buf[0] & 0x80 /* SSLv2 */ || buf[0] == 0x16 /* SSLv3/TLSv1 */) {
做握手操作
rc = ngx_ssl_handshake(c); rc = -1
n = SSL_do_handshake(c->ssl->connection);
握手时回调,通过调试可以看到有下列函数在调用,就是握手内部的调用了
ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); n = 0 SSL_get_ex_data(ssl_conn, ngx_ssl_connection_index)
{
"ssl23_accept() "
ssl23_accept()
ssl3_accept()
ssl3_accept()
ssl3_accept()
ssl3_accept()
"ssl3_accept() "
ssl3_accept()
"ssl3_accept() "
ssl23_get_client_hello()
ssl23_accept()
}
进行握手失败的处理
ngx_http_ssl_handshake_handler(c);
}
ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
ngx_http_close_connection(ngx_connection_t *c)
if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
mode = SSL_get_shutdown(c->ssl->connection);
SSL_set_quiet_shutdown(c->ssl->connection, 1);
SSL_set_shutdown(c->ssl->connection, mode);
ngx_close_connection(c);
ngx_del_conn(c, NGX_CLOSE_EVENT);
返回了
//从新请求,走原来的路,但是不是调用两次了,后面调试就是一次了呢(可能是第一次请求会走两次)
有认证////////////////
rev->handler = 0x4958a8
accept4 s = 10
rev->handler = 0x439127
rev->handler = ngx_http_ssl_handshake;
rev->handler = 0x439913
n = recv(c->fd, (char *) buf, 1, MSG_PEEK); c->fd = 10 buf = "\026" //说明是https请求
rc = ngx_ssl_handshake(c); rc = 0
n = SSL_do_handshake(c->ssl->connection); n = 1
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
//握手成功后的设置
c->ssl->handshaked = 1;
c->recv = ngx_ssl_recv;
c->send = ngx_ssl_write;
c->recv_chain = ngx_ssl_recv_chain;
c->send_chain = ngx_ssl_send_chain;
握手处理 和常规处理一样,读取请求头和处理等操作
ngx_http_ssl_handshake_handler(c);
c->ssl->no_wait_shutdown = 1;
c->read->handler = ngx_http_process_request_line;
ngx_http_process_request_line(c->read);
n = ngx_http_read_request_header(r);
ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size)
这里就是为什么要在初始化的时候设置一个读取标识了(看博文“nginx openssl 的集成代码流程”)
第一次
n = SSL_read(c->ssl->connection, buf, size); n = 1 buf = 0x77c430 "G"
c->ssl->last = ngx_ssl_handle_recv(c, n);
第二次n = SSL_read(c->ssl->connection, buf, size); n = 536buf = 0x77c431 "ET / HTTP/1.1\r\nAccept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/
x-sh ...
第三次n = SSL_read(c->ssl->connection, buf, size); n = -1 uf = 0x77c649 "" //表示读取完毕,这要根据读取字节大小来确定循环次数
这里点一下:如果有错,第一次握手的时候会发生错误情况是由于有数据正在写,所有会放到下个循环处理;这是根据内核处理方式来确定循环的。
sslerr = SSL_get_error(c->ssl->connection, n);
合成后的结果
r->header_in->last = 0x77c430 "GET / HTTP/1.1\r\nAccept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-s ...
处理完成后获取发送的信息发送给客户端
ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
n = SSL_write(c->ssl->connection, data, size);data = 0x784440 "HTTP/1.1 200 OK\r\nServer: nginx/1.0.12\r\nDate: Sun, 03 Mar 2013 07:42:02 GMT\r
\nContent- ... size = 382 //发送完成后,客户端返回
发送完成后等待超时,或其他错误,就走下面的步骤
ngx_http_finalize_request(r, rc);
ngx_http_finalize_connection(r);
ngx_ssl_free_buffer(c);c->fd = 11
其他细节
//一般请求,如何判断
wev->handler = 0x43c459
if (sscf->enable || addr_conf->ssl) { //正常 sscf->enable = 0
初始化:
ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
设置:enable 为 1
如果是http端口为443 请求
如果非安全协议,第一次recv就得到 buf = "G"
ngx_http_read_request_header(ngx_http_request_t *r)、
发送的内容就是:
400 Bad Request
The plain HTTP request was sent to HTTPS port
nginx/1.0.12
//成功的时候,第一次do——handel 握手的时候返回-1表示可读,进入下一次循环,下次循环的时候直接进入读取状态
c->ssl->handler = ngx_http_ssl_handshake_handler;
rev->handler = 0x498572
这次重新握手 ngx_ssl_handshake(ngx_connection_t *c)
ngx_http_ssl_handshake_handler(ngx_connection_t *c) 处理握手
这次循环读取
n = SSL_read(c->ssl->connection, buf, size);
请求完毕后关闭流程:
//非https 请求端口是这样关闭的:
ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c)
{
int n, sslerr, mode;
ngx_err_t err;
if (c->timedout) { //超时走
mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
SSL_set_quiet_shutdown(c->ssl->connection, 1);
} else {
mode = SSL_get_shutdown(c->ssl->connection);
}
SSL_set_shutdown(c->ssl->connection, mode);
ngx_ssl_clear_error(c->log);
n = SSL_shutdown(c->ssl->connection);
sslerr = 0;
if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) {
SSL_free(c->ssl->connection);
c->ssl = NULL;
return NGX_OK;
}
return NGX_ERROR;
}
//没有CA的时候
ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c)
{
int n, sslerr, mode;
ngx_err_t err;
if (c->timedout) { //超时
mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
SSL_set_quiet_shutdown(c->ssl->connection, 1);
} else {
mode = SSL_get_shutdown(c->ssl->connection);
if (c->ssl->no_wait_shutdown) {
mode |= SSL_RECEIVED_SHUTDOWN;
}
if (c->ssl->no_send_shutdown) {
mode |= SSL_SENT_SHUTDOWN;
}
if (c->ssl->no_wait_shutdown && c->ssl->no_send_shutdown) {
SSL_set_quiet_shutdown(c->ssl->connection, 1);
}
}
SSL_set_shutdown(c->ssl->connection, mode);
ngx_ssl_clear_error(c->log);
n = SSL_shutdown(c->ssl->connection);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
sslerr = 0;
if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) {
SSL_free(c->ssl->connection);
c->ssl = NULL;
return NGX_OK;
}
return NGX_ERROR;
}
//有认证的时候
ngx_ssl_shutdown(ngx_connection_t *c)
{
int n, sslerr, mode;
ngx_err_t err;
if (c->timedout) { //超时,可能是读取或写入超时导致
mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
SSL_set_quiet_shutdown(c->ssl->connection, 1);
} else {
mode = SSL_get_shutdown(c->ssl->connection);
if (c->ssl->no_wait_shutdown) {
mode |= SSL_RECEIVED_SHUTDOWN;
}
if (c->ssl->no_send_shutdown) {
mode |= SSL_SENT_SHUTDOWN;
}
if (c->ssl->no_wait_shutdown && c->ssl->no_send_shutdown) {
SSL_set_quiet_shutdown(c->ssl->connection, 1);
}
}
SSL_set_shutdown(c->ssl->connection, mode);
ngx_ssl_clear_error(c->log);
n = SSL_shutdown(c->ssl->connection);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
sslerr = 0;
/* SSL_shutdown() never returns -1, on error it returns 0 */
if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) {
SSL_free(c->ssl->connection);
c->ssl = NULL;
return NGX_OK;
}
return NGX_ERROR;
}
总结:
上面只是给了一个分析,openssl的一个流程,详细流程看博文“nginx openssl 的集成代码流程”