標籤 技術研究 下的所有文章

運營商級 NAT 內使用 Tunnelbroker

在學校裡想用 IPv6,但是學校沒給分發。於是就決定使用 Hurricane Electric 的 Tunnel Broker。不好說學校防火牆有沒有堵掉 protocol 41,也就是 6in4。但至少學校的 IPv4 出口不接受 ICMP。

然後 Tunnel Broker 就不開心了。說是必須要允許來自它的 ICMP,才能設定 IPv4 端點。那能怎麼辦,我也很無奈啊。那就只好從別的地方用什麼手段「中繼」一下了吧。

原本是想用 Digital Ocean 的,學校內連線它美國東部的資料中心只有 7 毫秒左右的延時。可是 Tunnel Broker 還是不高興。說這 IP 段在黑名單裡。就很生氣。換了另外一臺在美國中部的機子,成功建立端點。

一開始想的方案是通過 OpenVPN IP 隧道。因為,只要好好做轉發,就算端點在 NAT 後面也是沒有問題的。現實總是不太美好,總之,隧道內的隧道無法建立。去 superuser 題了個問,有人說「 IPv6 does not have fragmentation like IPv4 does, so shrinking the MTU with tunnels in tunnels could cause other problems. IPv6 also has a minimum MTU of 1280」。看了看自己 MTU 明明是 1500 —— 可能還有別的什麼玄學,總之這個方案被拋棄了。

然後就會想到直接用 OpenVPN 分發 IPv6 了,對吧?可是奈特使用的路由器,也就是之前提到的 MikroTIk 的路由器,上面的 OpenVPN 實現不支援 IPv6。

嗯 —— 那,放棄了?

當然不行。都研究了這麼多了。雖然路由器上面的 OpenVPN 不直接支援 v6,但是我們可以直接用 tap 隧道呀。tap 隧道的話就相當於 ethernet 了,好比兩張網卡用線連起來一樣。是執行在 Layer 2 上的。所以啥協議都能往上面套。

在伺服器直接分發估計也行,不過奈特傾向於在路由器這邊做。總之,無論怎麼做,先從 Tunnel Broker 申請一段 /48 的 IPv6 塊。然後,從裡面隨便選一塊 /64 出來。路由到 tap 介面的 link-local 地址上。也就是說:

ip -6 route add <your /64 zone>::/64 via fe80::...

然後回路由器來,在上面把 IPv6 路由到 tun 隧道的 IPv6 link-local 上。在 MikroTik 裡的話:

/ipv6 route add dst-address=2000::/3 gateway=fe80::...4%ovpn-tunnel

然後就搞定了。接下來就是區域網裝置的地址分配,不想在隧道伺服器那邊做,所以就在本地 LAN 橋上新增剛才路由到這兒的區域的地址塊,並且廣播:

/ipv6 address add address=<your /64 zone> interface=bridge advertise=yes

然後就:

IPv6 測試成功

IPv6 測試成功

好了。就這樣。

筆記:hAP ac (RB962UiGS-5HacT2HnT) 上的 5Ghz 無線配置

出於某些原因,用 OpenVPN 架了一個 site-to-site 的隧道 – 用來連線在學校宿舍裡的網路和某處的一個區域網。因為廣播的包也需要走隧道,那 OpenVPN 的 tun 隧道就行不通了,只能用支援 Layer 2 的 tap。隧道的這邊是一臺 RB3011UiAS-RM,手頭有一臺能使用的 hAP ac。現在想要做的事是,讓連線 WiFi 的移動裝置也能接入這個 VPN 的網路。

嗯,既然 Android/iOS 的 OpenVPN 不支援 tap,更何況 tap 上根本就沒有 DHCP,看著手頭有的裝置,能想到的只有設定一個無線網路,並且和 VPN 介面橋接來實現了。

說來學校是不讓學生自設 AP 的,如果私自架設 AP 會導致網口直接被禁用。不過,只要 WLAN 介面在 NAT 後面,就不會有事。猜測應該是有無線 IDS 記錄各個 WiFi 的 BSSID,如果在某個網口看見和 BSSID 一樣的 MAC,就禁用吧。為什麼會知道?因為在 cli 操作的時候一個不小心把 WLAN 介面和 WAN 介面橋接一塊兒去了,然後沒過幾分鐘,網口就被禁用了。如果學校沒有用魔法的話,這大概是唯一的方法。

