haproxy集成国密ssl功能[下]

上接[haproxy集成国密ssl功能上

4. 源码修改解析

  以下修改基本围绕haproxy的ssl_sock.c进行修改来展开的,为了将整个实现逻辑能够说明清楚,下述内容有部分可能就是直接摘抄haproxy的原有代码没有做任何修改,而大部分增加或者修改的内容则进行了特别的说明。

4.1 为bind指令的ssl子命令添加ntls选项解析能力


static struct bind_kw_list bind_kws = { "SSL", { }, {
......{ "force-tlsv10",          bind_parse_tls_method_options, 0 }, /* force TLSv10 */{ "force-tlsv11",          bind_parse_tls_method_options, 0 }, /* force TLSv11 */{ "force-tlsv12",          bind_parse_tls_method_options, 0 }, /* force TLSv12 */{ "force-tlsv13",          bind_parse_tls_method_options, 0 }, /* force TLSv13 */{ "force-ntlsv11",         bind_parse_tls_method_options, 0 }, /* force NTLSv11 */{ "generate-certificates", bind_parse_generate_certs,     0 }, /* enable the server certificates generation */{ "no-ca-names",           bind_parse_no_ca_names,        0 }, /* do not send ca names to clients (ca_file related) */{ "no-sslv3",              bind_parse_tls_method_options, 0 }, /* disable SSLv3 */{ "no-tlsv10",             bind_parse_tls_method_options, 0 }, /* disable TLSv10 */{ "no-tlsv11",             bind_parse_tls_method_options, 0 }, /* disable TLSv11 */{ "no-tlsv12",             bind_parse_tls_method_options, 0 }, /* disable TLSv12 */{ "no-ntlsv11",            bind_parse_tls_method_options, 0 }, /* disable TLSv13 */{ "no-tlsv13",             bind_parse_tls_method_options, 0 }, /* disable NTLSv11 */
......{ NULL, NULL, 0 },
}};

  这里添加了ntls、force-ntlsv11和no-ntlsv11三个指令选项。haproxy 通过INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);将指令选项的解析回调函数注册进去,在指令解析的时候将回调对应的选项解析函数。

4.1.1 ntls指令选项解析

  按照上面的配置,ntls的配置选项是交由bind_parse_ntls来解析的,源码如下:


