2012年1月30日 星期一

Qos + CBQ

單一主機的上傳,即 Client的下載(如瀏覽網頁)

[ client ] <---------- ech0 -[ server ]
 
[1.] 下載 CBQ的 script,cbq.init-v0.7.3
         https://sourceforge.net/projects/cbqinit

[2.] cbq.init 的初始預設作業
         mkdir /etc/sysconfig/cbq
         chmod u+x cbq.init
         cp cbq.init /sbin
 
[3.] cd /etc/sysconfig/cbq
         vi cbq-0002.eth0-80
DEVICE=eth0,100Mbit,10Mbit
RATE=100Kbit
WEIGHT=10Kbit
PRIO=5
RULE=*:80,
BOUNDED=yes
ISOLATED=no
[4.] 顯示 tc格式結果
         cbq.init compile           

      啟動
         cbq.init start
 
[5.] 從 Client端測試下載 web檔,限制在10KByte/s下載
         wget http://server/xxxfiles

NAT環境,以PORT number設置內部網路的上下載
模擬頻寬 512Kbps/512Kbps
attachments/month_200611/1163513806.png

[1.] 從 eth2出去的,目的為 25、20 port,分配各為 256Kbit、256Kbit,這對內部來說是上傳
         而從 eth1出去的,來源為110、80、20 port,分配各為 128Kbit、256Kbit、128Kbit,這對內部來看是下載
[2.] 下載的設定
         vi cbq-0002.eth1-110
DEVICE=eth1,100Mbit,10Mbit
RATE=128Kbit
WEIGHT=12Kbit
PRIO=5
RULE=:110,
BOUNDED=yes
ISOLATED=yes
         vi cbq-0003.eth1-80
DEVICE=eth1
RATE=256Kbit
WEIGHT=25Kbit
PRIO=7
RULE=:80,
BOUNDED=yes
ISOLATED=yes
PARENT=0002
         vi cbq-0004.eth1-20
DEVICE=eth1
RATE=128Kbit
WEIGHT=12Kbit
PRIO=8
RULE=:20,
BOUNDED=yes
ISOLATED=yes
PARENT=0002
[3.] 上傳設定
         vi cbq-0102.eth2-25
DEVICE=eth2,100Mbit,10Mbit
RATE=256Kbit
WEIGHT=25Kbit
PRIO=6
RULE=:25
BOUNDED=yes
ISOLATED=yes
         vi cbq-0103.eth2-20
DEVICE=eth2
RATE=256Kbit
WEIGHT=25Kbit
PRIO=8
RULE=:20
BOUNDED=yes
ISOLATED=yes
PARENT=0102
附註1:
cbq作用在流出的封包上
依整個linux box來看,從eht2出去是限制到上傳,從eth1出去限制到下傳

附註2:
cbq設定檔中的 RULE參數,如果”沒”加逗點的話為目的,”有”加逗點為來源

參數說明:
DEVICE=,,
DEVICE=eth0,10Mbit,1Mbit               # ifname = 網卡名稱
                                                         # bandwidth = 網卡上限頻寬
                                                         # weight = bandwidth / 10

RATE=2Mbit
WEIGHT=200Kbit                              # ADSL 2Mbits/256Kbits,即下載200kbytes,上傳25kbytes

PRIO=5                                             # 優先權 ,1到8,預設為5

PARENT=0002                                   # 上層,預設沒設

LEAF=none | tbf | sfq                        # 預設為tbf

BOUNDED=yes | no                           # 設成 yes,將在超出限制的情況下不允許從它的上層借入頻寬,
                                                          # 當設成 no,為允許時,LEAF必設 none 或 sfq
                                                          # 預設為 yes

ISOLATED=yes | no                            # 設成 yes,將不會借出沒用到的頻寬給下層使用
                                                           # 預設為 no

RULE=10.1.1.0/24:80                         # 目的為10.1.1.0的網段,且port為80
RULE=10.2.2.5                                    # 目的為10.2.2.5的主機
RULE=10.2.2.5:20/0xfffe                     # 目的為10.2.2.5的主機,且port為20和21
RULE=:25,10.2.2.128/26:5000            # 來源port為25,到目的網段為10.2.2.128,且port為5000
RULE=10.5.5.5:80,                               # 來源主機為10.5.5.5,且port 為80
      附註: RULE參數可以多個設定

NAT環境(延續上面的環境),FTP passive mode,有些 FTP並非全用 port number 20來傳輸資料,大部份會動用到 port numbers 1024以上的 port
 
關於 ftp的 passive mode,需搭配 iptables的 MARK才能有效限制到流量
iptables -t mangle -A POSTROUTING -o eth2 -p tcp --dport 1024:65535 -j MARK --set-mark 30
iptables -t mangle -A POSTROUTING -o eth1 -p tcp --sport 1024:65535 -j MARK --set-mark 20
 
   vi cbq-0103.eth2-20
DEVICE=eth2
RATE=256Kbit
WEIGHT=25Kbit
PRIO=8
RULE=:20
BOUNDED=yes
ISOLATED=yes
PARENT=0102
MARK=30         # <-- 加入MARK這行
   vi cbq-0004.eth1-20
DEVICE=eth1
RATE=128Kbit
WEIGHT=12Kbit
PRIO=8
RULE=:20,
BOUNDED=yes
ISOLATED=yes
PARENT=0002
MARK=20         # <-- 加入MARK這行
   附註: 為了限制 ftp的 passive mode,但也限制了 1024以上所有的 port
 

NAT環境
限制內部單一主機
attachments/month_200611/1163513824.png

   vi cbq-0002.eth2-host
DEVICE=eth2,100Mbit,10Mbit
RATE=100Kbit
WEIGHT=10Kbit
PRIO=5
RULE=192.168.1.1,
BOUNDED=yes
ISOLATED=yes
   vi cbq-0003.eth1-host
