Over the last few months I’ve been playing with MultiPath TCP and in this post I will show how I use it to leverage my humble True ADSL line at home.

For performance and security reasons, I tunnel all my traffic thru a VPN. This is not necessarily to circumvent censorship, but to circumvent the evil transparent proxiesmy ISP puts in middle. The total bandwidth available is ~10 mbps down / ~1 mbps up.

Introduction to MultiPath TCP

MultiPath TCP is an interesting effort to use multiple interfaces/networks for any single TCP connection. A Linux kernel implementation is being developed at multipath-tcp.org. Its main use cases are for mobile (transition between Wi-Fi and 3G) and datacenters. I exploit it to get better Internet browsing experience.

Old way

  1. SSH tunnel to EC2 instance in Singapore. Browser configured to use this tunnel as proxy
  2. SSH tunnel to EC2 instance in us-east (for accessing geo-blocked services)

Main drawback : If my ISP has issues talking to AWS, then I’m totally screwed. This happened a month or so ago where most links coming into True was severely limited, however link from Digital Ocean to True was healthy. I had to manually change my tunnels to a $5 Digital Ocean instance.

New way

Note: This is a constantly evolving setup as I find new things to play with.

Infrastructure involved :-

  • PC Engines APU system board - Replaces router. All magic happens here. gateway
  • ADSL modem in bridge mode.
  • EC2 instance in Singapore - The main proxy endpoint. Runs shadowsocksserver over MPTCP kernel. destination, jumpbox
  • EC2 instance in us-west - The proxy endpoint for US geo blocked traffic. Runs shadowsocks server over MPTCP kernel. destination
  • Digital Ocean instance in Singapore - An alternate path to reach the EC2 instance(s) jumpbox
  • VPS in CAT datacenter in Thailand - Another alternate path. All Thai ISPs usually have good connectivity to CAT. jumpbox
  • Android phone - With Dtac 3G for extra boost when needed. USB tethering. Bandwidth fluctuates a lot. I typically use it to get a boost in my upload bandwidth which is generally 100 kbps to 8 mbps.

All TCP Traffic is intercepted by the APU using iptables, diverted to redsocks, which sends it to the shadowsocks client, which sends it to the shadowsocks server running in EC2 Singapore. This socks connection has several ways to communicate with the EC2 instance.

APU <--> True ADSL Directly <--> EC2
APU <--> True ADSL Directly over OpenVPN/UDP <--> EC2
APU <--> True ADSL <--> via CAT VPS over OpenVPN/UDP <--> EC2
APU <--> True ADSL <--> via DO Singapore over OpenVPN/UDP <--> EC2
APU <--> Dtac 3G Directly <--> EC2 (Optional/ondemand)

Now I have 5 possible paths. MPTCP kernel creates a TCP connection over each available path and bonds them together and exposes it as a single TCP connection to the application. Packets are sent over paths that currently have the lowest delay. Now my available bandwidth is not impacted by congestion over some of these paths. All paths need to be congested for me to have a bad day… Also some path might have good uplink, some might have good downlink, with MPTCP you mix the best of both…

Example bmon stats when downloading a large file (I removed irreverent interfaces.)

  #   Interface                RX Rate         RX #     TX Rate         TX #
─────────────────────────────────────────────────────────────────────────────
xxx (source: local)
0 tun1 621.28KiB 628 38.82KiB 636
3 tun3 200.22KiB 198 9.42KiB 149
5 ppp0 1.07MiB 1018 119.42KiB 980
9 tun0 90.06KiB 90 5.94KiB 97

Configurations

Jumpbox

Jumpbox is pretty basic setup. It’s role is to provide additional gateways which MPTCP uses to build additional paths.

OpenVPN server configured normally. Set to not redirect default gateway. In my current setup I need to ensure that the server assigns the same IP to my client. This is not really that crucial, but it keeps things simple. Its important to configure each jumpbox to use a different IP range.

net.ipv4.ip_forward needs to be set to 1 to allow forwarding. In fact almost all boxes in the setup need this.

iptables rules needed :-

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t filter -A FORWARD -i tun0 -j ACCEPT
iptables -t filter -A FORWARD -o tun0 -j ACCEPT

Replace the tun0 and eth0 to suit your environment.

Destination

A destination server is remote end of our socks tunnel. It’s job is to service the socks connections patching them to the real destination.

This needs to run a MultiPath TCP kernel. On EC2 it is pretty simple. Launch an Ubuntu 14.04 instance with a pv-grub AKI. Then follow the apt-repository installation method. And ensure the grub loads the MPTCP kernel as its first choice.