/* parse the "ntls" bind keyword. Returns a set of ERR_* flags possibly with an error in <err>. */
static int bind_parse_ntls(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{char enc[MAXPATHLEN], sign[MAXPATHLEN], tls[MAXPATHLEN];int cfgerr = 0;int couple_cert = 0;const char *gm_cert_enc, *gm_cert_sign, *tls_cert;gm_cert_enc = gm_cert_sign = tls_cert = NULL;char* err2 = NULL;SSL_CTX *old_ctx = NULL;if (!*args[cur_arg + 1]) {memprintf(err, "'%s' : missing ntls enc certificate location", args[cur_arg]);return ERR_ALERT | ERR_FATAL;}else {gm_cert_enc = args[cur_arg + 1];}if (!*args[cur_arg + 2]) {memprintf(err, "'%s' : missing ntls sign certificate location", args[cur_arg]);return ERR_ALERT | ERR_FATAL;}else {gm_cert_sign = args[cur_arg + 2];}if (*args[cur_arg + 3]) {if (strstr(args[cur_arg + 3], ".pem") != NULL || strstr(args[cur_arg + 3], ".crt") != NULL) {/* 第三个参数必须是以.pem或.crt为扩展名的文件,这样子才会启用tls 和 ntls双证书模式 */couple_cert  = 1;tls_cert     = args[cur_arg + 1];gm_cert_enc  = args[cur_arg + 2];gm_cert_sign = args[cur_arg + 3];}}if (tls_cert) {if ((*tls_cert != '/' ) && global_ssl.crt_base) {if ((strlen(global_ssl.crt_base) + 1 + strlen(tls_cert) + 1) > MAXPATHLEN) {memprintf(err, "'%s' : tls certificate path too long", args[cur_arg]);return ERR_ALERT | ERR_FATAL;}snprintf(tls, sizeof(tls), "%s/%s",  global_ssl.crt_base, tls_cert);}else {strcpy(tls, tls_cert);}/* 加载tls证书 */cfgerr = ssl_sock_load_cert(tls, conf, &err2);if (cfgerr != 0) {memprintf(err, "load enc certificate %s failed, error:%s", tls, err2 ? err2: "" );if (err2) free(err2);return cfgerr;}}else {/* 如果没有tls证书,那么就没有调用ssl_sock_load_cert而创建一个新的ctx,在这里需要将conf->default_ctx置为空,让ssl_sock_load_ntls_cert新创建一个ctx,等ntls的enc和sign证书加载完成后,重新将conf->default_ctx设置回去。*/old_ctx = conf->default_ctx;conf->default_ctx = NULL;}if ((*gm_cert_enc != '/' ) && global_ssl.crt_base) {if ((strlen(global_ssl.crt_base) + 1 + strlen(gm_cert_enc) + 1) > MAXPATHLEN) {memprintf(err, "'%s' : enc certificate path too long", args[cur_arg]);return ERR_ALERT | ERR_FATAL;}snprintf(enc, sizeof(enc), "%s/%s",  global_ssl.crt_base, gm_cert_enc);}else {strcpy(enc, gm_cert_enc);}/* 加载ntls_enc证书 */cfgerr = ssl_sock_load_ntls_cert(enc, conf, 0, &err2);if (cfgerr != 0) {memprintf(err, "load enc certificate %s failed, error:%s",enc, err2 ? err2 : "");if (err2) free(err2);return cfgerr;}if ((*gm_cert_sign != '/' ) && global_ssl.crt_base) {if ((strlen(global_ssl.crt_base) + 1 + strlen(gm_cert_sign) + 1) > MAXPATHLEN) {memprintf(err, "'%s' : sign certificate path too long", args[cur_arg]);return ERR_ALERT | ERR_FATAL;}snprintf(sign, sizeof(sign), "%s/%s",  global_ssl.crt_base, gm_cert_sign);}else {strcpy(sign, gm_cert_sign);}/* 加载ntls_sign证书 */cfgerr = ssl_sock_load_ntls_cert(sign, conf, 1, &err2);if (cfgerr != 0) {memprintf(err, "load sign certificate %s failed, error:%s", sign, err2 ? err2 : "" );if (err2) free(err2);return cfgerr;}// 设置启用国密TLCP协议conf->enable_ntls = 1;/* 重新将default_ctx改成之前的old_ctx */if (old_ctx) {conf->default_ctx = old_ctx;}if (tls_cert) return cfgerr | 0x30000000;         /* 指明消耗3个参数 */elsereturn cfgerr | 0x20000000;         /* 指明消耗2个参数 */
}

  以上代码就是从配置指令中读取加密证书和签名证书,ntls可以同时支持国际和国密证书的加载,如果是双证书的情况,那么需要解析三个参数,所以返回的时候我们需要告诉配置解析框架到底消耗了几个参数,这个通过复用返回的错误值的高4个bit来实现。由于原来的haproxy框架是不支持可变个数参数的,因此,在兼容原始功能逻辑的基础上,需要略微修改一下haproxy的配置解析框架的代码,在cfg_parse-listen.c的cfg_parse_listen函数中,进行如下修改:

int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
{
......cur_arg = 2;while (*(args[cur_arg])) {static int bind_dumped;struct bind_kw *kw;char *err;kw = bind_find_kw(args[cur_arg]);if (kw) {char *err = NULL;int code, skip = 0;if (!kw->parse) {ha_alert("parsing [%s:%d] : '%s %s' : '%s' option is not implemented in this version (check build options).\n",file, linenum, args[0], args[1], args[cur_arg]);cur_arg += 1 + kw->skip ;err_code |= ERR_ALERT | ERR_FATAL;goto out;}code = kw->parse(args, cur_arg, curproxy, bind_conf, &err);/* skip表示回调函数在配置选项解析过程中,消耗了几个配置参数 */skip = (code >> 28) & 0x0000000F;  /* 从返回值中过滤出错误代码 */ err_code |= code & 0x0FFFFFFF;/* 用来兼容原生逻辑,如果解析函数没有返回了跳过多少个参数,则用配置中的设置 */if (skip == 0) {skip = kw->skip;}if (code & 0x0FFFFFFF) {  /* 如果本次调用配置解析回调函数返回错误了, 那么下面进行错误处理 */if (err && *err) {indent_msg(&err, 2);if (((code & (ERR_WARN|ERR_ALERT)) == ERR_WARN))ha_warning("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], err);elseha_alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], err);}elseha_alert("parsing [%s:%d] : '%s %s' : error encountered while processing '%s'.\n",file, linenum, args[0], args[1], args[cur_arg]);if (code & ERR_FATAL) {free(err);cur_arg += 1 + skip;goto out;}}free(err);cur_arg += 1 + skip;continue;}err = NULL;if (!bind_dumped) {bind_dump_kws(&err);indent_msg(&err, 4);bind_dumped = 1;}ha_alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'.%s%s\n",file, linenum, args[0], args[1], args[cur_arg],err ? " Registered keywords :" : "", err ? err : "");free(err);err_code |= ERR_ALERT | ERR_FATAL;goto out;}goto out;
......
}

  函数bind_parse_ntls是通过ssl_sock_load_ntls_cert来将这两个证书加载进bind_conf->default_ctx(ssl配置上下文),ssl_sock_load_ntls_cert代码如下:

#define FREE_CTX_RETURN(ctx, err)    		\if (ctx_new) {   					\SSL_CTX_free(ctx);  			\bind_conf->default_ctx = NULL; 	\}									\return (err)/* enc_sign = 0 表示加载加密证书  否则表示加载签名证书 */
static
int ssl_sock_load_ntls_cert(char 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/717512.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot+vue的疾病防控综合系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

计算机设计大赛 深度学习猫狗分类 - python opencv cnn

文章目录 0 前言1 课题背景2 使用CNN进行猫狗分类3 数据集处理4 神经网络的编写5 Tensorflow计算图的构建6 模型的训练和测试7 预测效果8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习猫狗分类 ** 该项目较为新颖&a…

Python测试框架pytest介绍用法

1、介绍 pytest是python的一种单元测试框架&#xff0c;同自带的unittest测试框架类似&#xff0c;相比于unittest框架使用起来更简洁、效率更高 pip install -U pytest 特点&#xff1a; 1.非常容易上手,入门简单,文档丰富&#xff0c;文档中有很多实例可以参考 2.支持简单的单…

C++内存模型与内存序

写在前面 在真正了解Memory Order的作用之前&#xff0c;曾经简单地将Memory Order等同于mutex和atomic来进行线程间数据同步&#xff0c;或者用来限制线程间的执行顺序&#xff0c;其实这是一个错误的理解。直到后来仔细研究了Memory Order之后&#xff0c;才发现无论是功能还…

Android 12 设置默认的屏幕亮度百分比

1、安卓每个版本的更新&#xff0c; 其核心代码也会随之更新&#xff0c;本次为Android 12 版本默认屏幕亮度的修改。 其中涉及的核心代码主要有&#xff1a; packages\apps\Settings\src\com\android\settings\display\BrightnessLevelPreferenceController.java frameworks…

力扣706:设计哈希映射

题目&#xff1a; 不使用任何内建的哈希表库设计一个哈希映射&#xff08;HashMap&#xff09;。 实现 MyHashMap 类&#xff1a; MyHashMap() 用空映射初始化对象void put(int key, int value) 向 HashMap 插入一个键值对 (key, value) 。如果 key 已经存在于映射中&#x…

【GPU驱动开发】- mesa编译与链接过程详细分析

前言 不必害怕未知&#xff0c;无需恐惧犯错&#xff0c;做一个Creator&#xff01; 一、总体框架图 暂时无法在飞书文档外展示此内容 二、Mesa API 处理 OpenGL 函数调用 Mesa API 负责实现 OpenGL 和其他图形 API 的函数接口。Mesa API 表是一个重要的数据结构&#xf…

c# 获得进程的标题

使用 System.Diagnostics.Process 类来获取所有 Internet Explorer 进程的标题。以下是如何做到这一点的代码示例&#xff1a; using System; using System.Diagnostics;class Program {static void Main(){foreach (Process process in Process.GetProcessesByName("iex…

数据中台的演进与实践——构建企业的数字核心_光点科技

数据中台&#xff0c;一个在近年来被频繁提及的概念&#xff0c;已经成为众多企业数字化转型的核心组成部分。然而&#xff0c;尽管它的重要性被业界广泛认可&#xff0c;对于数据中台的深入理解和有效实践仍然是许多企业面临的挑战。在本文中&#xff0c;我们将从数据中台的演…

从租完ecs云服务器 使用docker建立用户 全过程

一 登录root用户 ssh root公网ip 输入密码&#xff0c;若没有密码可以前往阿里云设置服务器root密码 二 创建新用户 并赋予 新用户sudo权限 adduser $USER usermod -aG sudo $USER 三 Ubuntu安装docker sudo apt-get remove docker docker-engine docker.io containerd ru…

蓝桥杯:门牌制作

题目 小蓝要为一条街的住户制作门牌号。 这条街一共有2020 位住户&#xff0c;门牌号从1 到2020 编号。 小蓝制作门牌的方法是先制作0 到9 这几个数字字符&#xff0c;最后根据需要将字符粘贴到门牌上&#xff0c;例如门牌1017 需要依次粘贴字符1、0、1、7&#xff0c;即需要1…

反向代理原理

反向代理是一种网络应用架构模式&#xff0c;主要用于将对一个或多个后端服务器的请求进行转发、负载均衡和缓存&#xff0c;以提高系统的安全性、性能和可靠性。 其原理如下&#xff1a; 1. 客户端向反向代理发送请求。 2. 反向代理服务器接收请求&#xff0c;并根据预设的规…

基于window安装Elasticsearch详细教程

目录 一、安装Java环境1.1 Java版本选择 二、下载和安装ES2.1 下载地址2.2 文件目录 3、启动服务3.1 以管理员身份打开cmd3.2 首次登录会有密码&#xff0c;需要记住3.3 访问 一、安装Java环境 1.1 Java版本选择 官网地址&#xff1a;https://www.elastic.co/cn/support/matr…

9个接口性能优化方案,RT从9000ms到180ms

昨天接到生产 SkyWalking 链路监控告警: 服务的百分位数响应时间在过去的 10 分钟内超过 2000 毫秒的次数达到 3 次。 经过不断的优化&#xff0c;将接口从 9000ms 优化到 180ms&#xff0c;先看结果 优化前&#xff1a; 优化后&#xff1a; 废话不多我们开始 一、定位性能差的…

Maven实战(2)之搭建maven私服

一, 背景: 如果使用国外镜像,下载速度比较慢; 如果使用阿里云镜像,速度还算OK,但是假如网速不好的时候,其实也是比较慢的; 如果没有网的情况下更加下载不了. 二, 本地仓库、个人/公司私服、远程仓库关系如下: 三, 下载安装nexus私服 略

Notepad3:告别Windows记事本,轻松进行文本编辑

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、什么是Notepad3&#xff1f;①Notepad3②核…

openGauss学习笔记-234 openGauss性能调优-系统调优-资源负载管理-资源管理准备-设置控制组

文章目录 openGauss学习笔记-234 openGauss性能调优-系统调优-资源负载管理-资源管理准备-设置控制组234.1 背景信息234.2 前提条件234.3 操作步骤234.3.1 创建子Class控制组和Workload控制组234.3.2 更新控制组的资源配额234.3.3 删除控制组 234.4 查看控制组的信息 openGauss…

第八节 龙晰Anolis 8.8 安装 DDE 桌面环境

一、前言 最小化安装的龙晰 Anolis OS 8.8 是不带图形化界面的&#xff0c;只能使用命令行&#xff0c;有些时候需要用到桌面环境&#xff0c;而DDE (Deepin Desktop Enviroment) 就是很好的桌面环境&#xff0c;它是指龙晰 Anolis 所搭载的中国自主桌面环境&#xff0c;用起来…

客户快递信息管理系统——导入文件识别存储

客户快递信息管理系统背景&#xff1a; 目前不少公司都提供网购服务&#xff0c;为了将商品快递给客户&#xff0c;就必须保存和管理客户的姓名、电话号码、邮寄地址等信息。为此&#xff0c;本项目要求完成一个小型客户快递信息管理系统&#xff0c;完成对客户快递信息的建立…

C++构造函数析构函数

构造和析构函数用于管理对象的初始化和清理工作&#xff0c;确保对象的正确生命周期管理。以下是其重要特性&#xff1a; 构造函数不能是虚函数 从存储空间角度&#xff1a; 虚函数是需要通过虚函数表和虚指针来调用的&#xff0c;如果用虚函数实现构造函数&#xff0c;而对象…