使用VMWare虚机Centos7.x实现网关、DHCP、修改HTTP User-Agent字段(绕过深信服、绿盟等对该字段的检测)
起因:
朋友公司上外网有限制:
1. 不能建立内网wifi给手机上网用;
2. 必须在上外网的电脑上安装深信服或绿盟的客户端。
解决方案:
为了解决能用手机通过内网wifi上网,研究了下,以下解决方案可实现:
1. 因为上外网必须安装客户端,因此必须在已经安装了这类客户端的已经能上外网的电脑上想办法,不能直接使用wifi路由器连接到内网(会提示需要安装客户端才能访问外网),所以使用在该电脑上安装虚机,把该虚机做成网关和DHCP服务器来作为路由器使用。
2. 因为深信服、绿盟这类流氓会检测HTTP的Header字段User-Agent,从而判断是手机上网还是电脑上网(有手机上网的包则会提示公司内部不准使用wifi路由器)(别问我怎么知道的,猜的行不行),所以需要在IP包进入公司内网前进行IP包的修改,把手机来的User-Agent模仿成电脑来的。
以下是具体操作和代码:
主机必须具有两个网卡:
一个接外网,名为“本地连接”,设置为共享,共享给VMware Network Adapter VMnet8;
一个接内网,名为“本地连接2”,先不配置。
在VMWare里面编辑“虚拟网络编辑器”:
VMnet0对应桥接模式,和“本地连接2”的网口卡桥接;
VMnet8对应nat模式,自动会和上面的“本地连接”共享上网。
建立Centos7.x虚机,建立两个网卡:
en16777736: 使用nat方式,接主机的VMnet8(VMWare的nat方式接口,通过主机的“本地连接”上外网);
en33554984: 使用Bridge方式,桥接主机的VMnet0(VMware的Bridge方式接口,通过主机的“本地连接2”接内网,给需要上外网的电脑使用)。
配置虚机的网口:
en16777736:使用dhcp client方式取得ip地址、网关和dns即可,此时虚机可上网:
# ping news.163.com
en33554984:静态配置:
# vi /etc/sysconfig/network-scripts/ifcfg-eno33554984
TYPE=Ethernet
DEVICE=eno33554984
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.211.1
NETMASK=255.255.255.0
GATEWAY=
# systemctl restart NetworkManager
配置主机的“本地连接2”的IP为192.168.211.2,网关为192.168.211.1,在主机上看看是否能ping 192.168.211.1
在虚机上看看能否ping 192.168.211.2
配置虚机为DHCP服务器:
# vi /etc/dhcp/dhcpd.conf
log-facility local7;
subnet 192.168.211.0 netmask 255.255.255.0 {
range 192.168.211.10 192.168.211.240;
option domain-name-servers 202.96.134.133 8.8.4.4;
option domain-name “www.maxshu.com”;
option broadcast-address 192.168.211.255;
default-lease-time 600;
max-lease-time 7200;
}
# systemctl restart dhcpd
# systemctl enable dhcpd
内部找台电脑,用动态地址方式看能否取到ip地址、网关、dns地址。
配置虚机为内部电脑的网关:
配置转发:
# vi /etc/sysctl.conf
net.ipv4.ip_forward=1
# sysctl -p
配置防火墙,把所有流量nat到eno1677736这个可上外网的网口:
# firewall-cmd –direct –add-rule ipv4 nat POSTROUTING 0 -o eno16777736 -j MASQUERADE
# firewall-cmd –permanent –direct –add-rule ipv4 nat POSTROUTING 0 -o eno16777736 -j MASQUERADE
配置防火墙,把所有从eno33554984这个内部网络来的流量前转到ACCEPT:
# firewall-cmd –direct –add-rule ipv4 filter FORWARD 0 -i eno33554984 -j ACCEPT
# firewall-cmd –permanent –direct –add-rule ipv4 filter FORWARD 0 -i eno33554984 -j ACCEPT
测试:
上面已经取得地址的电脑,看能否ping 8.8.4.4
修改所有内网来的手机上网http包的User-Agent字段为电脑上网方式(可以绕过深信服、绿盟这类检测内网是否有wifi路由器的功能):
就是把http包里面带有Android之类的User-Agent改为:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36\r\n
# yum install kernel-headers
# yum install python-devel
# yum install gcc
下载安装几个网络过滤的包:
# rpm -ivh libnfnetlink-1.0.1-4.el7.x86_64.rpm
# rpm -ivh libnfnetlink-devel-1.0.1-4.el7.x86_64.rpm
# rpm -ivh libnetfilter_queue-1.0.2-1.el7.x86_64.rpm
# rpm -ivh libnetfilter_queue-devel-1.0.2-1.el7.x86_64.rpm
下载安装python的netfilterqueue:
# yum install wget
# python get-pip.py
# pip install netfilterqueue
# pip install scapy
自己写几个脚本来修改IP包(最好不要加入自启动):
启动(必须先启动py脚本,再设置防火墙,否则一旦防火墙设置,网络包就出不来了,因为这条规则的功能就是把包送往py脚本里面的NetfilterQueue去处理,调试时可使用-d指定具体的目的地址来进行):
# cat http_modify_start.sh
nohup ./http_modify.py &
echo “$!” > http_modify.pid
firewall-cmd –direct –add-rule ipv4 mangle POSTROUTING 0 -j NFQUEUE
# for DEBUG: firewall-cmd –direct –add-rule ipv4 mangle POSTROUTING 0 -d 192.168.60.60 -j NFQUEUE
# firewall-cmd –direct –remove-rule ipv4 mangle POSTROUTING 0 -j NFQUEUE
停止(必须停止防火墙,再kill掉py脚本,否则一旦py脚本被杀,网络包就出不来了 ):
# cat http_modify_stop.sh
firewall-cmd –direct –remove-rule ipv4 mangle POSTROUTING 0 -j NFQUEUE
kill `cat http_modify.pid`
修改http包内容(注意bind时使用的是默认防火墙队列num 0,上面防火墙规则也是使用的默认值0(没配置)):
# cat http_modify.py
#!/usr/bin/env python
from netfilterqueue import NetfilterQueue
import re
from scapy.all import *
def callback(payload):
data = payload.get_payload()
pkt = IP(data)
#print “================================================”
#ls(pkt)
#print pkt.src
#print pkt.dst
if pkt.haslayer(TCP) and pkt.haslayer(Raw):
#print “Old IP Pkg:”
#ls(pkt[IP])
tcpPayload = re.sub(“User-Agent:.*Android.*\r\n”, “User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36\r\n” , str(pkt[TCP].payload))
tcpPayload = re.sub(“User-Agent:.*iPhone.*\r\n”, “User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36\r\n”, tcpPayload)
# print “=== HEX:TCP Payload:==>”
# print hexdump(tcpPayload)
# print “<===”
rawPkt = Raw(tcpPayload)
# print “TCP Raw Pkg:”
# ls(rawPkt)
# pkt[IP].ttl = 40
# print ‘Modified TTL: ‘ + str(pkt[IP].ttl)
ipPkt = IP()
ipPkt.version = pkt[IP].version
ipPkt.ihl = pkt[IP].ihl
ipPkt.tos = pkt[IP].tos
ipPkt.id = pkt[IP].id
ipPkt.flags = pkt[IP].flags
ipPkt.frag = pkt[IP].frag
ipPkt.ttl = pkt[IP].ttl
ipPkt.proto = pkt[IP].proto
ipPkt.src = pkt[IP].src
ipPkt.dst = pkt[IP].dst
ipPkt.options = pkt[IP].options
del ipPkt[IP].chksum # for auto calculate
del ipPkt[IP].len # for auto calculate
tcpPkt = TCP()
tcpPkt.sport = pkt[TCP].sport
tcpPkt.sport = pkt[TCP].sport
tcpPkt.dport = pkt[TCP].dport
tcpPkt.seq = pkt[TCP].seq
tcpPkt.ack = pkt[TCP].ack
tcpPkt.dataofs = pkt[TCP].dataofs
tcpPkt.reserved = pkt[TCP].reserved
tcpPkt.flags = pkt[TCP].flags
tcpPkt.window = pkt[TCP].window
tcpPkt.urgptr = pkt[TCP].urgptr
tcpPkt.options = pkt[TCP].options
del tcpPkt[TCP].chksum # for auto calculate
newPkt = ipPkt/tcpPkt/rawPkt
newPkt = newPkt.__class__(str(newPkt)) # this will lead to auto calculate TCP checksum, IP checksum, IP length.
#print “New IP Pkg:”
#ls(newPkt)
payload.set_payload(str(newPkt))
payload.accept()
def main():
q = NetfilterQueue()
q.bind(0, callback)
try:
print “Start http_modify.py …\r\n”
q.run() # Main loop
except KeyboardInterrupt:
q.unbind()
print “Finished http_modify.py!\r\n”
main()