socat
2013-05-21 15:06:20 阿炯

socat 是一个多功能的网络工具,名字来由是'Socket CAT',可以看作是netcat的加强版,采用C语言写成并在GPLv2协议下授权。它的主要特点就是在两个数据流之间建立通道,且支持众多协议和链接方式,如 IP、TCP、 UDP、IPv6、PIPE、EXEC、System、Open、Proxy、Openssl、Socket等。


The socat utility is a relay for bidirectional data transfers between two independent data channels.


socat is a relay for bidirectional data transfer between two independent data channels. Each of these data channels may be a file, pipe, device (serial line etc. or a pseudo terminal), a socket (UNIX, IP4, IP6 - raw, UDP, TCP), an SSL socket, proxy CONNECT connection, a file descriptor (stdin etc.), the GNU line editor (readline), a program, or a combination of two of these. These modes include generation of "listening" sockets, named pipes, and pseudo terminals.


There are many different types of channels socat can connect, including:
Files
Pipes
Devices (serial line, pseudo-terminal, etc)
Sockets (UNIX, IP4, IP6 - raw, UDP, TCP)
SSL sockets
Proxy CONNECT connections
File descriptors (stdin, etc)
The GNU line editor (readline)
Programs
Combinations of two of these


Abstract
what: "netcat++" (extended design, new implementation)
OS:   AIX, BSD, HP-UX, Linux, Solaris e.a. (UNIX)
lic:  GPLv2
inst: tar x...; ./configure; make; make install
doc:  README; socat.html, socat.1; xio.help
ui:   command line
exa:  socat TCP6-LISTEN:8080,reuseaddr,fork PROXY:proxy:www.domain.com:80
keyw: tcp, udp, ipv6, raw ip, unix-socket, pty, pipe, listen, socks4, socks4a,proxy-connect, ssl-client, filedescriptor, readline, stdio,exec, system, file, open, tail -f, termios, setsockopt, chroot,fork, perm, owner, trace, dump, dgram, ext3, resolver, datagram,multicast, broadcast, interface, socket, sctp, generic, ioctl


-------------------------------
为什么要使用socat

有很多方法可以有效地使用socat,比如:
TCP port forwarder (one-shot or daemon)
External socksifier
Tool to attack weak firewalls (security and audit)
Shell interface to Unix sockets
IP6 relay
Redirect TCP-oriented programs to a serial line
Logically connect serial lines on different computers

Establish a relatively secure environment (su and chroot) for running client or server shell scripts with network connections

socat基本语法

The syntax for socat is fairly simple:
socat [options] <address> <address>

必须提供源地址和目标地址才能正常工作,这些地址的使用语法是:
protocol:ip:port

其中这 2 个 address 就是关键了,address 类似于一个文件描述符,socat 所做的工作就是在 2 个 address 指定的描述符间建立一个 pipe 用于发送和接收数据。几个常用的 address 描述方式如下:
-,STDIN,STDOUT: 表示标准输入输出,可以就用一个横杠代替。
/var/log/syslog: 打开一个文件作为数据流,可以是任意路径。
TCP: 建立一个 TCP 连接作为数据流,TCP 也可以替换为 UDP 。
TCP-LISTEN: 建立 一个 TCP 监听端口,TCP 也可以替换为 UDP。
EXEC: 执行一个程序作为数据流。

以上规则中前面的 TCP 等都可以小写,在这些描述后可以附加一些选项,用逗号隔开。如 fork,reuseaddr,stdin,stdout,ctty 等。

socat的使用示例

Let's get started with some basic examples of using socat for various connections.

1. Connect to TCP port 80 on the local or remote system:
# socat - TCP4:www.example.com:80

In this case, socat transfers data between STDIO (-) and a TCP4 connection to port 80 on a host named www.example.com.

2. Use socat as a TCP port forwarder:
For a single connection, enter:
# socat TCP4-LISTEN:81 TCP4:192.168.10.10:80

