version 1.1.1.1, 2021/03/17 00:56:46
|
version 1.1.1.2, 2023/09/27 11:02:07
|
Line 1
|
Line 1
|
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley | /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley |
|
|
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
Line 18
|
Line 18
|
|
|
#ifdef HAVE_DUMPFILE |
#ifdef HAVE_DUMPFILE |
|
|
|
#include <netinet/icmp6.h> |
|
|
static u32 packet_count; |
static u32 packet_count; |
|
static void do_dump_packet(int mask, void *packet, size_t len, |
|
union mysockaddr *src, union mysockaddr *dst, int port, int proto); |
|
|
/* https://wiki.wireshark.org/Development/LibpcapFileFormat */ |
/* https://wiki.wireshark.org/Development/LibpcapFileFormat */ |
struct pcap_hdr_s { |
struct pcap_hdr_s { |
Line 79 void dump_init(void)
|
Line 83 void dump_init(void)
|
} |
} |
} |
} |
|
|
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst) | void dump_packet_udp(int mask, void *packet, size_t len, |
| union mysockaddr *src, union mysockaddr *dst, int fd) |
{ |
{ |
|
union mysockaddr fd_addr; |
|
socklen_t addr_len = sizeof(fd_addr); |
|
|
|
if (daemon->dumpfd != -1 && (mask & daemon->dump_mask)) |
|
{ |
|
/* if fd is negative it carries a port number (negated) |
|
which we use as a source or destination when not otherwise |
|
specified so wireshark can ID the packet. |
|
If both src and dst are specified, set this to -1 to avoid |
|
a spurious getsockname() call. */ |
|
int port = (fd < 0) ? -fd : -1; |
|
|
|
/* fd >= 0 is a file descriptor and the address of that file descriptor is used |
|
in place of a NULL src or dst. */ |
|
if (fd >= 0 && getsockname(fd, (struct sockaddr *)&fd_addr, &addr_len) != -1) |
|
{ |
|
if (!src) |
|
src = &fd_addr; |
|
|
|
if (!dst) |
|
dst = &fd_addr; |
|
} |
|
|
|
do_dump_packet(mask, packet, len, src, dst, port, IPPROTO_UDP); |
|
} |
|
} |
|
|
|
void dump_packet_icmp(int mask, void *packet, size_t len, |
|
union mysockaddr *src, union mysockaddr *dst) |
|
{ |
|
if (daemon->dumpfd != -1 && (mask & daemon->dump_mask)) |
|
do_dump_packet(mask, packet, len, src, dst, -1, IPPROTO_ICMP); |
|
} |
|
|
|
static void do_dump_packet(int mask, void *packet, size_t len, |
|
union mysockaddr *src, union mysockaddr *dst, int port, int proto) |
|
{ |
struct ip ip; |
struct ip ip; |
struct ip6_hdr ip6; |
struct ip6_hdr ip6; |
int family; |
int family; |
Line 96 void dump_packet(int mask, void *packet, size_t len, u
|
Line 138 void dump_packet(int mask, void *packet, size_t len, u
|
void *iphdr; |
void *iphdr; |
size_t ipsz; |
size_t ipsz; |
int rc; |
int rc; |
|
|
|
/* if port != -1 it carries a port number |
|
which we use as a source or destination when not otherwise |
|
specified so wireshark can ID the packet. |
|
If both src and dst are specified, set this to -1 to avoid |
|
a spurious getsockname() call. */ |
|
udp.uh_sport = udp.uh_dport = htons(port < 0 ? 0 : port); |
|
|
if (daemon->dumpfd == -1 || !(mask & daemon->dump_mask)) |
|
return; |
|
|
|
/* So wireshark can Id the packet. */ |
|
udp.uh_sport = udp.uh_dport = htons(NAMESERVER_PORT); |
|
|
|
if (src) |
if (src) |
family = src->sa.sa_family; |
family = src->sa.sa_family; |
else |
else |
Line 115 void dump_packet(int mask, void *packet, size_t len, u
|
Line 158 void dump_packet(int mask, void *packet, size_t len, u
|
memset(&ip6, 0, sizeof(ip6)); |
memset(&ip6, 0, sizeof(ip6)); |
|
|
ip6.ip6_vfc = 6 << 4; |
ip6.ip6_vfc = 6 << 4; |
ip6.ip6_plen = htons(sizeof(struct udphdr) + len); |
|
ip6.ip6_nxt = IPPROTO_UDP; |
|
ip6.ip6_hops = 64; |
ip6.ip6_hops = 64; |
|
|
|
if ((ip6.ip6_nxt = proto) == IPPROTO_UDP) |
|
ip6.ip6_plen = htons(sizeof(struct udphdr) + len); |
|
else |
|
{ |
|
proto = ip6.ip6_nxt = IPPROTO_ICMPV6; |
|
ip6.ip6_plen = htons(len); |
|
} |
|
|
if (src) |
if (src) |
{ |
{ |
memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ); |
memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ); |
Line 134 void dump_packet(int mask, void *packet, size_t len, u
|
Line 183 void dump_packet(int mask, void *packet, size_t len, u
|
/* start UDP checksum */ |
/* start UDP checksum */ |
for (sum = 0, i = 0; i < IN6ADDRSZ; i+=2) |
for (sum = 0, i = 0; i < IN6ADDRSZ; i+=2) |
{ |
{ |
sum += ip6.ip6_src.s6_addr[i] + (ip6.ip6_src.s6_addr[i+1] << 8) ; | sum += ntohs((ip6.ip6_src.s6_addr[i] << 8) + (ip6.ip6_src.s6_addr[i+1])) ; |
sum += ip6.ip6_dst.s6_addr[i] + (ip6.ip6_dst.s6_addr[i+1] << 8) ; | sum += ntohs((ip6.ip6_dst.s6_addr[i] << 8) + (ip6.ip6_dst.s6_addr[i+1])) ; |
| |
} |
} |
} |
} |
else |
else |
Line 147 void dump_packet(int mask, void *packet, size_t len, u
|
Line 195 void dump_packet(int mask, void *packet, size_t len, u
|
|
|
ip.ip_v = IPVERSION; |
ip.ip_v = IPVERSION; |
ip.ip_hl = sizeof(struct ip) / 4; |
ip.ip_hl = sizeof(struct ip) / 4; |
ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len); |
|
ip.ip_ttl = IPDEFTTL; |
ip.ip_ttl = IPDEFTTL; |
ip.ip_p = IPPROTO_UDP; | |
| if ((ip.ip_p = proto) == IPPROTO_UDP) |
| ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len); |
| else |
| { |
| ip.ip_len = htons(sizeof(struct ip) + len); |
| proto = ip.ip_p = IPPROTO_ICMP; |
| } |
|
|
if (src) |
if (src) |
{ |
{ |
Line 170 void dump_packet(int mask, void *packet, size_t len, u
|
Line 224 void dump_packet(int mask, void *packet, size_t len, u
|
sum = (sum & 0xffff) + (sum >> 16); |
sum = (sum & 0xffff) + (sum >> 16); |
ip.ip_sum = (sum == 0xffff) ? sum : ~sum; |
ip.ip_sum = (sum == 0xffff) ? sum : ~sum; |
|
|
/* start UDP checksum */ | /* start UDP/ICMP checksum */ |
sum = ip.ip_src.s_addr & 0xffff; |
sum = ip.ip_src.s_addr & 0xffff; |
sum += (ip.ip_src.s_addr >> 16) & 0xffff; |
sum += (ip.ip_src.s_addr >> 16) & 0xffff; |
sum += ip.ip_dst.s_addr & 0xffff; |
sum += ip.ip_dst.s_addr & 0xffff; |
Line 180 void dump_packet(int mask, void *packet, size_t len, u
|
Line 234 void dump_packet(int mask, void *packet, size_t len, u
|
if (len & 1) |
if (len & 1) |
((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */ |
((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */ |
|
|
udp.uh_sum = 0; | if (proto == IPPROTO_UDP) |
udp.uh_ulen = htons(sizeof(struct udphdr) + len); | { |
sum += htons(IPPROTO_UDP); | /* Add Remaining part of the pseudoheader. Note that though the |
sum += htons(sizeof(struct udphdr) + len); | IPv6 pseudoheader is very different to the IPv4 one, the |
for (i = 0; i < sizeof(struct udphdr)/2; i++) | net result of this calculation is correct as long as the |
sum += ((u16 *)&udp)[i]; | packet length is less than 65536, which is fine for us. */ |
for (i = 0; i < (len + 1) / 2; i++) | sum += htons(IPPROTO_UDP); |
sum += ((u16 *)packet)[i]; | sum += htons(sizeof(struct udphdr) + len); |
while (sum >> 16) | |
sum = (sum & 0xffff) + (sum >> 16); | udp.uh_sum = 0; |
udp.uh_sum = (sum == 0xffff) ? sum : ~sum; | 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; |
|
} |
|
else |
|
{ |
|
/* ICMP - ICMPv6 packet is a superset of ICMP */ |
|
struct icmp6_hdr *icmp = packet; |
|
|
|
/* See comment in UDP code above. */ |
|
sum += htons(proto); |
|
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; |
|
} |
|
|
rc = gettimeofday(&time, NULL); |
rc = gettimeofday(&time, NULL); |
pcap_header.ts_sec = time.tv_sec; |
pcap_header.ts_sec = time.tv_sec; |
pcap_header.ts_usec = time.tv_usec; |
pcap_header.ts_usec = time.tv_usec; |
pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len; |
|
|
|
if (rc == -1 || |
if (rc == -1 || |
!read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) || |
!read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) || |
!read_write(daemon->dumpfd, iphdr, ipsz, 0) || |
!read_write(daemon->dumpfd, iphdr, ipsz, 0) || |
!read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0) || | (proto == IPPROTO_UDP && !read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0)) || |
!read_write(daemon->dumpfd, (void *)packet, len, 0)) |
!read_write(daemon->dumpfd, (void *)packet, len, 0)) |
my_syslog(LOG_ERR, _("failed to write packet dump")); |
my_syslog(LOG_ERR, _("failed to write packet dump")); |
|
else if (option_bool(OPT_EXTRALOG)) |
|
my_syslog(LOG_INFO, _("%u dumping packet %u mask 0x%04x"), daemon->log_display_id, ++packet_count, mask); |
else |
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); |
|
|
} |
} |
|
|