Revision: 14925
Author:   adrian.chadd
Date:     Thu Jul 14 18:14:36 2011
Log: * Finish fleshing out the ICMPv6 send/receive code, thanks to Squid-3!
* Teach pinger about sending/receiving ICMPv6.

This does work. The hop count for IPv6 isn't there, but RTT works fine.

http://code.google.com/p/lusca-cache/source/detail?r=14925

Modified:
 /playpen/LUSCA_HEAD_ipv6/libpinger/icmp_v6.c
 /playpen/LUSCA_HEAD_ipv6/libpinger/icmp_v6.h
 /playpen/LUSCA_HEAD_ipv6/src/pinger.c

=======================================
--- /playpen/LUSCA_HEAD_ipv6/libpinger/icmp_v6.c        Thu Jul 14 08:00:44 2011
+++ /playpen/LUSCA_HEAD_ipv6/libpinger/icmp_v6.c        Thu Jul 14 18:14:36 2011
@@ -1,11 +1,34 @@
 #include "../include/config.h"

+/* This needs to be tested on Windows! */
+
 #include <stdio.h>
 #include <stdlib.h>
-
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/*
+ * Some system headers are only neeed internally here.
+ * They should not be included via the header.
+ */
+#if HAVE_NETINET_IP6_H
+#include <netinet/ip6.h>
+#endif
+
+#include <netinet/icmp6.h>
+
+#include "include/util.h"
+#include "libcore/varargs.h"
+#include "libsqdebug/debug.h"
+#include "libsqinet/sqinet.h"

 #include "icmp_v6.h"

+#define MAX_PKT6_SZ (MAX_PAYLOAD + sizeof(struct timeval) + sizeof (char) + \
+                         sizeof(struct icmp6_hdr) + 1)
+
 // Icmp6 OP-Codes
 // see http://www.iana.org/assignments/icmpv6-parameters
 // NP: LowPktStr is for codes 0-127
@@ -14,7 +37,7 @@
     "Destination Unreachable",  // 1 - RFC2463
     "Packet Too Big",           // 2 - RFC2463
     "Time Exceeded",            // 3 - RFC2463
-    "Parameter Problem",                // 4 - RFC2463
+    "Parameter Problem",        // 4 - RFC2463
     "ICMP 5",                   // 5
     "ICMP 6",                   // 6
     "ICMP 7",                   // 7
@@ -25,32 +48,32 @@

 // NP: HighPktStr is for codes 128-255
 const char *icmp6HighPktStr[] = {
-    "Echo Request",                                     // 128 - RFC2463
-    "Echo Reply",                                       // 129 - RFC2463
+    "Echo Request",                             // 128 - RFC2463
+    "Echo Reply",                               // 129 - RFC2463
     "Multicast Listener Query",                 // 130 - RFC2710
-    "Multicast Listener Report",                        // 131 - RFC2710
+    "Multicast Listener Report",                // 131 - RFC2710
     "Multicast Listener Done",                  // 132 - RFC2710
-    "Router Solicitation",                              // 133 - RFC4861
-    "Router Advertisement",                             // 134 - RFC4861
+    "Router Solicitation",                      // 133 - RFC4861
+    "Router Advertisement",                     // 134 - RFC4861
     "Neighbor Solicitation",                    // 135 - RFC4861
     "Neighbor Advertisement",                   // 136 - RFC4861
     "Redirect Message",                         // 137 - RFC4861
-    "Router Renumbering",                               // 138 - Crawford
-    "ICMP Node Information Query",                      // 139 - RFC4620
+    "Router Renumbering",                       // 138 - Crawford
+    "ICMP Node Information Query",              // 139 - RFC4620
     "ICMP Node Information Response",           // 140 - RFC4620
     "Inverse Neighbor Discovery Solicitation",  // 141 - RFC3122
     "Inverse Neighbor Discovery Advertisement", // 142 - RFC3122
-    "Version 2 Multicast Listener Report",              // 143 - RFC3810
-    "Home Agent Address Discovery Request",             // 144 - RFC3775
-    "Home Agent Address Discovery Reply",               // 145 - RFC3775
-    "Mobile Prefix Solicitation",                       // 146 - RFC3775
-    "Mobile Prefix Advertisement",                      // 147 - RFC3775
+    "Version 2 Multicast Listener Report",      // 143 - RFC3810
+    "Home Agent Address Discovery Request",     // 144 - RFC3775
+    "Home Agent Address Discovery Reply",       // 145 - RFC3775
+    "Mobile Prefix Solicitation",               // 146 - RFC3775
+    "Mobile Prefix Advertisement",              // 147 - RFC3775
     "Certification Path Solicitation",          // 148 - RFC3971
     "Certification Path Advertisement",         // 149 - RFC3971
     "ICMP Experimental (150)",                  // 150 - RFC4065
     "Multicast Router Advertisement",           // 151 - RFC4286
     "Multicast Router Solicitation",            // 152 - RFC4286
-    "Multicast Router Termination",                     // 153 - [RFC4286]
+    "Multicast Router Termination",             // 153 - [RFC4286]
     "ICMP 154",
     "ICMP 155",
     "ICMP 156",
@@ -60,3 +83,153 @@
     "ICMP 160"
 };