DEVICE=eth1,100Mbit,10Mbit
RATE=256Kbit
WEIGHT=25Kbit
PRIO=6
RULE=192.168.1.1
BOUNDED=yes
ISOLATED=yes
引用:
但此時上傳卻不受限制,因為封包進入 QOS EGRESS之前,
來源 IP已變成 Linux Box對外的 IP,所以 192.168.1.1主機是不受上傳限制,
所以要配合 iptables的 MARK
iptables -t mangle -A PREROUTING -i eth1 -s 192.168.1.1 -j MARK --set-mark 40
   再修改 cbq-0002.eth2檔
DEVICE=eth2,100Mbit,10Mbit
RATE=100Kbit
WEIGHT=10Kbit
PRIO=5
BOUNDED=yes
ISOLATED=yes
MARK=40         # <-- RULE拿掉,加入MARK
或者搭配方式
iptables -t mangle -A FORWARD -o eth2 -s 192.168.1.1 -j MARK --set-mark 40
或者
iptables -t mangle -A POSTROUTING -o eth2 -s 192.168.1.1 -j MARk --set-mark 40

NAT環境
分別限制入部單一主機與整個內部網段
 
全 Subnet 限制在 512k/64k,而 10.1.1.1主機則 100Mbps/10Mbit
                                                                           +---------[ 10.1.1.1 ]
                                 +-------------------+              |
[ internet ] -----ppp0 |                         | eth0-----+
                                 +-------------------+              |
                                                                           +-----------[ 10.1.1.0/24 ]
 
iptables設定
iptables -t mangle -A POSTROUTING          -s 10.1.1.1      -j MARK --set-mark 30
iptables -t mangle -A PREROUTING -i eth0 -s 10.1.1.0/24 -j MARK --set-mark 50
 
vi cbq-0002.ppp0
DEVICE=ppp0,100Mbit,10Mbit
RATE=100Mbit
WEIGHT=10Mbit
PRIO=5
BOUNDED=yes
ISOLATED=yes
MARK=30
vi cbq-0003.eth0
DEVICE=eth0,100Mbit,10Mbit
RATE=100Mbit
WEIGHT=10Mbit
PRIO=5
BOUNDED=yes
ISOLATED=yes
RULE=10.1.1.1
vi cbq-0007.ppp0
DEVICE=ppp0
RATE=64Kbit
WEIGHT=6Kbit
PRIO=7
BOUNDED=yes
ISOLATED=yes
parent=0002
MARK=50
vi  cbq-0008.eth0
DEVICE=eth0
RATE=512Kbit
WEIGHT=50Kbit
PRIO=7
BOUNDED=yes
ISOLATED=yes
parent=0003
RULE=10.1.1.0/24
--- 我是分隔線 ---
NAT環境
iptables的 MARK另設定方式
                                  +-----------+
[ internet ]-------eth1-|               |-eth0---------[ subnet ]
                                  +-----------+
 
限制下載
iptables -t mangle -A FORWARD -o eth0 -d 192.168.1.0/24 -j MARK --set-mark 10
 
vi cbq-0002.download
DEVICE=eth0,100Mbit,10Mbit
RATE=200Kbit
WEIGHT=20Kbit
PRIO=5
MARK=10
限制上傳
iptables -t mangle -A FORWARD -o eth1 -s 192.168.1.0/24 -j MARK --set-mark 20
 
vi cbq-0003.upload
DEVICE=eth1,100Mbit,10Mbit
RATE=50Kbit
WEIGHT=5Kbit
PRIO=5
MARK=20
--- 我是分隔線 ---

Bridge mode環境:
Br0        10.10.1.100/255.0.0.0
Eth0對外 0.0.0.0
Eth1對內 0.0.0.0
10.10.1.100 為 bridge server
10.10.1.78 透過 bridge server連外
以下為 bridge mode server的 ifconfig
br0   Link encap:Ethernet HWaddr 00:E0:81:50:36:3C
         inet addr:10.10.1.100 Bcast:10.255.255.255 Mask:255.0.0.0

eth0  Link encap:Ethernet HWaddr 00:E0:81:50:36:3D
         inet6 addr: fe80::2e0:81ff:fe50:363d/64 Scope:Link

eth1  Link encap:Ethernet HWaddr 00:E0:81:50:36:3C
         inet6 addr: fe80::2e0:81ff:fe50:363c/64 Scope:Link
情況一
外部 pc下載內部 pc 10.10.1.78上的 web檔案,即內部 pc上傳,經由 Bridge
作法一
vi cbq-0002.eth0
DEVICE=eth0,100Mbit,10Mbit
RATE=100Kbit
WEIGHT=10Kbit
PRIO=5
MARK=50
BOUNDED=yes
ISOLATED=yes
搭配MARK
iptables -t mangle -I POSTROUTING -o br0 -s 10.10.1.78 -j MARK --set-mark 50
 
注意 : 出去的介面是br0,才能對內部 PC上傳有限制

作法二
vi cbq-0002.eth0
# 介面需設eth0,br0無效
DEVICE=eth0,100Mbit,10Mbit
RATE=100Kbit
WEIGHT=10Kbit
PRIO=5
BOUNDED=yes
ISOLATED=yes
RULE=10.10.1.78,
# 或者RULE=:80,
情況二,內部 pc 10.10.1.78下載外部 pc上的web檔案,即內部 pc下傳,經由 Bridge
作法一
vi cbq-0002.eth1
DEVICE=eth1,100Mbit,10Mbit
RATE=100Kbit
WEIGHT=10Kbit
PRIO=5
BOUNDED=yes
ISOLATED=yes
RULE=10.10.1.78
# 或者可設為
#RULE=:80,
作法二
iptables -t mangle -I POSTROUTING -o br0 -d 10.10.1.78 -j MARK --set-mark 50

