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) {