Subject: Re: IPv6 PMTUD broken
To: Jun-ichiro itojun Hagino <itojun@itojun.org>
From: Ronald van der Pol <Ronald.vanderPol@rvdp.org>
List: current-users
Date: 06/09/2004 22:14:48
--45Z9DzgjV8m4Oswq
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Fri, Jun 04, 2004 at 20:15:51 +0900, Jun-ichiro itojun Hagino wrote:

> > Anything else I could try to pinpoint this?
> 
> 	try monitoring how it works with netstat -rn, netstat -sn and tcpdump,
> 	and compare them... (yes, it's painful i guess)

The problem only seems to happen with sendto().

I use the attached program. This is what I do:
- delete the host route
- start tcpdump in xterm 1
- start the program in xterm 2

---------------------------------------------------------------------------
connect() and send(), PMTUD works fine
---------------------------------------------------------------------------
xterm 1:
# route delete -inet6 2001:7b8:206:1:240:f4ff:fe37:8232
delete host 2001:7b8:206:1:240:f4ff:fe37:8232
# tcpdump -n -p -i ex0 -s0 -vvv host 2001:7b8:206:1:240:f4ff:fe37:8232 or icmp6
tcpdump: listening on ex0
21:56:13.843027 2001:888:1777:0:260:8ff:fed1:a403.65493 > 2001:7b8:206:1:240:f4ff:fe37:8232.53: [udp sum ok]  0 [0q] (1400) [flowlabel 0x5eb6] (len 1408, hlim 64)
21:56:13.846349 2001:888:1777::1 > 2001:888:1777:0:260:8ff:fed1:a403: icmp6: too big 1280 (len 1240, hlim 64)
21:56:18.859325 2001:888:1777:0:260:8ff:fed1:a403 > 2001:7b8:206:1:240:f4ff:fe37:8232: frag (0x696ca82c:0|1232) 65493 > 53:  0 [0q] (1224) [flowlabel 0x5eb6] (len 1240, hlim 64)
21:56:18.859464 2001:888:1777:0:260:8ff:fed1:a403 > 2001:7b8:206:1:240:f4ff:fe37:8232: frag (0x696ca82c:1232|176) [flowlabel 0x5eb6] (len 184, hlim 64)
21:56:18.935846 2001:7b8:206:1:240:f4ff:fe37:8232 > 2001:888:1777:0:260:8ff:fed1:a403: icmp6: 2001:7b8:206:1:240:f4ff:fe37:8232 udp port 53 unreachable (len 1240, hlim 58)
21:56:23.883967 2001:888:1777::1 > 2001:888:1777:0:260:8ff:fed1:a403: icmp6: neighbor sol: who has 2001:888:1777:0:260:8ff:fed1:a403(src lladdr: 00:00:24:c0:7b:f4) (len 32, hlim 255)
21:56:23.884109 2001:888:1777:0:260:8ff:fed1:a403 > 2001:888:1777::1: icmp6: neighbor adv: tgt is 2001:888:1777:0:260:8ff:fed1:a403(S) (len 24, hlim 255)
^C
46 packets received by filter
0 packets dropped by kernel
#

xterm 2:
$ ./a.out einstein.nlnetlabs.nl 1
connect()
send()
sleep()
send()
$
---------------------------------------------------------------------------
sendto(), PMTUD fails
---------------------------------------------------------------------------
xterm 1:
# route delete -inet6 2001:7b8:206:1:240:f4ff:fe37:8232
delete host 2001:7b8:206:1:240:f4ff:fe37:8232
# tcpdump -n -p -i ex0 -s0 -vvv host 2001:7b8:206:1:240:f4ff:fe37:8232 or icmp6
tcpdump: listening on ex0
21:59:41.756370 2001:888:1777:0:260:8ff:fed1:a403.65490 > 2001:7b8:206:1:240:f4ff:fe37:8232.53: [udp sum ok]  0 [0q] (1400) (len 1408, hlim 64)
21:59:41.759698 2001:888:1777::1 > 2001:888:1777:0:260:8ff:fed1:a403: icmp6: too big 1280 (len 1240, hlim 64)
21:59:46.750081 fe80::260:8ff:fed1:a403 > fe80::200:24ff:fec0:7bf4: icmp6: neighbor sol: who has fe80::200:24ff:fec0:7bf4(src lladdr: 00:60:08:d1:a4:03) (len 32, hlim 255)
21:59:46.750824 fe80::200:24ff:fec0:7bf4 > fe80::260:8ff:fed1:a403: icmp6: neighbor adv: tgt is fe80::200:24ff:fec0:7bf4(RS) (len 24, hlim 255)
21:59:46.760530 2001:888:1777:0:260:8ff:fed1:a403.65490 > 2001:7b8:206:1:240:f4ff:fe37:8232.53: [udp sum ok]  0 [0q] (1400) (len 1408, hlim 64)
21:59:46.763826 2001:888:1777::1 > 2001:888:1777:0:260:8ff:fed1:a403: icmp6: too big 1280 (len 1240, hlim 64)
21:59:46.874537 2001:888:1777::1 > 2001:888:1777:0:260:8ff:fed1:a403: icmp6: neighbor sol: who has 2001:888:1777:0:260:8ff:fed1:a403(src lladdr: 00:00:24:c0:7b:f4) (len 32, hlim 255)
21:59:46.874652 2001:888:1777:0:260:8ff:fed1:a403 > 2001:888:1777::1: icmp6: neighbor adv: tgt is 2001:888:1777:0:260:8ff:fed1:a403(S) (len 24, hlim 255)
21:59:51.870124 2001:888:1777:0:260:8ff:fed1:a403 > 2001:888:1777::1: icmp6: neighbor sol: who has 2001:888:1777::1(src lladdr: 00:60:08:d1:a4:03) (len 32, hlim 255)
21:59:51.870875 2001:888:1777::1 > 2001:888:1777:0:260:8ff:fed1:a403: icmp6: neighbor adv: tgt is 2001:888:1777::1(RS) (len 24, hlim 255)
21:59:51.874254 fe80::200:24ff:fec0:7bf4 > fe80::260:8ff:fed1:a403: icmp6: neighbor sol: who has fe80::260:8ff:fed1:a403(src lladdr: 00:00:24:c0:7b:f4) (len 32, hlim 255)
21:59:51.874347 fe80::260:8ff:fed1:a403 > fe80::200:24ff:fec0:7bf4: icmp6: neighbor adv: tgt is fe80::260:8ff:fed1:a403(S) (len 24, hlim 255)
^C
63 packets received by filter
0 packets dropped by kernel
# 

xterm 2:
$ ./a.out einstein.nlnetlabs.nl 0
sendto()
sleep()
sendto()
$
---------------------------------------------------------------------------

This is what I noticed in udp6_usrreq.c:

revision 1.34
date: 2000/10/19 01:14:13;  author: itojun;  state: Exp;  lines: +52 -8
validate ICMPv6 too big message.
XXX too restrictive given frequent uses of sendto(2)

Commenting out the #if 0 in line 215 did not help. When using sendto()
in6_pcblookup_connect() and in6_pcblookup_bind() both return 0.

Could you have a look at this again please?

	rvdp


--45Z9DzgjV8m4Oswq
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="test.c"

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>

#define DELAY	5

int
main(int argc, char **argv)
{
	struct sockaddr_in6 src, dst;
	socklen_t srclen, dstlen;
	int s, err;
	char msg[1400];
	struct addrinfo hints, *res;

	if (argc != 3) {
		printf("usage: %s host 0|1\n");
		exit(EXIT_FAILURE);
	}
	memset(&hints, '\0', sizeof(struct addrinfo));
	hints.ai_family = AF_INET6;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_flags = 0;
	hints.ai_protocol = 0;
	hints.ai_addrlen = 0;
	hints.ai_canonname = NULL;
	hints.ai_addr = NULL;
	hints.ai_next = NULL;

	err = getaddrinfo(argv[1], "domain", &hints, &res);
	if (err) {
		printf("invalid address %s\n", argv[1]);
		exit(EXIT_FAILURE);
	}
	memcpy(&dst, res->ai_addr, res->ai_addrlen);
	dstlen = res->ai_addrlen;
	freeaddrinfo(res);

	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
		perror("socket");
		exit(EXIT_FAILURE);
	}
	memset(&hints, '\0', sizeof(struct addrinfo));
	hints.ai_family = AF_INET6;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_flags = 0;
	hints.ai_protocol = 0;
	hints.ai_addrlen = 0;
	hints.ai_canonname = NULL;
	hints.ai_addr = NULL;
	hints.ai_next = NULL;

	err = getaddrinfo("bones.rvdp.org", "54321", &hints, &res);
	if (err) {
		printf("invalid address bones.rvdp.org\n");
		exit(EXIT_FAILURE);
	}
	memcpy(&src, res->ai_addr, res->ai_addrlen);
	srclen = res->ai_addrlen;
	freeaddrinfo(res);

	if (atoi(argv[2])) {
		printf("connect()\n");
		if (connect(s, (struct sockaddr *) &dst, dstlen) == -1) {
			perror("connect");
			exit(EXIT_FAILURE);
		}
		printf("send()\n");
		if (send(s, msg, sizeof(msg), 0) == -1) {
			perror("send");
			exit(EXIT_FAILURE);
		}
		printf("sleep()\n");
		sleep(DELAY);
		printf("send()\n");
		if (send(s, msg, sizeof(msg), 0) == -1) {
			perror("send");
			exit(EXIT_FAILURE);
		}
	} else {
		printf("sendto()\n");
		if (sendto(s, msg, sizeof(msg), 0, (struct sockaddr *) &dst,
							dstlen) == -1) {
			perror("sendto");
			exit(EXIT_FAILURE);
		}
		printf("sleep()\n");
		sleep(DELAY);
		printf("sendto()\n");
		if (sendto(s, msg, sizeof(msg), 0, (struct sockaddr *) &dst,
							dstlen) == -1) {
			perror("sendto");
			exit(EXIT_FAILURE);
		}
	}
}

--45Z9DzgjV8m4Oswq--