FSH – 助你接入私有网络中的 Linux 终端

Linuxer! 同事、朋友有技术问题需要你远程协助,可是双方计算机都连接在私有网络中怎么办?FSH 能助你接入私有网络中的 Linux 终端。

FSH 是采用服务器中转来穿透 NAT 的一种连接远程 Linux 终端的方案,服务端、客户端的源代码都是开放的,托管在 GitHub 上。

如何编译?

git clone git://github.com/heiher/hev-fsh
cd hev-fsh
git submodule init
git submodule update
make

如何使用?
公共转发服务:222.92.8.138:81

被控端

# 登录模式(root 用户运行)
bin/hev-fsh -s 222.92.8.138 -p 81
 
# 当前用户模式
bin/hev-fsh -s 222.92.8.138 -p 81
 
# 指定用户模块,如 nobody 用户(root 用户运行)
bin/hev-fsh -s 222.92.8.138 -p 81 -u nobody

主控端

bin/hev-fsh -s 222.92.8.138 -p 81 -c TOKEN

自建转发服务端

bin/hev-fsh -a 0.0.0.0 -p 端口
 
# 指定 LOG 文件
bin/hev-fsh -a 0.0.0.0 -p 端口 -l /var/log/fsh.log

Over!

How to connect to a WPA/WPA2 WiFi network using Linux command line

This is a step-to-step guide for connecting to a WPA/WPA2 WiFi network via the Linux command line interface. The tools are:
1. wpa_supplicant
2. iw
3. ip
4. ping

iw is the basic tool for WiFi network-related tasks, such as finding the WiFi device name, and scanning access points. wpa_supplicant is the wireless tool for connecting to a WPA/WPA2 network. ip is used for enabling/disabling devices, and finding out general network interface information.

The steps for connecting to a WPA/WPA2 network are:

1. Find out the wireless device name.

    $ /sbin/iw dev
    phy#0
    	Interface wlan0
    		ifindex 3
    		type managed

The above output showed that the system has 1 physical WiFi card, designated as phy#0. The device name is wlan0. The type specifies the operation mode of the wireless device. managed means the device is a WiFi station or client that connects to an access point.

2. Check that the wireless device is up.

    $ ip link show wlan0
    3: wlan0: (BROADCAST,MULTICAST) mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
        link/ether 74:e5:43:a1:ce:65 brd ff:ff:ff:ff:ff:ff

Look for the word “UP” inside the brackets in the first line of the output.

In the above example, wlan0 is not UP. Execute the following command to bring it up:

    $ sudo ip link set wlan0 up  
    [sudo] password for peter:

Note: you need root privilege for the above operation.

If you run the show link command again, you can tell that wlan0 is now UP.

    $ ip link show wlan0
    3: wlan0: (NO-CARRIER,BROADCAST,MULTICAST,UP) mtu 1500 qdisc mq state DOWN mode DEFAULT qlen 1000
        link/ether 74:e5:43:a1:ce:65 brd ff:ff:ff:ff:ff:ff

3. Check the connection status.

    $ /sbin/iw wlan0 link
    Not connected.

The above output shows that you are not connected to any network.

4. Scan to find out what WiFi network(s) are detected

    $ sudo /sbin/iw wlan0 scan
    BSS 00:14:d1:9c:1f:c8 (on wlan0)
            ... sniped ...
    	freq: 2412
    	SSID: gorilla
    	RSN:	 * Version: 1
    		 * Group cipher: CCMP
    		 * Pairwise ciphers: CCMP
    		 * Authentication suites: PSK
    		 * Capabilities: (0x0000)
            ... sniped ...

The 2 important pieces of information from the above are the SSID and the security protocol (WPA/WPA2 vs WEP). The SSID from the above example is gorilla. The security protocol is RSN, also commonly referred to as WPA2. The security protocol is important because it determines what tool you use to connect to the network.

5. Connect to WPA/WPA2 WiFi network.
This is a 2 step process. First, you generate a configuration file for wpa_supplicant that contains the pre-shared key (“passphrase”) for the WiFi network.

    $ sudo -s
    [sudo] password for peter: 
    $ wpa_passphrase gorilla >> /etc/wpa_supplicant.conf 
    ...type in the passphrase and hit enter...

wpa_passphrase takes the SSID as the single argument. You must type in the passphrase for the WiFi network gorilla after you run the command. Using that information, wpa_passphrase will output the necessary configuration statements to the standard output. Those statements are appended to the wpa_supplicant configuration file located at /etc/wpa_supplicant.conf.