vi cbq-0002.eth1
DEVICE=eth1,100Mbit,10Mbit
RATE=100Kbit
WEIGHT=10Kbit
PRIO=5
MARK=50
BOUNDED=yes
ISOLATED=yes


頻寬管理/限制 QOS + HTB 指令

HOST + upload

50kbyte/s for upload
25kbyte/s for http -> class 10:100
15kbyte/s for ftp -> class 10:200
10kbyte/s for others -> class 10:20

rate = 保證頻寬
ceil = 最大頻寬
attachments/month_200611/1163600502.png


# 刪除現有的規則
tc qdisc del dev eth0 root

# 定義頂層root規則
tc qdisc add dev eth0 root handle 10: htb default 20

# 定義class 10:1,這裡的50kbps即為50KByte/s
tc class add dev eth0 parent 10: classid 10:1 htb rate 50kbps ceil 50kbps

# 定義class 10:10
tc class add dev eth0 parent 10:1 classid 10:10 htb rate 40kbps ceil 40kbps

# 定義class 10:100
tc class add dev eth0 parent 10:10 classid 10:100 htb rate 25kbps ceil 40kbps
tc qdisc add dev eth0 parent 10:100 handle 101: pfifo
tc filter add dev eth0 parent 10: protocol ip prio 100 handle 100 fw classid 10:100

# 定義class 10:200
tc class add dev eth0 parent 10:10 classid 10:200 htb rate 15kbps ceil 40kbps
tc qdisc add dev eth0 parent 10:200 handle 102: pfifo
tc filter add dev eth0 paent 10: protocol ip prio 100 handle 200 fw classid 10:200

# 定義class 10:20
tc class add dev eth0 parent 10:1 classid 10:20 htb rate 10kbps ceil 50kbps
tc qdisc add dev eth0 parent 10:20 handle 103: pfifo

#
iptables -t mangle -A OUTPUT -p tcp --sport 80 -j MARK --set-mark 100
iptables -t mangle -A OUTPUT -m owner --uid-owner ftp -j MARK --set-mark 200



NAT + download

200KByte/s for download

class 10:10 prio 0 for 優先使用者或伺服器
class 10:20 prio 1 for 一般 ''
class 10:30 prio 2 for 濫用 ''

attachments/month_200611/1163600506.png


# 刪除現有的規則
tc qdisc del dev eth0 root

# root
tc qdisc add dev eth0 root handle 10: htb default 20

# root 10:1 class
tc class add dev eth0 parent 10: classid 10:1 htb rate 200kbps ceil 200kbps

# 10:10 class
tc class add dev eth0 parent 10:1 classid 10:10 htb rate 100kbps ceil 200kbps prio 0
tc qdisc add dev eth0 parent 10:10 handle 101: pfifo
# 將 MARK為 10的歸類於 class 10:10
tc filter add dev eth0 parent 10: protocol ip prio 100 handle 10 fw classid 10:10

# 10:20 class
tc class add dev eth0 parent 10:1 classid 10:20 htb rate 70kbps ceil 150kbps prio 1
tc qdisc add dev eth0 parent 10:20 handle 102: pfifo

# 10:30 class
tc class add dev eth0 parent 10:1 classid 10:30 htb rate 30kbps ceil 100kbps prio 2
tc qdisc add dev eth0 parent 10:30 handle 103: pfifo
# 將 MARK為 30的歸類於 class 10:30
tc filter add dev eth0 parent 10: protocol ip prio 100 handle 30 fw classid 10:30

iptables -t mangle -A POSTROUTING -d 192.168.0.135 -j MARK --set-mark 10
iptables -t mangle -A POSTROUTING -d 192.168.0.32 -j MARK --set-mark 30



NAT + upload

25KByte/s for upload

class 20:100 for HTTP
class 20:200 for 高優先權
class 20:20  for 一般
class 20:30  for 濫用

attachments/month_200611/1163600509.png


#
tc qdisc del dev ppp0 root

#
tc qdisc add dev ppp0 root handle 20: htb default 20
tc class add dev ppp0 parent 20: classid 20:1 htb rate 25kbps ceil 25kbps
tc class add dev ppp0 parent 20:1 classid 20:10 htb rate 15kbps ceil 25kbps
tc class add dev ppp0 parent 20:1 classid 20:20 htb rate 7kbps ceil 20kbps prio 2
tc class add dev ppp0 parent 20:1 classid 20:30 htb rate 3kbps ceil 10kbps prio 3
tc class add dev ppp0 parent 20:10 classid 20:100 htb rate 8kbps ceil 25kbps prio 0
tc class add dev ppp0 parent 20:10 classid 20:200 htb rate 7kbps ceil 25kbps prio 1

#
tc qdisc add dev ppp0 parent 20:20 handle 101: pfifo
tc qdisc add dev ppp0 parent 20:30 handle 102: pfifo
tc qdisc add dev ppp0 parent 20:100 handle 201: pfifo
tc qdisc add dev ppp0 parent 20:200 handle 202: pfifo

#
tc filter add dev ppp0 parent 20: protocol ip prio 100 handle 20 fw classid 20:20
tc filter add dev ppp0 parent 20: protocol ip prio 100 handle 30 fw classid 20:30
tc filter add dev ppp0 parent 20: protocol ip prio 100 handle 100 fw classid 20:100
tc filter add dev ppp0 parent 20: protocol ip prio 100 handle 200 fw classid 20:200

#
iptables -t mangle -A OUTPUT -p tcp --sport 80 -j MARK --set-mark 100
iptables -t mangle -A PREROUTING -i eth0 -s 192.168.0.135 -j MARK --set-mark 200
iptables -t mangle -A PREROUTING -i eth0 -s 192.168.0.32 -j MARK --set-mark 30


