socat是一個多功能的網絡工具,名字來由是” SOcket CAT”,因此可以看出它基於socket,能夠折騰socket相關的無數事情。
當然這些都不是我關心的重點。我發現並嘗試使用socat的原因可以參看此前的一次端口轉發的嘗試,本文的重點是介紹一下我對socat的使用心得,以及折騰了一個小時的GENTOO版socat服務腳本。
為了表示對網絡先驅的尊重,首先貼參考文章:
《Port Forwarding in user space [INFO]》和《How to forward port in user space using socat》
socat其實可以看作是netcat的加強N倍版,因此乍一看socat的命令行,那叫一個復雜。不過仔細一看后,其實發現socat的參數也是很有規律、簡潔的。例如,我需要的轉發功能是:
對於所有15000端口的TCP訪問,一律轉發到 server.wesnoth.org:15000 上。
於是,對應的命令就是:
1 socat -d -d -lf /var/log/socat.log TCP4-LISTEN:15000,reuseaddr,fork,su=nobody TCP4:server.wesnoth.org:15000“-d -d -lf /var/log/socat.log”是參數,前面兩個連續的-d -d代表調試信息的輸出級別,-lf則指定輸出信息的保存文件。
“TCP4-LISTEN:15000,reuseaddr,fork,su=nobody”是一號地址,代表在15000端口上進行TCP4協議的監聽,復用綁定的IP,每次又連接到來就fork復制一個進程進行處理,同時將執行用戶設置為nobody用戶。
“TCP4:server.wesnoth.org:15000″是二號地址,代表將socat監聽到的任何請求,轉發到server.wesnoth.org:15000上去。
但是在服務器上運行的命令,最好還是寫成為一個服務腳本,這樣便於后續重啟服務器之類的。剛好我的VPS服務器上的系統是gentoo,於是就費了點時間寫了一個腳本。
首先貼腳本的配置文件:
1
2
3
4
5
6
7
8 # Configuration for /etc/init.d/socat
# File: /etc/socat.conf
SOCAT_ARGS= "-d -d -d -lf /var/log/socat.log"
AUTOSTART= "wesnoth wesnoth6"
SOCAT_wesnoth= "TCP-LISTEN:15000,reuseaddr,fork,su=nobody TCP4:server.wesnoth.org:15000"
SOCAT_wesnoth6= "TCP6-LISTEN:15001,reuseaddr,fork,su=nobody TCP4:server.wesnoth.org:15000"然后貼腳本代碼,保存的位置當然是
/etc/init.d/socat
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 #!/sbin/runscript
# Copyright 1999-2007 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
BIN= /usr /bin /socat
SOCAT_CONF= /etc /socat.conf
SOCAT_ARGS= "-d -d -lf /var/log/socat.log"
[ ! -f $SOCAT_CONF ] || source $SOCAT_CONF
[ -x $BIN ] || exit 0
depend ( ) {
need net
}
start ( ) {
ebegin "Starting ${SVCNAME}"
if test "x$AUTOSTART" = "xnone" -o -z "x$AUTOSTART" ; then
ewarn "Autostart is set to 'none', so disabled."
exit 0
fi
for FORWARD in $AUTOSTART ; do
ARGS= ` eval echo \\\ $SOCAT_ $FORWARD `
PID= "/var/run/${SVCNAME}/$FORWARD.pid"
start-stop-daemon -b --start --exec ${BIN} --make-pidfile --pidfile "${PID}" -- ${SOCAT_ARGS} ${ARGS} &
done
eend $? "Check ${SOCAT_LOG} to see why startup failed"
}
stop ( ) {
ebegin "Stopping ${SVCNAME}"
for PID in /var /run / ${SVCNAME} /*.pid; do
start-stop-daemon --stop --quiet --exec ${BIN} --pidfile "${PID}"
done
eend $?
}
# vim: set ts=4 :接着,配置完
/etc/socat.conf
后,就可以啟動socat服務了:
1 /etc /init.d /socat start關閉服務的命令是:
1 /etc /init.d /socat stop當然,我更是直接加入到了boot服務組里了,下次開機時能夠自動啟動:
1 rc-update add socat boot好了,大功告成!
不過,依舊有一些問題。例如我首先使用 TCP4-LISTEN:15000 綁定了一個IPv4的TCP監聽后,接着使用 TCP6-LISTEN:15000 綁定則會提示失敗:
1
2
3 # socat -d -d TCP6-LISTEN:15000,reuseaddr,fork,su=nobody TCP4:server.wesnoth.org:15000
2010/09/29 23:19:42 socat[3166] E bind(3, {AF=10 [0000:0000:0000:0000:0000:0000:0000:0000]:15000}, 28): Address already in use
2010/09/29 23:19:42 socat[3166] N exit(1)可是此時查看網絡端口的監聽情況,並沒有發現IPv6上有監聽:
1
2
3
4
5
6
7 # netstat -an | grep LISTEN
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:21 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:15000 0.0.0.0:* LISTEN
tcp6 0 0 :::21 :::* LISTEN真是奇怪呢……可惜手頭沒有IPv6,難以測試啊……