但是無線還是得用的。偷偷的放在 NAT 後面,降低功率,選個不會干擾學校通訊的頻率 —— 只有這樣了。雖然覺得像是在做虧心事。看了看周圍的無線電頻率,都分佈在 CH 34-64, 149-165 裡。說實話這是第一次見排列這樣整齊的網路,每隔 5 個頻道就有一坨 20Mhz 的無線電,總之應該是做了很仔細的規劃,將不同 AP 之間的干擾降低到最低。我也不想打破這份寧靜,於是就決定使用 100-144 之間的頻率了。不知道為什麼沒有任何網路在這個區間,根據 FCC,這些個頻率在美國是能使用的,可能有些客戶端會拒絕使用這些頻率?沒有頭緒。

總之,既然這些區間完全沒有別的網路,那就可以放心的使用 80 Mhz 頻寬了。決定使用 CH 104-110。首先把國家設定成 US,頻率模式用 regularoy-domain。這樣頻率列表就只會顯示合法的頻率。

然後,來看看頻率表:

無線頻率表

無線頻率表

80 Mhz 的頻道是第二個,那麼我們就把中心頻道放那兒吧。也就是說,20/40/80Mhz eCee。(e: extension, C: center,即 eCee = CH104(20Mhz): e, CH106(80Mhz): C, CH108(20Mhz): e, CH110(40Mhz): e)。

總之,無線電配置看起來是這樣的:

無線電配置

無線電配置

配置好了,看看速度:

無線速率

無線速率

1300Mbps, 80Mhz,沒問題了。

筆記:在 OpenWRT 使用 PPTP 將兩個遠端局域網連通

需求:

  1. 兩個網段不同的局域網,文中使用:
    • 192.168.0.0/24
    • 192.168.1.0/24
  2. 一個PPTP服務器,使用獨立於上述兩個網絡的網段,文中使用:
    • 10.1.0.0/24

步驟:

  1. 按照這裡為OpenWRT配置PPTP支持。
  2. 設置PPTP
    1. 設置憑據
    2. 為PPTP創建新的防火牆區域,允許LAN=>PPTP轉發以及PPTP=>LAN轉發
    3. 在PPTP接口的高級選項中取消勾選「使用默認網關」。
    4. 在pptp伺服器上,chap-secret中為客戶端指定IP地址(推薦),文中使用:
      • 192.168.0.0/24網段的pptp賬戶:10.1.0.2
      • 192.168.1.0/24網段的pptp賬戶:10.1.0.3
    5. 將兩個OpenWRT的PPTP接上服務器。
  3. 配置靜態路由表
    1. 在192.168.0.0/24網段的路由上,設置下列路由:
      • 接口:pptp;目標:10.1.0.0,子網掩碼:255.255.255.0,網關10.1.0.1。
      • 接口:pptp;目標:192.168.1.0,子網掩碼:255.255.255.0,網關10.1.0.1。
    2. 在192.168.1.0/24網段的路由上,設置下列路由:
      • 接口:pptp;目標:10.1.0.0,子網掩碼:255.255.255.0,網關10.1.0.1。
      • 接口:pptp;目標:192.168.0.0,子網掩碼:255.255.255.0,網關10.1.0.1。
    3. 在pptp服務器上,設置下列路由:
      • 接口:pptp;目標:192.168.0.0,子網掩碼:255.255.255.0,網關10.1.0.2。
      • 接口:pptp;目標:192.168.1.0,子網掩碼:255.255.255.0,網關10.1.0.3。

      如果在步驟2.4中沒有為客戶端指定IP地址,則每次IP變動後都需要重新指定兩個192.168網段的網關至其在PPTP服務器上的IP地址。

至此,兩個網絡便已經通過pptp接在了一起。

問題:

  1. kmod-mppe似乎在某些路由器上沒法加載,那麼,直接禁用它吧。在服務端與客戶端中的pptp配置文件中注釋掉就可以了。
  2. OpenWRT的pptp有些奇怪。在pptp斷開後有幾率無法連接,這時候,把服務器地址修改下(域名換成IP,或者IP換成域名),就能解決了。

這些問題怎麼來的?誰知道呢…

使用 bind9 作為 GeoDNS 伺服器

