面试官:我问一个简单的问题,如何判断目标主机是否在监听一个UDP端口port?
我:给目标主机发送一个UDP报文(含目标port),如果收到回复,表示监听,否则表示没有监听。
面试官:有没有通用一点的方法
我:没有
目录
1、TCP监听端口
问题分析:
假设题目为是否在监听一个TCP端口,那就容易多了
1.1、connect接口
编程上:我们可以直接调用connect接口(unix),建链远端地址和端口,建链成功:在监听port;建链拒绝:表示未在监听
工具上:
1.2、telnet指令
格式:telnet [hostname] [port] //仅适用TCP
//client
[root@localhost ~]# telnet 10.43.42.199 20000
Trying 10.43.42.199...
telnet: connect to address 10.43.42.199: Connection refused
telnet: Unable to connect to remote host: Connection refused
[root@localhost ~]# telnet 10.43.42.199 30000
Trying 10.43.42.199...
Connected to 10.43.42.199 (10.43.42.199).
Escape character is '^]'.
xxxxxxxddddddddd
Connection closed by foreign host.
[root@localhost ~]#
==========================================================================
//remote
[root@localhost ~]# ./tcp_server 10.43.42.199 30000
wait for clients connect----------
client IP :10.43.85.162 34494
recv_buf=xxxxxxxddddddddd
^C
[root@localhost ~]#
报文:
1.3、nc 指令
//client
[root@localhost ~]# nc -vz 10.43.42.199 60001
nc: connect to 10.43.42.199 port 60001 (tcp) failed: Connection refused
[root@localhost ~]# nc -vz 10.43.42.199 60000
Connection to 10.43.42.199 60000 port [tcp/*] succeeded!
[root@localhost ~]#
===================================================================
//remote
[root@localhost ~]# ./tcp_server 10.43.42.199 60000
wait for clients connect----------
client IP :10.43.85.162 33741
^C
[root@localhost ~]#
报文:
2、UDP监听端口
connect 接口链接UDP套接字和远端主机UDP绑定的地址和端口,无论远端是否绑定,connect均可以链接成功,同时 telnet也仅适用于TCP,因此判断远端的存在监听UDP端口只能通过nc指令即netcat服务,假设UDP监听端口收到远端发来的探测包,直接弹回或者给予恢复应答,则客户端仅需判断是否有回环包回来即可,但是因为UDP是无连接的,可以收到包后不给以任何回复,编写服务器udp_server收到包直接打印输出。
2.1、nc + ping + traceroute
//client
[root@localhost ~]# nc -uvz 10.43.42.199 10000
[root@localhost ~]# nc -uvz 10.43.42.199 20000
Connection to 10.43.42.199 20000 port [udp/dnp] succeeded!
[root@localhost ~]#
//remote
[root@localhost ~]# ./udp_server 10.43.42.199 20000
client [10.43.85.162: 38752]
lenx =1,buf=X
client [10.43.85.162: 38752]
lenx =1,buf=X
client [10.43.85.162: 38752]
lenx =1,buf=X
client [10.43.85.162: 38752]
lenx =1,buf=X
client [10.43.85.162: 38752]
lenx =1,buf=X
通常情况,当服务器收到的 udp 报文发现没有发现监听端口会使用 icmp 协议回复差错报文(type = 3,code = 3),关于linux内核udp协议收包流程参见《linux内核协议栈 UDP之数据报接收过程Ⅰ》,实际抓包信息如下:
这里还有一个很重要的问题,就是 UDP 服务器收到远端的探测报文不会回复问题,因此客户端需要确认发出UDP探测报文已经到了目标机而不是中途丢了,因此事先检测一下客户端到目标机之间的链路是通的,否则netcat会错误的认为没有收到UDP的回复报文而认为远端还在监听相应的端口,测试链路不通场景如下:
[root@localhost ~]# ping 10.43.42.200 -c 5
PING 10.43.42.200 (10.43.42.200) 56(84) bytes of data.
--- 10.43.42.200 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 14010ms
[root@localhost ~]# nc -uvz 10.43.42.200 20000
Connection to 10.43.42.200 20000 port [udp/dnp] succeeded!
[root@localhost ~]#
可以到 10.43.42.200 的链路本来就不通,但是nc还是回复远端绑定udp端口20000,因此nc需要结合ping来使用。再有一点需要注意的是 ping 包均是 ICMP 报文,即使链路正常,还是不能保证百分之百保证UDP报文一定能到达对端,因为还有极少数的路由器或者一些防火墙设备可能会丢去一些端口较大的 UDP 报文,因此,此时还要借助 traceroute 判断 UDP 包是否到达了远端主机。