一只小小 發表於 2022-11-24 22:41:00

openwrt-22.03_debian_centos_ocserv_haproxy_stunnel

<h1 id="openwrt-2203_debian_centos_ocserv_haproxy_stunnel">openwrt-22.03_debian_centos_ocserv_haproxy_stunnel</h1>
<p><strong>转载注明来源: 本文链接 来自osnosn的博客</strong>,写于 2022-11-23.</p>
<h1 id="前言">前言</h1>
<ul>
<li>客户端:AnyConnect,由思科推出的客户端,目前已有支持Windows、Android、iOS、OS X、Ubuntu、WebOS等操作系统的版本;</li>
<li>也是基于SSL的加密连接。唯一的优点就是,openConnect的苹果客户端,叫 AnyConnect,国内市场就能免费装。</li>
<li>win客户端【gui.openconnect-vpn.net】【gitlab】【github】</li>
<li>win10,macOS,linux-gui 【anylink-client】</li>
<li>android 【ics-openconnect】【AnyLink-Secure-Client】</li>
<li>macOS 【openconnectui2】【SwiftConnect】</li>
</ul>
<h1 id="openwrt-2102">openwrt-21.02</h1>
<ul>
<li>网上有很多文章,自行搜索。</li>
</ul>
<h1 id="openwrt-2203">openwrt-22.03</h1>
<p>防火墙使用的是fw4,即nftables。</p>
<h2 id="安装配置">安装配置</h2>
<p>2022-11记录</p>
<h3 id="安装-openconnect-server">安装 OpenConnect Server。</h3>
<pre><code>opkg update
opkg install ocserv luci-app-ocserv
</code></pre>
<p>服务器证书,安装后就自动生成了。</p>
<h3 id="去web页面配置">去web页面配置。</h3>
<ul>
<li>(2022-11测)</li>
<li>Server Settings -&gt; Gerneal Settings
<ul>
<li>Enable server: 勾上,启用服务</li>
<li>User Authentication: plain</li>
<li>Port: 默认 4443, (按需修改)</li>
<li>Max clients: 8, (按需修改)</li>
<li>Max same clients: 2, (按需修改)</li>
<li>Dead peer detection time: 默认 180secs</li>
<li>Predictable IPs: 默认勾上。</li>
<li>Enable compression: 勾上,启用压缩</li>
<li>Enable UDP: 默认勾上。</li>
<li>AnyConnect client compatibility: 默认勾上。</li>
<li>Enable proxy arp: 不勾。(如果勾上,IP段的配置需要深厚的知识)</li>
<li>VPN IPv4-Network-Address: 192.168.100.1 设置IPv4, 建议和 lan不一样网段。</li>
<li>VPN IPv4-Netmask: 255.255.255.0</li>
<li>VPN IPv6-Network-Address: 留空</li>
<li>DNS servers: 设置DNS server的IP。(推送给client用的),<strong>建议测试一下,如果配错IP,对后面调试影响很大</strong></li>
<li>Routing table: 添加路由规则。(推送给client用的)
<ul>
<li>netmask,建议写数字。比如 "255.255.255.0" 写为 24 。这样不容易出错。</li>
<li>如果想让客户端全局使用这个连接,只设置一个 0/0的缺省路由,IP:0, netmask:0,不要写 "0.0.0.0"</li>
</ul>
</li>
</ul>
</li>
<li>Server Settings -&gt; Edit Template,修改欢迎词。<br>
<code>banner = "Welcome to MyHost"</code></li>
<li>User Settings
<ul>
<li>添加用户 (用户名,密码)</li>
</ul>
</li>
</ul>
<h3 id="设置防火墙允许wan口访问ocserv端口">设置防火墙,允许wan口访问ocserv端口。</h3>
<p>(让客户端可以连接ocserv服务。)</p>
<ul>
<li>主用TCP,如果UDP可用,就用。</li>
<li>如果openwrt, 有LAN, <span style="background: rgba(204, 255, 204, 1)"><strong>有WAN</strong></span>。设置input规则,(2022-11测)</li>
<li>防火墙-&gt; Traffic Rules
<ul>
<li>添加<pre><code>协议: TCP+UDP
Source zone: WAN
Source address: 留空
Source Port: 留空
Destination zone: Device (input)
Destination address: 留空
Destination Port: 4443 (按需,多个端口空格隔开)
Action: accept
Restrict to address family: IPv4 only 或者 IPv4 and IPv6
</code></pre>
</li>
</ul>
</li>
<li>如果openwrt只有LAN, <span style="background: rgba(255, 204, 204, 1)"><strong>无WAN</strong></span> (2024-09测)<br>
因为LAN对于端口访问无限制,所以不用创建 Traffic Rules</li>
</ul>
<h3 id="设置防火墙允许openconnect客户端访问lanwan">设置防火墙,允许openConnect客户端访问Lan/wan。</h3>
<p>(客户端连接后,客户机的访问限制。)</p>
<ul>
<li>ocserv 没有加入 firewall ZONE 的设置。所以只能手动添加转发规则。</li>
<li>检查 <code>sysctlnet.ipv4.ip_forward</code> 应该显示 = 1<br>
op中 ip_forward 默认就是 1。 所以不用管。</li>
<li>设置forward规则,(2022-11测)<br>
防火墙-&gt; Traffic Rules
<ul>
<li>添加<pre><code>协议: Any
Source zone: Any zone(forward)
Source address: ocserv 的IP段,比如 192.168.100.0/24
Destination zone: WAN 或 Any
   选Any,一条规则涵盖所有出口。或者添加多条规则,分别(按需)设置为WAN,LAN,wg0,