在繼續前,你需要先了解GeoDNS為何物,以及bind之基本使用方式。

簡單來說,若要讓bind為不同地區的使用者返回不同的查詢結果,則需要判斷DNS請求從何而來。國家IP資料從MaxMind便能獲取到。倘若要將MaxMind的IP地址資料庫變為bind的acl,可以利用這裡的指令碼。但是為了簡化過程,我們直接下載預先做好的的acl檔案。

要如何做到呢?依舊是透過上面提供的連結。

只需要下面這一條指令就能夠下載到acl了。

curl http://phix.me/geodns/download/MaxMind/GeoIP.acl.gz | zcat > geodns.acl

下載完成了之後,進到bind的全局設定裡頭,將這個檔案include進去,然後還需要稍微做些修改。

// This is the primary configuration file for the BIND DNS server named.
//
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the 
// structure of BIND configuration files in Debian, *BEFORE* you customize 
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local

include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";

// GeoDNS Configuration

// acl file sepified the IP zones of countries. 
include “/etc/bind/geodns.acl";

include "/etc/bind/named.conf.cn";
include "/etc/bind/named.conf.us";
include "/etc/bind/named.conf.any";

include “/etc/bind/named.conf.default-zones”;

在這裡,/etc/bind/named.conf.cn中指明瞭中國地區解析的地址,/etc/bind/named.conf.us則是美國,/etc/bind/named.conf.any則是任何。需要注意的是,要將any放在最後。否則any將會匹配任何查詢,換言之,在any之後的地區都不會被解析。

這裡將named.conf.cn的內容放出來作為範例:

view "china" {

	match-clients { CN; };
	recursion no;

	zone "magicnat.com" {
		type master;
		file "/etc/bind/zones-china/magicnat.com";
	};

	zone "magicnat.org" {
		type master;
		file "/etc/bind/zones-china/magicnat.org";
	};

	zone "nat.moe" {
		type master;
		file "/etc/bind/zones-china/nat.moe";
	};

	zone …
};

每一個view,就是每一個區域。這個區域要解析的國家在match-clients中定義。例如中國就是CN,美國則是US。也可以將兩個國家一併寫在match-clients中。若要匹配任何國家,則可以使用any。還有一點也是需要注意的:在使用view之後,就不能在view之外存在zones。在named.conf.default-zones中的區域就會出現問題。可以在配置檔案中將其include註釋,也可以將其加入一個view,就像這樣:

view "local" {

	match-clients { any; };
	recursion no;

	// prime the server with knowledge of the root servers
	zone "." {
		type hint;
		file "/etc/bind/db.root";
	};

	// be authoritative for the localhost forward and reverse zones, and for
	// broadcast zones as per RFC 1912

	zone "localhost" {
		type master;
		file "/etc/bind/db.local";
	};

	zone "127.in-addr.arpa" {
		type master;
		file "/etc/bind/db.127";
	};

	zone "0.in-addr.arpa" {
		type master;
		file "/etc/bind/db.0";
	};

	zone "255.in-addr.arpa" {
		type master;
		file "/etc/bind/db.255";
	};

};

最後一點:若是你像我這樣將default-zones的clients設為any的話,你得將載入default-zones的語句放在配置檔案的最末尾。原因和將any區域放在最後是一樣的。

ShadowManager 穩定版本釋出

歷時 4 個月(明明就是五天),shadowmanager的開發終於結束了。

ShadowManager 是一個用於同時維護多個不同加密的 shadowsocks 伺服器的輕量級,可擴展指令碼。

預設命令的使用方式如下:

add: 新增一個伺服器到 shadowmanager 的管理,需要 3 個參數。埠,密碼,和加密方法。
start: 啟動 shadowmanager,無需參數。
stop: 停止 shadowmanager,無需參數
restart: 重啟 shadowmanager,無需參數。
status: 檢視 shadowmanager 狀態,無需參數。
show: 顯示所有 shadowsocks 伺服器,無需參數。
remove: 移除指定 ID 的 shadowsocks 伺服器,使用 "show" 來檢視所有伺服器,需要 1 個參數,伺服器 ID。
enovr: 啟用一個或多個覆寫,可將覆寫名作為參數(可選)。
disovr: 禁用一個或多個覆寫,可將覆寫名作為參數(可選)。

