【学习记录】obfs4proxy 协议验证方式和部分源代码结构、函数分析

1 obfs4协议验证逻辑

  • 握手过程
Client Server SYN+ECN+CWR SYN+ACK ACK PSH+ACK+data Client Server
  • data内容
    涉及算法:curve25519

    客户端及服务端都必须有自己的Keypair实例。根据curve25519包中的定义,PrivateKey在一定范围内随机生成。根据ECC算法,PublicKey可以通过调用curve25519.ScalarBaseMult()从私钥生成。

    Representative秘钥根据公钥生成,在需要的时候可以调用extra25519.RepresentativeToPublicKey()函数再次转换为公钥。Keypair的定义及初始化代码位于NewKeypair()函数中,该函数在ntor.go文件中定义。

    用extra25519.go里的ScalarBaseMult(),根据privatekey生成public和representative。representative通过Elligator 2映射完成混淆,避免收集到相当数量的公钥后推断出加密算法。
    算法详细说明

    客户端及服务端都应当保存好私钥,将公钥以Representative秘钥的形式发送给对方。Obfs4客户端的连接过程从握手报文开始,因此我们来看一下客户端的握手报文。该报文的整体结构如下所示:

    1. Keypair.representative,其长度为20h字节。在服务器端,它可以作为还原客户端的公钥。(obfs4 bridge配置行)
    2. 使用随机字节的填充数据,其数据大小范围在4Dh至1FC0h之间,该填充数据会混淆握手数据包的大小,从而使其更难识别。
    3. 第一部分Keypair.representative的HMAC值。Obfs4使用SHA-256生成HMAC,长度为20h字节。Obfs4仅将前10h字节保留为HMAC,其余10h字节将被丢弃。
    4. Obfs4使用当前系统时间来计算UNIX Epoch时间(从UTC时间1970年1月1日星期四00:00:00开始)的小时值。计算数据包中前三个部分的HMAC值,加上(指拼接起来)字符串中的小时值。同样,其结果长度为20h字节,前10h字节作为数据包的第四部分。(防重放)

2 obfs4proxy源代码部分结构

  • common/ 密码学、socks5等组件
  • internal/ 更新的混淆算法
  • obfs4proxy/
    obfs4proxy.go 主函数
  • transports/
    包含meeklite、obfs2、3、4、 scramblesuit传输协议的实现
    • obfs4/
      • framing/ 数据帧的处理
        • handshake_ntor.go 完成obfs4握手,包括验证
        • obfs4.go 握手相关函数

3 obfs4proxy源代码部分函数

  • obfs4.go

    • WrapConn()
      调用了serverHandshake(),不管返回什么错,都closeAfterDelay()。

    • serverHandshake()
      新建服务端握手,设置基准超时时间。
      然后按能读取的最大长度(8192)设置缓冲区,读取收包,保存收包内容,接下来parseClientHandshake()解析内容。
      如果解析错误是ErrMarkNotFoundYet,继续读包,其他错误则函数返回错误。
      解析正常则清空缓冲区。

  • handshake_ntor.go

    • parseClientHandshake()
      对于接收内容过少/接收内容长度未达上限时,或找不到MarkMAC,准备了ErrMarkNotFoundYet的错误处理,可以返回继续读。
      其他错误都关闭连接。找不到markMAC/HMAC/包长度不合规(有握手中不需要的数据),返ErrInvalidHandshake。
      重放,返ErrReplayedHandshake。
      计算验证不通过,返ErrNtorFailed。

    • closeAfterDelay()
      closeAfterDelay()被修改,修复了因阈值产生FIN和RST的漏洞。旧版本会在延迟30s/接收一定长度数据后终止连接,新版本都是延迟30s终止连接。

    • SetReadDeadline()
      开始读数据30s后,再有数据进入也返回超时错误,并终止连接。(论文里说有随机延迟,我没找到)

  • obfs4proxy.go

    • serverHandler()
      调用WrapConn(),如果返回错误,在日志中记录握手失败。
    • serverAcceptLoop()
      让服务器循环开启与客户端的握手,调用serverHandler()。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值