NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/47408: sendto(2) issue with IPv6 UDP datagrams



>Number:         47408
>Category:       kern
>Synopsis:       sendto(2) issue with IPv6 UDP datagrams
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Jan 05 20:55:00 +0000 2013
>Originator:     Anthony Mallet
>Release:        6.99.16, Thu Jan  3 14:14:16 CET 2013
>Organization:
>Environment:
NetBSD cactus 6.99.16 NetBSD 6.99.16 (CACTUS) #21: Thu Jan  3 14:14:16 CET 2013
>Description:
I'm fighting with pkgsrc/net/wide-dhcpv6. To make a long story short, I think I
finally isolated the issue, that I can reproduce with the attached test program.

It seems that, for any socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP), the second
sendto(2) call will fail with EISCONN, even though the socket is never
connected. Also, trying to explicitly connect the socket will fail. This does
not happen for AF_INET.

Here is the output of the attached test program. This is on a Jan 3 -current,
and I get the same results on another -current machine from Oct 20. I can
verify with tcpdump that the packets are correctly transmitted (or not). I 
could test on a Linux machine and it worked fine.

ficus[~] > gcc -Wall -o sendto sendto.c
ficus[~] > ./sendto -4
sendto: 1st sendto: PASS
sendto: 2nd sendto: PASS
sendto: 1st connect: PASS
sendto: 1st send: PASS
sendto: 2nd connect: PASS
sendto: 2nd send: PASS
ficus[~] > ./sendto -6
sendto: 1st sendto: PASS
sendto: 2nd sendto: FAIL: Socket is already connected
sendto: 1st connect: FAIL: Socket is already connected
sendto: 1s send: FAIL: Destination address required
sendto: 2nd connect: FAIL: Socket is already connected
sendto: 2nd send: FAIL: Destination address required
ficus[~] > 

>How-To-Repeat:
/* this is the sendto(2) test program */
#include <sys/socket.h>

#include <netinet/in.h>

#include <err.h>
#include <netdb.h>
#include <string.h>

int
main(int argc, const char *argv[])
{
  struct addrinfo hints;
  struct addrinfo *res;
  const char msg[] = "sendto test";
  int S, s;
  int e;

  /* lookup localhost addr, depending on argv[1] */
  memset(&hints, 0, sizeof(hints));
  if (argc > 1 && !strcmp("-6", argv[1]))
    hints.ai_family = AF_INET6;
  else
    hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_DGRAM;
  hints.ai_protocol = IPPROTO_UDP;
  hints.ai_flags = 0;
  e = getaddrinfo("localhost", "9999", &hints, &res);
  if (e) errx(2, "getaddrinfo: %s", gai_strerror(e));

  /* server socket */
  S = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  if (S < 0) err(2, "server socket");
  if (bind(S, res->ai_addr, res->ai_addrlen) < 0) err(2, "bind");

  /* client socket */
  s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  if (s < 0) err(2, "client socket");

  /* sendto */
  e = sendto(s, msg, sizeof(msg), 0, res->ai_addr, res->ai_addrlen);
  if (e != sizeof(msg))
    warn("1s sendto: FAIL");
  else
    warnx("1st sendto: PASS");

  e = sendto(s, msg, sizeof(msg), 0, res->ai_addr, res->ai_addrlen);
  if (e != sizeof(msg))
    warn("2nd sendto: FAIL");
  else
    warnx("2nd sendto: PASS");

  /* connect + send */
  e = connect(s, res->ai_addr, res->ai_addrlen);
  if (e)
    warn("1st connect: FAIL");
  else
    warnx("1st connect: PASS");
  e = send(s, msg, sizeof(msg), 0);
  if (e != sizeof(msg))
    warn("1s send: FAIL");
  else
    warnx("1st send: PASS");

  e = connect(s, res->ai_addr, res->ai_addrlen);
  if (e)
    warn("2nd connect: FAIL");
  else
    warnx("2nd connect: PASS");
  e = send(s, msg, sizeof(msg), 0);
  if (e != sizeof(msg))
    warn("2nd send: FAIL");
  else
    warnx("2nd send: PASS");

  return 0;
}

>Fix:



Home | Main Index | Thread Index | Old Index