For multiple connections, use the fork option as used in the examples below:
# socat TCP4-LISTEN:81,fork,reuseaddr TCP4:192.168.10.10:80

This example listens on port 81, accepts connections, and forwards the connections to port 80 on the remote host(192.168.10.10).

# socat TCP-LISTEN:3307,reuseaddr,fork UNIX-CONNECT:/var/lib/mysql/mysql.sock

The above example listens on port 3307, accepts connections, and forwards the connections to a Unix socket on the remote host.

3. Implement a simple network-based message collector:
# socat -u TCP4-LISTEN:3334,reuseaddr,fork OPEN:/tmp/test.log,creat,append

In this example, when a client connects to port 3334, a new child process is generated. All data sent by the clients is appended to the file /tmp/test.log. If the file does not exist, socat creates it. The option reuseaddr allows an immediate restart of the server process.

4. Send a broadcast to the local network:

# socat - UDP4-DATAGRAM:224.255.0.1:6666,bind=:6666,ip-add-membership=224.255.0.1:eth0

In this case, socat transfers data from stdin to the specified multicast address using UDP over port 6666 for both the local and remote connections. The command also tells the interface eth0 to accept multicast packets for the given group.

socat的实际用例

Socat is a great tool for troubleshooting. It is also handy for easily making remote connections. Practically, I have used socat for remote MySQL connections. In the example below, I demonstrate how I use socat to connect my web application to a remote MySQL server by connecting over the local socket.

1. On my remote MySQL server, I enter:
# socat TCP-LISTEN:3307,reuseaddr,fork UNIX-CONNECT:/var/lib/mysql/mysql.sock &

This command starts socat and configures it to listen by using port 3307.

2. On my webserver, I enter:
# socat UNIX-LISTEN:/var/lib/mysql/mysql.sock,fork,reuseaddr,unlink-early,user=mysql,group=mysql,mode=777 TCP:192.168.100.5:3307 &

The above command connects to the remote server 192.168.100.5 by using port 3307.

However, all communication will be done on the Unix socket /var/lib/mysql/mysql.sock, and this makes it appear to be a local server.

总结(Wrap up)

socat是一个复杂的实用工具,对于每个系统管理员来说,它确实是一个很好的工具,可以完成任务并进行故障排除。 点击这里可以看到更多的官方示例。

--------------------------------------------------------------
socat 使用实例

-------------------------------
文件操作

通过 socat 读取文件

# 从绝对路径读取
$ socat - /var/www/html/freeoa.php

# 从相对路径读取
$ socat - ./freeoa.php

注:这里的路径一般是绝对路径,如果要使用相对路径记得要加上 ./ 。

写入文件
$ echo "This is Test" | socat - /tmp/hello.html

-------------------------------
网络管理

连接远程端口
$ socat - TCP:192.168.9.92:3306

监听一个新端口
$ socat TCP-LISTEN:7000 -

-------------------------------
端口转发
在实际生产中我们经常会遇到到一个场景就是,用一台机器作为转发服务器,连接 AB 两个网段,将转发服务器的某个端口上的流量转发到 B 网段的某台机器的某个端口,这样 A 网段的服务器就可以通过访问转发服务器上的端口访问到 B 网段的服务器端口。这样的场景一般在和客户建立专线的连接时候经常用到,一般也可以采用 iptables 做转发,但是比较复杂。socat 可以很轻松的完成这个功能,但是 socat 不支持端口段转发,只适用于单端口或者少量端口。

转发 TCP

监听 192.168.9.92 网卡的 15672 端口,并将请求转发至 172.17.0.15 的 15672 端口。
$ socat  -d -d -lf /var/log/socat.log TCP4-LISTEN:15672,bind=192.168.9.92,reuseaddr,fork TCP4:172.17.0.15:15672