find 指令 + mtime 找出時間異動的檔案

-mtime : 指定時間曾被異動過的檔案,意思是檔案內容被更改過
-ctime : 指定時間曾被更改過的檔案,意思是檔案權限被更改過
-atime : 指定時間曾被存取過的檔案,意思是檔案被讀取過

1。時間是以 24 小時為一個單位,而不是以天的

2。2009/01/10 12:00 時間開始找一天內的,會列出 2009/01/09 12:00 ~ 2009/01/10 12:00 時間內的檔案

找出 3 天"以前"被異動過的檔案 (前第三天以前 → 2009/01/07 12:00 以前的檔案) (> 72 小時)
find /var/log/ -mtime +3 -type f -print
找出 3 天內被異動過的檔案 (2009/01/07 12:00 ~ 2009/01/10 12:00 內的檔案) (0 ~ 72 小時內)
find /var/log/ -mtime -3 -type f -print
找出前第 3 天被異動過的檔案 (2009/01/06 12:00 ~ 2009/01/7 12:00 內的檔案) (72 ~ 96 小時)
find /var/log/ -mtime 3 -type f -print
找出第 3 天被異動過的檔案 (也可以這樣寫)
find /var/log/ -mtime +2 -mtime -4 -type f -print

Vim Cheat Sheet for Programmers

利用 nc 指令建立後門

只要一行簡單的指令即可達成
下載
測試環境: windows XP, Win 7
打開命令提示字元,輸入
nc -e cmd.exe -l -p 12345
再從別台 clinet 執行 telnet server 12345 就可以下 DOS 指令了


更多内容 http://ssorc.tw/rewrite.php/category-34-3.html#ixzz1kvJSACVR

iptables 模組 recent 防字典(Brute force)與port scan等攻擊

recent 是 iptables 的一個模組,可以用來作一段時間阻擋某些連線,

recent 所搭配的參數有

--name XXX  # 記錄資訊的檔案名稱,它會存在 /proc/net/ipt_recent/XXX,以下簡稱資料庫

--set # 指定符合條件的,加入或更新於XXX內

--rcheck #與資料庫比對,但不會修改更新

--update #與資料庫比對,會作修改更新

--remove # 與資料庫比對,存在就刪,不存在則否

--seconds X # 比對小於這個秒數的記錄才作動作,看是要更新還是刪除

--hitcount X # 重覆發生幾次連線


來個範例:

第一種
iptables -A INPUT -p icmp --icmp-type 8 -m recent --name ICMP_check --rcheck --seconds 60 --hitcount 6 -j DROP
iptables -A INPUT -p icmp --icmp-type 8 -m recent --set --name ICMP_check
第二種
iptables -A INPUT -p icmp --icmp-type 8 -m recent --name ICMP_check --update --seconds 60 --hitcount 6 -j DROP
iptables -A INPUT -p icmp --icmp-type 8 -m recent --set --name ICMP_check
這兩個的差別在於 --update 與 --rcheck,這先要提到 --seconds 的設定是條件觸發生時會去檢查最近60秒內的記錄,只要符合的話(多於6個ping),第七個ping會被drop掉,

而 --update 會一直更新記錄,--rcheck不會一直更新時間只會檢查而已

所以

第一種ping的結果
PING 10.10.10.168 (10.10.10.168) 56(84) bytes of data.
64 bytes from 10.10.10.168: icmp_seq=0 ttl=64 time=0.318 ms
64 bytes from 10.10.10.168: icmp_seq=1 ttl=64 time=0.293 ms
64 bytes from 10.10.10.168: icmp_seq=2 ttl=64 time=0.294 ms
64 bytes from 10.10.10.168: icmp_seq=3 ttl=64 time=0.286 ms
64 bytes from 10.10.10.168: icmp_seq=4 ttl=64 time=0.311 ms
64 bytes from 10.10.10.168: icmp_seq=5 ttl=64 time=0.271 ms
64 bytes from 10.10.10.168: icmp_seq=60 ttl=64 time=0.312 ms
64 bytes from 10.10.10.168: icmp_seq=61 ttl=64 time=0.286 ms
64 bytes from 10.10.10.168: icmp_seq=62 ttl=64 time=0.629 ms
64 bytes from 10.10.10.168: icmp_seq=63 ttl=64 time=0.271 ms
64 bytes from 10.10.10.168: icmp_seq=64 ttl=64 time=0.299 ms
64 bytes from 10.10.10.168: icmp_seq=65 ttl=64 time=0.285 ms
第二種ping的結果
PING 10.10.10.168 (10.10.10.168) 56(84) bytes of data.
64 bytes from 10.10.10.168: icmp_seq=0 ttl=64 time=0.318 ms
64 bytes from 10.10.10.168: icmp_seq=1 ttl=64 time=0.293 ms
64 bytes from 10.10.10.168: icmp_seq=2 ttl=64 time=0.294 ms
64 bytes from 10.10.10.168: icmp_seq=3 ttl=64 time=0.286 ms
64 bytes from 10.10.10.168: icmp_seq=4 ttl=64 time=0.311 ms
64 bytes from 10.10.10.168: icmp_seq=5 ttl=64 time=0.271 ms
第一種會一直在每一次的60秒過後再回應ping,第二種不會,因為--rcheck是會在第7個ping就停止更新記錄,過了60秒後,才再次更新,此時發現是過了60秒了,就可以再有ping的回應了,

而--update是會一直更新為最新的時間點,除非你停止ping,否則會一直ping不到,直到停止後過了60秒。


那如果這樣子設定的話,就是把 --set 放在前面,其資料庫的記錄會隨時更新
iptables -A INPUT -p icmp --icmp-type 8 -m recent --set --name ICMP_check
iptables -A INPUT -p icmp --icmp-type 8 -m recent --name ICMP_check --rcheck --seconds 60 --hitcount 6 -j DROP

