当前位置: 首页 > news >正文

nginx stream proxy 模块的ssl连接源码分析

目录

  • 1. 源起
  • 2. 分析验证环境的配置
  • 3. 源码分析
    • 3.1 代理模块的请求入口点分析
    • 3.2 发起与上游服务器的连接
    • 3.3 连接回调
    • 3.4 TCP连接建立成功后为上下游数据透传做准备
    • 3.5 TCP连接的ssl上下文初始化
    • 3.6 ssl握手成功后的处理
    • 3.7 连接数据的收与发

1. 源起

  我一直来对ssl建立连接的过程一知半解,以前分析nginx代码的时候一旦碰到ssl连接部分的代码都是直接跳过,前面在分析ngx_http_upstream_dynamic_module的时候正好想到了是不是可以给它添加一个能够支持https健康检查的功能,所以今天决定沉下心来仔细分析一下nginx本身的与上游服务器建立连接的实现逻辑。

  为了简单起见,我决定选用ngx_stream_proxy_module模块作为分析学习的目标,因为相对于ngx_http_stream_proxy_module来说,前者逻辑上更加纯粹,少了七层的业务逻辑,让我能够更加专注地去分析关于ssl连接处理逻辑部分。

  希望这次通过分析,能够对ssl连接的建立以及其后续的读写交互的实现逻辑有个整体的把握,在此基础上,将来为ngx_http_upstream_dynamic_module实现一个能够支持https主动健康检测的功能。

  这次,我准备采用官方原生的最新稳定版nginx 1.24.0作为分析对象。为什么不用tengine呢?因为现在的tengine还夹杂了国密openssl的支持逻辑,采用官方原生版本更加纯粹,让分析的目标更加聚焦。

2. 分析验证环境的配置

  配置一个分析验证环境来进行测试分析还是非常简单的,过程如下:

  1. 从官网下载好nginx 1.24.0版本后进行解压,然后用以下命令进行配置:

	./configure --prefix=`pwd` --with-stream --with-stream_ssl_module

  这样nginx从源码层面就开启了支持ssl的TCP代理能力。

  2. 对nginx.conf文件进行配置,配置内容如下:

#user  nobody;
worker_processes  1;#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;#pid        logs/nginx.pid;events {worker_connections  1024;
}stream {server {listen 9000;proxy_ssl on;               /* 连接上游服务器采用ssl协议 */proxy_pass 104.193.88.77:443;}
}

  3. 启动nginx,进行curl测试:

 curl "http://127.0.0.1:9000/test/" -v*   Trying 127.0.0.1:9000...