Destination address: 留空
Action: accept
Restrict to address family: IPv4 only (按需)
</code></pre>
</li>
</ul>
</li>
<li>op默认有一条规则,对于已经建立的连接,返回的数据包是允许的。<br>
会自动匹配,返回到目标地址192.168.100.0/24的转发。<br>
所以,<strong>不需要</strong>专门配置,返回数据包的规则。</li>
<li>如果op<span style="background: rgba(204, 255, 204, 1)"><strong>有WAN口</strong></span>,则已经有Masquerade规则。无需额外添加。(2022-11测)</li>
<li>如果op<span style="background: rgba(255, 204, 204, 1)"><strong>无WAN</strong></span><strong>,<span style="background: rgba(204, 255, 204, 1)">有LAN</span></strong>,则需要手工添加IP伪装规则。(2024-09测)<br>
防火墙-&gt; NAT Rules
<ul>
<li>添加<pre><code>Name: 自己取名
Restrict address family: Automatic(默认)/ipv4/ipv6,选自动,或按需
Protocol: Any(默认) 或 按需
Outbound zone: LAN
   如果还有其他出口需要IP伪装,则添加多条NAT规则,设定对应的Outbound zone
Source address: ocserv 的IP段,比如 192.168.100.0/24
Destination address: Any
Action: MASQUERADE (IP伪装)
其他选项卡的内容,全部用默认,不修改。
</code></pre>
</li>
</ul>
</li>
<li>如果发现openconnect客户端还是<strong>不能上网</strong>,可能是dns解析失败。(immortalwrt24.10; 2025-08测)<br>
检查 dnsmasq的配置,菜单位置 "网络 -&gt; DHCP/DNS"。<br>
对于 dnsmasq 和 dnsmasq-full 以下几项的位置不同,自己找找。<pre><code class="language-yaml">- DNS 重定向: 默认勾上,DNS解析劫持。(通常这项不影响)
- 重绑定保护(丢弃RFC1918地址): RFC1918就是内网地址。如果内网使用,去掉这个勾。
- 仅本地服务: 默认勾上,但oc客户端通常不在lan网段,所以要去掉这个勾。
</code></pre>
</li>
</ul>
<h2 id="重新生成ocserv-的证书">重新生成ocserv 的证书</h2>
<ul>
<li>仅用于 Openwrt-22.03</li>
<li>安装了 <code>ocserv</code>, 默认会安装<code>certtool</code>依赖包。如果没有<code>certtool</code>命令,则手动安装<code>opkg install certtool</code>。</li>
<li>如果删除 <code>rm /etc/ocserv/*.pem</code>, 然后 <code>/etc/init.d/ocserv restart</code> ,<br>
所有证书,会重新生成一遍。不过, 除了有效时间变了,其他内容都没改变。</li>
<li>在目录 <code>/etc/ocserv/pki/</code> 有两个文件,修改一下。<strong>自定义证书内容</strong>(按需)。<br>
比如加一行 <code>organization = "xx"</code>,见【Certtool's template file format】<pre><code>## pki/server.tmpl 中加入两行,用来匹配服务器IP或域名
dns_name = "192.168.1.123"
#ip_address = "192.168.1.123"
</code></pre>
</li>
<li>执行以下四行命令。重新生成证书,ECC或RSA证书,覆盖原来的。<pre><code class="language-bash">## 可以用 --bits 3072 指定 RSA私钥的长度,或者使用 --ecc 生成 secp256r1的 ECDSA私钥
certtool --ecc --generate-privkey --outfile /etc/ocserv/ca-key.pem
certtool --template /etc/ocserv/pki/ca.tmpl --generate-self-signed --load-privkey /etc/ocserv/ca-key.pem --outfile /etc/ocserv/ca.pem
certtool --ecc --generate-privkey --outfile /etc/ocserv/server-key.pem
certtool --template /etc/ocserv/pki/server.tmpl --generate-certificate --load-privkey /etc/ocserv/server-key.pem --load-ca-certificate /etc/ocserv/ca.pem --load-ca-privkey /etc/ocserv/ca-key.pem --outfile /etc/ocserv/server-cert.pem
## 查看证书
certtool -i --load-certificate server-cert.pem
</code></pre>
<ul>
<li>用命令生成私钥<code>certtool --key-type XXX --generate-privkey --outfile server-key.pem</code><br>
<code>XXX</code>分别用<code>ecdsa ed25519 eddsa ed448 x25519 x448 gost01 gost12-256 gost12-512</code>代替。<br>
ca 和 server 都使用 ecdsa 证书 (secp256r1),<span style="background: rgba(204, 255, 204, 1)"><strong>连接正常</strong></span>,没有问题。<br>
使用 eddsa(ed25519), ed25519, ed448, x25519, x448, gost01, gost12-256, gost12-512,服务能启动, 客户端连接时报错<code>服务器通信错误</code>。服务端报<code>No supported cipher suites have been found.</code>,<span style="background: rgba(255, 204, 204, 1)">不支持</span>。(2025-08测)。</li>
<li>用命令生成私钥<code>certtool --key-type ecdsa --curve secp256r1 --generate-privkey --outfile server-key.pem</code><br>
分别尝试<code>secp192r1 secp224r1 secp256r1 secp384r1 secp512r1</code>。<br>
用secp192r1 secp224r1, 服务能启动,客户端连接时报错,<span style="background: rgba(255, 204, 204, 1)">不支持</span>。<br>
用secp256r1 secp384r1 secp512r1 工作正常,<span style="background: rgba(204, 255, 204, 1)"><strong>连接正常</strong></span>,没有问题。(2025-08测)。</li>
</ul>
</li>
<li>然后重启服务 <code>/etc/init.d/ocserv restart</code></li>
<li>以上的自签名证书<code>server-cert.pem</code>,无需转换格式,ios可以通过Safari导入ios系统中,但oc客户端连接时还是显示证书<span style="background: rgba(255, 204, 204, 1)">不被信任</span>。<br>
ios的oc客户端,连接服务时,弹出警告"证书不被信任",点击<strong>查看详细</strong>,就能<strong>导入服务器证书</strong>。导入后,下次连接就<span style="background: rgba(204, 255, 204, 1)">不再弹出警告了</span> (证书IP或域名与实际相符)。</li>
<li>也可以使用 Let's Encrypt 证书,不影响"用户证书认证"。参考【使用 Let's Encrypt 在 Ubuntu 22.04 上设置 OpenConnect VPN 服务器 (ocserv)】<br>
oc客户端要使用域名连接,并且<strong>域名要和证书匹配</strong>。否则还是会警告,证书不被信任。
<ul>
<li>证书申请完成后,修改 <code>/etc/ocserv/ocserv.conf.template</code> 中<pre><code>server-cert = /etc/letsencrypt/vpn.example.com/fullchain.pem
server-key = /etc/letsencrypt/vpn.example.com/privkey.pem
</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="用户证书认证">用户证书认证</h2>
<ul>
<li>参考【在 OpenConnect VPN 服务器 (ocserv) 中设置证书身份验证】</li>
<li>让 ocserv 支持 密码 或 用户证书 认证。即,使用任意一种认证。(2025-08测,op24.10)</li>
<li>OpenConnect -&gt; Server Settings -&gt; Edit Template 中<br>
找到并修改<pre><code class="language-ini">#auth = "certificate"   改为   enable-auth = "certificate"
#ca-cert = /etc/ocserv/ca.pem    #去掉注释
#cert-user-oid = 0.9.2342.19200300.100.1.1    #去掉注释。这项代表,用户名在证书的uid中
#cert-user-oid = 2.5.4.3    #或者改为这一行,并去掉注释。这项代表,用户名在证书的cn中
</code></pre>
保存并提交。</li>
<li>创建文件 <code>/etc/ocserv/pki/client.tmpl</code>,内容如下,按需修改,其中 <code>uid=</code> 的用户名必须存在与"用户密码"认证的配置中。<pre><code class="language-ini">organization = "vpn.example.com"
cn = "oc user2"
# A user id of the certificate owner.
uid = "user2"
expiration_days = 3650
tls_www_client
signing_key
encryption_key
</code></pre>
</li>
<li>在<code>/etc/ocserv</code> 目录中执行以下命令<pre><code class="language-bash">## 继续使用原有的CA证书。 # 或者按上一节的方法,重新生成一个CA证书。
# 创建用户私钥,如果使用rsa则去掉 --ecc,如需指定rsa私钥长度 --bits 4096
certtool --generate-privkey --outfile client2-key.pem --ecc
# 生成用户证书
certtool --generate-certificate --load-privkey client2-key.pem --load-ca-certificate ca.pem --load-ca-privkey ca-key.pem --template pki/client.tmpl --outfile client2.pem
# 打包为.p12文件
certtool --to-p12 --load-privkey client2-key.pem --load-certificate client2.pem --pkcs-cipher aes-256 --outfile client2.p12 --outder
# 为IOS打包.p12文件。ios不支持上一行的加密打包方式。
certtool --to-p12 --load-privkey client2-key.pem --load-certificate client2.pem --pkcs-cipher 3des-pkcs12 --outfile ios-client2.p12 --outder
## 查看证书
certtool -i --load-certificate client2.pem
</code></pre>
</li>
<li>把 <code>/etc/ocserv/client2.p12</code> 和 <code>/etc/ocserv/ios-client2.p12</code> 放在某个网站目录中,让用户下载导入。<br>
用户证书使用 ecc证书 (secp256r1),<span style="background: rgba(204, 255, 204, 1)"><strong>认证通过</strong></span>,没有问题。
<ul>
<li>IOS中,用Safari打开url,证书导入ios系统是<span style="background: rgba(255, 204, 204, 1)">无效的</span>,oc客户端中并不显示。<br>
ios 的oc客户端中选择导入用户证书,只能从URL导入,必须是 <code>https://</code>,网站不能是自签名证书。<br>
证书导入后,断开后,直接重连就<span style="background: rgba(204, 255, 204, 1)">不用输入密码了</span>。(2025-08测)</li>
<li>其他客户端,没有测试。</li>
</ul>
</li>
</ul>
<h2 id="尝试用nginx反代到ocserv失败">尝试用nginx反代到ocserv(失败)</h2>
<ul>
<li>认证部分,用到几个路径 <code>/</code>, <code>/auth</code>, <code>/+CSCOT+/</code>, <code>/CSCOSSLC/</code>,<br>
可以成功反代。直到输入完 账号,密码。然后说证书不对。</li>
<li>把nginx的server证书,copy一份给 ocserv共用。<br>
证书就对了,继续之后,握手连接失败。<br>
发现进入了专用协议。没法反向代理了。</li>
<li>放弃。</li>
</ul>
<h2 id="使用-haproxy做端口复用">使用 haproxy做端口复用</h2>
<ul>
<li>安装 haproxy,使用 TCP模式,根据 sni分流,让 nginx的https 和 ocserv共用端口。<br>
见本贴的后面 【ubuntu】 的配置。</li>
</ul>
<hr>
<h1 id="debian">Debian</h1>
<p>2023-10记录</p>
<h2 id="安装配置-1">安装配置</h2>
<ul>
<li>使用的系统为,<br>
debian-11 (bullseye).<br>
debian-12 (bookworm).</li>
<li>安装 <code>apt install ocserv</code>
<ul>
<li>卸载 <code>apt purge ocserv; apt autoremove; 然后删除 /etc/ocserv/ 目录</code></li>
</ul>
</li>
<li>装好,ocserv 默认就已经启动。deb-11<br>
ocserv 默认启动,但启动失败,因为没配置证书。deb-12<br>
配置文件在 <code>/etc/ocserv/ocserv.conf</code></li>
<li>默认设置
<ul>
<li>使用端口 tcp/443 和 udp/443,</li>
<li>支持多种认证方式。<pre><code class="language-ini">## auth directives. Available options: certificate, plain, pam, radius, gssapi.
#auth = "pam"    #用pam认证
#auth = "pam"      #使用系统用户
#auth = "plain"   #使用密码文件+ 一次性密码
auth = "plain"       #使用密码文件,用ocpasswd命令创建密码文件
#auth = "certificate"      #使用证书认证
#auth = "radius"   #使用radius认证
</code></pre>
deb11 默认是 <code>auth = "pam"</code><br>
deb12 默认是 <code>auth = "plain"</code></li>
<li>IP, DNS, 路由。<br>
默认 <code>ipv4-network = 192.168.1.0</code><br>
默认 <code>dns = 192.168.1.1</code> <strong>建议测试一下,如果配错IP,对后面调试影响很大</strong><br>
默认 <code>route = 192.168.0.0/16</code></li>
</ul>
</li>
<li>
<h3 id="修改配置文件-etcocservocservconf">修改配置文件 /etc/ocserv/ocserv.conf</h3>
<pre><code class="language-ini">tcp-port = 443#工作端口,默认443,按需更改
udp-port = 443
auth = "plain"   #使用密码文件
#以下三行证书配置,是deb11 默认设置。
#以下三行证书配置,deb12, 默认 没有配置,所以启动失败。
server-cert = /etc/ssl/certs/ssl-cert-snakeoil.pem
server-key = /etc/ssl/private/ssl-cert-snakeoil.key
ca-cert = /etc/ssl/certs/ca-certificates.crt
ipv4-network = 192.168.100.0   #分配给客户端的IP段
ipv4-netmask = 255.255.255.0
dns = 192.168.1.1   #推送给客户端的dns
route = default       #客户端设置默认网关,所有流量走这个连接
no-route = 192.168.2.0/24#按需,客户端,这个网段的流量不走这个连接
banner = "Welcome MyHost"#按需。不写这行,认证后没有提示直接OK。
</code></pre>
</li>
<li>然后,创建密码文件,创建用户和密码,<code>ocpasswd -c /etc/ocserv/passwd.ocsusename</code></li>
<li>可以自己创建/申请 ca 和 server 证书,替换默认证书。<br>
自己创建证书可以用 certtool命令,来自<code>apt install gnutls-bin</code>包。<br>
见上文 OpenWRT 的配置中,重新生成证书,RSA证书。<br>
或见下文 CentOS8 的配置中,自己创建证书(自签名),ECC证书。</li>
<li>最后重启 ocserv 生效。<br>
<code>service ocserv restart</code></li>
<li>检查 <code>net.ipv4.ip_forward = 1</code> 打开<strong>内核转发</strong>。</li>
<li>检查防火墙规则,<strong>允许转发</strong>,<pre><code class="language-bash"># 如果FORWARD 规则链的 policy accept, 有没有这两条规则都不影响转发。
# 如果FORWARD 规则链的 policy drop, 就必须添加这两条规则。
#使用 iptables
iptables -I FORWARD -s 192.168.100.0/24 -j ACCEPT
iptables -I FORWARD -d 192.168.100.0/24 -j ACCEPT
#使用 nft (policy accept, 有没有这两条规则都不影响转发)
#在chain xx{ type filter hook forward priority filter; policy drop(或accept); } 中,加入,
ip daddr 192.168.100.0/24 counter accept
ip saddr 192.168.100.0/24 counter accept
#或者,用openwrt那样的两条规则,替换上面两条,
ct state established,related accept
ip saddr 192.168.100.0/24 counter accept
</code></pre>
至此,oc客户端(192.168.100.x)发出的数据包,就能转发出去。但因为对方没有对应的路由规则,返回包,回不来 (表现为网络不通)。</li>
<li>配置 <strong>IP伪装(MASQUERADE)</strong>。<br>
如果,出口网卡是固定IP,用 SNAT规则,性能更好。<br>
假设,你的出口网卡设备为 "eth0",使用 eth0 上的IP 做伪装。<br>
即,配置NAT(网络地址转换)规则,把从192.168.100.x发出的数据包,转换为,以eth0的IP发出。<pre><code class="language-bash">#使用 iptables
iptables -t nat -I POSTROUTING -s 192.168.100.0/24 -o eth0 -j MASQUERADE
#使用 nft
#在chain xx{ type nat hook postrouting priority srcnat; policy accept; }中,加入,
oifname "eth0" ip saddr 192.168.100.0/24 counter masquerade
</code></pre>
</li>
<li>配置完成。oc客户端连上后,就可以从 eth0 向外访问了。</li>
</ul>
<h2 id="nft防火墙规则">nft防火墙规则</h2>
<ul>
<li>特殊情况下(有docker)的<strong>FORWARD规则</strong></li>
<li>使用 nft rule,如果有2个相同的 hook,policy分别是 accept和drop。<br>
写入 policy accept 中的 accept rule,就不起作用了。必须要写入到 policy drop的 chain中。</li>
<li>nft rule,如果多个相同的hook,policy 都是 accept,写入的 drop rule,好像也会有问题。</li>
<li>我测试的时候,debian上装了docker,docker生成了一堆规则(iptables)。<br>
其中docker的 FORWARD chain 的 policy 是drop。<br>
所以只能用,<pre><code class="language-bash">iptables -I FORWARD -s 192.168.100.0/24 -j ACCEPT
iptables -I FORWARD -d 192.168.100.0/24 -j ACCEPT
</code></pre>
另建nft chain,总是无效,<pre><code>chain forward {#这里的规则总是匹配不到
   type filter hook forward priority -5;
   ip daddr 192.168.100.0/24 counter accept
   ip saddr 192.168.100.0/24 counter accept
}
</code></pre>
</li>
<li>这两条iptables 的 forward 规则,
<ul>
<li>使用 iptables.service 在开机时导入。(未测试)</li>
<li>使用 /etc/rc.local 写入。(未测试)</li>
<li>考虑在docker启动后,再插入。<br>
参考【使用systemd将iptables规则在docker启动后自动导入】</li>
</ul>
</li>
</ul>
<h2 id="pve的lxc-container">pve的LXC container</h2>
<ul>
<li>ocserv 需要使用 tun 设备。</li>
<li>LXC 中的 debian,实际使用的是 pve的内核,无法加载kmod (tun.ko),所以没有 /dev/net/tun 设备。<br>
LXC中,虽然能配置 ocserv,能运行。但客户端登陆时,因找不到 tun设备而<span style="background: rgba(255, 204, 204, 1)">连接失败</span>。</li>
<li>放弃。</li>
</ul>
<hr>
<h1 id="centos8">CentOS8</h1>
<p>2023-10记录</p>
<h2 id="安装配置-2">安装配置</h2>
<ul>
<li>安装 <code>yum install ocserv</code>
<ul>
<li>卸载 <code>yum remove ocserv; yum autoremove; 然后删除 /etc/ocserv/ 目录</code></li>
</ul>
</li>
<li>装好,ocserv 默认没启动。也没激活。<br>
配置文件在 <code>/etc/ocserv/ocserv.conf</code></li>
<li>修改 <code>ocserv.conf</code> 配置文件,<pre><code class="language-ini">tcp-port = 443#工作端口,默认443
udp-port = 443
server-cert = /etc/pki/ocserv/public/server.crt
server-key = /etc/pki/ocserv/private/server.key
ca-cert = /etc/pki/ocserv/cacerts/ca.crt
auth = "plain"#默认 auth ="pam"
ipv4-network = 192.168.100.0/24#默认没配置,分配给客户端的IP段
dns = 192.168.1.1   #默认没配置,推送给客户端的dns, **建议测试一下,如果配错IP,对后面调试影响很大**
route = default   #默认没配置,推送给客户端的route
no-route = 192.168.2.0/24#按需,推送给客户端的排除route
banner = "Welcome MyHost"#按需
</code></pre>
</li>
<li>然后,创建密码文件,创建用户和密码,<code>ocpasswd -c /etc/ocserv/passwd.ocsusename</code></li>
<li><code>service ocserv start</code>直接启动。第一次启动,会<strong>自动执行</strong> ocserv-genkey 生成所需的证书。</li>
<li>如果对证书<strong>不满意</strong>,自己创建证书(自签名),ECC证书,用 certtool命令,来自<code>yum install gnutls-utils</code>包。<pre><code class="language-bash">cd /etc/pki/ocserv/
cat &lt;&lt;EOF &gt; ca.tmpl#ca证书模板,按需修改前两行
cn = "Your CA name"
organization = "Your fancy name"
serial = 1
expiration_days = 3650
ca
signing_key
cert_signing_key
crl_signing_key
EOF
certtool --generate-privkey --key-type ecdsa --bits 256 --outfile ca-key.pem#生成ca密钥
certtool --generate-self-signed --load-privkey ca-key.pem --template ca.tmpl --outfile ca-cert.pem#自签名ca证书
cat &lt;&lt;EOF &gt; server.tmpl#服务证书模板,按需修改前两行
cn = "Your hostname or IP"
organization = "Your fancy name"
expiration_days = 3650
signing_key
encryption_key
tls_www_server
EOF
certtool --generate-privkey --key-type ecdsa --bits 256 --outfile server-key.pem#生成server密钥
certtool --generate-certificate --load-privkey server-key.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --template server.tmpl --outfile server-cert.pem#server证书
mv ca-key.pem private/ca.key   #移到正确位置。如果没有,ocserv会自己重新生成
mv ca-cert.pem cacerts/ca.crt
mv server-key.pem private/server.key#移到正确位置。如果没有,ocserv会自己重新生成
mv server-cert.pem public/server.crt
</code></pre>
</li>
<li>防火墙,<strong>开放ocserv端口</strong>。<pre><code class="language-bash">firewall-cmd --zone=public --add-port=443/tcp
firewall-cmd --zone=public --add-port=443/udp
firewall-cmd --zone=public --add-port=443/tcp --permanent
firewall-cmd --zone=public --add-port=443/udp --permanent
</code></pre>
</li>
<li>检查 <code>net.ipv4.ip_forward = 1</code> 打开<strong>内核转发</strong>。</li>
<li>检查防火墙规则,<strong>允许转发</strong>,<br>
通常是允许的。可以不用配置。<pre><code class="language-bash">#可能用这个命令# firewall-cmd --zone &lt;Zone Name&gt; --add-forward#没测试
</code></pre>
</li>
<li>配置 <strong>IP伪装(MASQUERADE)</strong>。<pre><code class="language-bash">firewall-cmd --list-all-zones#查看所有的zone,确定出口网卡在哪个zone
firewall-cmd --zone public --add-masquerade#通常在public zone
firewall-cmd --zone public --add-masquerade --permanent #系统重启也有效
</code></pre>
</li>
<li>激活服务,启动服务。<pre><code>systemctl enable ocserv   #激活
systemctl restart ocserv#重启
</code></pre>
</li>
<li>Centos8, 安装的haproxy-1.8.27 , 开启 haproxy的log记录,见【在centos8 配置haproxy日志功能】,【Haproxy之日志打印】<br>
需要在 chroot目录中创建log文件,<code>/var/lib/haproxy/dev/log</code><br>
或者,开启 rsyslog的 514/UDP.<br>
否则 haproxy 无法发送log到 rsyslog 中。</li>
</ul>
<h1 id="ubuntu">ubuntu</h1>
<ul>
<li>安装,配置方法与debian相同</li>
</ul>
<h2 id="openwrt-作为客户端连接ubuntu的-ocserv">openwrt 作为客户端,连接Ubuntu的 ocserv</h2>
<ul>
<li>发现每 41-56分钟,连接会断开又马上重连。<br>
Ubuntu的 ocserv.conf 中, 默认为 idle-timeout = 1200</li>
<li>在openwrt中,增加一个定时任务,每30分钟ping一下对端。<br>
发现还是 50-56分钟断开一次。</li>
<li>在openwrt中,定时任务,每20分钟ping一下对端。<br>
连接不再断开。</li>
<li>改 idle-timeout = 3610<br>
openwrt 不ping (删掉定时任务),连接每2小时断开一次。<br>
openwrt 每小时ping一下,连接不再断开。</li>
<li>改 idle-timeout = 1810<br>
openwrt 半小时ping一下,连接不再断开。</li>
<li>客户端换immortalWrt24,报错,(2025-08)<pre><code>/lib/netifd/vpnc-script: line 120: can't create /tmp/dnsmasq.d/openconnect.vpn-ocs0: nonexistent directory
Failed to open /dev/vhost-net: No such file or directory
DTLS handshake failed: Resource temporarily unavailable, try again. (每分钟一次)
</code></pre>
网络原因 udp不通,导致handshake失败,在服务端 ocserv.conf 注释掉 <code>udp-port=</code><br>
immWrt24中<code>luci-proto-openconnect</code>缺少内核依赖包,安装<code>kmod-vhost-net</code>解决。<br>
新版dnsmasq-full修改了目录名,dnsmasq.d找不到,暂时无法解决。</li>
<li>配置openconnect客户端时,
<ul>
<li>填写 "VPN 服务器证书的 SHA1 哈希值" 以下任意一种格式都可以,
<ul>
<li><code>certtool --fingerprint --load_certificate server-cert.pem</code> 得到 "证书指纹SHA1"</li>
<li><code>openssl x509 -in server-cert.pem -noout -fingerprint</code> 去掉冒号得到 "证书指纹SHA1"</li>
<li>参考【官网的说明】使用SHA256 hash<br>
<code>openssl x509 -in server-cert.pem -pubkey -noout | openssl pkey -pubin -outform der |openssl dgst -sha256 -binary |openssl enc -base64</code><br>
格式为: "pin-sha256:abcd1234567"</li>
</ul>
</li>
<li>或者,不填写 "VPN 服务器证书的 SHA1 哈希值", 填写 "CA 证书"</li>
</ul>
</li>
</ul>
<h2 id="使用haproxy做端口复用">使用haproxy做端口复用</h2>
<ul>
<li>【immortalwrt上的haproxy配置参考】</li>
<li>在Ubuntu,安装<code>apt install stunnel4</code></li>
<li>配置stunnel
<ul>
<li>使用 certtool 创建服务器证书。见【这里】</li>
<li>创建配置文件,【stunnel 官方文档】<br>
<code>cp /usr/share/doc/stunnel4/examples/stunnel.conf-sample /etc/stunnel/stunnel.conf</code></li>
<li>修改配置文件 /etc/stunnel/stunel.conf,保留全局设置,<pre><code>setuid = stunnel4
setgid = stunnel4
pid = /var/run/stunnel4/stunnel.pid
output = /var/log/stunnel4/stunnel.log
</code></pre>
</li>
<li>去掉例子中原来的 client和server设置,添加以下server设置。<br>
给ssh套上SSL。给mysql也套一层SSL。<pre><code>
client = no
accept= 127.0.0.1:10022
connect = 127.0.0.1:22
cert = /etc/ssl/stunnel/server-cert.pem
key= /etc/ssl/stunnel/server-key.pem
    # mysql自己就有ssl,前面再套ssl,效率是低了,但能用
client = no
accept= 127.0.0.1:13306
connect = 127.0.0.1:3306
cert = /etc/ssl/stunnel/server-cert.pem
key= /etc/ssl/stunnel/server-key.pem
</code></pre>
</li>
</ul>
</li>
<li>在Ubuntu,修改nginx的ssl配置,监听端口改到 2443,让出443口,给haproxy用。<br>
并加上 proxy-protocol 的相关配置,见【这里的nginx的配置】</li>
<li>在Ubuntu,修改 ocserv配置,其他的配置不改动,只找以下三项,并修改。<pre><code>listen-host = 127.0.0.2#改本地监听
tcp-port =1443   #改端口
listen-proxy-proto = true#接受 proxy-protocol
</code></pre>
</li>
<li>在Ubuntu,安装<code>apt install haproxy</code> 【文档2.0.33】</li>
<li>配置 haproxy,按sni域名分流<pre><code>... #保留原有的 global和 defaults配置。timeout的默认的单位是 ms, 默认值是50s
frontend tls_tcp
   bind :443
   mode tcp
   option   tcplog
   tcp-request inspect-delay 5s
   tcp-request content accept if { req.ssl_hello_type 1 }
   use_backend ocserv       if { req.ssl_sni -i ocs.myxxxx.com }
   use_backend ssh-tls       if { req.ssl_sni -i ssh.myxxxx.com }
   use_backend mysql-tls   if { req.ssl_sni -i sql.myxxxx.com }
   use_backend nginx         if { req.ssl_sni -i www.myxxxx.com }
   default_backend nginx
backend ocserv
   mode tcp
   server ocserv 127.0.0.2:1443 check-ssl check-send-proxy send-proxy-v2
   timeout tunnel 1810s    #配合ocserv的idle-timeout
backend ssh-tls
   mode tcp
   # stunnel 不支持,不接受 proxy-protocol
   # ssh看到的来源IP是来自stunnel的IP,无法通过来源IP做访问控制。
   server ssh 127.0.0.1:10022 check-ssl
backend mysql-tls
   mode tcp
   # mysql自己就有ssl/tls,前面再套一层ssl/tls,效率降低,但能用。
   # mysqld显示来源IP为stunnel所在的IP,导致无法通过来源IP做访问控制。
   server mysql 127.0.0.1:13306 check-ssl
backend nginx
   mode tcp
   server nginx 127.0.0.1:2443 check-ssl check-send-proxy send-proxy-v2
   #tcp-request content reject   #拒绝连接/直接断开连接
</code></pre>
</li>
<li>stunnel不支持proxy-protocol, 可以考虑用 gost替代, gost支持 proxy-protocol。<br>
不过 ssh, mysqld 都不支持 proxy-protocol, 所以最终的服务还是无法获取来源IP。</li>
<li>检查是否有错误 <code>haproxy -f /etc/haproxy/haproxy.cfg -c</code></li>
<li>重启 haproxy服务,使之生效。</li>
<li>因为 ocserv本身就有ssl,就无法用 haproxy的SSL Termination(SSL终止),让haproxy接管ssl部分。<br>
再说,haproxy的TCP模式也无法做SSL终止。SSL终止似乎只能用于mode http。<br>
所以,以上配置使用SSL-Pass-Through(SSL穿透/透传)。</li>
</ul>
<h3 id="immortalwrt24-上的openconnect客户端">immortalWrt24 上的openconnect客户端</h3>
<ul>
<li>在openwrt中的 ocs客户端无法指定sni的域名。有两个办法解决。任意一个办法都可以。
<ul>
<li>修改 /etc/hosts 增加一行或多行,ip在前域名在后,空格分隔。如 <code>192.168.100.22ocs.myxxxx.com</code><br>
有的版本的openwrt,重启后 hosts的内容会丢失。</li>
<li>网络 -&gt; DHCP/DNS -&gt; DNS记录 -&gt; 主机名映射,把域名/IP 添加在这里。<br>
然后重启dnsmasq, <code>/etc/init.d/dnsmasq restrat</code></li>
</ul>
</li>
<li>网络 -&gt; 接口 -&gt; ocs0, 修改 "VPN服务器" 为 "ocs.myxxxx.com:443"</li>
<li>重启 ocs 网络接口,openconnect就连上去了。</li>
</ul>
<h3 id="pymysql-连接套了-ssltls的mysql">pymysql 连接套了 ssl/tls的mysql</h3>
<pre><code># 从各大搜索引擎搜索,都搜不到例程。询问各种AI给出的例程,全都是错的,AI都在一本正经的瞎说。
# PyMySQL-0.9.3, Python-3.8.10,通过查看源码+测试,2025-10测试通过
# PyMySQL-1.1.1, Python-3.7.5,2025-10测试通过
import pymysql
import ssl
import socket
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_context.check_hostname = False    #不验证域名
ssl_context.verify_mode=ssl.CERT_NONE   #不验证证书
sni_host='sql.myxxxx.com'      #SNI 域名
db=pymysql.connect(user='root',passwd='123456',db='dbname',use_unicode=True,defer_connect=True)

ssocket = ssl_context.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM), server_hostname=sni_host)
ssocket.connect(('192.168.100.22', 443))
db.connect(sock=ssocket)
#或者
#ssocket = ssl_context.wrap_socket(socket.create_connection(('192.168.100.22',443)), server_hostname=sni_host)
#db.connect(sock=ssocket)

#cur=db.cursor()
#cur.execute(sql)
#db.commit()
#cur.close()

db.close()
print('show ssocket closed or not:', ssocket)
</code></pre>
<h1 id="参考">参考</h1>
<ul>
<li>【openconnect/ocserv】</li>
<li>【openconnect/recipes】</li>
<li>【ocserv-configuration-basic】</li>
<li>【Debian下搭建Ocserv(openconnect server),并启用证书验证】</li>
<li>【在Debian 10 Buster上设置OpenConnect VPN服务器(ocserv)】</li>
<li>【Debian下安装配置Ocserv搭建Cisco Anyconnect的开源服务端】</li>
</ul>
<p>----end----</p>
<hr>
<p><strong>转载注明来源: 本文链接 https://www.cnblogs.com/osnosn/p/16923645.html</strong><br>
<strong>来自 osnosn的博客 https://www.cnblogs.com/osnosn/</strong> .</p>
<hr><br><br>
来源:https://www.cnblogs.com/osnosn/p/16923645.html
頁: [1]
查看完整版本: openwrt-22.03_debian_centos_ocserv_haproxy_stunnel