or

iptables -A INPUT -p icmp --icmp-type 8 -m recent --set --name ICMP_check
iptables -A INPUT -p icmp --icmp-type 8 -m recent --name ICMP_check --update --seconds 60 --hitcount 6 -j DROP
/proc/net/ipt_recent/XXX 的內容長這樣子
src=10.10.10.165 ttl: 64 last_seen: 306003766 oldest_pkt: 2 306003766, 306003766, 305994749, 305994749, 305995750, 305995750, 305996752, 305996752, 305997752, 305997752, 305998756, 305998756, 305999760, 305999760, 306000762, 306000762, 306001763, 306001763, 306002764, 306002764
src=10.10.10.165  # 就是來源IP囉
last_seen: 306003766 # 從英文字面看來是最新的時間記錄,但這個數值怎麼算,不了 !!!!
oldest_pkt: 2 # 記錄幾個連線,20一次回圈,從0開始
在 oldest_pkt: 2 之後的數值跟 last_seen的數值是同屬性的,可以記錄20個,如果要改變這個儲存的量要這麼作 → modprobe ipt_recent ip_pkt_list_tot=50
那可以記錄幾筆來源ip呢,預設是 100,modprobe ipt_recent ip_list_tot=1024 可以改成1024筆


更多内容 http://ssorc.tw/rewrite.php/read-1053.html#ixzz1kvGzL8Oy

Port knocking

Port knocking 目前尚未有個正式的中文翻譯名詞,但大陸有人將它翻成 "端口碰撞" 技術。我簡單的說一下它的原理,以往我們要連 22 port (ssh) 時,必須在防火牆上打洞,開放 22 port 讓人連進來。 Port knocking 的原理就是 22 port 平時是關閉的,你必須先敲某一個port,再敲某一個 port 之後,  22 port 才會為你打開。這樣就有效的保護了 22 port 的安全性了。用 port scan 等工具也掃不到 22 port ,因為平時是關閉的。


目前此法只適用 linux 的 iptables
以下內容,紅字部份皆為指令或是您需要修改的內容 ,藍字部份則為設定檔內容。

iptables 防火牆的設定如下

iptables -N door
#新增一個叫做 door 的 chain。
iptables -A door -m recent --name knock1 --remove
#把進來door chain裡的封包,除去標籤名為 knock1 的封包。
iptables -A door -m recent --set --name knock2
#把進來door chain裡的封包,貼上標籤名為 knock2 的封包。
iptables -A INPUT -p tcp --dport 168 -m recent --set --name knock1
#把連線目標埠為168的封包,貼上 knock1 的標籤。
iptables -A INPUT -p tcp --dport 978 -m recent --rcheck --name knock1 -j door
#把連線目標埠為978、同時也要有貼著 knock1標籤的封包,送到 door 處理
#===> 也就是移去knock1標籤、然後被貼上 knock2 標籤。
iptables -A INPUT -p tcp --dport 22 -m recent --rcheck --seconds 5 --name knock2 -j ACCEPT
#被貼上 knock2 標籤的封包,同時也想連我的 22 port 時,讓它通過。

它的概念是,你在5秒內正確的連168port再接978port的一個連線封包會被依次貼上 knock1再清除,再被貼上 knock2 的標籤,有著 knock2 的標籤後,才能通過22 port 。
註意:不需要再在 iptables 內特別為168 和 978 port 打洞了,所以不要再多加這樣的兩行
iptables -A INPUT -i eth0 -p tcp --dport 168 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 978 -j ACCEPT
↑這樣會使你的 port knocking 設定不會成功的。
至於要怎麼敲 168 port 和 978 port 呢?
telnet 192.168.0.136 168
telnet 192.168.0.136 978
用這樣的指令就能敲port了。


參考資料:
Portknocking 觀念與 iptables 實作技術以保護SSH等公開服務
↑此文 Port knocking 觀念介紹寫的不錯,可惜實作的指令有些錯誤,我看了好久,才看明白,重覆試了好多次並改了指令後才試成功。
Top 20 OpenSSH Server Best Security Practices
↑請看 #18 這一項,可惜它的實作指令也有些語法寫錯,我按它的指令操作,沒試成功。

2012年1月18日 星期三

自定義iptables/netfilter的目標模塊

 

自定義iptables/netfilter的目標模塊

 
本文檔的Copyleft歸yfydz所有,使用GPL發布,可以自由拷貝,轉載,轉載時請保持文檔的完整性,嚴禁用於任何商業用途。
msn: yfydz_no1@hotmail.com
來源: http://yfydz.cublog.cn

1. 前言
Linux中的netfilter提供了一個防火牆框架,具有很好的擴展性,除了自帶的模塊之外,用戶可以根據自己的需求定義新的防火牆模塊加入其中,而編程過程也不是很複雜,只要依葫蘆畫瓢即可,可在原來的類似功能的模塊基礎上修改即可,甚至對各函數是如何調用,一些內部結構是如何定義的都不用詳細了解,本文即介紹如何編寫自定義的目標模塊。
 
目標(target)是防火牆規則策略中的結果部分,定義對數據包要進行如何處理,如接受、丟棄、修改、繼續等。在具體實現時分為兩部分,內核部分和用戶空間部分:內核中是以netfilter的擴展模塊實現,定義該模塊並將其掛接到netfilter的目標鍊錶中後,在內核進行目標檢測時自動根據目標名稱查找該模塊而調用相應的目標函數,完成真正的目標功能;在用戶空間,目標模塊是作為iptables的一個擴展動態庫來實現,只是一個用戶接口,不完成實際目標功能,完成接收用戶輸入並將目標數據結構傳遞到內核的功能,該庫的名稱有限制,必須為libipt_xxx.so,其中“xxx”是該目標的名字,為區別於匹配,
通常目標的名稱一般都是用大寫。