* Connected to 127.0.0.1 (127.0.0.1) port 9000 (#0)
> GET /test/ HTTP/1.1
> Host: 127.0.0.1:9000
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 500 Internal Server Error
< Content-Length: 0
< Content-Type: text/plain; charset=utf-8
< Date: Wed, 07 Feb 2024 02:57:01 GMT
< Server: bfe
< 
* Connection #0 to host 127.0.0.1 left intact

  从上面的信息中已经可以看到上游服务器已经响应了,只不过它响应是500错误,这个无所谓,至少表明https透明代理的功能已经正常工作了。

3. 源码分析

  本文主要聚焦在ssl连接逻辑的分析,所以中间会跳过和ssl逻辑不太相关的代码,虽然可能这部分对nginx本身的功能逻辑非常重要。另外,本文也假设只是TCP代理,不对UDP代理进行分析。

  下面直接进入主题,从代理模块的请求入口点开始分析。

3.1 代理模块的请求入口点分析

  代理模块的请求入口点是ngx_stream_proxy_handler函数,一旦客户端和nginx建立了TCP连接后,nginx就会调用代理模块的这个函数,开始与上游服务器建立连接。

  该函数源码主要就是以下列出的三个步骤:

static void
ngx_stream_proxy_handler(ngx_stream_session_t *s)
{/* 创建ngx_stream_upstream_t上下文,对它进行必要的初始化,并关联到ngx_stream_session_t中 *//* 如果上游服务器的地址已经解析好就调用ngx_stream_proxy_connect开始连接上游服务器 *//* 如果上游服务器的地址需要域名解析则开启异步解析流程 */   
}

  因此,我们需要重点关注的是ngx_stream_proxy_connect,它负责与上游服务器建立TCP连接。

3.2 发起与上游服务器的连接

static void
ngx_stream_proxy_connect(ngx_stream_session_t *s)
{ngx_int_t                     rc;ngx_connection_t             *c, *pc;ngx_stream_upstream_t        *u;ngx_stream_proxy_srv_conf_t  *pscf;c = s->connection;c->log->action = "connecting to upstream";pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);u = s->upstream;u->connected = 0;u->proxy_protocol = pscf->proxy_protocol;if (u->state) {u->state->response_time = ngx_current_msec - u->start_time;}u->state = ngx_array_push(s->upstream_states);if (u->state == NULL) {ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);return;}ngx_memzero(u->state, sizeof(ngx_stream_upstream_state_t));u->start_time = ngx_current_msec;u->state->connect_time = (ngx_msec_t) -1;u->state->first_byte_time = (ngx_msec_t) -1;u->state->response_time = (ngx_msec_t) -1;/* 创建SOCKET,并发起异步连接请求*/rc = ngx_event_connect_peer(&u->peer);ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "proxy connect: %i", rc);if (rc == NGX_ERROR) {ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);return;}u->state->peer = u->peer.name;if (rc == NGX_BUSY) {ngx_log_error(NGX_LOG_ERR, c->log, 0, "no live upstreams")

相关文章:

nginx stream proxy 模块的ssl连接源码分析

目录 1. 源起2. 分析验证环境的配置3. 源码分析3.1 代理模块的请求入口点分析3.2 发起与上游服务器的连接3.3 连接回调3.4 TCP连接建立成功后为上下游数据透传做准备3.5 TCP连接的ssl上下文初始化3.6 ssl握手成功后的处理3.7 连接数据的收与发1. 源起 我一直来对ssl建立连接的过…...

C#面:Static Nested Class 和 Inner Class 有什么不同

这是两种不同的类嵌套方式。 Static Nested Class &#xff1a; 是一个静态嵌套类&#xff0c;它是在外部类中定义的一个静态类。它可以访问外部类的静态成员和方法&#xff0c;但不能直接访问外部类的非静态成员和方法。静态嵌套类可以独立于外部类实例化&#xff0c;即可以…...

LeetCode、208. 实现 Trie (前缀树)【中等,自定义数据结构】

文章目录 前言LeetCode、208. 实现 Trie (前缀树)【中等&#xff0c;自定义数据结构】题目链接与分类思路 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领…...

java数据结构与算法刷题-----LeetCode151. 反转字符串中的单词

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 解题思路 这道题&#xff0c;可以理解为&#xff0c;将字符串颠倒&#xf…...

《Java 简易速速上手小册》第8章:Java 性能优化(2024 最新版)

文章目录 8.1 性能评估工具 - 你的性能探测仪8.1.1 基础知识8.1.2 重点案例&#xff1a;使用 VisualVM 监控应用性能8.1.3 拓展案例 1&#xff1a;使用 JProfiler 分析内存泄漏8.1.4 拓展案例 2&#xff1a;使用 Gatling 进行 Web 应用压力测试 8.2 JVM 调优 - 魔法引擎的调校8…...

mysql全国省市县三级联动创表sql(一)

1. 建表sql CREATE TABLE province (id VARCHAR ( 32 ) PRIMARY KEY COMMENT 主键,code CHAR ( 6 ) NOT NULL COMMENT 省份编码,name VARCHAR ( 40 ) NOT NULL COMMENT 省份名称 ) COMMENT 省份信息表;CREATE TABLE city (id VARCHAR ( 32 ) PRIMARY KEY COMMENT 主键,code …...

go面试题--使用两个goroutine交替打印数字与字母

使用两个goroutine交替打印数字与字母 题目如下&#xff1a; 使用两个goroutine交替打印序列&#xff0c;一个goroutine打印数字&#xff0c;另外一个goroutine打印字母&#xff0c;最终效果如下&#xff1a; 12AB34CD56EF78GH910IZ1112KL1314MN1516OP1718QR1920ST2122UV2324W…...

DolphinScheduler-3.2.0 集群搭建

目录 一、基础环境准备 1.1 组件下载地址 1.2 前置准备工作 二、 DolphinScheduler集群部署 2.1 解压安装包 2.2 配置数据库 2.3 准备 DolphinScheduler 启动环境 2.3.1 配置用户免密及权限 2.3.2 配置机器 SSH 免密登陆 2.3.3 启动 zookeeper集群 2.3.4 修改instal…...

07:Kubectl 命令详解|K8S资源对象管理|K8S集群管理(重难点)

Kubectl 命令详解&#xff5c;K8S资源对象管理&#xff5c;K8S集群管理 kubectl管理命令kubectl get 查询资源常用的排错命令kubectl run 创建容器 POD原理pod的生命周期 k8s资源对象管理资源文件使用资源文件管理对象Pod资源文件deploy资源文件 集群调度的规则扩容与缩减集群更…...

【设计模式】springboot3项目整合模板方法深入理解设计模式之模板方法(Template Method)

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《Spring 狂野之旅&#xff1a;底层原理高级进阶》 &#x1f680…...

Windows搭建docker+k8s

安装Docker Desktop 从官网下载&#xff0c;然后直接安装即可&#xff0c;过程很简单&#xff0c;一直Next就行。 有一点需要注意就是要看好对应的版本&#xff0c;因为后边涉及到版本的问题。 https://www.docker.com/products/docker-desktop 安装完成&#xff0c;双击图…...

年假作业10

一、选择题 BBDBACCCAD 二、填空题 1,4,13,40 3715 358 5 2 6 1 5 4 8 2 0 2 三、编程题 1、 #include <iostream> #include<array> #include <limits> using namespace std; int main() {array<int,10> score;array<int,10>::iterat…...

[ai笔记4] 将AI工具场景化,应用于生活和工作

欢迎来到文思源想的AI空间&#xff0c;这是技术老兵重学ai以及成长思考的第4篇分享内容&#xff01; 转眼已经到了大年初三&#xff0c;但是拜年的任务还只完成了一半&#xff0c;准备的大部头的书&#xff0c;现在也就看了两本&#xff0c;还好AI笔记通过每天早起坚持了下来。…...

【生产实测可用】Redis修改集群弱口令

起因 漏扫redis连接发现弱口令需要修改 先连上去看看是空口令还是弱口令 redis-cli -p 6379 -h a.b.c.d info sentinel找到启动服务器的配置文件 cp -av /app/redis-7001/redis.conf /app/redis-7001/redis.conf.bak20240207 echo "requirepass 口令" >>/a…...

备战蓝桥杯---图论基础理论

图的存储&#xff1a; 1.邻接矩阵&#xff1a; 我们用map[i][j]表示i--->j的边权 2.用vector数组&#xff08;在搜索专题的游戏一题中应用过&#xff09; 3.用邻接表&#xff1a; 下面是用链表实现的基本功能的代码&#xff1a; #include<bits/stdc.h> using nam…...

[office] excel2003进行可视性加密的方法 #媒体#其他#知识分享

excel2003进行可视性加密的方法 Excel如何对重要文件进行可视性的加密处理呢?下面是小编带来的关于excel2003进行可视性加密的方法&#xff0c;希望阅读过后对你有所启发! excel2003进行可视性加密的方法&#xff1a; 可视性加密步骤1&#xff1a;打开你要加密的excel2003文档…...

算法沉淀——分治算法(leetcode真题剖析)

算法沉淀——分治算法 快排思想01.颜色分类02.排序数组03.数组中的第K个最大元素04.库存管理 III 归并思想01.排序数组02.交易逆序对的总数03.计算右侧小于当前元素的个数04.翻转对 分治算法是一种解决问题的算法范式&#xff0c;其核心思想是将一个大问题分解成若干个小问题&a…...

Qt 进程守护程序

Qt 进程守护程序 简单粗暴的监控&#xff0c;方法可整合到其他代码。 一、windows环境下 1、进程查询函数 processCount函数用于查询系统所有运行的进程中该进程运行的数量&#xff0c;比如启动了5个A进程&#xff0c;该函数查询返回的结果就为5。 windows下使用了API接口查询…...

Linux_文件系统

假定外部存储设备为磁盘&#xff0c;文件如果没有被使用&#xff0c;那么它静静躺在磁盘上&#xff0c;如果它被使用&#xff0c;则文件将被加载进内存中。故此&#xff0c;可以将文件分为内存文件和磁盘文件。 内存文件 磁盘文件 软、硬链接 一.内存文件 1.1 c语言的文件接口 …...

算法沉淀——链表(leetcode真题剖析)

算法沉淀——链表 01.两数相加02.两两交换链表中的节点03.重排链表04.合并 K 个升序链表05.K个一组翻转链表 链表常用技巧 1、画图->直观形象、便于理解 2、引入虚拟"头节点" 3、要学会定义辅助节点&#xff08;比如双向链表的节点插入&#xff09; 4、快慢双指针…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...