Next we also need shadowsocks server running. RTFM its pretty simple. Before using shadowsocks I was using a simple ssh -D tunnel, but I found it to be inefficient. Often times one large transfer would make all other TCP streams stuck. Perhaps this has something to do with the fact that with SSH everything is happening over a single TCP stream whereas shadowsocks makes a new socks connection dedicated to each TCP connection.

Gateway

The gateway is the most complicated component. Running stock Debian wheezy with MPTCP kernel installed via their apt repository. A lot of services run here. I will not elaborate on some of them.

dbcpd - Assign LAN users with IP

bind - For DNS recursion. Since we tunnel most traffic to Singapore, I also set bind to send DNS queries thru OpenVPN.

iptables - I use iptables to do the NAT. NAT all UDP packets to OpenVPN. Send all outgoing TCP connections to redsocks.

# Generated by iptables-save v1.4.14 on Sat Nov 22 00:37:10 2014
*nat
:PREROUTING ACCEPT [378881:57485495]
:INPUT ACCEPT [210208:17266788]
:OUTPUT ACCEPT [4099955:310913862]
:POSTROUTING ACCEPT [3239510:252587265]
:REDSOCKS - [0:0]
- -A PREROUTING -i br0 -p tcp -j REDSOCKS
- -A PREROUTING -i br0 -j REDSOCKS
- -A POSTROUTING -o tun1 -j MASQUERADE
- -A POSTROUTING -o tun0 -j MASQUERADE
- -A POSTROUTING -o tun2 -j MASQUERADE
- -A POSTROUTING -o eth0 -j MASQUERADE
- -A REDSOCKS -d 0.0.0.0/8 -j RETURN
- -A REDSOCKS -d 10.0.0.0/8 -j RETURN
- -A REDSOCKS -d 127.0.0.0/8 -j RETURN
- -A REDSOCKS -d 169.254.0.0/16 -j RETURN
- -A REDSOCKS -d 172.16.0.0/12 -j RETURN
- -A REDSOCKS -d 192.168.0.0/16 -j RETURN
- -A REDSOCKS -d 224.0.0.0/4 -j RETURN
- -A REDSOCKS -d 240.0.0.0/4 -j RETURN
- -A REDSOCKS -d a.b.c.d/32 -j RETURN
- -A REDSOCKS -d e.f.g.h/32 -j RETURN
- -A REDSOCKS -d i.j.k.l/32 -j RETURN
- -A REDSOCKS -d m.n.o.p/32 -j RETURN
- -A REDSOCKS -d q.r.s.t/32 -j RETURN
- -A REDSOCKS -s 192.168.5.1/32 -j RETURN
- -A REDSOCKS -s 192.168.5.1/32 -j RETURN
- -A REDSOCKS -s 192.168.1.2/32 -j RETURN
- -A REDSOCKS -s 192.168.5.32/27 -p tcp -j REDIRECT --to-ports 12345
COMMIT
# Completed on Sat Nov 22 00:37:10 2014
# Generated by iptables-save v1.4.14 on Sat Nov 22 00:37:10 2014
*filter
:INPUT ACCEPT [115657469:73738905421]
:FORWARD ACCEPT [64078:47442189]
:OUTPUT ACCEPT [122121802:63701527314]
- -A FORWARD -i eth1 -j ACCEPT
- -A FORWARD -o eth1 -j ACCEPT
- -A FORWARD -i br0 -j ACCEPT
- -A FORWARD -o br0 -j ACCEPT
- -A FORWARD -i eth0 -j ACCEPT
- -A FORWARD -o eth0 -j ACCEPT
COMMIT
# Completed on Sat Nov 22 00:37:10 2014
# Generated by iptables-save v1.4.14 on Sat Nov 22 00:37:10 2014
*mangle
:PREROUTING ACCEPT [118734314:74507536093]
:INPUT ACCEPT [115635709:73734306355]
:FORWARD ACCEPT [3100331:759352048]
:OUTPUT ACCEPT [122104929:63698976437]
:POSTROUTING ACCEPT [125198421:64456746251]
- -A PREROUTING ! -d 192.168.5.0/24 -i br0 -j MARK --set-xmark 0x1/0xffffffff
- -A PREROUTING -d 10.8.0.10/32 -i br0 -j MARK --set-xmark 0x3/0xffffffff
- -A PREROUTING -d 192.168.10.1/32 -i br0 -j MARK --set-xmark 0x2/0xffffffff
COMMIT
# Completed on Sat Nov 22 00:37:10 2014

