楔子
今天朋友找我解决一个问题,他的java服务在阿里服务器里监听了某端口(使用的TCP),但通过公网无法连接。我尝试在本地telnet那个端口(跨公网),不通。在他服务器里telnet 127.0.0.1 端口,是通的。说明服务正常监听了端口。但由于我不熟悉他的java服务,无法判断该java服务是否只监听了本地回环地址。
因此公网无法访问大概有两种可能,一,java服务只监听了本地回环地址; 二、防火墙限制了端口
排除第二种情况对我来说比较简单,我通过netcat在服务器监听端口,然后在本地telnet,不通!说明问题的确出在防火墙身上。该服务器为Ubuntu,使用ufw status
查看防火墙状态,显示为inactive
,也就是关闭状态。再查看阿里云安全组规则,已经开放了tcp/udp的所有端口(-1/-1)。后面我再次执行ufw disable
,端口就通了。所以这是ufw的bug?
引子有点长了。主要是为了说明,如果想知道与服务器之间的tcp连接是否通,可以使用netcat工具去判断。下面介绍下netcat ~
netcat是什么
是一种计算机网络实用程序,用于使用TCP或UDP读写网络连接,号称 TCP/IP 的瑞士军刀。大家一般简写为nc
。总之,涉及到网络的事儿,它几乎都能做。为什么叫瑞士军刀,因为它体积很小,不同版本的nc可执行文件只有几十k到300多k,而且大部分linux发行版都有预安装。
各种版本
netcat有许多版本,能力从弱到强为:GUN、BSD、Ncat。基础功能三者都一样,不同的是一些版本额外内置了些高级/有趣的功能(例如Ncat有个参数--chat
,可以创建匿名聊天室)。
大部分centos6内置的是BSD版本的nc,我的Centos7里边内置的nc是Ncat(属于nmap工具集里边)
使用man nc
,拉到最下边可以看到你的nc版本。(使用man你基本能够查阅所有的用法了,其它软件也是如此,只要是标准安装的)
ps. socat号称是更为强大的nc,有兴趣的小伙伴可以自己去看看。
用途
检查端口通不通
以往我一直使用telnet来判断某个端口是否通,但telnet是基于tcp协议的,如果要判断udp端口就无能为力了。这时可以使用nc来判断。为了方便实验,本文统一使用同一台机器模拟服务端和客户端。
# 咱们使用nc创建一个tcp协议监听的端口。-l为listen,默认协议为tcp nc -l 8088 # 使用nc连上该端口。-v(verbose)用于显示更多信息,-z(zero I/O)表示不发送数据包,仅显示连接状态。 # 下面succeed表示端口是通的 nc -vz 127.0.0.1 8088 Connection to 127.0.0.1 8088 port [tcp/radan-http] succeeded! # 创建一个udp端口。-u指使用udp协议 nc -lu 8088 # 同样,加一个u表示使用udp连接该端口,同时你会看到服务端打印出若干个X。 # 不是说加了z参数就不会发数据包吗,为什么服务端收到了报文?我认为udp是无连接状态的,通过系统调用write # 往该套接字发数据,通过返回值才知道包发出去没有,从而判断udp端口是否通 nc -vzu 127.0.0.1 8088 Connection to 127.0.0.1 8088 port [udp/radan-http] succeeded!
端口扫描
# 扫描tcp端口。-w(wait)指定连接超时时间,单位秒。 # 连接成功的端口将作为标准输出 nc -v -w3 -z 127.0.0.1 1-65535 | tee succeed_port.log # 下面摘抄部分连接成功的端口 Connection to 127.0.0.1 22 port [tcp/ssh] succeeded! Connection to 127.0.0.1 25 port [tcp/smtp] succeeded! Connection to 127.0.0.1 80 port [tcp/http] succeeded! Connection to 127.0.0.1 443 port [tcp/https] succeeded! Connection to 127.0.0.1 1100 port [tcp/mctp] succeeded! Connection to 127.0.0.1 1111 port [tcp/lmsocialserver] succeeded! Connection to 127.0.0.1 2255 port [tcp/vrtp] succeeded! Connection to 127.0.0.1 3001 port [tcp/*] succeeded! Connection to 127.0.0.1 3306 port [tcp/mysql] succeeded! Connection to 127.0.0.1 4300 port [tcp/corelccam] succeeded! Connection to 127.0.0.1 4369 port [tcp/epmd] succeeded! Connection to 127.0.0.1 5672 port [tcp/amqp] succeeded! Connection to 127.0.0.1 6553 port [tcp/*] succeeded! # 扫描udp端口。nc -v -zu 127.0.0.1 1-65535 # 以下为我本地扫描结果 Connection to 127.0.0.1 636 port [udp/ldaps] succeeded! Connection to 127.0.0.1 35157 port [udp/*] succeeded! Connection to 127.0.0.1 54890 port [udp/*] succeeded!
文件传输
归根到底都是创建一个tcp/udp连接,通过连接收发数据而已。所以,无论数据是ascii字符串,二进制文件都可以发送/接收。
为了加快传输速率/加密,你甚至还可以在发送之前对数据进行压缩/加密。
对于大文件,个人认为还是scp、rsync这类专业的工具靠谱。小文件可以试试这种方法,毕竟简单,不需要ssh认证。
# 接收端监听端口,把数据包重定向到指定文件 nc -l 8085 > file.ext # 发送方往指定ip:端口发送数据 nc 127.0.0.1 8085 < file.ext
ssh代理
是的,可以用作ssh代理!!如果某台内网机器需要通过代理才能连接,那么给ssh配置个代理是个不错的选择。这样ssh和scp都可以正常访问那台机器。
主要是利用了ssh的ProxyCommand选项,例如你要访问的机器ip为1.2.3.4,代理ip:端口为5.6.7.8:1988,那么编辑 ~/.ssh/config
Host 1.2.3.4 ProxyCommand nc -X 5 -x 5.6.7.8:1988 %h %p
-X指定代理协议,默认为5 (socks5),还有其他选项:4(socks4)、connect(https)
-x指定代理地址[端口]
具体的使用场景可以参考我的另一篇文章《在挂着VPN的虚拟机搭建代理服务》
网络测速
接收端:
nc -l port > /dev/null
发送端:
dd if=/dev/zero bs=9100004096 count=1 | nc 接收端ip port
最后你会看到结果:
2147479552 bytes (2.1 GB) copied, 12.7978 s, 168 MB/s
其它
另外还可以做以下事情,但我觉得一般来说用处不大。ps. 有些版本的nc可能参数有所差异或没有对应的特性
- 远程执行shell/bash。例子:服务端执行
nc -l 8083 -e /bin/bash(或shell)
,客户端nc 127.0.0.1 8083
,然后客户端就可以执行bash/shell了。但这种用法不要在公网用,否则很危险呐 - 网速测试(已补充到本文)。
- 啊,编不出来了~
ps. 有啥实用/有趣的用途,欢迎留言。