关于UDP接收icmp端口不可达(port unreachable)

本篇分为3部分

1:报文格式

2:产生的原因

3:linux协议栈如何处理

4:应用层如何获取

1:

报文如下,10.30.13.1往10.30.16.10的80端口发送了一个UDP报文,80端口其实监听的是TCP。

服务器回复了一个类型为端口不可达的ICMP,ICMP数据部分就是请求UDP ip层及其以上的数据。

2:原因

   首先原因就是接收udp报文的服务器对应的端口没有开启UDP服务器。注意这里的描述,并不是端口没有开启服务,而是没有开启UDP服务,如果开启了TCP服务,照样也会回port unreachable。

3:Linux内核对UDP处理:

(1):作为服务器接受到一个UDP请求

首先,做为服务器,当一个报文经过查路由,目的ip是上送本机的时候,经过netfilter 判决后,

调用ip_local_deliver_finish,它根据ip头中的协议类型(TCP/UDP/ICMP/......),调用不同的4层接口函数进行处理。所以之前说了,即使开启了TCP服务,服务器建立的socket的hash和udp超找socket的hash不一致,也会回端口不可达。

对于udp而言,handler 是udp_rcv,它直接调用了__udp4_lib_rcv,查找相应的sock,

如果sk不存在if(sk != NULL),就回复icmp destination unreachable(这就是服务器没有对应端口接受UDP的处理流程),函数非常简单

    所以作为服务器,收到一个目的端口并未监听的报文,直接回复端口不可达。

那么作为客户端,如何处理服务器回复的 端口不可达 报文呢?

起始当初想法很简单,我认为,不同的协议之间是不会干涉的,即TCP和UDP直接是不会干涉的。

何况这种不伦不类的icmp?后来想错了。

(2)作为客户端收到ICMP端口不可达的回复

    作为客户端,端口不可达报文进入ip_local_deliver_finish,它调用icmp_rcv函数,进行处理。(其实这也是当初我认为客户端udp不会对端口不可达数据进行相应的原因,因为udp处理流程是udp_rcv)。

    

    实际上icmp_rcv函数最重要的是 它调用了:icmp_pointers[icmph->type].handler(skb);

handler = icmp_unreach

icmp_unreach函数最终的一步,就是它最后一步:

是不是很像ip_local_deliver_finish?

是很像,只是ip_local_deliver_finish中,调用了ipprot->handler,而这里调用了ipprot->err_handler

对于udp,err_handler = udp_err = __udp4_lib_err

在该函数中,只有进入如下的流程,应用程序才会反应:

__udp4_lib_err先根据skb->data中dip和sip,查找socket,skb->data是icmp的负载

故先调用 __udp4_lib_lookup 查找socket,传参时,sip和dip需要反一下。

__udp4_lib_err:

先决条件是inet->recverr为非0,或者inet->recverr为0但是udp处于TCP_ESTABLISHED状态。

否则应用程序休想收到该端口不可达的数据,应用程序就等着read超时吧。所以说,为了获取udp端口不可达的情况

有2种方法:

(1):

int val = 1;

setsockopt(fd, IPPROTO_IP, IP_RECVERR , &val,sizeof(int));

(2):

对udp进行connect操作,并且将sendto改成send

4:

udp获知端口不可达的源程序(方法1:设置Socket选项;方法2:对UDP进行Connect)

注意,阻塞情况下,recvfrom会阻塞,即使收到端口不可达消息,也会阻塞。但是经过 方法1 和 方法2后,recvfrom会返回,返回值是-1,然后 判断errno是否是ECONNREFUSED来判断是否收到端口不可达消息。

#include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
unsigned char revc_buf[1024];
 