Note: you need root privilege to write to /etc/wpa_supplicant.conf.

    $ cat /etc/wpa_supplicant.conf 
    # reading passphrase from stdin
    network={
    	ssid="gorilla"
    	#psk="testtest"
    	psk=4dfe1c985520d26a13e932bf0acb1d4580461dd854ed79ad1a88ec221a802061
    }

The second step is to run wpa_supplicant with the new configuration file.

    $ sudo wpa_supplicant -B -D wext -i wlan0 -c /etc/wpa_supplicant.conf
    -B means run wpa_supplicant in the background.
    -D specifies the wireless driver. wext is the generic driver.
    -c specifies the path for the configuration file.

Use the iw command to verify that you are indeed connected to the SSID.

    $ /sbin/iw wlan0 link
    Connected to 00:14:d1:9c:1f:c8 (on wlan0)
    	SSID: gorilla
    	freq: 2412
    	RX: 63825 bytes (471 packets)
    	TX: 1344 bytes (12 packets)
    	signal: -27 dBm
    	tx bitrate: 6.5 MBit/s MCS 0
 
    	bss flags:	short-slot-time
    	dtim period:	0
    	beacon int:	100

6. Obtain IP address by DHCP

    $ sudo dhclient wlan0

Use the ip command to verify the IP address assigned by DHCP. The IP address is 192.168.1.113 from below.

    $ ip addr show wlan0
    3: wlan0:  mtu 1500 qdisc mq state UP qlen 1000
        link/ether 74:e5:43:a1:ce:65 brd ff:ff:ff:ff:ff:ff
        inet 192.168.1.113/24 brd 192.168.1.255 scope global wlan0
        inet6 fe80::76e5:43ff:fea1:ce65/64 scope link 
           valid_lft forever preferred_lft forever

7. Add default routing rule.
The last configuration step is to make sure that you have the proper routing rules.

    $ ip route show
    192.168.1.0/24 dev wlan0  proto kernel  scope link  src 192.168.1.113

The above routing table contains only 1 rule which redirects all traffic destined for the local subnet (192.168.1.x) to the wlan0 interface. You may want to add a default routing rule to pass all other traffic through wlan0 as well.

    $ sudo ip route add default via 192.168.1.254 dev wlan0
    $ ip route show
    default via 192.168.1.254 dev wlan0 
    192.168.1.0/24 dev wlan0  proto kernel  scope link  src 192.168.1.113

8. ping external ip address to test connectivity

    $ ping 8.8.8.8
    PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
    64 bytes from 8.8.8.8: icmp_req=1 ttl=48 time=135 ms
    64 bytes from 8.8.8.8: icmp_req=2 ttl=48 time=135 ms
    64 bytes from 8.8.8.8: icmp_req=3 ttl=48 time=134 ms
    ^C
    --- 8.8.8.8 ping statistics ---
    3 packets transmitted, 3 received, 0% packet loss, time 2000ms
    rtt min/avg/max/mdev = 134.575/134.972/135.241/0.414 ms

The above series of steps is a very verbose explanation of how to connect a WPA/WPA2 WiFi network. Some steps can be skipped as you connect to the same access point for a second time. For instance, you already know the WiFi device name, and the configuration file is already set up for the network. The process needs to be tailored according to your situation.

From: http://linuxcommando.blogspot.com/2013/10/how-to-connect-to-wpawpa2-wifi-network.html
Over!

Redirect TCP transmissions over Socks5 proxy

重定向 TCP 传输通过 Socks5 代理,此方案用于 Linux 平台。

下载、编译 HevSocks5TProxy

git clone git://github.com/heiher/hev-socks5-tproxy
cd hev-socks5-tproxy
git submodule init
git submodule update
make

运行 HevSocks5TProxy

bin/hev-socks5-tproxy conf/main.ini
# 127.0.0.1 : 本地监听地址
# 10800 : 本地监听端口
# 127.0.0.1 : Socks5 服务器地址
# 1080 : Socks5 服务器端口

本地全局启用
用于本地主机,重定向所有的 TCP 传输经过 Socks5 代理

sudo iptables -t nat -A OUTPUT -d xxx.xxx.xxx.xxx/32 -j RETURN # Bypass,远程 Socks5 服务器地址不通过代理
sudo iptables -t nat -A OUTPUT -m tcp -p tcp -j REDIRECT --to-port 10800

网关全局启用
用于网关服务器,重定向所有的 TCP 传输经过 Socks5 代理

sudo iptables -t nat -A OUTPUT -d xxx.xxx.xxx.xxx/32 -j RETURN # Bypass,远程 Socks5 服务器地址不通过代理
sudo iptables -t nat -A PREROUTING -m tcp -p tcp -j REDIRECT --to-port 10800

DNS 转发
对于 DNS 污染情况,参考 Forwarding DNS queries on TCP transport

