Open vislee opened 3 months ago
一些场景需要选择性的将指定部分的流量劫持到服务端。 例如,ssl vpn就是把客户机访问公司内网的流量劫持后通过加密隧道转到公司内网。
加密隧道可以用:socks5 over tls 实现。
socks5 over tls
如何进行流量劫持呢?有2种:
操作系统网络设置一般都支持代理,只需要把本地的socks5客户端监听端口配置到网络设置SOCKS代理就可以实现流量劫持。 一般只有浏览器才会使用这个代理,每个app都有自己配置socks代理的地方,不通用。
TUN模拟了网络层设备,用户态可以直接读该tun设备,读到的数据是IP报文。如果要拿到payload就需要解析tcp/ip协议,有两种方案得到payload:
启动代理程序监听本地的IP和端口,等待接收tun设备转过来的数据。 通过路由或者fake ip,把应用程序的流量先重定向到tun设备,用户态程序读取到tun设备的IP报文做NAT转换再写回去(注意目标IP和端口是上述代理监听的IP和端口)。通过操作系统协议栈再收到应用程序拿到tcp的payload,然后可以通过socks5转到服务端。
NAT:
tcpdump抓包
程序日志:
TCP首部校验和计算三部分:TCP首部+TCP数据+TCP伪首部。
TCP伪首部: 共有12字节,包含IP首部的一些字段,有如下信息:32位源IP地址、32位目的IP地址、8位保留字节(置0)、8位传输层协议号(TCP是6,UDP是17)、16位TCP报文长度(TCP首部+数据)。
首先,把伪首部、TCP报头、TCP数据分为16位的字,如果总长度为奇数个字节,则在最后增添一个位都为0的字节。 把TCP报头中的校验和字段置为0。 其次,用反码相加法(对每16bit进行二进制反码求和)累加所有的16位字(进位也要累加,进位则将高位叠加到低位)。 最后,将上述结果作为TCP的校验和,存在检验和字段中。
func sumCompat(b []byte) (sum uint32) { n := len(b) if n&1 != 0 { n-- sum += uint32(b[n]) << 8 } for i := 0; i < n; i += 2 { sum += (uint32(b[i]) << 8) | uint32(b[i+1]) } return }
https://zu1k.com/posts/coding/tun-mode/
概述
一些场景需要选择性的将指定部分的流量劫持到服务端。 例如,ssl vpn就是把客户机访问公司内网的流量劫持后通过加密隧道转到公司内网。
原理
加密隧道可以用:
socks5 over tls
实现。如何进行流量劫持呢?有2种:
使用操作系统代理
操作系统网络设置一般都支持代理,只需要把本地的socks5客户端监听端口配置到网络设置SOCKS代理就可以实现流量劫持。 一般只有浏览器才会使用这个代理,每个app都有自己配置socks代理的地方,不通用。
使用tun虚拟网卡
TUN模拟了网络层设备,用户态可以直接读该tun设备,读到的数据是IP报文。如果要拿到payload就需要解析tcp/ip协议,有两种方案得到payload:
使用操作系统的协议栈解析
启动代理程序监听本地的IP和端口,等待接收tun设备转过来的数据。 通过路由或者fake ip,把应用程序的流量先重定向到tun设备,用户态程序读取到tun设备的IP报文做NAT转换再写回去(注意目标IP和端口是上述代理监听的IP和端口)。通过操作系统协议栈再收到应用程序拿到tcp的payload,然后可以通过socks5转到服务端。
NAT:
tcpdump抓包
程序日志:
用户态解析tcp/ip协议栈
TCP首部校验和计算三部分:TCP首部+TCP数据+TCP伪首部。
TCP伪首部: 共有12字节,包含IP首部的一些字段,有如下信息:32位源IP地址、32位目的IP地址、8位保留字节(置0)、8位传输层协议号(TCP是6,UDP是17)、16位TCP报文长度(TCP首部+数据)。
首先,把伪首部、TCP报头、TCP数据分为16位的字,如果总长度为奇数个字节,则在最后增添一个位都为0的字节。 把TCP报头中的校验和字段置为0。 其次,用反码相加法(对每16bit进行二进制反码求和)累加所有的16位字(进位也要累加,进位则将高位叠加到低位)。 最后,将上述结果作为TCP的校验和,存在检验和字段中。
总结
https://zu1k.com/posts/coding/tun-mode/