Extend packet dump system to RA.

This commit is contained in:
Simon Kelley
2022-01-29 22:52:21 +00:00
parent fc664d114d
commit b5dafc0b7e
4 changed files with 86 additions and 25 deletions

View File

@@ -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

View File

@@ -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 */

View File

@@ -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);
}

View File

@@ -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))
@@ -195,6 +199,10 @@ void icmp6_packet(time_t now)
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))));