Friday, December 4, 2015

How WiFiDog Works

I introduced WiFiDog in a previous post. In this post, I examine how WiFiDog works by exploiting Netfilter/Iptables.

WiFiDog creates the following chains in magle table, WiFiDog_br-wlan_Incoming /Outgoing /Trusted, and WiFiDog_br-wlan_AuthServers /Global /Internet /Known /Locked /Unknown /Validate in filter table. br-wlan is the GatewayInterface set in /etc/wifidog.conf

WiFiDog_br-wlan_Outgoing is chained in mangle PREROUTING. If a client passes authentication, WiFiDog daemon inserts a rule in WiFiDog_br-wlan_Outgoing, marking the packets from this user with mark 0x2.

WiFiDog_br-wlan_Internet is chained in filter FORWARD table. The contents in this chain is derived from /etc/wifidog.conf, which resembles the following:

Chain WiFiDog_br-wlan_Internet (1 references)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere             state INVALID
TCPMSS     tcp  --  anywhere      anywhere    tcp flags:SYN,RST/SYN TCPMSS clamp to PMTU
WiFiDog_br-wlan_AuthServers  all  --  anywhere        anywhere            
WiFiDog_br-wlan_Locked  all  --  anywhere             anywhere         mark match 0x254
WiFiDog_br-wlan_Global  all  --  anywhere             anywhere            
WiFiDog_br-wlan_Validate  all  --  anywhere           anywhere         mark match 0x1
WiFiDog_br-wlan_Known  all  --  anywhere              anywhere         mark match 0x2
WiFiDog_br-wlan_Unknown  all  --  anywhere            anywhere            

At this point, WiFiDog is capable of separating known users and unknown users. However, there is one more thing, redirecting unknown users to the web portal. This is done with WiFiDog_br-wlan_Unknown chain in the nat table. There is a rule:
REDIRECT   tcp  --  anywhere             anywhere         tcp dpt:www redir ports 2060
which redirects unkown user's HTTP connection to 2060 port on the router.

Enable Web Proxy Auto-discovery on OpenWrt with Dnsmasq

Recently, I set up shaodowsocks and polipo on an OpenWrt router. I'd like every client connected be able to bypass the Great Fire Wall of China automatically. This can be done by pushing an proxy auto-config to the client. And there exists a protocol called Web Proxy Autodiscovery (WPAD).

Dnsmasq is capable of WPAD. Just add this line in /etc/config/dhcp.conf under config dhcp lan section

list dhcp_option '252,http://192.168.10.1:8000/proxy.pac'

the HTTP URL should be replaced adequately. There should be no spaces between the comma and URL. You can convert GFWlist to a PAC file with gfwlist2pac.

