TCP连接一个IP或端口不存在的主机时,会发生什么?

目录

一.要点回顾

二.连一个 IP 不存在的主机时,握手过程是怎样的

1、局域网内

2、局域网外

三.连IP 地址存在但端口号不存在的主机的握手过程

1、目的IP是回环地址

2、目的IP局域网内

3、 目的IP局域网外

4.总结 


一.要点回顾

戳我,回顾正常情况下TCP的连接过程。

二.连一个 IP 不存在的主机时,握手过程是怎样的

不存在的IP,分两种,局域网内和局域网外的。

1、局域网内

我们可以假设  192.168.31.xx  形式的IP,就是局域网内的IP。否则就是局域网外的IP

假设我们当前设备的IP地址为192.168.31.6,现在尝试与目的IP地址为192.168.31.7的主机建立TCP连接,但实际上这个目的主机并不存在。

 我们使用Wireshark进行抓包

可以发现根本没有三次握手的包,只有一些 ARP 包,在询问“谁是 192.168.31.7。

这里有三个问题

  • 为什么会发ARP请求?

  • 为什么没有TCP握手包?

  • ARP本身是没有重试机制的,为什么ARP请求会发那么多遍?

首先我们看下正常情况下执行connect,也就是第一次握手 的流程。

图片

应用层执行connect过后,进程会从用户态进入到内核态,此时进入 传输层,因为是TCP第一次握手,会加入TCP头,且置SYN标志。

图片

然后进入网络层,我想要连的是 192.168.31.7 ,虽然它是瞎编的,但IP头还是得老老实实把它加进去。

此时需要重点介绍的是邻居子系统,它在网络层和数据链路层之间。可以通过ARP协议将目的IP转为对应的MAC地址,然后数据链路层就可以用这个MAC地址组装帧头

我们看下那么ARP协议的流程

  1. 先到本地ARP表查一下有没有 192.168.31.7 对应的 mac地址,有的话就返回,这里显然是不可能会有的。
  2. 看下 192.168.31.7  跟本机IP  192.168.31.6在不在一个局域网下。如果在的话,就在局域网内发一个 arp 广播,内容就是 前面提到的 “谁是 192.168.31.7,告诉一下 192.168.31.6”。 
  3. 如果目的IP跟本机IP不在同一个局域网下,那么会去获取默认网关的MAC地址,然后把消息发给默认网关,让默认网关发到互联网,找到下一跳路由器,一跳一跳的发送数据,直到把消息发到目的IP上,又或者找不到目的地最终被丢弃。
  4. 第2和第3点都是本地没有查到 ARP 缓存记录的情况,这时候会把SYN报文放进一个队列(叫unresolved_queue)里暂存起来,然后发起ARP请求;等ARP层收到ARP回应报文之后,会再从缓存中取出 SYN 报文,组装 MAC 帧头,完成刚刚没完成的发送流程。

如果经过 ARP 流程能正常返回 MAC 地址,那皆大欢喜,直接给数据链路层,经过 ring buffer 后传到网卡,发出去。

但因为现在这个IP是瞎编的,因此不可能得到目的地址 MAC ,所以消息也一直没法到数据链路层。整个流程卡在了ARP流程中。

抓包是在数据链路层之后进行的,因此 TCP 第一次握手的包一直没能抓到,只能抓到为了获得  192.168.31.7 的MAC地址的ARP请求。

此时 因为 TCP 协议是可靠的协议,对于 TCP 层来说,第一次握手的消息,已经发出去了,但是一直没有收到 ACK。也不知道消息是出去后是遇到什么事了。为了保证可靠性,它会不断重发。

而每一次重发,都会因为同样的原因(没有目的 MAC 地址)而尬在了 ARP 那个流程里。因此,才看到好几次重复的 ARP 消息。

那回到刚刚的三个问题

  • 为什么会发 ARP 请求?

    因为目的地址是瞎编的,本地ARP表没有目的机器的MAC地址,因此发出ARP消息。

  • 为什么没有 TCP 握手包?

    因为协议栈的数据到了网络层后,在数据链路层前,就因为没有目的MAC地址,没法发出。因此抓包软件抓不到相关数据。

  • 为什么 ARP 请求会发那么多遍?

    因为 TCP 协议的可靠性,会重发第一次握手的消息,但每一次都因为没有目的 MAC 地址而失败,每次都会发出ARP请求。