+
+/*
+ * XXX Duplicated with icmp_v4.c
+ */
+static int
+in_cksum(unsigned short *ptr, int size)
+{
+    long sum;
+    unsigned short oddbyte;
+    unsigned short answer;
+    sum = 0;
+    while (size > 1) {
+        sum += *ptr++;
+        size -= 2;
+    }
+    if (size == 1) {
+        oddbyte = 0;
+        *((unsigned char *) &oddbyte) = *(unsigned char *) ptr;
+        sum += oddbyte;
+    }
+    sum = (sum >> 16) + (sum & 0xffff);
+    sum += (sum >> 16);
+    answer = (unsigned short) ~sum;
+    return (answer);
+}
+
+void
+pingerv6SendEcho(struct pingerv6_state *state, sqaddr_t *to,
+  int opcode, char *payload, int len)
+{
+    char pkt[MAX_PKT6_SZ];
+    struct icmp6_hdr *icmp = NULL;
+    size_t icmp6_pktsize = 0;
+    int x;
+
+    /*
+     * cevans - beware signed/unsigned issues in untrusted data from
+     * the network!!
+     */
+    if (len < 0)
+        len = 0;
+
+    /* Construct Icmp6 ECHO header */
+    memset(pkt, 0, MAX_PKT6_SZ);
+    icmp = (struct icmp6_hdr *) pkt;
+    icmp->icmp6_type = ICMP6_ECHO_REQUEST;
+    icmp->icmp6_code = 0;
+    icmp->icmp6_cksum = 0;
+    icmp->icmp6_id = state->icmp_ident;
+    icmp->icmp6_seq = (u_short) state->icmp_pkts_sent++;
+
+    icmp6_pktsize = sizeof(struct icmp6_hdr);
+
+    /* Add payload */
+    if (len > 0) {
+        memcpy(pkt + icmp6_pktsize, payload,
+          MIN(len, MAX_PKT6_SZ - icmp6_pktsize));
+       icmp6_pktsize = MIN(icmp6_pktsize + len, MAX_PKT6_SZ);
+    }
+
+    /* Calculate checksum */
+    icmp->icmp6_cksum = in_cksum((u_short *) pkt, icmp6_pktsize);
+
+    /* Send! */
+    x = sendto(state->icmp_sock, (const void *) pkt,
+      icmp6_pktsize, 0, sqinet_get_entry_ro(to),
+      sqinet_get_length(to));
+
+    if (x < 0)
+ debug(42, 0) ("%s: sendto(icmpsock): %s\n", __func__, xstrerror());
+}
+
+char *
+pingerv6RecvEcho(struct pingerv6_state *state, int *icmp_type,
+  int *payload_len, sqaddr_t *src, int *hops)
+{
+    int n;
+    struct sockaddr_storage from;
+    static char *pkt = NULL;
+    struct icmp6_hdr *icmp6header = NULL;
+    socklen_t fromlen;
+
+    (*icmp_type) = -1;
+    fromlen = sizeof(from);
+
+    if (state->icmp_sock < 0) {
+        debug(42, 0) ("dropping ICMPv6 read. No socket!?\n");
+        return NULL;
+    }
+
+    if (pkt == NULL) {
+        pkt = (char *)xmalloc(MAX_PKT6_SZ);
+    }
+
+    n = recvfrom(state->icmp_sock,
+                 (void *)pkt,
+                 MAX_PKT6_SZ,
+                 0,
+                 (struct sockaddr *) &from,
+                 &fromlen);
+
+    sqinet_set_sockaddr(src, &from);
+
+    icmp6header = (struct icmp6_hdr *) pkt;
+
+    if (icmp6header->icmp6_type != ICMP6_ECHO_REPLY) {
+        debug(42, 1) ("%s: unknown ICMP response, code %d\n",
+          __func__, icmp6header->icmp6_type);
+        return NULL;
+    }
+    (*icmp_type) = icmp6header->icmp6_type;
+
+    if (icmp6header->icmp6_id != state->icmp_ident) {
+        debug(42, 1) ("%s: unknown ICMP id: %d != %d\n",
+          __func__, icmp6header->icmp6_id,
+          state->icmp_ident);
+        return NULL;
+    }
+
+ (*hops) = 1; /* XXX there's no easy way to extract hops from the reply */
+
+    (*payload_len) = n - sizeof(struct icmp6_hdr);
+    return pkt + sizeof(struct icmp6_hdr);
+}
+
+void
+pingerv6_state_init(struct pingerv6_state *state, int icmp_ident)
+{
+    state->icmp_sock = -1;
+    state->icmp_pkts_sent = 0;
+    state->icmp_ident = icmp_ident;
+}
+
+int
+pingerv6_open_icmpsock(struct pingerv6_state *state)
+{
+    state->icmp_sock = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+    if (state->icmp_sock < 0) {
+        debug(42, 0) ("%s: icmp_sock: %s\n", __func__, xstrerror());
+        return 0;
+    }
+    return 1;
+}
+
+void
+pingerv6_close_icmpsock(struct pingerv6_state *state)
+{
+    close(state->icmp_sock);
+    state->icmp_sock = -1;
+}
=======================================
--- /playpen/LUSCA_HEAD_ipv6/libpinger/icmp_v6.h        Thu Jul 14 08:00:44 2011
+++ /playpen/LUSCA_HEAD_ipv6/libpinger/icmp_v6.h        Thu Jul 14 18:14:36 2011
@@ -1,7 +1,25 @@
 #ifndef        __LIBPINGER_ICMP_V6_H__
 #define        __LIBPINGER_ICMP_V6_H__

