WiFi热点分享S-S流量实现全局透明代理

来源:互联网 发布:网络危机公关联系方式 编辑:程序博客网 时间:2024/04/28 03:47

平时使用s-s或SSH科&学*上%网的时候,感觉速度和稳定性和速度比VPN强不少,但是独乐乐不如众乐乐,如何把我连上ss的电脑做成热点,通过wifi分享给周围其他的人呢?又如何将ss变成一个全局的透明代理,而不仅仅限于浏览器和少数几个支持代理的软件呢?

做此项研究的起因是公司的一个同事需要科学上网做开发,于是我把ss通过Privoxy转换成http代理爽快的给她用了,但是她反映没什么作用,我看了一下才知道,她在电脑里部署了一个apache服务器用来运行php服务,php程序中有一个耗时操作是链接远在新加坡的MYSQL服务器获取数据,但是该MYSQL服务器被墙了访问很慢,于是php就卡住了,需要想办法让apache服务也翻出墙去,而apache并没有设置代理的相关选项。

如果有一个wifi,链接上该wifi以后电脑里的全部程序都实现了S-S代理,不需要配置这配置那设置各种代理,那岂不是效率高得多,于是从这个出发点开始,我开始用手上的Ubuntu电脑制作一个可以科学上网的笔记本PC路由器。

如果你手上有老旧的笔记本电脑舍不得扔的话,不妨改造成一个科学上网路由器,发挥最大价值。


该方法同样适用于分享一个wifi给PS4这样的设备去外网玩游戏用

 大体思路

我的Ubuntu笔记本有两块网卡,一块插网线的有线网卡,一块WIFI无线网卡,用Ubuntu系统自带的功能将无线网卡做成一个热点,然后该无线网卡以有线网卡为网关,所有流量流经有线网卡,当有设备通过WIFI链接上我无线网卡分享出的热点后,所有的流量经过iptables的端口转发后发送给redsocks,再经redsocks发送给S-S的客户端,最后将流量发送给远程代理服务器,这样无线网卡就变成了一个透明代理,所有通过我电脑分享WIFI上网的设备都实现了全局代理。

 所需设备和软件

Ubuntu设备一台,据备无线网卡和有线网卡(我用的是一台普通的ThinkPad笔记本)。

一个S-S帐号(一般十块钱左右一月,网上很多卖的)。

S-S 客户端

redsocks服务(Ubuntu直接使用apt-get指令安装即可)后记:推荐使用redsocks2

iptables服务(Ubuntu自带的即可)


 部署过程

第一步:安装SS客户端

这个方面网上有很多文章介绍,这里就不多说了,总之需要在本机开启一个socks5代理的端口,如果比如127.0.0.1:1080。

(ps:如果要分享给区域网其他用户使用这个端口,就配置成局域网地址:1080比如192.168.1.81:1080)

因为Ubuntu上命令行的SS,也就是通过apt-get install sslocal安装的S-S版本太低,不支持RC4-MD5加密方法(python 支持),于是我这里用的是图形界面的S-S-Qt5

(ps:图形界面的S-S-Qt5稳定性不强,经常请求数一多和流量一高的时候就崩溃,所以推荐去编译github上最新的SS命令行客户端,具体步骤可以参考我的博文《Ubuntu编译运行ss-redir打造透明代理Wifi环境》,最新C语言版的SS我没有见过崩溃的情况出现,非常稳定)。

大体的配置如下:


注:为了防止代理服务器DNS解析出问题,上面的“服务器地址”推荐直接使用IP地址,而不是域名。

第二步:部署redsocks服务

redsocks是非常好用的代理软件,用于把普通的tcp流量转换成socks5协议的流量,是这个实现中的关键。

后记:redsocks本身有很多bug,造成redsocks运行极不稳定,推荐使用国内一大神修改后的Redsocks2,稳定性极高,并且集成了SS功能在里面,Redsocks2可以完全取代ss客户端,具体可以参考我的博客《Ubuntu编译运行Redsocks2实现透明代理》,注意,redsocks2的配置文件也和redsocks不同。

部署起来也不麻烦,首先通过下面的指令进行安装

sudo apt-get updatesudo apt-get install redsocks
然后修改redsocks的配置文件 /etc/redsocks.conf,如下