参数说明:
1. -d -d  前面两个连续的 -d -d 代表调试信息的输出级别。
2. -lf /var/log/socat.log 指定输出信息的文件保存位置。
3. TCP4-LISTEN:15672 在本地建立一个 TCP IPv4 协议的监听端口,也就是转发端口。这里是 15672,请根据实际情况改成你自己需要转发的端口。
4. bind 指定监听绑定的 IP 地址,不绑定的话将监听服务器上可用的全部 IP。
5. reuseaddr 绑定一个本地端口。
6. fork TCP4:172.17.0.15:15672 指的是要转发到的服务器 IP 和端口,这里是 172.17.0.15 的 15672 端口。

转发 UDP

转发 UDP 和 TCP 类似,只要把 TCP4 改成 UDP4 就行了。

$ socat -d -d -lf /var/log/socat.log UDP4-LISTEN:123,bind=192.168.9.92,reuseaddr,fork UDP4:172.17.0.15:123

NAT 映射

在一个 NAT 网络环境中,也是可以通过 Socat 将内部机器端口映射到公网上的。

在外部公网机器上执行
$ socat tcp-listen:1234 tcp-listen:3389

在内部私网机器上执行
$ socat tcp:outerhost:1234 tcp:192.168.1.34:3389

这样,你外部机器上的 3389 就映射在内网 192.168.1.34 的 3389 端口上了。

-------------------------------
文件传递

文件传送

将文件 demo.tar.gz 使用 2000 端口从 192.168.9.92 传到 192.168.9.93,文件传输完毕后会自动退出。

在 192.168.9.92 上执行
$ socat -u open:freeoa20.tar.gz tcp-listen:2000,reuseaddr

在 192.168.9.93 上执行
$ socat -u tcp:192.168.9.92:2000 open:freeoa20.tar.gz,create

-u 表示数据传输模式为单向,从左面参数到右面参数。
-U 表示数据传输模式为单向,从右面参数到左面参数。

读写分流功能

socat 具有一个独特的读写分流功能,比如:可以实现一个假的 Web Server,客户端连过来之后就把 read.html 里面的内容传过去,同时把客户端的数据保存到 write.txt 里面。

$ socat open:read.html\!\!open:write.txt,create,append tcp-listen:8000,reuseaddr,fork

!! 符号用于合并读写流,前面的用于读,后面的用于写。由于 ! 在 Shell 中是特殊字符,所以这里在命令行中使用 \ 对其进行了转义。

-------------------------------
其它功能

监听一个 TCP 端口
$ socat tcp-listen:12345 -

向 TCP 端口发送数据
$ echo "test" | socat - tcp-connect:127.0.0.1:12345

监听一个 UDP 端口
$ socat udp-listen:23456 -

向一个 UDP 端口发送数据
$ echo "test" | socat - udp-connect:127.0.0.1:23456

监听一个 Unix Socket
$ socat unix-listen:/tmp/unix.socket -

向本地 Unix Socket 发送数据
$ echo "test" | socat - unix-connect:/tmp/unix.sock

监听本地 Unix Datagram Socket
$ socat unix-recvfrom:/tmp/unix.dg.sock -

向本地 Unix Datagram Socket 发送数据
$ echo "test" | socat - unix-sendto:/tmp/unix.dg.sock

通过 Openssl 来加密传输过程

假设有一个服务器主机,地址为 server.domain.org。 并且服务端程序使用 4433 端口。为了尽可能的简单,我们使用一个非常简单的服务功能,即服务端仅回显数据(echo),客户端只进行标准输入(stdio)。要进行 Openssl 加密数据传输,首先需要生成 Openssl 证书。

生成服务端的证书

# 为服务端的证书取一个基本的名字。
$ FILENAME=server
# 生成公钥私钥对。
$ openssl genrsa -out $FILENAME.key 1024
# 生成一个自签名的证书,会提示你输入国家代号、姓名等,或者按下回车键跳过输入提示。
$ openssl req -new -key $FILENAME.key -x509 -days 3653 -out $FILENAME.crt
# 用刚生成的密钥文件和证书文件来生成PEM文件。
$ cat $FILENAME.key $FILENAME.crt >$FILENAME.pem