Over!

Forwarding DNS queries on TCP transport

转发 UDP 协议的 DNS 查询至 TCP 协议传输,目前可以有效的抵御某些组织的 DNS 污染,此方案用于 Linux 平台。

下载、编译 DNS Forwarder

git clone git://github.com/heiher/hev-lib
cd hev-lib
make static
cd ..
 
git clone git://github.com/heiher/hev-dns-forwarder
cd hev-dns-forwarder
make

运行 DNS Forwarder

bin/hev-dns-forwarder 127.0.0.1 5300 8.8.8.8
# 127.0.0.1 : 本地监听地址
# 5300 : 本地监听端口
# 8.8.8.8 :  上游 DNS 服务器

本地全局启用
用于本地主机,透明转发所有的本机 DNS 查询

sudo iptables -t nat -A OUTPUT -m udp -p udp --dport 53 -j REDIRECT --to-port 5300

或直接设置本地的 DNS 服务器为 127.0.0.1,并将 Forwarder 的本地监听端口修改为 53。

网关全局启用
用于网关服务器,透明转发所有网关服务的主机的 DNS 查询

sudo iptables -t nat -A PREROUTING -m udp -p udp --dport 53 -j REDIRECT --to-port 5300

Over!

Linux netfilter REDIRECT target 构建透明代理原理

构建透明代理至于需要满足两个条件:1. 能够劫持应用程序产生的需代理的网络数据包。2. 能够获得这些数据包的原目的地址。

Linux netfilter 有一个 REDIRECT target,可用于 nat 表的 PREROUTING 和 OUTPUT 链上,其工作流程是将上述的两个链上命中的数据包的目的地址修改成(即重定向)该包进入网卡的主 IP 地址,如果是本地回环网络产生的包即重定向到 127.0.0.1。目标端口从参数指定,协议支持 tcp, udp, dccp or sctp。

从上面的情况看,Linux netfilter 的 REDIRECT target 可以实现透明代理的第一个条件,而第二个条件在强大的 Linux netfilter 子系统中也有方法:

#include <linux/netfilter_ipv4.h>
 
struct sockaddr_in orig_addr;
socklen_t orig_addr_len = sizeof (orig_addr);
if (0 == getsockopt(client_fd, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr*) &orig_addr, &orig_addr_len)) {
        printf ("This is original destination address => %s:%u\n", inet_ntoa (orig_addr.sin_addr), ntohs (orig_addr.sin_port));
}

Over!

Firefox for Android 代理设置

目前发现 Android 平台的浏览器原生支持代理配置的仅 Firefox for Android(官方下载),不仅支持 HTTP、HTTPS 和 Socks4、5,还支持 PAC 脚本。

全局代理配置
在 Firefox 中访问 about:config,使用 proxy 过滤器并的找到 network.proxy.socks, network.proxy.socks_port, network.proxy.socks_remote_dns, network.proxy.type 并更改成图中配置。
Screenshot_2014-09-19-13-34-16

Screenshot_2014-09-19-13-34-28

自动代理配置
将 PAC 脚本放至于 /sdcard/proxy.pac,在 Firefox 中访问 about:config,使用 proxy 过滤器并的找到 network.proxy.autoconfig_url, network.proxy.type 并更改成图中配置。
Screenshot_2014-09-19-13-33-51

Screenshot_2014-09-19-13-42-48

Over!

QEMU 高性能网络配置

QEMU 的网络配置最简单的是 -net user 模式,从 Guest OS 角度看 Host OS 为其提供了 NAT 和 DHCP 服务。此模式也有两点明显的不足之处:
1. 网络传输性能较差。
2. Host OS 访问 Guest OS 网络服务、Guest OS 互相访问对话网络服务都不方便。

这里推荐使用 -net tap 模式,大概的工作原理是 QEMU 进程会使用 Linux tun 子系统创建一个虚拟的 tap 类型的网络接口,这个虚拟的链路的一端在 Host OS 角度即是一个 Ethernet 类型的网络接口,另一端被 QEMU 连接到其在 Guest OS 中虚拟化的 Ethernet 网络接口上。Tap 类型的接口工作在链路层,链路上承载的协议与常规的 Ethernet 相比无多余的限制。这种情况看上去就像是 Host 与 Guest 都有一个网络接口直连着。

Host OS 还可以创建一个 Bridge,然后将 QEMU 创建的 tap 类型的网口都加入到同一个 Bridge 上面,这样就相当于将多个 Guest 及 Host 的一个网口都连接到同一个交换机上。当然创建多个 Bridge 进行分组管理也可以。

配置实例
Host OS