Note: a.b.c.de.f.g.hi.j.k.lm.n.o.p and q.r.s.t are public internet ips that I don’t want redsocks to intercept.

Interfaces

  • br0 - LAN
  • tun[0-3] - Various Jumpboxes. OpenVPN tunnels.

Also, each interface is maintains its own routing tables using if-up scripts. For example this is what gets executed when one of the tunnels comes alive.

<pre><code>#!/bin/sh
ip rule add from 10.8.0.20 table 2 || true
ip route add 10.8.0.0/24 dev tun0 scope link table 2 || true
ip route add default via 10.8.0.21 dev tun0 table 2 || true
ip rule add fwmark 3 table 2 || true
</code></pre>

The fwmark is added so if in future I want to pipe different traffic to go thru this interface I can set the corresponding iptables rule.

All local services are scoped to listen only on local interfaces to avoid random people connecting to local services.

redsocks - Accepts intercepted connections and pipes it off to shadowsocks client

shadowsocks client - sends all TCP connections to shadowsocks servers running in EC2 Singapore and US. By default intercepted traffic is sent to Singapore, however any application on any computer in the network could be set to explicitly use any of the available proxies.

wvdial - To dial the ADSL connection which is itself behind a Carrier-grade NAT. Sometimes the connection stops working while pppd things its still connected. Am ugly CRON script to test the network and flip it if needed.

<pre><code>#!/bin/bash

IP=`/sbin/ip route | grep -v default | grep ppp0 | cut -d " " -f 1`
COUNT=`echo $IP | wc -l` echo $IP $COUNT
if [ $COUNT -eq 1 ]
then
ping -c 10 $IP > /dev/null
if [ $? -eq 0 ]
then
echo "ppp0 is up"
else
echo "ppp0 is down"
kill -SIGHUP `pgrep pppd`
beep -l 25
fi
else
echo "ppp0 not found?!?!?!?1"
fi
</code></pre>

The script above tries to ping the default gateway of the ppp0 interface to find out if it is really up. SIGHUP signals pppd to handup and redial. I don’t bother maintaining the pid of pppd because currently I use ppp0 exclusively for the ADSL modem.

Missing parts

There are some issues I am having that I need to sort out work-around for.

  • Default connection unstable. If the initial syn packet for ppp0 (my default interface) fails, then the connection cant be established. I need to look deeper into MPTCP docs to figure out how to make it such that if the initial TCP connection setup fails on ppp0 then make it try tun0, tun1 and so on.
  • Connection fairness. Sometimes if I am doing a big upload, everything else (like browsing websites) seems too slow. The upload is hogging all the available uplink, which is already too tiny. I have my suspicions on buffer bloat…
  • Higher uplink usage. When downloading something, I see ~10% upload traffic corresponding to it. This is lot higher than a simple setup. I need to investigate deeper whats causing it. Perhaps MPTCP or the socks setup or OpenVPN. The example bmon stats above show this as well 119.42KiB uplink while downloading @ 1.07MiB.
  • EC2 bandwidth is expensive. I would like to use Digital Ocean boxes for socks proxies. This is a little tricky since DO does not allow loading custom kernels. I need to figure out kexec to make this possible. Unsure if this way is stable…
  • Advanced routing. I would like to programatically decide which external IP should go thru which proxy. For example most Thai IPs I would like to go direct. Some American destinations should go thru the US proxy, rest thru Singapore proxy. Perhaps in future add an European proxy.. Currently the only way to use the American proxy is to explicitly configure a particular application to use socks proxy.
  • UDP tunneling. UDP traffic currently goes directly using a single OpenVPN session. There is no load-balancing being performed on it. I would like to switch to a different socks client/server. One that does UDP associate.

Future path enhancements

More paths can be added to get better throughput.

  • 3G dongles from various providers.
  • The shitty Wi-Fi that your apartment/office provides.
  • More ADSL/Cable connections from diverse providers with different backbones.

Conclusion

MPTCP is a fantastic piece of technology. Hat-tip to everyone who contributed to it. The PC Engines ALU box is also awesome. Decent x86_64 box consuming only about 6 to 12W power.

In the future I will do a walk-thru type post on how to setup a Raspberry Pi as a one-arm gateway doing a subset of what I described above. The most challenging part is getting a MPTCP enabled kernel on the pi, which requires kernel patching and compiling. The throughput will likely be very limited because MPTCP has a higher CPU overhead than regular TCP.

Tags: mptcp tcp network 
Categories: 

