Bug 50839 - icmp time-exceeded causes tcp connect to return success bogusly
Summary: icmp time-exceeded causes tcp connect to return success bogusly
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 4.8-STABLE
Hardware: Any Any
: Normal Affects Only Me
Assignee: silby
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-04-11 23:40 UTC by Barney Wolff
Modified: 2003-06-25 03:45 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Barney Wolff 2003-04-11 23:40:05 UTC
	TCP connect(2) returns 0 if a routing loop causes an ICMP unreach-time-
	exceeded to be returned.  Problem is that the cmd code is mapped to
	error 0 in in_input.

Fix: b:/usr/src/sys/netinet $ diff -u ip_input.c.orig ip_input.c


Here's the test prog:

/*	conntime.c	Barney Wolff	<barney@databus.com>	*/

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/errno.h>
extern int errno;
#include <sys/time.h>

#ifdef __FreeBSD__
#define sigignore(x) signal(x,SIG_IGN)
#endif

main(int argc,char **argv) {
	int sockfd,lsockfd,i,recv=0,cookie=0,dofork=0;
	struct sockaddr_in skinaddr;
	struct timeval start,end;

	if (argc < 3) {
		fprintf(stderr,"%0 ipaddr port\n");
		exit(1);
	}

	sigignore(SIGPIPE);

	memset(&skinaddr,0,sizeof(skinaddr));
	skinaddr.sin_family = AF_INET;
	skinaddr.sin_addr.s_addr = inet_addr(argv[1]);
	skinaddr.sin_port = htons((short)atoi(argv[2]));

	if ((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
		{perror("socket"); exit(2);}

	i = 1;
	setsockopt(sockfd,SOL_SOCKET,SO_KEEPALIVE,&i,sizeof(i));

	gettimeofday(&start,NULL);
	i = connect(sockfd,(struct sockaddr *)&skinaddr,sizeof(skinaddr));
	gettimeofday(&end,NULL);

	if (i < 0) perror("connection failed");
	fprintf(stderr,"connect returned in %d usec\n",
		1000000*(end.tv_sec-start.tv_sec)+end.tv_usec-start.tv_usec);
	if (i == 0) {
		start = end;
		i = write(sockfd,"GET /\r\n\r\n",9);
		gettimeofday(&end,NULL);
		if (i < 0) perror("write failed");
		fprintf(stderr,"write returned in %d usec\n",
			1000000*(end.tv_sec-start.tv_sec)+end.tv_usec-start.tv_usec);
	}
}--xhbVGMPOMUOgAjfUvNekJ1eCoXTRrrX5n9EaPLwAq2SxdYNr
Content-Type: text/plain; name="file.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="file.diff"

--- ip_input.c.orig     Wed Apr  9 14:07:16 2003
+++ ip_input.c  Fri Apr 11 17:54:11 2003
@@ -1696,7 +1696,7 @@
        0,              EMSGSIZE,       EHOSTDOWN,      EHOSTUNREACH,
        EHOSTUNREACH,   EHOSTUNREACH,   ECONNREFUSED,   ECONNREFUSED,
        EMSGSIZE,       EHOSTUNREACH,   0,              0,
-       0,              0,              0,              0,
+       0,              0,              EHOSTUNREACH,   0,
        ENOPROTOOPT,    ECONNREFUSED
 };
  
(This patch is to current.)
How-To-Repeat: 	Set up routing loop (I just added a /32 bogus route on my internal net
	to do this).  Connect to looped destination.  Connect returns 0, but
	socket is of course not writable.  Test prog attached.  This fails on
	both stable and current.
Comment 1 silby freebsd_committer freebsd_triage 2003-05-23 06:51:29 UTC
Responsible Changed
From-To: freebsd-bugs->silby

Barney reminded me to take this
Comment 2 silby freebsd_committer freebsd_triage 2003-06-25 03:44:47 UTC
State Changed
From-To: open->closed

Committed to both -current and -stable.