sudo brctl addbr br0
sudo brctl stp br0 off
sudo ifconfig br0 192.168.5.1/24 up
qemu-system-x86_64 --enable-kvm -net nic,model=virtio -net tap,helper=/usr/lib/qemu/qemu-bridge-helper ...

Guest OS

sudo ifconfig eth0 192.168.5.2/24 up
sudo route add default gw 192.168.5.1

外网配置
Guest OS 中如需连接外部网络,有两种方式:
1. NAT 模式,Host OS 视 Guest OS 所处的 Bridge 是一个内网,由 Host OS 提供 NAT 服务,配置与常规的 Linux NAT 配置一样。
2. Bridge 模式,只需将 Host OS 上连接外网的网口也增加到 Guest OS 所属的 Bridge 中。

Windows virtio 驱动
Guest 中如果安装 Windows 操作系统,需要安装 virtio (net) 驱动,详见:http://www.linux-kvm.org/page/WindowsGuestDrivers/Download_Drivers

Tips: 注意防火墻的配置。

Over!

一种 HTTP 会话劫持的防御方法

HTTP 会话劫持也是 TCP 会话劫持,它是利用了 TCP Seqnum 的可预见性来伪造有效的响应包,并抢先响应客户端同时使得客户端主动丢弃原服务器的响应包。在这个层面想区分哪一个响应包是伪造的是有困难的,但结合实际情况考虑问题也还有一些思路。

我们以劫持程序的设计者角度考虑:
1. 劫持程序不是什么都劫持了,只有符合条件被命中的 HTTP 请求才会劫持的,那也就是说劫持程序需要一个完整或至少包含它需要的信息的请求才可以劫持,我想 Host, QueryString, Referer 这些应该少不了。
2. 劫持程序不希望维护 TCP 上下文进行流重组。因为维护起来成本比较高。
3. 基于上一点来说,劫持程序也就不希望一个 HTTP 请求被拆分在两个或多个包中传输。

从实际检测来看,大多数的 HTTP 请求还是包含在一个独立的 TCP 包中传输的,只有很少的情况被拆分了。我想你一定想到了什么了,对!我们就假设当前在用的劫持程序都没有维护 TCP 传输上下文进行流重组,那么人为对前向链路上的流进行强制拆分,就应该能够逃过被劫持。

实现的方式应该会有很多,我在应用层代理层面实现了一个简单的原型,方式是将前向链路的 Buffer size 强制在了 16 字节。代码托管在 Github => https://github.com/heiher/hev-socks5-proxy/tree/anti-hijack

从抓包来看,HTTP 请求在传输时被拆分了:

packet 0:[syn]
packet 1: GET / HTTP/1.1\r\n
packet 2: Host: xxxx
packet 3: ...

Over!

Forward special packets

主机A与主机B之间建立了一条 IPIP 遂道,两个主机之间生成的TCP协议且源端口是8000的包需要通过遂道传输到对方后,通过对方的网关发送出去。

On Host A

TUN_IFACE="tun-b"
HOST_A_IP="10.0.0.3"
HOST_B_IP="10.0.3.2"
TUN_GATEWAY="192.168.4.2"
HOST_GATEWAY="10.0.0.1"
 
sudo iptunnel add ${TUN_IFACE} mode ipip remote ${HOST_B_IP} local ${HOST_A_IP}
sudo ifconfig ${TUN_IFACE} up
sudo route add -host ${TUN_GATEWAY} dev ${TUN_IFACE}
 
sudo iptables -t mangle -A POSTROUTING -p tcp -m tcp --sport 8000 -m mark ! --mark 0x8888 -j TEE --gateway ${TUN_GATEWAY}
sudo iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 8000 -j MARK --set-mark 0x8888
sudo iptables -t mangle -A PREROUTING -m mark --mark 0x8888 -j TEE --gateway ${HOST_GATEWAY}

On Host B

TUN_IFACE="tun-a"
HOST_A_IP="10.0.0.3"
HOST_B_IP="10.0.3.2"
TUN_GATEWAY="192.168.4.1"
HOST_GATEWAY="10.0.3.1"
 
sudo iptunnel add ${TUN_IFACE} mode ipip remote ${HOST_A_IP} local ${HOST_B_IP}
sudo ifconfig ${TUN_IFACE} up
sudo route add -host ${TUN_GATEWAY} dev ${TUN_IFACE}
 
sudo iptables -t mangle -A POSTROUTING -p tcp -m tcp --sport 8000 -m mark ! --mark 0x8888 -j TEE --gateway ${TUN_GATEWAY}
sudo iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 8000 -j MARK --set-mark 0x8888
sudo iptables -t mangle -A PREROUTING -m mark --mark 0x8888 -j TEE --gateway ${HOST_GATEWAY}

Over!