服务端证书生成完成后,复制信任证书 server.crt 到 SSL 客户端所在的主机上。

生成客户端证书

# 为客户端证书取一个不同的文件名
$ FILENAME=client

重复上述服务端生成证书的流程。然后复制 client.pem 到 SSL 客户端主机,复制 client.crt 到服务端主机。至此完成了证书交换,服务端有 server.pem、client.crt 两个文件,客户端有 client.pem 、server.crt 两个文件。

其次我们需要建立 Openssl 服务端,在服务端我们不再用 tcp-listen (tcp-l) ,而用 openssl-listen (ssl-l) 。cert 参数告诉 socat 包含证书和私钥的文件,cafile 参数指向客户端的证书文件。如果客户端能提供相关联的私钥,我们则认为该连接是可靠的。

$ socat openssl-listen:4433,reuseaddr,cert=server.pem,cafile=client.crt echo

运行这个命令后,socat 会在 4433 端口监听,并要求客户端进行身份验证。最后在客户端建立一个加密的链接,用 openssl-connect 或者 ssl 替换你的 tcp-connect 或 tcp 地址关键字,然后添加 cert 和 cafile 选项。

$ socat stdio openssl-connect:server.domain.org:4433,cert=client.pem,cafile=server.crt
test
test

这个命令用来建立一个到服务程序的安全的连接。如果服务端和客户端成功建立连接后,会回显在客户端输入的内容。


建立一个正向 Shell

服务端
# 在服务端 7005 端口建立一个 Shell。
$ socat TCP-LISTEN:7005,fork,reuseaddr EXEC:/bin/bash,pty,stderr
或者
$ socat TCP-LISTEN:7005,fork,reuseaddr system:bash,pty,stderr

客户端
# 连接到服务器的 7005 端口,即可获得一个 Shell。readline 是 GNU 的命令行编辑器,具有历史功能。
$ socat readline tcp:127.0.0.1:7005


反弹一个交互式的 Shell

当有主机连接服务端的 7005 端口时,将会发送客户端的 Shell 给服务端。

服务端
$ socat -,raw,echo=0 tcp-listen:7005

客户端
$ socat tcp-connect:192.168.9.92:7005 exec:'bash -li',pty,stderr,setsid,sigint,sane

fork 服务
将一个使用标准输入输出的单进程程序变为一个使用 fork 方法的多进程服务,非常方便。

$ socat TCP-LISTEN:1234,reuseaddr,fork EXEC:./helloworld

不同设备的通信

将 U 盘进行网络共享
$ socat -d -d /dev/ttyUSB1,raw,nonblock,ignoreeof,cr,echo=0 TCP4-LISTEN:5555,reuseaddr

将终端转发到串口
$ socat READLINE,/dev/ttyS0,raw,echo=0,crnl

让 socat 后台运行

默认情况下 socat 只在前台运行,如果要让 socat 一直在后台运行,可以使用 nohup 命令来保证其在后台一直运行。
$ nohup socat  -d -d -lf /var/log/socat.log TCP4-LISTEN:15672,bind=192.168.9.92,reuseaddr,fork TCP4:172.17.0.15:15672 &

除了 nohup 外,Linux 下让进程在后台运行的方法还很多,比如:screen、tmux 等。

在 Linux 中一切都是文件,无论是 Socket 还是其他设备。所以从理论上来说,一切能够在文件层级访问的内容都可以成为 socat 的数据流的来源。2 个 address 可以任意发挥,能够做到的事情还有很多。这样比起来,socat 的确比 netcat 更加强大。



最新版本:1.7


项目主页:http://www.dest-unreach.org/socat/