Using MultiPath TCP to enhance home networks的更多相关文章

  1. Multipath TCP and load balancers

    Load balancers play a very important role in today’s Internet. Most Internet services are provided b ...

  2. Multipath TCP on iOS11 : A closer look at the TCP Options(转)

    Multipath TCP uses a variety of TCP options to use different paths simultaneously. Several Multipath ...

  3. 揭开 iOS 7 之 Multipath TCP 的面纱(转)

    看到中文圈似乎讨论 iOS 7 的这个特性的还不多,于是我稍微研究了一下这个「Mutlipath TCP」,写点心得.过程是这样的: Olivier Bonaventure 通过 Wireshark ...

  4. 使用 Multipath TCP 为 iOS 创建备份连接(转)

    这篇文章的英文版如下: https://support.apple.com/en-us/HT201373 这里咱们采用苹果手机打开测试网站,发现没有检测到MPTCP,初步猜想可能需要打开什么设置,后续 ...

  5. Apple uses Multipath TCP

    http://blog.multipath-tcp.org/blog/html/2018/12/15/apple_and_multipath_tcp.html December 15, 2018 Ap ...

  6. multipath tcp experiment

    git clone https://github.com/Neohapsis/mptcp-abuse.git sudo apt-get install python-pip sudo pip inst ...

  7. [转载] TCP协议缺陷不完全记录

    原文: http://www.blogjava.net/yongboy/archive/2015/05/07/424917.html tcp是一个非常复杂并且古老的协议, 之前教科书上将的很多东西应用 ...

  8. TCP 函数

    [root@localhost tt]# man listen LISTEN() Linux Programmer’s Manual LISTEN() NAME listen - listen for ...

  9. Congestion Avoidance in TCP

    Congestion Avoidance in TCP Consequence of lack of congestion control When a popular resource is sha ...

随机推荐

  1. 事件总线EventBus

    什么是事件总线管理? 将事件放到队列里,用于管理和分发: 保证应用的各个部分之间高效的通信及数据,事件分发: 模块间解耦: 什么是EventBus? EventBus是发布/订阅的事件总线.Event ...

  2. 模式识别之ocr项目---(模板匹配&BP神经网络训练)

    摘 要 在MATLAB环境下利用USB摄像头采集字符图像,读取一帧保存为图像,然后对读取保存的字符图像,灰度化,二值化,在此基础上做倾斜矫正,对矫正的图像进行滤波平滑处理,然后对字符区域进行提取分割出 ...

  3. 【转】Android IDA 动态调试最完善攻略,跨过各种坑

    前提条件和运行环境一定要写清楚,不然会有很多坑,坑死人. (1)IDA 是最新的7.0版本  (2) JDB 使用Java安装目录下的 (3)系统是win10 使用命令窗口时有很大的差别 (4)手机是 ...

  4. Android 四大组件学习之BroadcastReceiver一

    本节课学习四大组件最后一个, 广播接受者. 顾名思义广播接受者就是接受广播呗.比方在现实社会中,曾经每一个人家都有一台收音机,这可就能够去接受广播发出来的消息.大家都知道.程序世界也是參照的显示生活设 ...

  5. mac 权限问题

    终端输入sudo chown -R zjtc /usr/local

  6. EasyDarwin开源流媒体云平台之EasyRMS录播服务器功能设计

    需求背景 EasyDarwin开发团队维护EasyDarwin开源流媒体服务器也已经很多年了,之前也陆陆续续尝试过很多种服务端录像的方案,有:在EasyDarwin中直接解析收到的RTP包,重新组包录 ...

  7. EasyDarwin接入ffmpeg实现264转图片快照功能

    本文转自:http://blog.csdn.net/cai6811376/article/details/51774467 EasyDarwin一直坚持开源精神,所以我们着手把EasyDarwin中使 ...

  8. 配置hadoop用户SSH无密码登陆 的2种方式 落脚点是 可以ssh免密进入的主机名写入动作发出主机的 known_hosts,而被无密进入主机的authorized_keys文件 免密登录

    cat /proc/versionLinux version 3.10.0-327.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version ...

  9. Could not find com.android.tools.lint:lint-gradle:26.1.2.

    allprojects { repositories { flatDir { dirs 'libs' } jcenter() google() }}

  10. go 包的问题

    同一个包下的所有方法,都整合到一个里面去了,通过包名可以任意调用包下的方法. 文件夹的名字必须要和文件里面的package的名字一样,否则会报错... 导文件就是文件所在的包 导包import(),是 ...