Output the proper number of names, the proper number of times.
[icmp-dn.git] / idnlookup.c
index bd45b75..39c95d7 100644 (file)
@@ -25,6 +25,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <arpa/inet.h>
 #include <sys/types.h>
 #include <sys/poll.h>
@@ -62,7 +63,7 @@ unsigned char buf[65536];
 /* DN decompression not yet implemented, since I don't know where to
  * begin counting the offset from -- the beginning of the ICMP
  * payload, or from the beginning of the DN data buffer? */
-void printdn(FILE *f, unsigned char *dnbuf, size_t size)
+void printdn(FILE *f, unsigned char *dnbuf, size_t size, int onlyfirst)
 {
     unsigned char *p;
     
@@ -73,11 +74,15 @@ void printdn(FILE *f, unsigned char *dnbuf, size_t size)
                fprintf(stderr, "domain name decompression not implemented, aborting\n");
                exit(1);
            }
-           printf("%.*s.", (int)*p, p + 1);
+           fprintf(f, "%.*s", (int)*p, p + 1);
            p += 1 + (int)*p;
+           if(*p != 0)
+               fprintf(f, ".");
        }
        p++;
-       printf("\n");
+       fprintf(f, "\n");
+       if(onlyfirst)
+           break;
     }
 }
 
@@ -86,7 +91,7 @@ void cksum(void *hdr, size_t len)
     struct icmphdr *ih;
     u_int8_t *cb;
     int i;
-    u_int8_t b1, b2;
+    int b1, b2;
     
     ih = (struct icmphdr *)hdr;
     cb = (u_int8_t *)hdr;
@@ -98,14 +103,27 @@ void cksum(void *hdr, size_t len)
     }
     if(i & 1)
        b1 += cb[len - 1];
+    while(1) {
+       if(b1 >= 256) {
+           b2 += b1 >> 8;
+           b1 &= 0xff;
+           continue;
+       }
+       if(b2 >= 256) {
+           b1 += b2 >> 8;
+           b2 &= 0xff;
+           continue;
+       }
+       break;
+    }
     cb = (u_int8_t *)&ih->checksum;
-    cb[0] = ~b1;
-    cb[1] = ~b2;
+    cb[0] = ~(u_int8_t)b1;
+    cb[1] = ~(u_int8_t)b2;
 }
 
 void usage(void)
 {
-    fprintf(stderr, "usage: idnlookup [-h] [-t timeout] host\n");
+    fprintf(stderr, "usage: idnlookup [-hTa] [-t timeout] host\n");
 }
 
 int main(int argc, char **argv)
@@ -117,18 +135,28 @@ int main(int argc, char **argv)
     struct reqhdr req;
     struct rephdr rep;
     struct iphdr iphdr;
+    size_t hdrlen;
     struct addrinfo *ai, *cai, aihint;
     struct pollfd pfd;
     struct timeval tvb, tvc;
     struct sockaddr_storage name;
-    int timeout, elapsed;
+    int timeout, dispttl, onlyfirst;
+    int elapsed, timedout, found;
     
     timeout = 3000;
-    while((c = getopt(argc, argv, "ht:")) != -1) {
+    dispttl = 0;
+    onlyfirst = 1;
+    while((c = getopt(argc, argv, "haTt:")) != -1) {
        switch(c) {
        case 't':
            timeout = atoi(optarg);
            break;
+       case 'a':
+           onlyfirst = 0;
+           break;
+       case 'T':
+           dispttl = 1;
+           break;
        case 'h':
        case '?':
        case ':':
@@ -144,7 +172,6 @@ int main(int argc, char **argv)
     }
     
     memset(&aihint, 0, sizeof(aihint));
-    aihint.ai_family = PF_INET; /* Only IPv4 for now. */
     aihint.ai_socktype = SOCK_RAW;
     aihint.ai_protocol = IPPROTO_ICMP;
     ret = getaddrinfo(argv[optind], NULL, &aihint, &ai);
@@ -170,15 +197,17 @@ int main(int argc, char **argv)
            exit(1);
        }
        
+       timedout = 0;
+       found = 0;
        gettimeofday(&tvb, NULL);
        while(1) {
            pfd.fd = s;
            pfd.events = POLLIN;
            gettimeofday(&tvc, NULL);
            elapsed = ((tvc.tv_sec - tvb.tv_sec) * 1000) + ((tvc.tv_usec - tvb.tv_usec) / 1000);
-           if(elapsed > timeout) {
-               fprintf(stderr, "idnlookup: timeout\n");
-               exit(1);
+           if(elapsed >= timeout) {
+               timedout = 1;
+               break;
            }
            ret = poll(&pfd, 1, timeout - elapsed);
            if(ret < 0) {
@@ -199,31 +228,46 @@ int main(int argc, char **argv)
                if(name.ss_family == AF_INET) {
                    if(memcmp(&(((struct sockaddr_in *)&name)->sin_addr), &(((struct sockaddr_in *)cai->ai_addr)->sin_addr), sizeof(struct in_addr)))
                        continue;
+                   if(ret < sizeof(iphdr) + sizeof(rep))
+                       continue;
+                   hdrlen = sizeof(iphdr);
+                   memcpy(&iphdr, buf, sizeof(iphdr));
+                   if(iphdr.protocol != IPPROTO_ICMP)
+                       continue;
                } else if(name.ss_family == AF_INET6) {
                    if(memcmp(&(((struct sockaddr_in6 *)&name)->sin6_addr), &(((struct sockaddr_in6 *)cai->ai_addr)->sin6_addr), sizeof(struct in6_addr)))
                        continue;
+                   if(ret < sizeof(rep))
+                       continue;
+                   hdrlen = 0;
                } else {
                    continue;
                }
                
-               if(ret < sizeof(iphdr) + sizeof(rep))
-                   continue;
-               memcpy(&iphdr, buf, sizeof(iphdr));
-               memcpy(&rep, buf + sizeof(iphdr), sizeof(rep));
-               if(iphdr.protocol != IPPROTO_ICMP)
-                   continue;
+               memcpy(&rep, buf + hdrlen, sizeof(rep));
                if(rep.type != ICMP_NAMEREP)
                    continue;
                if((ntohs(rep.id) != id) || (ntohs(rep.seq != 0)))
                    continue;
                
+               found = 1;
                break;
            }
        }
        
-       printdn(stdout, buf + sizeof(iphdr) + sizeof(rep), ret - sizeof(iphdr) - sizeof(rep));
-       
        close(s);
+       
+       if(found) {
+           if(dispttl)
+               printf("%i\n", ntohl(rep.ttl));
+           printdn(stdout, buf + hdrlen + sizeof(rep), ret - hdrlen - sizeof(rep), onlyfirst);
+           break;
+       }
+    }
+    
+    if(timedout) {
+       fprintf(stderr, "idnlookup: timeout\n");
+       exit(1);
     }
     
     return(0);