summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2022-01-29 22:52:21 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2022-01-29 22:52:21 +0000
commitb5dafc0b7e3a3b6bad70d33a64873dbb6e8087a3 (patch)
tree487440bf68d89180d8d255770c712d91927cbe2b
parentfc664d114d6e11ced4912b746f18d543f662066b (diff)
downloaddnsmasq-b5dafc0b7e3a3b6bad70d33a64873dbb6e8087a3.tar.gz
Extend packet dump system to RA.
-rw-r--r--man/dnsmasq.82
-rw-r--r--src/dnsmasq.h3
-rw-r--r--src/dump.c88
-rw-r--r--src/radv.c18
4 files changed, 86 insertions, 25 deletions
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 398c2c6..abed551 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -734,7 +734,7 @@ Specify the location of a pcap-format file which dnsmasq uses to dump copies of
.TP
.B --dumpmask=<mask>
Specify which types of packets should be added to the dumpfile. The argument should be the OR of the bitmasks for each type of packet to be dumped: it can be specified in hex by preceding the number with 0x in the normal way. Each time a packet is written to the dumpfile, dnsmasq logs the packet sequence and the mask
-representing its type. The current types are: 0x0001 - DNS queries from clients, 0x0002 DNS replies to clients, 0x0004 - DNS queries to upstream, 0x0008 - DNS replies from upstream, 0x0010 - queries send upstream for DNSSEC validation, 0x0020 - replies to queries for DNSSEC validation, 0x0040 - replies to client queries which fail DNSSEC validation, 0x0080 replies to queries for DNSSEC validation which fail validation, 0x1000 - DHCPv4, 0x2000 - DHCPv6, 0x8000 - TFTP.
+representing its type. The current types are: 0x0001 - DNS queries from clients, 0x0002 DNS replies to clients, 0x0004 - DNS queries to upstream, 0x0008 - DNS replies from upstream, 0x0010 - queries send upstream for DNSSEC validation, 0x0020 - replies to queries for DNSSEC validation, 0x0040 - replies to client queries which fail DNSSEC validation, 0x0080 replies to queries for DNSSEC validation which fail validation, 0x1000 - DHCPv4, 0x2000 - DHCPv6, 0x4000 - Router advertisement, 0x8000 - TFTP.
.TP
.B --add-mac[=base64|text]
Add the MAC address of the requestor to DNS queries which are
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index a921f7d..ad2837e 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -700,6 +700,7 @@ struct hostsfile {
#define DUMP_SEC_BOGUS 0x0080
#define DUMP_DHCP 0x1000
#define DUMP_DHCPV6 0x2000
+#define DUMP_RA 0x4000
#define DUMP_TFTP 0x8000
/* DNSSEC status values. */
@@ -1798,7 +1799,7 @@ int do_arp_script_run(void);
#ifdef HAVE_DUMPFILE
void dump_init(void);
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src,
- union mysockaddr *dst, unsigned short port);
+ union mysockaddr *dst, int port);
#endif
/* domain-match.c */
diff --git a/src/dump.c b/src/dump.c
index 4aae008..3d9ef1f 100644
--- a/src/dump.c
+++ b/src/dump.c
@@ -18,6 +18,8 @@
#ifdef HAVE_DUMPFILE
+#include <netinet/icmp6.h>
+
static u32 packet_count;
/* https://wiki.wireshark.org/Development/LibpcapFileFormat */
@@ -79,8 +81,9 @@ void dump_init(void)
}
}
+/* port == -1 ->ICMPv6 */
void dump_packet(int mask, void *packet, size_t len,
- union mysockaddr *src, union mysockaddr *dst, unsigned short port)
+ union mysockaddr *src, union mysockaddr *dst, int port)
{
struct ip ip;
struct ip6_hdr ip6;
@@ -116,10 +119,19 @@ void dump_packet(int mask, void *packet, size_t len,
memset(&ip6, 0, sizeof(ip6));
ip6.ip6_vfc = 6 << 4;
- ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
- ip6.ip6_nxt = IPPROTO_UDP;
ip6.ip6_hops = 64;
+ if (port == -1)
+ {
+ ip6.ip6_plen = htons(len);
+ ip6.ip6_nxt = IPPROTO_ICMPV6;
+ }
+ else
+ {
+ ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
+ ip6.ip6_nxt = IPPROTO_UDP;
+ }
+
if (src)
{
memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ);
@@ -137,7 +149,6 @@ void dump_packet(int mask, void *packet, size_t len,
{
sum += ip6.ip6_src.s6_addr[i] + (ip6.ip6_src.s6_addr[i+1] << 8) ;
sum += ip6.ip6_dst.s6_addr[i] + (ip6.ip6_dst.s6_addr[i+1] << 8) ;
-
}
}
else
@@ -148,9 +159,18 @@ void dump_packet(int mask, void *packet, size_t len,
ip.ip_v = IPVERSION;
ip.ip_hl = sizeof(struct ip) / 4;
- ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len);
ip.ip_ttl = IPDEFTTL;
- ip.ip_p = IPPROTO_UDP;
+
+ if (port == -1)
+ {
+ ip.ip_len = htons(sizeof(struct ip) + len);
+ ip.ip_p = IPPROTO_ICMP;
+ }
+ else
+ {
+ ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len);
+ ip.ip_p = IPPROTO_UDP;
+ }
if (src)
{
@@ -181,31 +201,59 @@ void dump_packet(int mask, void *packet, size_t len,
if (len & 1)
((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
- udp.uh_sum = 0;
- udp.uh_ulen = htons(sizeof(struct udphdr) + len);
- sum += htons(IPPROTO_UDP);
- sum += htons(sizeof(struct udphdr) + len);
- for (i = 0; i < sizeof(struct udphdr)/2; i++)
- sum += ((u16 *)&udp)[i];
- for (i = 0; i < (len + 1) / 2; i++)
- sum += ((u16 *)packet)[i];
- while (sum >> 16)
- sum = (sum & 0xffff) + (sum >> 16);
- udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
+ if (port == -1)
+ {
+ /* ICMP - ICMPv6 packet is a superset of ICMP */
+ struct icmp6_hdr *icmp = packet;
+
+ /* See comment in UDP code below. */
+ sum += htons(family == AF_INET6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP);
+ sum += htons(len);
+
+ icmp->icmp6_cksum = 0;
+ for (i = 0; i < (len + 1) / 2; i++)
+ sum += ((u16 *)packet)[i];
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+ icmp->icmp6_cksum = (sum == 0xffff) ? sum : ~sum;
+
+ pcap_header.incl_len = pcap_header.orig_len = ipsz + len;
+ }
+ else
+ {
+ /* Add Remaining part of the pseudoheader. Note that though the
+ IPv6 pseudoheader is very different to the IPv4 one, the
+ net result of this calculation is correct as long as the
+ packet length is less than 65536, which is fine for us. */
+ sum += htons(IPPROTO_UDP);
+ sum += htons(sizeof(struct udphdr) + len);
+
+ udp.uh_sum = 0;
+ udp.uh_ulen = htons(sizeof(struct udphdr) + len);
+
+ for (i = 0; i < sizeof(struct udphdr)/2; i++)
+ sum += ((u16 *)&udp)[i];
+ for (i = 0; i < (len + 1) / 2; i++)
+ sum += ((u16 *)packet)[i];
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+ udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
+ pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
+ }
+
rc = gettimeofday(&time, NULL);
pcap_header.ts_sec = time.tv_sec;
pcap_header.ts_usec = time.tv_usec;
- pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
if (rc == -1 ||
!read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) ||
!read_write(daemon->dumpfd, iphdr, ipsz, 0) ||
- !read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0) ||
+ (port != -1 && !read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0)) ||
!read_write(daemon->dumpfd, (void *)packet, len, 0))
my_syslog(LOG_ERR, _("failed to write packet dump"));
else
- my_syslog(LOG_INFO, _("dumping UDP packet %u mask 0x%04x"), ++packet_count, mask);
+ my_syslog(LOG_INFO, _("dumping packet %u mask 0x%04x"), ++packet_count, mask);
}
diff --git a/src/radv.c b/src/radv.c
index 2b6d944..021c62a 100644
--- a/src/radv.c
+++ b/src/radv.c
@@ -123,7 +123,11 @@ void ra_start_unsolicited(time_t now, struct dhcp_context *context)
and pick up new interfaces */
if (context)
- context->ra_short_period_start = context->ra_time = now;
+ {
+ context->ra_short_period_start = now;
+ /* start after 1 second to get logging right at startup. */
+ context->ra_time = now + 1;
+ }
else
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE))
@@ -162,7 +166,7 @@ void icmp6_packet(time_t now)
return;
packet = (unsigned char *)daemon->outpacket.iov_base;
-
+
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
{
@@ -187,13 +191,17 @@ void icmp6_packet(time_t now)
if (packet[1] != 0)
return;
-
+
if (packet[0] == ICMP6_ECHO_REPLY)
lease_ping_reply(&from.sin6_addr, packet, interface);
else if (packet[0] == ND_ROUTER_SOLICIT)
{
char *mac = "";
struct dhcp_bridge *bridge, *alias;
+
+#ifdef HAVE_DUMPFILE
+ dump_packet(DUMP_RA, (void *)packet, sz, (union mysockaddr *)&from, NULL, -1);
+#endif
/* look for link-layer address option for logging */
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
@@ -543,6 +551,10 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &send_iface, sizeof(send_iface));
}
+#ifdef HAVE_DUMPFILE
+ dump_packet(DUMP_RA, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL, (union mysockaddr *)&addr, -1);
+#endif
+
while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
save_counter(-1), 0, (struct sockaddr *)&addr,
sizeof(addr))));