Go 实现 TLS 双向认证

Python013

Go 实现 TLS 双向认证,第1张

将会在 config 文件夹中生成 ca.key 和 ca.crt 文件

将会在 config 文件夹中生成 server.key 、 server.csr 和 server.crt 文件

签名方式: SHA-256 ,默认的 SHA-1 签名算法安全性不够高,Go 中会出现警告。

将会在 config 文件夹中生成 client.key 、 client.csr 和 client.crt 文件

签名方式: SHA-256 ,默认的 SHA-1 签名算法安全性不够高,Go 中会出现警告。

wireshark 截图如下:

在写websocket包的时候发现一个比较有趣问题!go 使用 TLS验证的时候发现 websocket 使用不了。深入了解发现其中奥秘:go 在执行 TLS 验证时候默认是使用 http2 协议进行的!但是 websocket 是无法支持 http2 协议(暂时),导致这个问题所在的原因!

使用空 map 来使用 http1.x协议

因为默认支持h2,所有我们把降到http1.x。

使用 http.Hijacker 对其进行劫持 net.Conn , 让程序员自己控制使用!其实这个时候已经脱离 http 协议规范!

发现使用 Hijacker 会脱离 http 协议范畴,可以解决h2与websocket的相关问题!

协议: 状态码:101 , Upgrade , Connection, Sec-WebSocket-Accept

实现最简单 websocket 连接!

websocket连接已经建立,有些 sec 是默认添加上去!

根据 http.Listen 进行向下追踪

在 func (srv *Server) Serve(l net.Listener) error 发现原由

对 c.setState 进入分析

发现当 case 是 Hijack【StateHijacked, StateClosed】状态时候执行 trackConn

add 为 false ,对其 delete(s.activeConn,c) 。Hijacker是满足相关条件

所以在 go c.serve(connCtx) 里面不在给 Hijacker 进行操作!导致 http header 无法设置!最后交给程序员自己操作!

go中自带的rpc可以直接复用http server处理请求的那一套流程去创建连接,连接创建完毕后再使用Hijack方法拿到连接。

注: github.com/gorilla/websocket

这包就接入 HIjacker ,直接使用现成包就香~~~~~

CoreDNS是使用go语言编写的快速灵活的DNS服务,采用链式插件模式,每个插件实现独立的功能,底层协议可以是tcp/udp,也可以是TLS,gRPC等。默认监听所有ip地址,可使用bind插件指定监听指定地址。

格式如下

SCHEME是可选的,默认值为dns://,也可以指定为tls://,grpc://或者https://。

ZONE是可选的,指定了此dnsserver可以服务的域名前缀,如果不指定,则默认为root,表示可以接收所有的dns请求。

PORT是选项的,指定了监听端口号,默认为53,如果这里指定了端口号,则不能通过参数-dns.port覆盖。

一块上面格式的配置表示一个dnsserver,称为serverblock,可以配置多个serverblock表示多个dnsserver。

下面通过一个例子说明,如下配置文件指定了4个serverblock,即4个dnsserver,第一个监听端口5300,后面三个监听同一个端口53,每个dnsserver指定了特定的插件。

下图为配置的简略图

a. 从图中可看到插件执行顺序不是配置文件中的顺序,这是因为插件执行顺序是在源码目录中的plugin.cfg指定的,一旦编译后,顺序就固定了。

b. .根serverblock虽然指定了health,但是图中却没有,这是因为health插件不参与dns请求的处理。能处理dns请求的插件必须提供如下两个接口函数。

dns请求处理流程

收到dns请求后,首先根据域名匹配zone找到对应的dnsserver(最长匹配优先),如果没有匹配到,则使用默认的root dnsserver。

找到dnsserver后,就要按照插件顺序执行其中配置的插件,当然并不是配置的插件都会被执行,如果某个插件成功找到记录,则返回成功,否则根据插件是否配置了fallthrough等来决定是否执行下一个插件。

plugin.cfg

源码目录下的plugin.cfg指定了插件执行顺序,如果想添加插件,可按格式添加到指定位置。

源码目录下的Makefile根据plugin.cfg生成了两个go文件:zplugin.go和zdirectives.go。

core/dnsserver/zdirectives.go将所有插件名字放在一个数组中。

codedns 主函数

codedns.go 首先导入了包"github.com/coredns/coredns/core/plugin",此包内只有一个文件zplugin.go,此文件为自动生成的,主要导入了所有的插件,执行每个插件的init函数。

接着执行 run.go Run

此文件又引入了包"github.com/coredns/coredns/core/dnsserver",其init函数在 dnsserver/register.go 文件中,如下所示,主要是注册了serverType

剩下的就是解析参数,解析配置文件后,执行caddy.Start。

这里就是根据配置文件中指定的serverblock,执行插件的setup进行初始化,创建对应的server,开始监听dns请求

tcp协议调用Serve,udp协议调用ServePacket

收到DNS请求后,调用ServeDNS,根据域名匹配dnsserver,如果没有匹配不到则使用根dnsserver,然后执行dnsserver中配置的插件

以k8s插件为例

参考

//如何写coredns插件

http://dockone.io/article/9620

//coredns源码分析

https://wenku.baidu.com/view/34cabc1e346baf1ffc4ffe4733687e21af45ff7c.html

https://blog.csdn.net/zhonglinzhang/article/details/99679323

https://www.codercto.com/a/89703.html

//NodeLocal DNSCache

https://www.cnblogs.com/sanduzxcvbnm/p/16013560.html

https://blog.csdn.net/xixihahalelehehe/article/details/118894971