int main()
{
	int fd,ret,recv_len,size=1024;
	struct sockaddr_in server_addr,addr;
	int val = 1;
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = inet_addr("192.168.2.254");
	server_addr.sin_port = htons(77);
	
	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if(fd < 0)
	{	
		perror("socket fail ");
		return -1;
	}
	
	printf("socket sucess\n");
 
        //方法1
	#if 1
	setsockopt(fd, IPPROTO_IP, IP_RECVERR , &val,sizeof(int));
	if(sendto(fd, "nihao", strlen("nihao"), 0, (const struct sockaddr *)&(server_addr), sizeof(struct sockaddr_in))<0)
	{
		perror("sendto fail ");
		return -1;
	}
	printf("sendto sucess\n");
	recv_len = recvfrom(fd, revc_buf, sizeof(revc_buf), 0, (struct sockaddr *)&addr, (int *)&size);
	if (recv_len == -1)
	{
		if (errno == ECONNREFUSED)
		{
			printf("Recv port unreachable\n");
		}
	}
	//方法2
	#elif 0
	ret = connect(fd, (const struct sockaddr *) &(server_addr), sizeof (struct sockaddr_in));
	if(ret < 0)
	{
		printf("connect fail\n");
		return -1;
	}
	
	ret = send(fd, "ni hao", strlen("nihao"),0);
	if(ret < 0)
	{
		printf("write fail\n");
		return -1;
	}
	
	ret = recvfrom(fd, revc_buf, sizeof(revc_buf), 0, (struct sockaddr *)&addr, (int *)&size);
	if (ret == -1) {
		if (errno == ECONNREFUSED)
		{
			printf("Recv port unreachable\n");
		}
	}
 
	#endif
	close(fd);
	
	return 0;
}

如果对你有用,请打赏一元哦:http://www.mrpre.com/

  • 28
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
### 回答1: "ICMP端口不可"是一种Internet控制消息协议(ICMP)错误消息。当一台计算机尝试发送数据包到另一台计算机的特定端口,但该端口上没有进程在运行时,目标计算机将发送此消息作为响应。这通常意味着目标计算机未正确配置或没有正在运行的服务来处理传入的数据包。 ### 回答2: ICMP(Internet Control Message Protocol)是TCP/IP协议族中的一个辅助性协议,主要用于在IP主机之间传递控制和错误信息。当某个目标主机无法到某个端口时,就会返回一个ICMP Port Unreachable错误消息。 ICMP Port Unreachable错误消息是由目标主机发送的,用于告诉源主机目标不可端口不可用。当源主机向目标主机的某个端口发送数据包时,如果目标主机无法找到该端口,就会向源主机发送一个ICMP Port Unreachable错误消息。 ICMP Port Unreachable错误消息通常用于以下两种情况: 1. 由于某些原因,目标主机的端口不可用,因此无法接收来自源主机的数据包。可能的原因包括:目标主机上没有运行应用程序,防火墙阻止了该端口的访问,或者该端口已被占用并且无法访问。 2. 源主机尝试通过Internet连接到目标主机的某个端口。这种情况下,ICMP Port Unreachable错误消息通常被用于指示目标主机无法接收来自Internet的连接。 对于源主机来说,收到ICMP Port Unreachable消息时,它会中止发送到目标主机的数据包,因为目标主机无法接收来自该端口的数据。此时,源主机需要重新配置其应用程序,并确保它们使用可用的端口来连接目标主机。或者检查防火墙规则,确保它不会阻止与目标主机的端口通信。 总之,ICMP Port Unreachable错误消息通常表示目标主机的某个端口不可用或无法访问。该错误消息是由目标主机返回给源主机的,告知源主机不能到目标的端口。源主机需要针对该错误消息重新配置应用程序或检查防火墙规则,以确保它可以正确地连接到目标主机的端口。 ### 回答3: ICMP端口不可ICMP Port Unreachable)是一种网络通信错误。它通常发生在网络协议的传输层。在传输层中,当一个数据包被发送到一个不可端口时,接收方主机会发送一个ICMP消息,告诉发送方主机接收方主机上的端口无法到。 这种错误通常是由于目标主机的端口或服务未启动引起的,例如当您尝试连接一个未开启Web服务器的机器上的Web端口时。此时,您将收到一个ICMP端口不可消息,告诉您该端口不可访问。此错误也可能是由于网络防火墙或路由器的阻塞引起的,例如当主机的ICMP流量被拦截时。 ICMP端口不可是网络故障排除中非常常见的错误之一。如果您收到ICMP端口不可消息,则可能需要检查目标主机和目标端口是否启动。如果目标主机和目标端口已启动,那么您需要检查网络防火墙或路由器是否已阻止流量。您可以尝试添加一个例外以确保数据包能够通过网络中的安全设备。 总之,ICMP端口不可是一种常见的网络通信错误,通常表示目标主机或端口未启动。为了排除此错误,您可能需要确保目标主机和端口已启动,并检查网络防火墙或路由器是否阻止了流量。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值