netdev
[Top] [All Lists]

Re: ICMPv6 Echo Reply bug in Linux 2.2.15 ?

To: kuznet@xxxxxxxxxxxxx
Subject: Re: ICMPv6 Echo Reply bug in Linux 2.2.15 ?
From: Thomas Moestl <tmoestl@xxxxxxx>
Date: Fri, 26 May 2000 21:32:08 +0200
Cc: netdev@xxxxxxxxxxx
In-reply-to: <200005261723.VAA00756@ms2.inr.ac.ru>; from kuznet@ms2.inr.ac.ru on Fri, May 26, 2000 at 09:23:51PM +0400
References: <20000515180749.A479@flux.local> <200005261723.VAA00756@ms2.inr.ac.ru>
Sender: owner-netdev@xxxxxxxxxxx
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






<Prev in Thread] Current Thread [Next in Thread>