base {// debug: connection progress & client list on SIGUSR1log_debug = off;// info: start and end of client sessionlog_info = on;/* possible `log' values are: *   stderr *   "file:/path/to/file" *   syslog:FACILITY  facility is any of "daemon", "local0"..."local7" */log = "syslog:daemon";// detach from consoledaemon = on;/* Change uid, gid and root directory, these options require root * privilegies on startup. * Note, your chroot may requre /etc/localtime if you write log to syslog. * Log is opened before chroot & uid changing. */user = redsocks;group = redsocks;// chroot = "/var/chroot";/* possible `redirector' values are: *   iptables   - for Linux *   ipf        - for FreeBSD *   pf         - for OpenBSD *   generic    - some generic redirector that MAY work */redirector = iptables;}redsocks {/* `local_ip' defaults to 127.0.0.1 for security reasons, * use 0.0.0.0 if you want to listen on every interface. * `local_*' are used as port to redirect to. */local_ip = 0.0.0.0;//本地监听的ip地址和端口,一般默认即可local_port = 12345;// `ip' and `port' are IP and tcp-port of proxy-server// You can also use hostname instead of IP, only one (random)// address of multihomed host will be used.ip = 127.0.0.1;//S-S 客户端提供的socks5代理端口port = 1080;// known types: socks4, socks5, http-connect, http-relaytype = socks5;// login = "foobar";//使用SS客户端一般不需要用户名和密码// password = "baz";}redudp {//这个配置是UDP请求转TCP请求的配置,用于DNS转换// `local_ip' should not be 0.0.0.0 as it's also used for outgoing// packets that are sent as replies - and it should be fixed// if we want NAT to work properly.local_ip = 0.0.0.0;//不要修改,保持默认local_port = 10053;//不要修改,保持默认// `ip' and `port' of socks5 proxy server.ip = 127.0.0.1;//S-S 客户端提供的socks5代理端口port = 1080;//login = username;//使用客户端一般没有用户名和密码//password = pazzw0rd;// kernel does not give us this information, so we have to duplicate it// in both iptables rules and configuration file.  By the way, you can// set `local_ip' to 127.45.67.89 if you need more than 65535 ports to// forward ;-)// This limitation may be relaxed in future versions using contrack-tools.dest_ip = 8.8.8.8;//DNS的服务器地址,推荐8.8.8.8dest_port = 53;//DNS的服务器的服务端口,使用默认的53即可udp_timeout = 30;udp_timeout_stream = 180;}dnstc {//配置UDP DNS转发端口// fake and really dumb DNS server that returns "truncated answer" to// every query via UDP, RFC-compliant resolver should repeat same query// via TCP in this case.local_ip = 127.0.0.1;//给DNS请求 UDP包转TCP包的转发地址,注意这里不要改成0.0.0.0local_port = 5300;//给DNS请求 UDP包转TCP包的转发接口}

然后重启redsocks服务

$ sudo service redsocks start


第三步:也是最容易出错的一步了,就是使用iptables配置相关路由协议

我这里把我配置的贴出来

//避免局域网回路sudo iptables -t nat -A PREROUTING -d 127.0.0.0/24 -j RETURN sudo iptables -t nat -A PREROUTING -d 192.168.0.0/16 -j RETURN//让发给其他设备的数据包顺利通过,下面的10.42.0.0/16是连接了Ubuntu热点的设备的ip地址段sudo iptables -t nat -A PREROUTING -d 10.42.0.0/16 -j RETURN//将其他的数据包,也就是其他设备访问网络的数据包全部转发到redsocks的服务端口sudo iptables -t nat -A PREROUTING -p tcp -j REDIRECT --to-ports 12345//配置好上面的路由规则就可以实现所有连接热点的设备自动科学上网了,但是DNS解析还是在墙内解析,会碰到DNS污染无法访问facebook等网站,所以下面将DNS请求包也转发至SS//将UDP的DNS解析请求通过redsocks转换成tcp的DNS请求sudo iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 5300//将TCP的DNS请求通过SS发送给SS客户端进行远程墙外解析sudo iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 12345

这里不得不说一下,在设置了上面的PREROUTING规则之后,连上笔记本分享wifi的设备就已经把所有的tcp流量走了S-S代理,但是使用udp协议的DNS查询请求还是走的本地,而墙内对facebook,twitter,google这样的网站一般都进行了DNS污染,也就是解析他们的域名时会返回错误的IP地址。即使把DNS服务器设置成8.8.8.8或者OpenDNS也会因为其他服务器的DNS缓存而得到错误的IP地址,况且8.8.8.8等DNS服务器的流量早就已经被墙了,根本ping不通。

所以我们需要让DNS解析请求也经过SS代理服务器进行解析,但是redsocks不支持udp协议包的转发,而且有些SS代理服务器也不支持udp协议,所以此时我们就需要将udp协议包转换成tcp协议包,发送到SS代理服务器解析,然后再以tcp协议包发回,获得解析结果。这些步骤redsocks已经设计好了,只需要向上面贴的加上OUTPUT路由协议即可实现。

但是按上面的iptables配置添加了OUTPUT的路由协议,我Ubuntu本机应用的DNS解析都瘫痪了,但好在我可以让浏览器和其他服务直接挂S-S的客户端进行上网,也就是不走系统默认的DNS解析,而是让每个应用自主的使用代理解析DNS,于是也就忽略了这个缺陷。

下面贴一下DNS被污染后的解析结果


可以看到IP被指向了非美国的IP,而curl这个IP是得不到任何相应的,下面贴一下经过redsocks udp转tcp协议后正确DNS解析的结果


第四步:修改Ubuntu的DNS解析服务器

只需要修改/etc/resolv.conf文件,如下将默认的127.0.0.1前面加上#,然后添加8.8.8.8做dns服务器

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN#nameserver 127.0.0.1nameserver 8.8.8.8

将DNS服务器改成8.8.8.8,以后的DNS请求就会转换成tcp协议通过SS代理服务器的转发到代理服务器当地的8.8.8.8解析后返回,防止DNS污染

保存以后一般立即生效,无需重启

后记:该方法会导致Ubuntu系统自身无法获得DNS结果而无法上网,但是wifi客户端是没有问题的,最方便的解决方案是让Ubuntu本机的dnsmasq请求OpenDNS的非53端口,详细做法可以看我的博客《Dnsmasq+ipset+iptables基于域名的流量管理》,但是更好的办法是使用pdnsd将UDP的DNS请求转换为TCP协议的请求来防止投毒污染,具体做法可以参考我的博客《Ubuntu16.04用Pdnsd替换dnsmasq防止DNS污染》


第五步:开启Ubuntu的Wifi热点功能

开启该项功能不麻烦,可以参考下面经验

http://jingyan.baidu.com/article/363872ecd8f35d6e4ba16f97.html


好了,目前为止该做的都已经完成了,现在可以打开手机链接一下试试科学上网好使不好使,推荐首先测试国内网站,排除DNS污染的影响,比如百度搜索"ip"看看自己的ip是否已经变成了代理服务器的ip,然后再访问被墙网站。


 开发中遇到的坑

首先就是Ubuntu分享出来的WIFI,除了小米手机意外的设备,比如电脑,iphone,Android手机连接都没有问题,但是小米手机一连接该WIfi我的笔记本无线网卡就会挂掉,Ubuntu提示“设备未就绪”,经过一番调试,发现这有可能和udp DNS转tcp有关,我当时为了减少WIFI信号上的冲突,将无线网卡的频率限制在了2.4G的波段4,于是小米手机链接后网卡挂是必现事件,后来将波段改成了自动之后,Ubuntu给我设置在了波段一,网卡挂掉的频率减少了很多,不是必现了。后来我又加上了WIFI密码,网卡几乎就不挂了(之前我都不设WIFI密码,任何设备都可以连接)。所以在这里推荐将波段设置为自动,并且设置连接密码来提高稳定性。


当然用上面的方式,在接入设备多的时候还是会导致无线掉线,最好的方式还是用专门的无线路由器来连接客户端而不是使用Ubuntu电脑自带的小wifi网卡,然后把Ubuntu电脑作为网关进行流量转发实现代理,相关实现可以看我的博客《OpenWrt基于HAProxy的透明代理负载均衡和高可用部署》


还有一个问题不得不说,redsocks和S-S-Qt5一样在Ubuntu上运行的稳定性很差,连接的人数一多,或者数据传输量比较大的时候会莫名其妙的挂掉,一般我都使用nslookup命令来查询DNS测试是否宕机,如果能查寻到正确结果,说明redsocks和S-S都没问题,反之这两个服务至少挂掉了一个,redsocks服务挂掉之后12345端口并不会关掉,使用netstat -ntl还是可以看到,但是如果S-S服务挂了,那么1080端口就看不到了,通过netstat -ntl命令就可以查到是哪个服务挂了,如果是redsocks服务挂掉,可以使用

$ sudo service redsocks restart

来重启服务,一般重启后几十秒后就会恢复正常

一般redsocks挂都是因为too many open files,也就是说redsocks建立的socks连接数超过linux内核的限制,ubuntu系统默认限制是1024,需要修改配置文件来提高这个限制,需要编辑 /etc/security/limits.conf这个文件如下

#*               soft    core            0#root            hard    core            100000#*               hard    rss             10000#@student        hard    nproc           20#@faculty        soft    nproc           20#@faculty        hard    nproc           50#ftp             hard    nproc           0#ftp             -       chroot          /ftp#@student        -       maxlogins       4* soft nofile 65000* hard nofile 65000# End of file

主要是中间65000两句,配置完成后重启计算机,使用ulimit -n来查看当前文件限制,如果返回65000说明修改成功。

S-S稳定性提高方案是将客户端移到别的电脑上,或者使用最新的python版或者libev版,我使用windows客户端稳定性极高,几乎不会掉线。

为了进一步提高redsocks的稳定性,我使用crontab每分钟重启一次redsocks,不然的话虽然文件限制提高了,但是redsocks并不会清理某些已没用的连接,所以需要定时重启一下redsocks(redsocks2已经解决这一问题)方法如下:

首先修改crontab的配置文件

$ sudo crontab -e

在最下面添加这样一行

*/10 * *   *   *     /etc/init.d/redsocks restart

然后重启crontab服务

sudo service cron restart

过几分钟观察crontab定时任务有没有很好的运行

service cron status


这样每10分钟redsocks都会重启一次redsocks,就不会出现too many open files导致无法连通网络了

后记:上面的方法并不优雅,推荐使用Redsocks2,没有不关闭连接的bug,几乎不会崩溃,详情可以看我的博客《Ubuntu编译运行Redsocks2实现透明代理》

 高负载分流方案

这么好的东西,只需连上一个WIFI就能实现全局科学上网,速度还比VPN快好多,当然会有很多人用,人数多了之后主要的瓶颈就在wifi信号和ss流量上,目前我使用的单个节点能平均能跑到10Mb/s,峰值能达到30Mb/s感觉还够用,但是如果以后人数更多,加上下载和看视频的流量,也许就捉襟见肘了。那么我们可以使用多个SS代理服务器进行分流,我打算这么做,1台延迟低的节点做DNS解析,主要是得益于redsocks的DNS和普通流量分离的做法,剩下几个节点做数据分流。分流方案我打算用ip地址进行分流,因为Ubuntu的无线网卡有DHCP功能,而且对连接设备的ip分配是随机的,于是可以根据设备的ip进行分段分流。
首先需要实现的是开启多个redsocks实例,监听不同的端口,这个比较容易实现,首先我们需要复制原来的配置文件并且进行修改,比如将原来的1080端口换成1081端口,然后再开启一个S-S客户端实例挂在另一个代理节点在127.0.0.1:1081接口,这个使用S-S-Qt5很容易实现。我们把新的redsocks配置文件命名为 redsocks2

然后我们使用-c参数开启redsocks实例,监听两个不同的端口实现分流

$ sudo /usr/bin/redsocks -c /etc/redsocks

$ sudo /usr/bin/redsocks -c /etc/redsocks2

然后修改S-S客户端,监听1080和1081两个端口分别使用不同的节点


然后使用iptable路由协议根据ip地址进行分流

$ sudo iptables -t nat -I PREROUTING 5 -p tcp -m iprange --src-range 10.42.0.100-10.42.0.254 -j REDIRECT --to-ports 23456

$ sudo iptables -t nat -A PREROUTING -p tcp -s 10.42.0.0/16 -j REDIRECT --to-ports 12345

这样就将一半的流量分流至了另一个ss站点,该WIFI的带宽瞬间增长一倍。使用这种方案还能配置更多节点,让WIFI的瓶颈不再是带宽限制,最终实现全公司人科学上网工作。

后记:上面的仅仅是通过ip段来实现负载均衡,但是对于SS服务端没有实现均衡,最好的方式不是对客户端进行均衡,而是将客户端发来的所有流量负载均衡和高可用到多个不同的ss服务器上去,实现方法可以看我的博客《OpenWrt基于HAProxy的透明代理负载均衡和高可用部署》

另外有人会说这样使用iptables折腾是不是太麻烦了,如果有一个VPN帐号,Ubuntu原生在分享Wifi的时候就可以自动配置,根本不需要任何配置,用Windows使用VPN之后再加上WIFI共享精灵等软件共享出来的也是VPN科学上网后的,那我们为什么还非要搞的这么复杂呢?

S-S使用socks5协议,是一种将流量压缩并加密的优秀传输协议,相比起PPTP的VPN隧道具有几个明显的优势:

1、安全性好,数据传输经过了充分的加密,不容易深度包检测发现流量特征

2、稳定性好,L2TP掉线率很高,并且掉线以后往往缺乏自动重连的机制,但是S-S的客户端一般不会轻易掉线

3、服务器搭建成本低,不需要配置密钥,只需开启一个服务即可

4、速度快,S-S的速度在请求人数多的时候非常明显,并且可以配合锐速这样种变态功能进行加速,效果非常好

鉴于S-S的这些优点,现在已经很难买到PPTP协议的VPN了,即使买到,往往也很难连上。

后记:我们也可以把SS转换成PPTP或者OpenVPN来使用,这样可以照顾那些喜欢挂VPN上网的人,SS转VPN的方法可以看我的博客《Socks5代理(SS/SSH)转国内PPTP VPN的方法》

0 0
原创粉丝点击