+/* XXX this must match the v4 define! */
+#define MAX_PAYLOAD     SQUIDHOSTNAMELEN
+
 extern const char *icmp6LowPktStr[];
 extern const char *icmp6HighPktStr[];

+struct pingerv6_state {
+       int icmp_ident;
+       int icmp_pkts_sent;
+       int icmp_sock;
+};
+
+extern void pingerv6SendEcho(struct pingerv6_state *, sqaddr_t *to,
+  int opcode, char *payload, int len);
+extern char * pingerv6RecvEcho(struct pingerv6_state *, int *icmp_type,
+  int *payload_len, sqaddr_t *from, int *hops);
+
+extern void pingerv6_state_init(struct pingerv6_state *, int icmp_ident);
+extern int pingerv6_open_icmpsock(struct pingerv6_state *);
+extern void pingerv6_close_icmpsock(struct pingerv6_state *);
+
 #endif /* __LIBPINGER_ICMP_V6_H__ */
=======================================
--- /playpen/LUSCA_HEAD_ipv6/src/pinger.c       Thu Jul 14 09:47:54 2011
+++ /playpen/LUSCA_HEAD_ipv6/src/pinger.c       Thu Jul 14 18:14:36 2011
@@ -86,8 +86,9 @@
     char payload[MAX_PAYLOAD];
 } icmpEchoData;

-static void pingerRecv(void);
-static void pingerLog(int, struct in_addr, int, int);
+static void pingerRecv4(void);
+static void pingerRecv6(void);
+static void pingerLog(int, sqaddr_t *, int, int);
 static void pingerSendtoSquid(pingerReplyData * preply);
 static void pingerOpen(void);
 static void pingerClose(void);
