Hello,

There seems to be a problem with the source address selection for UDP
datagrams. I use Linux kernel 2.3.99-pre6 and glibc 2.1.3.

I would expect that if I bind() a socket to a specific global scope
unicast address and send a datagram on the socket, that the source address
of the datagram would be the bound address. This doesn't seem to be the
case.

I have attached 2 small programs, a server and a client, that demonstrates
my problem. Here is a sample session:

h83% ./server &
Waiting
[2] 2127
h83% ./client 3ffe:200:13::3
Received message of length: 6
Source address: ::1
h83% 

Is this a bug in the kernel, or have I misunderstood something?

Regards,

Pontus

-- 
Pontus Lidman, [EMAIL PROTECTED], Software Engineer
No matter how cynical you get, it's impossible to keep up.
Scene: www.dc-s.com | MUD: tyme.envy.com 6969 | irc: irc.quakenet.eu.org
/* IPv6 UDP listen, prints source address */

#include <stdio.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>

#define PORT 9999

int main() {

  int s6;
  int len2;
  char msgbuf[16384];
  struct protoent *prent;
  struct sockaddr_in6 from6;
  struct sockaddr_in6 lstn6;
  int sendersize;

  prent=getprotobyname("udp");
  if (!prent) perror("Can't get protocol");

  if (-1==(s6=socket(PF_INET6,SOCK_DGRAM,prent->p_proto)))
    perror("Can't create IPv6 socket");

  bzero(&lstn6,sizeof(struct sockaddr_in6));
  lstn6.sin6_port=htons((short) PORT);
  lstn6.sin6_addr=in6addr_any;

  if (-1==bind(s6,&lstn6,sizeof(lstn6))) perror("bind");

  printf("Waiting\n");

  while (1) {
    sendersize=sizeof(struct sockaddr_in6);
    len2=recvfrom(s6,msgbuf,8192,0,&from6,&sendersize);
    if (len2==-1) perror("recvfrom");
    else {
      char sadr[1024];
      printf("Received message of length: %d\n",len2);
      if (getnameinfo((struct sockaddr *) &from6,sizeof(from6),
                  sadr,1024,NULL,0,NI_NUMERICHOST))
        strcpy(sadr,"<unknown>");
      printf("Source address: %s\n",sadr);
    }
  }  
}
/* IPv6 UDP send with source address */

#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>

#define PORT 9999
#define SRC_PORT 9998

int main(int argc, char **argv) {
  int s;
  char *msg="hej!!\0";
  struct protoent *prent;
  struct sockaddr_in6 to,from;
  struct in6_addr my_addr;

  if (argc<2) {
    printf("Give IPv6 address to bind to\n");
    exit(1);
  }

  if (NULL==(prent=getprotobyname("udp"))) {
    perror("getprotobyname");
  }

  bzero(&to,sizeof(struct sockaddr_in6));
  to.sin6_port=htons((short) PORT);
  inet_pton(AF_INET6,argv[1],&my_addr);
  to.sin6_addr=my_addr;

  bzero(&from,sizeof(struct sockaddr_in6));
  from.sin6_port=htons((short) SRC_PORT);
  from.sin6_addr=my_addr;
  
  if (-1==(s=socket(PF_INET6,SOCK_DGRAM,prent->p_proto))) {
    perror("socket");
  }

  if (-1==bind(s,&from,sizeof(from)))
    perror("bind");
  
  if (-1==sendto(s,msg,6,0,&to,sizeof(struct sockaddr_in6))) {
    perror("sendto");
  }  
  
  return 0;
}

Reply via email to