Shadowmanager 的特性之一是其可擴展性,在 Shadowmanager 中,提供了覆寫(Overrides),包含(Includes)與鉤子(Hooks)。它們可以被用來修改那些未在 Shadowmanager 中給出選項的行為。包含在 Shdowmanager 載入後讀取,覆寫在 Shadowmanager 載入之前。在每個覆寫之前都有兩位字元,它們所代表的是載入的優先順序。優先順序從 00 排列至 zz,字元越往後,優先順序越高。

目前,Shadowmanager 提供這些覆寫:

  • 00-no-root:該覆寫通過替換 root 檢測函數來跳過 root 檢查,在需要臨時關閉 root 檢測時很有用。
  • 10-base64-encrypted-passwd:使用 base64 來儲存伺服器的密碼。這在你需要在密碼中使用特殊字元時有用。
  • 20-json-to-shadowmanager:該覆寫提供了一個 ‘json2manager’ 命令,可以用於將shadowsocks json 配置檔案轉換為 shadowmanager 的配置檔案。
  • 30-generate-qr-code:為 Shadowmanager 的伺服器生成二維碼。
  • 40-randpass:新增一個命令 ‘add-randpass’ 至 shadowmanager,這個命令允許使用者新增隨機密碼的 shadowsocks 伺服器。
  • 70-time-limit:以小時限制每個 shadowsocks 伺服器可以使用的時間。這個覆寫會使用 pre-add 事件鉤子,並新增一個 Cronjob 來檢查賬戶並移除過期伺服器。
  • 90-pre-server-daemon:為每個伺服器使用單獨的程序。在需要分開統計每個伺服器的流量時有用。
  • 90-screen-start:這個覆寫將替換 ‘start’ 命令原本的實現,使用該覆寫會讓 shadowsocks 伺服器在 screen 內啟動,而不是作為服務啟動。這在需要檢視伺服器日誌時有用。
  • 99-chinese-usage:這個覆寫提供了中文的幫助文字。
  • aa-wizard:為 shadowmanager 的伺服器新增、伺服器移除等操作提供一個嚮導。
  • zz-interactive-mode:這個覆寫會使得 shadowmanager 以互動式模式啟動。該方法可能會引起一些問題,故不推薦。

鉤子是在特定行為執行前後運行的函數。這些鉤子可以在 hooks/ 中定義。某些覆寫可能會按需修改鉤子來達成某些目的。在非原版的實現中也可以定義鉤子。(例如覆寫與包含,甚至鉤子本身!)

usage: hook <hooked_function>

Hook 命令會檢測函數是否存在,若存在則會將其執行。

若想要新增您自己的命令用法與解釋至 shadowmanager,您可以使用 ‘add-help’ 與 ‘add-usage’。這兩個命令都會從標準輸入讀取輸入。幫助文字的語言可以在這兩個命令的參數內定義。若留空,則會被作為預設語言顯示(當偏好語言不能被提供時使用)。

usage: echo '   <your-command>: <your-explaination>' | add-help [help-language]
usage: echo '   <your-command>: command-name <parameters>' | add-usage [help-language]

Shadowmanager 釋出於 MIT 協議。項目地址:https://github.com/MagicNAT/shadowmanager/

隨手摘記:重啟基於tcp的伺服器而不丟包的巧妙做法

最近伺服器上掛著的站多了起來,於是發現重啟httpd時候會丟掉不少的請求… 雖然不是一個很大的問題,但是不解決總是讓人心裡不舒服,故稍作研究,發現了一個利用iptabels DROP請求從而巧妙的解決客戶端被拒絕連線的問題。

想法來自:http://www.mail-archive.com/haproxy@formilux.org/msg06885.html

做法很簡單,就是這樣:

iptables -I INPUT -p tcp --dport the_port_of_server --syn -j DROP
... restart your service ...
iptables -D INPUT -p tcp --dport the_port_of_server --syn -j DROP

簡單來說,就是三個步驟。先DROP通往服務埠的連線,因為是DROP,故客戶端不會收到拒絕連線的資訊。於是客戶端會繼續傳送tcp請求,直到超時或收到響應。之後便是重啟服務,然後移除iptables規則,這時,客戶端便能收到伺服器的迴應了,並且在此期間,客戶端並沒有收到任何伺服器拒絕連線的訊息。