小结

连一个 IP 不存在的主机时,如果目的IP在局域网内,则第一次握手会失败,接着不断尝试重发握手的请求。同时,本机会不断发出ARP请求,企图获得目的机器的 MAC 地址。并且,因为没能获得目的 MAC 地址,这些 TCP 握手请求最终都发不出去,

2、局域网外

上面提到的是,目的 IP 在局域网内的情况,下面讨论目的IP在局域网外的情况。

我们将10.225.31.11作为这次要用的局域网外IP。

先抓包看一下。

图片

这次的现象是能发出 TCP 第一次握手的 SYN包

这里有个问题

  • 为什么连局域网外的 IP 现象跟连局域网内不一致?

这个问题的答案其实在上面 ARP 的流程里已经提到过了,如果目的 IP 跟本机 IP 不在同一个局域网下,那么会去获取默认网关的 MAC 地址,这里就是指获取家用路由器的MAC地址

此时ARP流程成功返回家用路由器的 MAC 地址,数据链路层加入帧头,消息通过网卡发到了家用路由器上

消息会通过互联网一直传递到某个局域网为  10.225.31.xx 的路由器上,那个路由器 发出ARP 请求,询问他们局域网内的机器有没有叫 10.225.31.11的 (结果当然没有)。

最终没能发送成功,发送端也就迟迟收不到目的机的第二次握手响应。

因此触发TCP重传。

三.连IP 地址存在但端口号不存在的主机的握手过程

前面提到的是IP地址压根就不存在的情况。假如IP地址存在但端口号是瞎编的呢?

1、目的IP是回环地址

图片

现象也比较简单,已经IP地址是存在的,也就是在互联网中这个机器是存在的。

那么我们可以正常发消息到目的IP,因为对应的MAC地址和IP都是正确的,所以,数据从数据链路层到网络层都很OK。

直到传输层,TCP协议在识别到这个端口号对应的进程根本不存在时,就会把数据丢弃,响应一个RST消息给发送端。

图片

连回环地址时端口不存在

RST是什么?

我们都是到TCP正常情况下断开连接是用四次挥手,那是正常时候的优雅做法。

异常情况下,收发双方都不一定正常,连挥手这件事本身都可能做不到,所以就需要一个机制去强行关闭连接。

RST 就是用于这种情况,一般用来异常地关闭一个连接。它在TCP包头中,在收到置了这个标志位的数据包后,连接就会被关闭,此时接收到 RST的一方,一般会看到一个 connection reset 或  connection refused 的报错。

图片

2、目的IP局域网内

刚刚提到本机IP是 192.168.31.6 ,局域网内有台 192.168.31.1 。同样尝试连一个不存在的端口。

图片

连存在的局域网内IP,端口不存在抓包

此时现象跟前者一致。

唯一不同的是,前者是回环地址,RST数据是从本机的传输层返回的。而这次的情况,RST数据是从目的机器的传输层返回的。

图片

3、 目的IP局域网外

找一个存在的外网ip,例如 47.102.221.141 。

进行连接连接,发现与前面两种情况是一致的,目的机器在收到我的请求后,立马就通过 RST标志位 断开了这次的连接。

图片

这一点跟前面两种情况一致。

熟悉小白的朋友们都知道,每次搞事情做测试,都会用  baidu.com 。

这次也不例外,ping 一下 baidu.com ,获得它的 IP: 220.181.38.148  。

