diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2022-01-29 22:52:21 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2022-01-29 22:52:21 +0000 |
commit | b5dafc0b7e3a3b6bad70d33a64873dbb6e8087a3 (patch) | |
tree | 487440bf68d89180d8d255770c712d91927cbe2b | |
parent | fc664d114d6e11ced4912b746f18d543f662066b (diff) | |
download | dnsmasq-b5dafc0b7e3a3b6bad70d33a64873dbb6e8087a3.tar.gz |
Extend packet dump system to RA.
-rw-r--r-- | man/dnsmasq.8 | 2 | ||||
-rw-r--r-- | src/dnsmasq.h | 3 | ||||
-rw-r--r-- | src/dump.c | 88 | ||||
-rw-r--r-- | src/radv.c | 18 |
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 */ @@ -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); } @@ -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)))); |