@@ -101,8 +102,8 @@
 }
 #endif /* ifdef _SQUID_MSWIN_ */

-
 struct pingerv4_state v4_state;
+struct pingerv6_state v6_state;

 void
 pingerOpen(void)
@@ -181,6 +182,7 @@
 pingerClose(void)
 {
     pingerv4_close_icmpsock(&v4_state);
+    pingerv6_close_icmpsock(&v6_state);
 #ifdef _SQUID_MSWIN_
     shutdown(socket_to_squid, SD_BOTH);
     close(socket_to_squid);
@@ -189,7 +191,7 @@
 }

 static void
-pingerSendEcho(struct in_addr to, int opcode, char *payload, int len)
+pingerSendEcho(sqaddr_t *to, int opcode, char *payload, int len)
 {
     icmpEchoData echo;
     int icmp_pktsize;
@@ -207,16 +209,20 @@
         icmp_pktsize += MIN(len, MAX_PAYLOAD);
     }

-    pingerv4SendEcho(&v4_state, to, opcode, (char *) &echo, icmp_pktsize);
+    if (sqinet_get_family(to) == AF_INET) {
+        pingerv4SendEcho(&v4_state, sqinet_get_v4_inaddr(to,
+          SQADDR_ASSERT_IS_V4), opcode, (char *) &echo, icmp_pktsize);
+    } else if (sqinet_get_family(to) == AF_INET6) {
+ pingerv6SendEcho(&v6_state, to, opcode, (char *) &echo, icmp_pktsize);
+    }
     pingerLog(ICMP_ECHO, to, 0, 0);
 }

 /*
  * This is an IPv4-specific function for now.
  */
-#warning IPv6-ify this!
 static void
-pingerRecv(void)
+pingerRecv4(void)
 {
     char *pkt;
     struct timeval now;
@@ -224,6 +230,7 @@
     static pingerReplyData preply;
     struct timeval tv;
     struct sockaddr_in *v4;
+    sqaddr_t from6;

     int icmp_type, payload_len, hops;
     struct in_addr from;
@@ -259,20 +266,77 @@
     preply.rtt = tvSubMsec(tv, now);
     preply.psize = payload_len;
     pingerSendtoSquid(&preply);
-    pingerLog(icmp_type, from, preply.rtt, preply.hops);
+    sqinet_init(&from6);
+    sqinet_set_v4_inaddr(&from6, &from);
+    pingerLog(icmp_type, &from6, preply.rtt, preply.hops);
+    sqinet_done(&from6);
 }

 static void
-pingerLog(int icmp_type, struct in_addr addr, int rtt, int hops)
-{
-    debug(42, 2) ("pingerLog: %9d.%06d %-16s %d %-15.15s %dms %d hops\n",
-       (int) current_time.tv_sec,
-       (int) current_time.tv_usec,
-       inet_ntoa(addr),
-       (int) icmp_type,
-       icmpPktStr[icmp_type],
-       rtt,
-       hops);
+pingerRecv6(void)
+{
+    char *pkt;
+    struct timeval now;
+    icmpEchoData *echo;
+    static pingerReplyData preply;
+    struct timeval tv;
+    sqaddr_t from;
+    int icmp_type, payload_len, hops;
+    char sbuf[MAX_IPSTRLEN];
+
+    sqinet_init(&from);
+
+    debug(42, 1) ("%s: called\n", __func__);
+
+ pkt = pingerv6RecvEcho(&v6_state, &icmp_type, &payload_len, &from, &hops);
+    debug(42, 1) ("%s: returned %p\n", __func__, pkt);
+
+    if (pkt == NULL) {
+        sqinet_done(&from);
+        return;
+    }
+
+#if GETTIMEOFDAY_NO_TZP
+    gettimeofday(&now);
+#else
+    gettimeofday(&now, NULL);
+#endif
+
+    if (do_debug(42, 9)) {
+        (void) sqinet_ntoa(&from, sbuf, MAX_IPSTRLEN, SQADDR_NONE);
+ debug(42, 9) ("pingerRecv: %d payload bytes from %s\n", payload_len,
+          sbuf);
+    }
+
+    echo = (icmpEchoData *) pkt;
+    sqinet_copy_tosockaddr(&from, &preply.from);
+    preply.opcode = echo->opcode;
+    preply.hops = hops;
+    memcpy(&tv, &echo->tv, sizeof(tv));
+    preply.rtt = tvSubMsec(tv, now);
+    preply.psize = payload_len;
+    pingerSendtoSquid(&preply);
+    pingerLog(icmp_type, &from, preply.rtt, preply.hops);
+    sqinet_done(&from);
+}
+
+
+
+static void
+pingerLog(int icmp_type, sqaddr_t *addr, int rtt, int hops)
+{
+    char sbuf[MAX_IPSTRLEN];
+    if (do_debug(42, 2)) {
+        (void) sqinet_ntoa(addr, sbuf, MAX_IPSTRLEN, SQADDR_NONE);
+ debug(42, 2) ("pingerLog: %9d.%06d %-16s %d %-15.15s %dms %d hops\n",
+          (int) current_time.tv_sec,
+          (int) current_time.tv_usec,
+          sbuf,
+          (int) icmp_type,
+          icmpPktStr[icmp_type],
+          rtt,
+          hops);
+    }
 }

 static int
@@ -281,7 +345,7 @@
     static pingerEchoData pecho;
     int n;
     int guess_size;
-    struct sockaddr_in *v4;
+    sqaddr_t to;

     memset(&pecho, '\0', sizeof(pecho));
     n = read(socket_from_squid, (char *) &pecho, sizeof(pecho));
@@ -303,18 +367,13 @@
        return 0;
     }