2. 內核模塊
目標在2.4內核和在2.6內核中的函數參數略有區別,兩者不兼容,但只要簡單修改後即可相互移植,主體部分不需要改變,本文以2.6內核的模塊為例。
 
為方便說明,還是通過舉例來進行說明,要實現的目標是修改IP頭中的ID字段,在實際使用中這個功能是沒什麼實際意義的,只是用來舉例說明。
 
在內核中已經自帶了net/ipv4/netfilter/ipt_ID.c模塊用來修改IP頭中的ID字段,我們可以以此模塊為基礎來進行修改。
 
首先要定義要進行目標的數據結構,用來描述目標條件,以ipt_ID.h頭文件為基礎修改為:

/* include/linux/netfilter_ipv4/ipt_ID.h */ 
#ifndef _IPT_ID_H_target 
#define _IPT_ID_H_target
struct ipt_id_target_info { 
 /* network order. */ 
 u_int16_t id; // id是16位的數
};
#endif /*_IPT_ID_H_target*/
 
然後是定義內核模塊處理,最主要的是定義一個ipt_target目標結構,該結構在include/linux/netfilter_ipv4/ip_tables.h中定義:
 
/* Registration hooks for targets. */ 
struct ipt_target 

 struct list_head list;
 const char name[IPT_FUNCTION_MAXNAMELEN];
 /* Called when user tries to insert an entry of this type: 
           hook_mask is a bitmask of hooks from which it can be 
           called. */ 
 /* Should return true or false. */ 
 int (*checkentry)(const char *tablename, 
     const struct ipt_entry *e, 
     void *targinfo, 
     unsigned int targinfosize, 
     unsigned int hook_mask);
 /* Called when entry of this type deleted. */ 
 void (*destroy)(void *targinfo, unsigned int targinfosize);
 /* Returns verdict. Argument order changed since 2.4, as this 
           must now handle non-linear skbs, using skb_copy_bits and 
           skb_ip_make_writable. */ 
 unsigned int (*target)(struct sk_buff **pskb, 
          const struct net_device *in, 
          const struct net_device *out, 
          unsigned int hooknum, 
          const void *targinfo, 
          void *userdata);
 /* Set this to THIS_MODULE. */ 
 struct module *me; 
};

該結構中有以下幾個參數:
struct list_head list:用來掛接到目標鍊錶,必須初始化為{NULL, NULL};
name:該目標名稱的名稱,必須是唯一的;
checkentry函數:用於對用戶層傳入的 ​​數據進行合法性檢查,如目標數據長度是否正確,是否是在正確的表中使用等;
destroy函數:用於釋放該目標中動態分配的資源,在規則刪除時會調用;
target函數:該函數是最主要函數,完成對數據包的策略處理,包括對包中的數據進行修改,函數返回結果可能是NF_ACCEPT(接受)/NF_DROP(丟棄)/NF_STOLEN(偷竊,指該包處理由該目標接管,不再由系統網絡棧處理)/IPT_CONTINUE(繼續,繼續按後面的規則對該包進行檢查)等;
struct module *me:指向模塊本身。
 
本例中的目標結構定義如下:
static struct ipt_target ipt_id_reg = { 
 .name = "ID", 
 .target = target, 
 .checkentry = checkentry, 
 .me = THIS_MODULE, 
};
 
target函數是目標的核心函數,返回1表示數據符合目標條件,0表示不目標,函數定義為:
 unsigned int (*target)(struct sk_buff **pskb, 
          const struct net_device *in, 
          const struct net_device *out, 
          unsigned int hooknum, 
          const void *targinfo, 
          void *userdata); 
在target函數參數為:
skb:數據包
in:數據進入的網卡
out:數據發出的網卡
hooknum:hook號,取值為:NF_IP_PRE_ROUTING/NF_IP_LOCAL_IN/NF_IP_FORWARD /
NF_IP_LOCAL_OUT/NF_IP_POST_ROUTING之一
targetinfo:目標條件信息的指針
offset:碎片數據偏移量
userdata:特殊專用數據,目前內核中基本沒有用到,通常都是NULL;
 
 
check函數對數據進行檢查,返回1表示數據合法,0表示非法,函數定義為:
 int (*checkentry)(const char *tablename, 
     const struct ipt_entry *e, 
     void *targinfo, 
     unsigned int targinfosize, 
     unsigned int hook_mask) ;
tablename:表名,如“filter”,“nat”,“mangle”等,可用來限制目標只能在指定的表中處理;
struct ipt_entry *e:指向規則的指針;
targetinfo:用戶空間傳入的 ​​目標條件信息的指針;
targetinfosize:用戶空間傳入目標條件信息的長度;
hook_mask:表示掛接點(PREROUTING/INPUT/FORWARD/OUTPUT/POSTROUTING)的掩碼,可用來限制目標只能在指定的掛接點中處理;
 
宏IPT_ALIGN用來得到實際目標結構的實際大小。
 
本例中需要檢查目標數據長度是否正確,表名是否是“mangle”,因為需要對數據進行修改,所以一般要在mangle表中進行處理,其實也可以不限制;
 
destroy函數釋放該目標中動態分配的資源,無返回值,函數定義為:
 void (*destroy)(void *targetinfo, unsigned int targetinfosize); 
函數參數同check()函數說明,在本例中,並沒有分配相關資源,所以沒定義此函數。
 
最後在模塊初始化函數中要調用ipt_register_target()函數將一個ipt_target目標結構掛接到系統目標鍊錶中,在模塊的結束函數中調用ipt_unregister_target()函數將目標結構從目標鍊錶中去除。
 