$ ping baidu.com
PING baidu.com (220.181.38.148): 56 data bytes
64 bytes from 220.181.38.148: icmp_seq=0 ttl=48 time=35.728 ms
64 bytes from 220.181.38.148: icmp_seq=1 ttl=48 time=38.052 ms
64 bytes from 220.181.38.148: icmp_seq=2 ttl=48 time=37.845 ms
64 bytes from 220.181.38.148: icmp_seq=3 ttl=48 time=37.210 ms
64 bytes from 220.181.38.148: icmp_seq=4 ttl=48 time=38.402 ms
64 bytes from 220.181.38.148: icmp_seq=5 ttl=48 time=37.692 ms
^C
--- baidu.com ping statistics ---
6 packets transmitted, 6 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 35.728/37.488/38.402/0.866 ms

发消息到给百度域名背后的 IP,且瞎随机指定一个端口 8080, 抓包。

图片

现象却不一致。没有 RST 。而且触发了第一次握手的重试消息。这是为什么?

这是因为baidu的机器,作为线上生产的机器,会设置一系列安全策略,比如只对外暴露某些端口,除此之外的端口,都一律拒绝。

所以很多发到 8080端口的消息都在防火墙这一层就被拒绝掉了,根本到不了目的主机里,而RST是在目的主机的TCP/IP协议栈里发出的,都还没到这一层,就更不可能发RST了。因此发送端发现消息没有回应(因为被防火墙丢了),就会重传。所以才会出现上述抓包里的现象。

图片

4.总结 

连一个 IP 不存在的主机时

  • 如果IP在局域网内,会发送N次ARP请求获得目的主机的MAC地址,同时不能发出TCP握手消息。

  • 如果IP在局域网外,会将消息通过路由器发出,但因为最终找不到目的地,触发TCP重试流程。

连IP 地址存在但端口号不存在的主机时

  • 不管目的IP是回环地址还是局域网内外的IP地址,目的主机的传输层都会在收到握手消息后,发现端口不正确,发出RST消息断开连接。

  • 当然如果目的机器设置了防火墙策略,限制他人将消息发到不对外暴露的端口,那么这种情况,发送端就会不断重试第一次握手。

  • 14
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Java中可以使用第三方库来扫描一个IP段内的端口是否开放,如 `nmap4j` 库。该库是基于Nmap的Java封装,可以通过调用Java接口实现端口扫描和漏洞扫描等功能。 以下是使用 `nmap4j` 库扫描一个IP段内是否存在 MySQL 数据库的示例代码: ```java import org.nmap4j.Nmap4j; import org.nmap4j.core.flags.Flag; import org.nmap4j.core.nmap.ExecutionResults; import org.nmap4j.core.nmap.NMapExecutionOptions; import org.nmap4j.data.nmaprun.Host; import org.nmap4j.data.nmaprun.NmapRun; import org.nmap4j.parser.NmapRunParser; import java.util.ArrayList; import java.util.List; public class PortScanner { public static void main(String[] args) throws Exception { // 设置要扫描的IP地址范围 String ipAddressRange = "192.168.1.1-255"; // 设置要扫描的端口号 int port = 3306; // 创建Nmap实例 Nmap4j nmap = new Nmap4j("/usr/bin/nmap"); // 设置扫描选项 NMapExecutionOptions scanOptions = new NMapExecutionOptions(); scanOptions.addFlags(Flag.TCP_SYN_SCAN, Flag.OS_DETECTION); scanOptions.addScanTarget(ipAddressRange); // 执行扫描 nmap.execute(scanOptions); // 解析扫描结果 String output = nmap.getOutput(); NmapRunParser parser = new NmapRunParser(); NmapRun nmapRun = parser.parse(output); List<String> result = new ArrayList<String>(); for (Host host : nmapRun.getHosts()) { // 获取主机地址 String address = host.getAddress().getAddr(); // 判断端口是否开放 if (host.getPorts().getPorts().stream().anyMatch(p -> p.getPortId() == port && p.getState().getState().equals("open"))) { result.add(String.format("%s:%d", address, port)); } } // 输出扫描结果 System.out.println("扫描结果:"); System.out.println(String.join("\n", result)); } } ``` 上述代码使用 `nmap4j` 库执行端口扫描,并解析扫描结果来判断指定端口是否开放。可以根据需要修改代码来扫描其他类型的数据库或服务。需要注意的是,在使用第三方库进行端口扫描也需要获得相应的授权,并谨慎操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值