A note for iPad users:
iPad do not enable WPAD by default (because WPAD can redirect a client's HTTP connection without informing the user). The user can enable it in the configuration for wireless access points.

Saturday, November 21, 2015

WifiDog on Openwrt

WifiDog is a Captive Portal on Openwrt. It utilizes Linux netfilter in order to force a client to log in before granting access to the Internet. Although there is a Wifi in its name, it can work on wired network as well. WifiDog has two components, a gateway and an auth server. The gateway is running on an access point, and redirects unknown clients to the auth server's login page. The auth server is simply a Web server which implements WifiDog's auth protocol.

To install wifidog gateway on openwrt, just type opkg install wifidog in command line. It's config file is at /etc/wifidog.conf. You may want to customize GatewayID, GatewayInterface,  AuthServer, CheckInterval, and TrustedMACList. The comments in the config file explains these options clearly.

The crucial part is the AuthServer section. Upon connection, the client will be redirected to the auth server for authentication. You should have at least one AuthServer section. If you have multiple AuthServer sections, WifiDog will use the first auth server that responses to its ping request. The auth server implements wifidog's auth and ping protocols. An auth server written in php is available at https://github.com/wifidog/wifidog-auth. You may also write an auth server which suits you need. I have written one in python.

You should understand wifidog's protocols before writing an auth server. The protocol is fully describe in http://dev.wifidog.org/wiki/doc/developer/WiFiDogProtocol_V1. I will give a summary below.

Wifidog gateway keeps a list of authorized users' IP, MAC and token. If an unknown user tries to visit a website, it will be redirect to the auth server's login page. If login is successful, the user will be redirected to the gateway's portal with the URL containing the user's IP, MAC and token (a random string). The gateway will verify these information with auth server via auth protocol. Every check interval (default value is 60 seconds), the gateway will contact the auth server and check every user's token by the auth protocol. If the re-authorization for a user fails, the gateway will remove the user from the list and then blocks its internet access. The auth protocol also allow the gateway to send accounting information for a user to the auth server.

Thursday, October 29, 2015

Connecting two networks with OpenVPN

I have two routers in two cities, both is connected to the Internet via different ISPs. I wanted to let computers behind both routers to be able to talk to each other directly (without port forwarding and other stuff).

Firstly, I set up a OpenVPN server in p2p mode with static keys, whose IP address is 129.168.20.1, on one router, and a p2p client, whose IP address is 192.168.20.2, on the other router. Below are their configuration files:

p2pserver.conf
-------------------------------
mode p2p
proto udp
port 2333
dev tun
ifconfig 192.168.20.1 192.168.20.2
secret static.key
mssfix 1450
verb 1
log /tmp/p2p.log
keepalive 10 120
persist-tun
persist-key
route 192.168.99.0 255.255.255.0

p2pclient.conf
---------------------------------
mode p2p 
proto udp 
dev tun
remote server's_domain name 2333
ifconfig 192.168.20.2 192.168.20.1
verb 1
secret static.key
keepalive 10 120
log /tmp/p2p.log
mssfix 1450
route 192.168.33.0 255.255.255.0


There is one thing to notice. You should add route of the other end's subnet, so that all traffic to the other subnet will be forwarded through the tun device. To enable forwarding through tun device, you should add firewall rules.

Firstly, add following lines in /etc/config/network

config interface 'p2phome'
option ifname 'tun0'
option _orig_ifname 'tun0'
option _orig_bridge 'false'
option proto 'none'

Then, add the new interface to the lan zone of firewall. And enable forwarding in the lan zone. This can be done with OpenWRT's Web UI.

Tuesday, October 6, 2015

Auto run VirtualBox VM in background on Fedora 22 with systemd

Recently, I discovered that VirtualBox has a headless mode, where you can run a VM in background. You can start a VM in background with this command,

VBoxManage startvm Win7 --type headless

Win7 is the name of the VM

You can also save the state of a VM with this command,

VBoxManage controlvm Win7 savestate

So, I wrote a systemd service file so as to start and stop the VM automatically.

[Unit]
Description=Vbox for win7
After=network.target multi-user.target vboxdrv.service

[Service]
Type=forking
ExecStart=/usr/bin/VBoxManage startvm Win7 --type headless
ExecStop=/usr/bin/VBoxManage controlvm Win7 savestate
TimeoutSec=60

[Install]
WantedBy=default.target

Put this file as vbox.service in ~/.config/systemd/user/ and use systemctl --user to manage the service.

Monday, September 14, 2015

Python as a tftp server

There is a python package called tftpy which implements a tftp client and server. It's more handy for me to set up a temporary tftp server, compared with Fedora's tftp-server package, which relies on systemd.

In order to listen on port 69, python must be running as root. Then, type these lines in the python interactive shell. 

from tftpy import TftpServer
server = TftpServer("tftproot")
serve.listen()

tftproot is the path to the tftproot directory.

Tuesday, September 1, 2015

Redshift on Fedora 22

Redshift adjusts the screen's color temperature according to the time. It relieves your eyes when working at night. It's homepage is http://jonls.dk/redshift

To install redshift on Fedora 22, type sudo dnf install redshift in terminal. You may also install redshift-gtk, a GUI front-end for gnome desktop. Then you should enable location service in privacy settings. Also add these lines to /etc/geoclue/geoclue.conf to allow redshift to get location from geoclue.

[redshift]
allowed=true
system=false
users=

Finally, type redshift in terminal, and you should notice the change of the color temperature of your screen. However, the shipped systemd service does not work (redshift starts, but no change of color temperature, quite mysterious.) So I installed redshift-gtk and make it autostart when I login. 

Saturday, August 29, 2015

Openconnect Server (ocserv) on Openwrt

I'd like to set up a VPN server on a router running Openwrt. There are several choices, L2TP, PPTP, OpenVPN and openconnect. PPTP is not very secure. L2TP must be used with IPSec for security. While OpenVPN and openconnect are both SSL-VPN. They are easy to configure and adaptive to the restrictions of ISP. Because there is a luci app for openconnect server. It's easier to set up than OpenVPN. I would set up an openconnect server, which operates in pseudo-bridge mode, meaning remote clients are on the same subnet as the computers at home.

Tuesday, July 28, 2015

Openwrt Synchronized Wifi Hotspot

There are three wireless routers at my home. All run Openwrt. One acts as gateway. The other two are APs. Sometimes, my mother wants to turn off WiFi before sleep. She would power off the gateway router. As a result, all clients will connect to the other two APs, and cannot access the Internet.

I want to make things more elegant. When the two APs detect that the gateway is down, they will turn off their wifi as well, and turn it on when the gateway is online again. Fortunately, the two APs have enough ROM for python. So I need not mess around with shell scripts.

Friday, July 24, 2015

Netgear WNR2000 v4 刷 OpenWrt 和 Gargoyle

最近淘了一个二手的WNR2000,硬件版本v4,使用AR9341单芯片方案,4MB闪存,32MB内存。发现自带固件功能太弱,可玩性不高,故刷Openwrt.

WNR2000是Openwrt支持的硬件,可以参考http://wiki.openwrt.org/toh/netgear/wnr2000,但是这个网页里的信息过时了。telnetenable已经不适用于这台WNR2000。可喜的是电路板上留有TTL焊盘,焊上排针就可以使用。离网络口隔离变压器最远的是GND,然后是RX,TX,波特率是115200。

连接上TTL即可看到终端,官方固件是基于Openwrt改造的,进入终端还有Openwrt的字符画。不过可用的指令很少。

Monday, July 6, 2015

用netcat传送文件

一些特殊情况下,比如ssh挂掉了,可以用netcat传输文件。当然,是明文传输。

首先在接收端listen,输入
nc -l 6000 > filename
然后在发送端输入
nc IP 6000 < file_to_send

IP是接收端IP地址,filename是文件保存的名字。

也可以改成在发送端Listen,适用于BusyBox里不支持-l的netcat

发送端:
cat file_to_send | pv -b | nc -l -p 3333
接收端:
nc IP 3333 > filename


还有一个办法,用Python的SimpleHTTPServer和wget

服务端:
python -m SimpleHTTPServer
会在当前目录下运行一个HTTP服务器,端口号为8000

客户端:
wget http://IP:8000/filename

Saturday, May 16, 2015

Python实现A记录查询

最近在学计算机网络,用的教材是Computer Networking: A Top Down Approach. 第二章节介绍了DNS。以前用Python实现过基于TCP和文本应答的协议,不过没有处理过DNS这样结构紧凑的协议。

由于Python本身是没有类型的,而DNS对每一项的字长有严格要求(这种协议用C实现相当直接),因此要先生成固定长度的数据。有多种实现方法,比如:
bytearray, struct.pack, binascii.unhexlify, 直接在string中使用\x转义

Wednesday, March 25, 2015

Python跨平台需要注意的问题

最近在写一个Python小程序,需要移植到windows上,遇到了几个小问题,记录一下。

可以使用sys.platform判断系统类型

ossaudiodev在Windows下不可用,用PyAudio替代

Windows在使用open打开文件时会区别'rb'和'r',而Linux的'r'和'rb'是等价的。因此在Windows下打开二进制文件必须用'rb'模式

Windows7下的Python在读取用户给定的中文路径时会出错,要先把路径转换到unicode,可以使用uni_path = unicode(path, "utf8")

PyGTK写的程序会变得很丑,暂时还不知道怎么解决。以后改用PySide好了

在Windows下最好把Python安装目录放到PATH环境变量里,这样比较方便用pip

Saturday, March 7, 2015

Gnome 3.14添加自动启动

Fedora21已经找不到gnome-session-properties了,虽然gnome-tweak-tools提供了添加子启动程序的功能,不过相当鸡肋。最后找到一个方法可以实现原来gnome-session-properties的功能

在~/.config/autostart/下新建一个xxx.desktop文件,内容如下:
[Desktop Entry]
Type=Application
Name=xscreensaver-autostart
Comment=Autostart xscreensaver
Exec=/usr/libexec/xscreensaver-autostart
Terminal=false
X-Desktop-File-Install-Version=0.22
X-GNOME-Autostart-enabled=true
OnlyShowIn=GNOME;

要注意的是,Exec后面必须是程序的完整路径。

真心想吐槽Gnome,怎么越改越麻烦了。

Wednesday, March 4, 2015

Python学习笔记之subprocess

Python提供了一个库,subprocess,可以很方便地启动一个子进程并与之交互。

最简单的使用方式是:
subprocess.call(args),其中的args是a list of strings,args[0]是调用的程序路径,其后均为参数。call会阻塞直到子进程结束。call的返回值是子进程的返回值。这个函数与C的system很相似。

subprocess.check_output(args)与call相似,不过它会把子进程的输出作为一个bytestring返回

这个库最强大的函数是Popen,它其实是一个类的Constructer,完整形式是:
subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

args与上文相同,不过这个调用不会阻塞当前进程,stdin,stdout,stderr可以是一个打开的file,或者是subprocess.PIPE,如果是PIPE,父进程可以用xxx.stdin/stderr/stdout与子进程通信。

其实呢,上述这些函数都是C的fork和execve的包装,它们大大简化了编程。如果要在C下实现Popen的功能,父进程需要现用pipe获得一个管道,然后fork,在子进程中关闭管道写端,用dup2重定向管道到stdin,接着execve,在父进程中需要关闭管道读端,然后向子进程输入数据,这些代码少说也要个5行。

现在觉得Python的官方库文档已经很完善了,而且不要翻墙,以后估计就不再写官方库的学习笔记了

Wednesday, February 25, 2015

Openwrt配置6in4

美国一家ISP, Hurricane Electric提供免费的IPv6接入的服务,叫做Tunnel Broker, 这个服务使用了6in4转换机制。用户只需要在网站注册,就可以申请免费的6in4隧道。不过有一个限制是Endpoint必须有公网IP。

对于刷好Openwrt Barrier Breaker的路由器,只需要简单的操作就可以实现6in4

1. 在tunnelbroker上申请一个隧道,申请时可以选择ping延迟最低服务节点。申请成功后会获得一个页面,里面有配置6in4的全部信息。

2.在Openwrt中新建一个Interface,名称为henet,选择Protocol为6in4,如果没有这个选项,请安装luci-proto-ipv6,6in4软件包,点击Sumbit

3.修改将tunnelbroker上的信息填入henet的配置中,具体可以参考http://wiki.openwrt.org/doc/uci/network#protocol_6to4_ipv6-in-ipv4_tunnel如果你的公网IP会变化,需要勾选,并填写一些信息,Update Key可以在Tunnel Details页面的Advanced选项中看到。

4.将henet的firewall zone设置为wan。

5. 在/etc/config/firewall下添加:
    config rule
    option src 'wan'
    option target 'ACCEPT'
    option proto '41'


6.修改/etc/config/network,在lan下添加option ip6addr,其后地址可以从Routed /64中任选一个。

重新启动路由器,并且刷新本机的DHCP,就可以获得一个公网IPV6地址了。测试网址http://test-ipv6.com/

不过,由于中国内并没有服务节点,最近的节点延迟也有100ms+,加之国际出口带宽有限,这种方式获得的IPv6质量很不好。

Sunday, February 22, 2015

Openwrt配置WLAN漫游

Update:

802.11f was deprecated. The new kid in town is 802.11r. OpenWrt 21.02 supports 802.11r. Here is a post on how to enable it.

家里有两台无线路由,都以AP的形式接入LAN。而我希望做的是能让无线设备在两个AP中选择信号最好的接入,并且实现漫游。

我所在大学的无线网络支持在同一个AC下漫游,因为学校采用的是H3C的解决方案,他们的私有技术可以支持接入点的快速切换。而我家中的路由一个是ralink的方案,一个是atheros的方案,不过它们都刷了OpenWrt系统。上网搜索后发现802.11协议只支持由客户端(比如手机)发起的切换。与GSM的handover不同,802.11的handover必须先断开链接,再建立新的链接。

要实现漫游,只需要把两个接入点的SSID,加密方式(我使用WPA2-PSK-CCMP)和密钥保持一致,两个AP使用不重叠的信道。

此外,还有一个802.11f协议,用于支持不同厂商AP之间的通信。要在Openwrt上开启这个协议,只需要在/etc/config/wireless里面增加一个 iapp_interface 字段,可以参考这个wiki.

应用这些设置后,我的小米手机可以自动在两个接入点中漫游,切换延迟大约半秒。