Twisted – 折腾(存档) https://blog.sorz.org 已停止更新和维护。该页面为2018年3月创建的存档,其内容可能已过于陈旧、与现状不符,仅作为历史存档用作参考。 Sun, 14 Jan 2018 11:08:20 +0000 zh-CN hourly 1 https://wordpress.org/?v=4.9.4 简单的 SSTP 服务器 /p/sstp-server/ /p/sstp-server/#comments Wed, 01 Oct 2014 10:48:23 +0000 https://sorz.org/?p=347963 SSTP (Secure Socket Tunneling Protocol) 是微软开发的一种 VPN 协议,用 SSL/TLS 加密 PPP 流量。参见 使用 SSTP 协议的 VPN 有什么优势和缺陷?

本来没怎么关注这个东西,支持少非主流,IP over TCP,也是因为一些奇怪的事突然有了这方面需求了,才开始了解它。

SoftEther

目前在 Linux,服务器似乎只有 SoftEther 这个实现。这软件也是挺拼的,把各种流行的非主流的 VPN 协议都给实现了一遍,跨平台,GPL。还提供傻瓜化的 GUI 管理,中日英三语界面,简直就是部署 VPN 的大杀器。只是一来太重,二来对 RADIUS 支持不全,不太符合需求。

DIY

因为内部走的是 PPP,如果只是调用 pppd 并转发数据,由 pppd 负责用户认证等麻烦事,自己实现一个目测也不是太复杂。加上微软的官方文档甚详,近来又一直想学一下 Twisted 但又不知如何入手,决定来写一个试试。

托 Twisted 的简单易用,挺顺利地初步完成了这个 SSTP 服务器。

代码放在 GitHub 和 PyPI 上了,sorz/sstp-server
PyPI

安装使用

供参考,详见sstpd --help

sudo apt-get install python-dev python-pip python-twisted
sudo pip install sstp-server
sudo sstpd -c cert.pem --local 10.0.0.1 --remote 10.0.0.0/24

关于证书,请参考 HTTPS 证书相关教程。
别忘了建/etc/ppp/options.sstpd,一个例子:

name sstpd
require-mschap-v2
nologfd
nodefaultroute
ms-dns 8.8.8.8
ms-dns 8.8.4.4

需要 IPv6 支持的,可加参数--listen ::

麻烦

折腾过程中遇到的主要障碍还是关于 PPP 的。简单地转发是不行的,因为每个 SSTP 包中只允许放入一个 PPP frame,需要自行分离出每个 frame。

PPP 这个古老的协议比预想中的要复杂。Windows 在 SSTP 中使用的其实是这个 HDLC-like Framing。找了一份 SSTP 客户端的代码,它是自行对两种格式进行了转换。好在后来发现 pppd 其实自身就支持 HDLC(sync 参数),于是成功偷懒

但后来发现 HDLC 似乎需要 Linux 内核支持(CONFIG_PPP_SYNC_TTY = yes)。

更新:
果然偷懒失败了,用 HDLC 取巧的方法是不行的,偶尔会有 frame 被截断,后面就全乱了。于是还是老老实实地照着 RFC 1662 来做 framing,自行 (un)escape 一些字符。但是这样性能变得很糟糕,试着把这部分用 C 扩展重写了一遍。想来这还是我第一次出于解决问题的需要写 C 呢……

感谢 @deba12 指出了这个问题,并协助测试、改善性能。

安全性

目前这个实现其实是不完整的,没有实现 Crypto binding 部分,导致其可能遭受中间人攻击。

使用了 SSL 还会遭受中间人攻击?微软在文档末尾提供了一个这种攻击的情境,挺有意思的。

攻击者建立一个假 Wi-Fi AP,然后诱骗用户连接。
Wi-Fi 使用 802.11 EAP 进行认证,用户以为他是在登录 Wi-Fi,但实际上,攻击者将这个认证请求转发给了 SSTP(PPP) 服务器!用户确实在和真的认证服务器在对话,只不过认证的不是 Wi-Fi 而是 SSTP 服务。

Crypto binding 可以防止这种攻击,想详细了解请参见微软文档。
但实现这个有些复杂,我这边的使用情境暂时没有这个需求,就先放一放了。
(懒你就直说 _(:з」∠)_

]]>
/p/sstp-server/feed/ 73