修改net/ipv4/netfilter/Makefile和Kconfig文件,加入關於ipt_ID相關內容即可在編譯內核中自動編譯,或者單獨直接將其編譯為模塊插入內核。
 
ipt_ID.c代碼如下:
/* This is a module which is used for setting the ID field of a packet. 
 * based on ipt_ID.c 
 * in fact, it's useless. 
 */
#include  
#include  
#include  
#include
#include  
#include
MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("yfydz< yfydz_no1@hotmail.com >"); 
MODULE_DESCRIPTION("iptables ID mangling module");
 
static unsigned int 
target(struct sk_buff **pskb, 
       const struct net_device *in, 
       const struct net_device *out, 
       unsigned int hooknum, 
       const void *targinfo, 
       void *userinfo) 

 const struct ipt_id_target_info *idinfo = targinfo;
//如果當前包的ID值和指定值不同,將指定值賦值給IP頭中的ID字段
 if ((*pskb)->nh.iph->id != idinfo->id) { 
  u_int16_t diffs[ 2];
  if (!skb_ip_make_writable(pskb, sizeof(struct iphdr))) 
   return NF_DROP;
  diffs[0] = htons((*pskb)->nh.iph->id) ^ 0xFFFF; 
  (*pskb)->nh.iph->id 
   = idinfo->id; 
  diffs[1] = htons((* pskb)->nh.iph->id); 
//由於IP包數據進行了修改,需要重新計算IP頭中的校驗和
  (*pskb)->nh.iph->check 
   = csum_fold(csum_partial(( char *)diffs, 
       sizeof(diffs), 
       (*pskb)->nh.iph->check 
       ^0xFFFF)); 
  (*pskb)->nfcache |= NFC_ALTERED; 
 } 
//返回IPT_CONTINUE,表示繼續按下一條規則處理數據包
 return IPT_CONTINUE; 
}
 
static int 
checkentry(const char *tablename, 
    const struct ipt_entry *e, 
           void *targinfo, 
           unsigned int targinfosize, 
           unsigned int hook_mask) 

 const u_int8_t id = ((struct ipt_id_target_info *)targinfo)->id; 
//檢查用戶傳入數據的長度是否正確
 if (targinfosize != IPT_ALIGN(sizeof(struct ipt_id_target_info))) { 
  printk(KERN_WARNING "ID: targinfosize %u != %Zu\n", 
         targinfosize, 
         IPT_ALIGN(sizeof(struct ipt_id_target_info))); 
  return 0; 
 } 
//判斷是否在mangle表中
 if (strcmp(tablename, "mangle") != 0) { 
  printk(KERN_WARNING "ID: can only be called from \"mangle\" table, not
\"%s\"\n", tablename); 
  return 0; 
 }
 return 1; 
}
 
static struct ipt_target ipt_id_reg = { 
 .name = "ID", 
 .target = target, 
 .checkentry = checkentry, 
 .me = THIS_MODULE, 
};
 
static int __init init(void) 

 return ipt_register_target(&ipt_id_reg); 
}
 
static void __exit fini(void) 

 ipt_unregister_target(&ipt_id_reg); 
}
 
module_init(init); 
module_exit(fini);
 
如果對包中的數據進行了修改,需要修改數據頭相應的校驗和,如IP頭校驗和和TCP/UDP頭校驗和,所以可能會需要調用如csum_partial(),tcp_v4_check(),csum_tcpudp_magic (),ip_s​​end_check(iph)等函數計算校驗和,這些函數的使用方法可參考內核中的代碼實例。
 
有些目標對包的操作比較複雜,如REJECT,MIRROR等,需要構造回應包發出,所以一般目標要比匹配要復雜一些。

3. iptables用戶層目標模塊
iptables中的擴展目標模塊是以動態庫方式處理,在命令行中用“-j xxx”來使iptables調用相應的libipt_xxx.so動態庫,擴展的目標代碼通常在iptables-/extension目錄下,編譯好的動態庫缺省放在/usr/local/lib/iptables目錄下。
 
目標動態庫的作用用於解析用戶輸入的目標信息,顯示目標信息等功能。
 
寫好libipt_xxx.c程序後放到iptables-/extension目錄下,修改該目錄下的Makefile文件,將xxx添加到擴展表中,make就能自動將其編譯為動態庫。
 
對於目標,最重要的數據結構就是struct iptables_target結構,擴展的目標程序就是要定義一個這個結構並將其掛接到iptables目標鍊錶中,該結構定義如下:
 
struct iptables_target 

 struct iptables_target *next;
 ipt_chainlabel name;
 const char *version;
 /* Size of target data. */ 
 size_t size;
 /* Size of target data relevent for userspace comparison purposes */ 
 size_t userspacesize;
 /* Function which prints out usage message. */ 
 void (*help)(void);
 /* Initialize the target. */ 
 void (*init)(struct ipt_entry_target *t, unsigned int *nfcache);
 /* Function which parses command options; returns true if it 
           ate an option */ 
 int (*parse)(int c, char **argv, int invert, unsigned int *flags, 
       const struct ipt_entry *entry, 
       struct ipt_entry_target **target );
 /* Final check; exit if not ok. */ 
 void (*final_check)(unsigned int flags);
 /* Prints out the target iff non-NULL: put space at end */ 
 void (*print)(const struct ipt_ip *ip, 
        const struct ipt_entry_target *target, int numeric);
 /* Saves the targinfo in parsable form to stdout. */ 
 void (*save)(const struct ipt_ip *ip, 
       const struct ipt_entry_target *target);
 /* Pointer to list of extra command-line options */ 
 struct option *extra_opts;
 /* Ignore these men behind the curtain: */ 
 unsigned int option_offset; 
 struct ipt_entry_target *t; 
 unsigned int tflags; 
 unsigned int used; 
