Hi!
> > If somebody needs it, I can post some code.
> Please, post some tcpdump better.
OK, here it comes. The problem seems to be a little different from
what I first thought, though.
tcpdump -i eth0 shows no traffic (eth0 was the interface whose
link-local address I tried to ping)
-----------------------------------------------------------------------------
tcpdump -i lo
-----------------------------------------------------------------------------
21:06:53.017227 ::1 > fe80::200:86ff:fe39:cb0 icmpv6: echo request
21:06:53.017227 ::1 > fe80::200:86ff:fe39:cb0 icmpv6: echo request
21:06:53.017275 fe80::200:86ff:fe39:cb0 > ::1 icmpv6: echo reply
21:06:53.017275 fe80::200:86ff:fe39:cb0 > ::1 icmpv6: echo reply
-----------------------------------------------------------------------------
, which is certainly strange, because recvfrom actually returns
::1 in the from field in my code!
(btw, the double packets listed are a bug in my libpcap or tcpdump,
I think).
So, the ICMPv6 module seems to be ok, and the error is somewhere later
in the chain ;-)
I will post some code anyway, perhaps it's my fault ;-)
As you can see, I use recvfrom in the relevant part, and almost
immediately put the address out, so I hope I did not clobber it.
The address is however ::1, although the packet source address
must have been correct.
-----------------------------------------------------------------------------
static int ping6(struct in6_addr a, int timeout, int rep)
{
char buf[1024];
int i,tm;
int rve=1;
int len;
int isock,osock;
struct icmp6_filter f;
struct sockaddr_in6 from;
struct icmp6_hdr icmpd;
struct icmp6_hdr *icmpp;
struct msghdr msg;
unsigned short id=(unsigned short)(rand()&0xffff);
socklen_t sl;
ICMP6_FILTER_SETBLOCKALL(&f);
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REQUEST,&f);
for (i=0;i<rep;i++) {
/* Open a raw socket for replies */
isock=socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (isock==-1) {
printf("icmpv6 ping: socket() failed:
%s\n",strerror(errno));
return -1;
}
if
(setsockopt(isock,IPPROTO_ICMPV6,ICMP6_FILTER,&f,sizeof(f))==-1) {
printf("icmpv6 ping: setsockopt() for is failed: %s\n",
strerror(errno));
close(isock);
return -1;
}
fcntl(isock,F_SETFL,O_NONBLOCK);
/* send icmp_echo_request */
osock=socket(PF_INET6,SOCK_RAW,IPPROTO_ICMPV6);
if (osock==-1) {
printf("icmpv6 ping: socket() failed.\n");
close(isock);
return -1;
}
/* enable error queueing and checksumming. --checksumming
should be on by default.*/
if
(setsockopt(osock,SOL_IPV6,IPV6_RECVERR,&rve,sizeof(rve))==-1) {
printf("icmpv6 ping: setsockopt() for os failed:
%s\n",strerror(errno));
close(osock);
close(isock);
return -1;
}
icmpd.icmp6_type=ICMP6_ECHO_REQUEST;
icmpd.icmp6_code=0;
icmpd.icmp6_cksum=0;
icmpd.icmp6_id=htons((short)id);
icmpd.icmp6_seq=htons((short)i);
from.sin6_family=AF_INET6;
from.sin6_flowinfo=0;
from.sin6_port=0;
from.sin6_addr=a;
printf("Pinging %s
(ICMPv6)\n",inet_ntop(AF_INET6,&from.sin6_addr,buf,1024));
if
(sendto(osock,&icmpd,sizeof(icmpd),0,&from,sizeof(from))==-1) {
printf("icmpv6 ping: sendto() failed:
%s.\n",strerror(errno));
close(osock);
close(isock);
return -1;
}
fcntl(osock,F_SETFL,O_NONBLOCK);
/* listen for reply. */
tm=0;
do {
memset(&msg,0,sizeof(msg));
msg.msg_control=buf;
msg.msg_controllen=1024;
if (recvmsg(osock,&msg,MSG_ERRQUEUE)!=-1) {
close(osock);
close(isock);
return -1; /* error in sending (e.g. no route
to host) */
}
sl=sizeof(from);
if
((len=recvfrom(isock,&buf,sizeof(buf),0,&from,&sl))!=-1){
if (len<sizeof(struct icmp6_hdr)) {
printf("Truncated reply.\n");
} else {
icmpp=(struct icmp6_hdr *)buf;
printf("Reply from %s, id=%i(%s),
seq=%i(%s)\n",inet_ntop(AF_INET6,&from.sin6_addr,buf,1024),
ntohs(icmpp->icmp6_id),ntohs(icmpp->icmp6_id)==id?"OK":"mismatch",
ntohs(icmpp->icmp6_seq),ntohs(icmpp->icmp6_seq)<=i?"OK":"mismatch");
if (ntohs(icmpp->icmp6_id)==id &&
ntohs(icmpp->icmp6_seq)<=i) {
close(osock);
close(isock);
return
(i-ntohs(icmpp->icmp6_seq))*timeout+tm; /* return the number of ticks */
}
}
} else {
if (errno!=EAGAIN)
{
close(osock);
close(isock);
return -1; /* error */
}
}
usleep(100000);
tm++;
} while (tm<timeout);
close(osock);
close(isock);
}
return -1; /* no answer */
}
-----------------------------------------------------------------------------
Sorry if there is a dumb mistake,
Thomas
|