-    if (pecho.to.ss_family == AF_INET) {
-        v4 = (struct sockaddr_in *) &pecho.to;
-        pingerSendEcho(v4->sin_addr,
-          pecho.opcode,
-          pecho.payload,
-          pecho.psize);
-          return n;
-    } else if (pecho.to.ss_family == AF_INET6) {
-        debug(42, 1) ("%s: AF_INET6; not supported yet\n", __func__);
-        return 0;    /* Not currently supported */
-    } else
-        return 0;
+    sqinet_init(&to);
+    sqinet_set_sockaddr(&to, &pecho.to);
+    pingerSendEcho(&to,
+      pecho.opcode,
+      pecho.payload,
+      pecho.psize);
+    return n;
 }

 static void
@@ -337,6 +396,7 @@
     const char *debug_args = "ALL,1";
     char *t;
     time_t last_check_time = 0;
+    int maxfd = 0;

 /*
  * cevans - do this first. It grabs a raw socket. After this we can
@@ -356,16 +416,25 @@
     if (! pingerv4_open_icmpsock(&v4_state))
         exit(1);

+    pingerv6_state_init(&v6_state, getpid() & 0xffff);
+    if (! pingerv6_open_icmpsock(&v6_state))
+        exit(1);
+
     setgid(getgid());
     setuid(getuid());

+    /* Calculate the maximum FD for select() */
+    maxfd = MAX(maxfd, v4_state.icmp_sock);
+    maxfd = MAX(maxfd, v6_state.icmp_sock);
+
     for (;;) {
        tv.tv_sec = PINGER_TIMEOUT;
        tv.tv_usec = 0;
        FD_ZERO(&R);
        FD_SET(socket_from_squid, &R);
        FD_SET(v4_state.icmp_sock, &R);
-       x = select(v4_state.icmp_sock + 1, &R, NULL, NULL, &tv);
+       FD_SET(v6_state.icmp_sock, &R);
+       x = select(maxfd + 1, &R, NULL, NULL, &tv);
        getCurrentTime();
        if (x < 0 && errno == EINTR)
                continue;
@@ -380,7 +449,9 @@
                exit(1);
            }
        if (FD_ISSET(v4_state.icmp_sock, &R))
-           pingerRecv();
+           pingerRecv4();
+       if (FD_ISSET(v6_state.icmp_sock, &R))
+           pingerRecv6();
        if (PINGER_TIMEOUT + last_check_time < squid_curtime) {
            debug(42, 2) ("pinger: timeout occured\n");
            if (send(socket_to_squid, (char *) &tv, 0, 0) < 0) {

--
You received this message because you are subscribed to the Google Groups 
"lusca-commit" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/lusca-commit?hl=en.

Reply via email to