[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1283920965.2634.723.camel@edumazet-laptop>
Date: Wed, 08 Sep 2010 06:42:45 +0200
From: Eric Dumazet <eric.dumazet@...il.com>
To: David Miller <davem@...emloft.net>
Cc: brian.haley@...com, ole@....pl, netdev@...r.kernel.org
Subject: Re: [PATCH] inet: dont set inet_rcv_saddr in connect()
Le mardi 07 septembre 2010 à 20:34 -0700, David Miller a écrit :
> From: Brian Haley <brian.haley@...com>
> Date: Tue, 07 Sep 2010 22:34:59 -0400
>
> > Is this really the right thing to do? Linux has been doing this forever,
> > right? Just like BSD has done it forever.
>
> Indeed, I checked for this in Stevens volume 2 when I reviewed
> Eric's patch, the logic is identical.
>
> > The way I've always "cleared" a local address is to set the address
> > family to AF_UNSPEC on the next connect() call, as mentioned on the
> > man page. I just want to make sure we're not changing something
> > just to work around a broken application, sendto()/sendmsg() work
> > perfect in this case by not setting the local address.
> >
Problem is AF_UNSPEC always clears the remote address (as stated in
manual), and sometimes local one (as not stated)
if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
inet_reset_saddr(sk);
This is the workaround that was coded years ago in Linux to undo the
local addr setting ;)
Following program produces this output :
local addr=0x7f000001 sin_port=37877
after connect(AF_UNSPEC) local addr=0x0 sin_port=0
local addr=0x7f000001 sin_port=37877
after connect(AF_UNSPEC) local addr=0x7f000001 sin_port=0
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int fd;
struct sockaddr_in target, me;
socklen_t len;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
perror("socket");
return 1;
}
memset(&target, 0, sizeof(target));
target.sin_family = AF_INET;
target.sin_port = 123;
target.sin_addr.s_addr = htonl(0x7f000001);
if (connect(fd, (const struct sockaddr *)&target, sizeof(target)) == -1) {
perror("connect");
close(fd);
return 2;
}
len = sizeof(me);
if (getsockname(fd, (struct sockaddr *)&me, &len)== -1) {
perror("getsockname");
close(fd);
return 3;
}
printf("local addr=0x%x sin_port=%u\n",
ntohl(me.sin_addr.s_addr), ntohs(me.sin_port));
memset(&target, 0, sizeof(target));
target.sin_family = AF_UNSPEC;
if (connect(fd, (const struct sockaddr *)&target, sizeof(target)) == -1) {
perror("connect AF_UNSPEC");
close(fd);
return 4;
}
len = sizeof(me);
if (getsockname(fd, (struct sockaddr *)&me, &len)== -1) {
perror("getsockname 2");
close(fd);
return 3;
}
printf("after connect(AF_UNSPEC) local addr=0x%x sin_port=%u\n",
ntohl(me.sin_addr.s_addr), ntohs(me.sin_port));
memset(&target, 0, sizeof(target));
target.sin_family = AF_INET;
target.sin_addr.s_addr = htonl(0x7f000001);
if (bind(fd, (const struct sockaddr *)&target, sizeof(target)) == -1) {
perror("bind");
close(fd);
return 2;
}
len = sizeof(me);
if (getsockname(fd, (struct sockaddr *)&me, &len)== -1) {
perror("getsockname");
close(fd);
return 3;
}
printf("local addr=0x%x sin_port=%u\n",
ntohl(me.sin_addr.s_addr), ntohs(me.sin_port));
memset(&target, 0, sizeof(target));
target.sin_family = AF_UNSPEC;
if (connect(fd, (const struct sockaddr *)&target, sizeof(target)) == -1) {
perror("connect AF_UNSPEC");
close(fd);
return 4;
}
len = sizeof(me);
if (getsockname(fd, (struct sockaddr *)&me, &len)== -1) {
perror("getsockname 2");
close(fd);
return 3;
}
printf("after connect(AF_UNSPEC) local addr=0x%x sin_port=%u\n",
ntohl(me.sin_addr.s_addr), ntohs(me.sin_port));
return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists