当前位置:网站首页>About UDP receiving ICMP port unreachable

About UDP receiving ICMP port unreachable

2022-04-23 15:04:00 Mrpre

This article is divided into 3 part

1: Message format

2: Cause of occurrence

3:linux How the protocol stack handles

4: How to get

1:

The message is as follows ,10.30.13.1 Go to 10.30.16.10 Of 80 The port sent a UDP message ,80 The port actually listens to TCP.

The server replied to an unreachable port ICMP,ICMP The data part is the request UDP ip Layer and above .

2: reason

    The first reason is to receive udp The port corresponding to the message server is not opened UDP The server . Notice the description here , It's not that the port is not open , But it didn't open UDP service , If it's on TCP service , Still will return port unreachable.

3:Linux Kernel pair UDP Handle :

(1): As a server, I received a UDP request

First , As a server , When a message passes through the check route , Purpose ip It's time to deliver this machine , after netfilter After the verdict ,

call ip_local_deliver_finish, It is based on ip Protocol type in header (TCP/UDP/ICMP/......), Call different 4 Layer interface function for processing . So I said before , Even if it's turned on TCP service , Established by the server socket Of hash and udp Super search socket Of hash atypism , It also returns that the port is unreachable .

about udp for ,handler yes udp_rcv, It directly calls __udp4_lib_rcv, Find the corresponding sock,

If sk non-existent if(sk != NULL), Just reply icmp destination unreachable( This means that the server does not have a corresponding port to accept UDP Process flow ), The function is very simple

    So as a server , A message that the destination port is not listening is received , The direct reply port is unreachable .

So as a client , How to handle the reply from the server Port unreachable The message ?

At first, the idea was very simple , In my submission , There is no interference between different agreements , namely TCP and UDP There is no direct interference .

Not to mention this nondescript icmp? Then I was wrong .

(2) Received as a client ICMP Port unreachable reply

    As a client , Port unreachable message entry ip_local_deliver_finish, It calls icmp_rcv function , To deal with .( In fact, this is what I thought at the beginning udp There will be no corresponding reason for port unreachable data , because udp The process is udp_rcv).

    

    actually icmp_rcv The most important thing about functions is It calls for :icmp_pointers[icmph->type].handler(skb);

handler = icmp_unreach

icmp_unreach The final step of the function , It's the last step :

Is it very similar ip_local_deliver_finish?

It's very much like , It's just ip_local_deliver_finish in , Called ipprot->handler, And here you call ipprot->err_handler

about udp,err_handler = udp_err = __udp4_lib_err

In this function , Only enter the following process , The application will react :

__udp4_lib_err First, according to skb->data in dip and sip, lookup socket,skb->data yes icmp The load of

So call... First __udp4_lib_lookup lookup socket, Reference time ,sip and dip It needs to be reversed .

__udp4_lib_err:

The prerequisite is inet->recverr For the wrong 0, perhaps inet->recverr by 0 however udp be in TCP_ESTABLISHED state .

Otherwise, the application cannot expect to receive data that is unreachable to the port , The application is waiting read Time out . So , In order to obtain udp Port unreachable condition

Yes 2 Methods :

(1):

int val = 1;

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

(2):

Yes udp Conduct connect operation , And will sendto Change to send

4:

udp Learn the source program that the port is unreachable ( Method 1: Set up Socket Options ; Method 2: Yes UDP Conduct Connect)

Be careful , In case of congestion ,recvfrom It will block , Even if a port unreachable message is received , It will also block . But after Method 1 and Method 2 after ,recvfrom Returns the , The return value is -1, then Judge errno Whether it is ECONNREFUSED To determine whether the port unreachable message is received .

#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");
 
        // Method 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");
		}
	}
	// Method 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;
}

If it works for you , One yuan, please :http://www.mrpre.com/

版权声明
本文为[Mrpre]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204231409587664.html