#ifdef NO_SHARED_LIBS 
 unsigned int loaded; /* simulate loading so options are merged properly */ 
#endif 
};
 
struct iptables_target結構參數說明如下:
next:目標鍊錶的下一個,目標鍊錶是一個單向鍊錶;
name:目標的名稱,必須是唯一的;
version:iptables的版本;
size:目標結構的數據長度;
userspacesize :用於目標部分的數據長度,通常此值等於size,但某些情況 ​​可能會小於size;
help函數:打印幫助信息,當"-j xxx -h"時調用;
init函數:初始化函數,可對目標結構賦初值;
parse函數:解析用戶輸入參數,這是最主要的處理函數;
final_check函數:對用戶數據進行最後的檢查;
print函數:打印目標信息,iptables -L時調用
save函數:保存當前iptables規則時打印目標格式,被iptables-save程序調用;
extra_opts:選項信息,選項格式是標準的UNIX選項格式,通過getopt函數識別;
option_offset:選項偏移;
t:指向iptables規則;
tflags:規則相關標誌
used:模塊使用計數;
 
本例中,用戶輸入的參數是新的ID值,格式為:
“-j ID --set-id id_value ” id_value為id的實際數值。
 
libipt_id.c函數就是填寫struct iptables_target結構,然後定義動態庫初始化函數_init()將該結構掛接到iptables的選項鍊表中。程序在libipt_id.c的基礎上修改,程序比較簡單,直接將代碼列出,相關說明在註釋中:
 
/* libipt_id.c */ 
/* Shared library add-on to iptables to add ID target support. */ 
#include  
#include  
#include  
#include
#include  
#include  
#include
struct idinfo { 
 struct ipt_entry_target t; 
 struct ipt_id_target_info id; 
};

/* Function which prints out usage message. */ 
static void 
help(void) 

 unsigned int i;
 printf( 
"ID target v%s options:\n" 
" --set-id value Set ID of IP headere\n", 
IPTABLES_VERSION);
}
 
// opts結構第一個參數為選項名稱,
//第二個參數為1表示選項名稱後還帶參數,為0表示選項名稱後不帶參數
//第3個參數是標誌,表示返回數據的格式,一般都設為0 
//第4個參數表示該選項的索引值
static struct option opts[] = { 
 { "set-id", 1, 0, '1' }, 
 { 0 } 
} ;
/* Initialize the target. */ 
static void 
init(struct ipt_entry_target *t, unsigned int *nfcache) 

//空函數,不需要預處理
}
 
static void 
parse_id(const unsigned char *s, struct ipt_id_target_info *info) 

 unsigned int i, id;
 if (string_to_number(s, 0, 255, &id) != -1) { 
//注意要將主機序數據轉換為網絡序
      info->id = htons((u_int16_t )id); 
      return; 
 } 
 exit_error(PARAMETER_PROBLEM, "Bad ID value `%s'", s); 
}
 
/* Function which parses command options; returns true if it 
   ate an option */ 
static int 
parse(int c, char **argv, int invert, unsigned int *flags, 
      const struct ipt_entry *entry, 
      struct ipt_entry_target **target) 

 struct ipt_id_target_info *idinfo 
  = (struct ipt_id_target_info *)(*target)->data;
 switch (c) { 
 case '1': 
  if (*flags) 
   exit_error(PARAMETER_PROBLEM, 
              "ID target: Cant specify --set-id twice"); 
  parse_id(optarg, idinfo); 
  *flags = 1; 
  break;
 default: 
  return 0; 
 }
 return 1; 
}
 
static void 
final_check(unsigned int flags) 

 if (!flags) 
  exit_error(PARAMETER_PROBLEM, 
             "ID target: Parameter --set-id is required"); 
}
 
static void 
print_id(u_int8_t id, int numeric) 

 unsigned int i;
 printf("0x%x ", ntohs(id)); 
}
 
/* Prints out the targinfo. */ 
static void 
print(const struct ipt_ip *ip, 
      const struct ipt_entry_target *target, 
      int numeric) 

 const struct ipt_id_target_info *idinfo = 
  (const struct ipt_id_target_info *)target->data; 
 printf("ID set "); 
 print_id(idinfo->id, numeric); 
}
 
/* Saves the union ipt_targinfo in parsable form to stdout. */ 
static void 
save(const struct ipt_ip *ip, const struct ipt_entry_target *target) 

 const struct ipt_id_target_info *idinfo = 
  (const struct ipt_id_target_info *)target->data;
 printf("--set-id 0x%x ", ntohs(idinfo->id)); 
}
 
static 
struct iptables_target id 
= { NULL, 
    "ID", 
    IPTABLES_VERSION, 
    IPT_ALIGN(sizeof(struct ipt_id_target_info)), 
    IPT_ALIGN(sizeof(struct ipt_id_target_info)), 
    &help, 
    &init, 
    &parse, 
    &final_check, 
    &print, 
    &save, 
    opts 
};
 
void _init(void) 

 register_target(&id); 
}
 
4. 結論
netfilter/iptables可以很方便地擴展新的目標模塊,只需要按指定的方式編寫代碼就可以,讓開發者將注意力集中在功能的具體實現上,而不用再考慮其他因素,在具體實現時可以以現成的目標模塊為基礎進行修改即可,甚至不需要更仔細了解內部結構的定義就可以完成編碼,是一個程序模塊化的很優秀的實現例子。在netfilter官 ​​方網站( www.netfilter.org )上提供patch-o-matic程序包,其中包含了許多愛好者編寫的未併入Linux官方內核中的匹配和目標模塊。

How to use simple speedtest in RaspberryPi CLI

  pi@ChunchaiRPI2:/tmp $  wget -O speedtest-cli https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py --2023-06-26 10:4...