diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2022-09-05 18:04:35 +0100 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2022-09-05 18:04:35 +0100 |
commit | ce372917fef8e89a2a928735a2470f6d9c0e253c (patch) | |
tree | ff66422bbf93e4e8145ced62febc1dda67619510 | |
parent | 09d741f58a50f7e9ec2d6e0634f8ab5b11a7de5f (diff) | |
download | dnsmasq-ce372917fef8e89a2a928735a2470f6d9c0e253c.tar.gz |
Tweak packet dump code to make port numbers more accurate.
Also add query-ids with log-queries=extra.
-rw-r--r-- | src/dhcp.c | 15 | ||||
-rw-r--r-- | src/dhcp6.c | 12 | ||||
-rw-r--r-- | src/dnsmasq.h | 6 | ||||
-rw-r--r-- | src/dump.c | 125 | ||||
-rw-r--r-- | src/forward.c | 32 | ||||
-rw-r--r-- | src/radv.c | 4 | ||||
-rw-r--r-- | src/rfc3315.c | 2 | ||||
-rw-r--r-- | src/tftp.c | 8 |
8 files changed, 120 insertions, 84 deletions
@@ -177,8 +177,7 @@ void dhcp_packet(time_t now, int pxe_fd) return; #ifdef HAVE_DUMPFILE - dump_packet(DUMP_DHCP, (void *)daemon->dhcp_packet.iov_base, sz, (union mysockaddr *)&dest, NULL, - pxe_fd ? PXE_PORT : daemon->dhcp_server_port); + dump_packet_udp(DUMP_DHCP, (void *)daemon->dhcp_packet.iov_base, sz, (union mysockaddr *)&dest, NULL, fd); #endif #if defined (HAVE_LINUX_NETWORK) @@ -464,8 +463,8 @@ void dhcp_packet(time_t now, int pxe_fd) dest.sin_addr = mess->yiaddr; dest.sin_port = htons(daemon->dhcp_client_port); - dump_packet(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL, - (union mysockaddr *)&dest, daemon->dhcp_server_port); + dump_packet_udp(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL, + (union mysockaddr *)&dest, fd); #endif send_via_bpf(mess, iov.iov_len, iface_addr, &ifr); @@ -478,8 +477,8 @@ void dhcp_packet(time_t now, int pxe_fd) #endif #ifdef HAVE_DUMPFILE - dump_packet(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL, - (union mysockaddr *)&dest, daemon->dhcp_server_port); + dump_packet_udp(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL, + (union mysockaddr *)&dest, fd); #endif while(retry_send(sendmsg(fd, &msg, 0))); @@ -1147,8 +1146,8 @@ static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz) fromsock.in.sin_port = htons(daemon->dhcp_server_port); fromsock.in.sin_addr = from.addr4; fromsock.sa.sa_family = AF_INET; - - dump_packet(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, 0); + + dump_packet_udp(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, -1); } #endif diff --git a/src/dhcp6.c b/src/dhcp6.c index edb87a4..1c8c679 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -119,8 +119,8 @@ void dhcp6_packet(time_t now) return; #ifdef HAVE_DUMPFILE - dump_packet(DUMP_DHCPV6, (void *)daemon->dhcp_packet.iov_base, sz, - (union mysockaddr *)&from, NULL, DHCPV6_SERVER_PORT); + dump_packet_udp(DUMP_DHCPV6, (void *)daemon->dhcp_packet.iov_base, sz, + (union mysockaddr *)&from, NULL, daemon->dhcp6fd); #endif for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) @@ -142,8 +142,8 @@ void dhcp6_packet(time_t now) if (relay_reply6(&from, sz, ifr.ifr_name)) { #ifdef HAVE_DUMPFILE - dump_packet(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL, - (union mysockaddr *)&from, DHCPV6_SERVER_PORT); + dump_packet_udp(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL, + (union mysockaddr *)&from, daemon->dhcp6fd); #endif while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, @@ -254,8 +254,8 @@ void dhcp6_packet(time_t now) from.sin6_port = htons(port); #ifdef HAVE_DUMPFILE - dump_packet(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), - NULL, (union mysockaddr *)&from, DHCPV6_SERVER_PORT); + dump_packet_udp(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), + NULL, (union mysockaddr *)&from, daemon->dhcp6fd); #endif while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 990d27f..36d17fe 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1803,8 +1803,10 @@ int do_arp_script_run(void); /* dump.c */ #ifdef HAVE_DUMPFILE void dump_init(void); -void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, - union mysockaddr *dst, int port); +void dump_packet_udp(int mask, void *packet, size_t len, union mysockaddr *src, + union mysockaddr *dst, int fd); +void dump_packet_icmp(int mask, void *packet, size_t len, union mysockaddr *src, + union mysockaddr *dst); #endif /* domain-match.c */ @@ -21,6 +21,8 @@ #include <netinet/icmp6.h> 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 */ struct pcap_hdr_s { @@ -81,9 +83,45 @@ void dump_init(void) } } -/* port == -1 ->ICMPv6 */ -void dump_packet(int mask, void *packet, size_t len, - union mysockaddr *src, union mysockaddr *dst, int port) +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 ip6_hdr ip6; @@ -100,13 +138,14 @@ void dump_packet(int mask, void *packet, size_t len, void *iphdr; size_t ipsz; 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(port); - if (src) family = src->sa.sa_family; else @@ -121,15 +160,12 @@ void dump_packet(int mask, void *packet, size_t len, ip6.ip6_vfc = 6 << 4; ip6.ip6_hops = 64; - if (port == -1) - { - ip6.ip6_plen = htons(len); - ip6.ip6_nxt = IPPROTO_ICMPV6; - } + if ((ip6.ip6_nxt = proto) == IPPROTO_UDP) + ip6.ip6_plen = htons(sizeof(struct udphdr) + len); else { - ip6.ip6_plen = htons(sizeof(struct udphdr) + len); - ip6.ip6_nxt = IPPROTO_UDP; + proto = ip6.ip6_nxt = IPPROTO_ICMPV6; + ip6.ip6_plen = htons(len); } if (src) @@ -161,15 +197,12 @@ void dump_packet(int mask, void *packet, size_t len, ip.ip_hl = sizeof(struct ip) / 4; ip.ip_ttl = IPDEFTTL; - if (port == -1) - { - ip.ip_len = htons(sizeof(struct ip) + len); - ip.ip_p = IPPROTO_ICMP; - } + 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) + sizeof(struct udphdr) + len); - ip.ip_p = IPPROTO_UDP; + ip.ip_len = htons(sizeof(struct ip) + len); + proto = ip.ip_p = IPPROTO_ICMP; } if (src) @@ -191,7 +224,7 @@ void dump_packet(int mask, void *packet, size_t len, sum = (sum & 0xffff) + (sum >> 16); 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 >> 16) & 0xffff; sum += ip.ip_dst.s_addr & 0xffff; @@ -201,25 +234,7 @@ 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. */ - 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 + if (proto == IPPROTO_UDP) { /* Add Remaining part of the pseudoheader. Note that though the IPv6 pseudoheader is very different to the IPv4 one, the @@ -241,7 +256,25 @@ void dump_packet(int mask, void *packet, size_t len, 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); pcap_header.ts_sec = time.tv_sec; pcap_header.ts_usec = time.tv_usec; @@ -249,9 +282,11 @@ void dump_packet(int mask, void *packet, size_t len, if (rc == -1 || !read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) || !read_write(daemon->dumpfd, iphdr, ipsz, 0) || - (port != -1 && !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)) 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 my_syslog(LOG_INFO, _("dumping packet %u mask 0x%04x"), ++packet_count, mask); diff --git a/src/forward.c b/src/forward.c index 0291986..e8249a6 100644 --- a/src/forward.c +++ b/src/forward.c @@ -510,7 +510,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, if (errno == 0) { #ifdef HAVE_DUMPFILE - dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &srv->addr, daemon->port); + dump_packet_udp(DUMP_UP_QUERY, (void *)header, plen, NULL, &srv->addr, fd); #endif /* Keep info in case we want to re-send this packet */ @@ -839,8 +839,8 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header, NULL, NULL, NULL); #ifdef HAVE_DUMPFILE if (STAT_ISEQUAL(status, STAT_BOGUS)) - dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS, - header, (size_t)plen, &forward->sentto->addr, NULL, daemon->port); + dump_packet_udp((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS, + header, (size_t)plen, &forward->sentto->addr, NULL, -daemon->port); #endif } @@ -950,13 +950,13 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header, set_outgoing_mark(orig, fd); #endif + server_send(server, fd, header, nn, 0); + server->queries++; #ifdef HAVE_DUMPFILE - dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr, daemon->port); + dump_packet_udp(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr, fd); #endif log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, daemon->keyname, &server->addr, STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0); - server_send(server, fd, header, nn, 0); - server->queries++; return; } @@ -1045,16 +1045,16 @@ void reply_query(int fd, time_t now) if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME) server->edns_pktsz = daemon->edns_pktsz; -#ifdef HAVE_DUMPFILE - dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY, - (void *)header, n, &serveraddr, NULL, daemon->port); -#endif - /* log_query gets called indirectly all over the place, so pass these in global variables - sorry. */ daemon->log_display_id = forward->frec_src.log_id; daemon->log_source_addr = &forward->frec_src.source; +#ifdef HAVE_DUMPFILE + dump_packet_udp((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY, + (void *)header, n, &serveraddr, NULL, fd); +#endif + if (daemon->ignore_addr && RCODE(header) == NOERROR && check_for_ignored_address(header, n)) return; @@ -1251,7 +1251,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he header->id = htons(src->orig_id); #ifdef HAVE_DUMPFILE - dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source, daemon->port); + dump_packet_udp(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source, src->fd); #endif #if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS) @@ -1566,7 +1566,7 @@ void receive_query(struct listener *listen, time_t now) daemon->log_source_addr = &source_addr; #ifdef HAVE_DUMPFILE - dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL, daemon->port); + dump_packet_udp(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL, listen->fd); #endif #ifdef HAVE_CONNTRACK @@ -1653,7 +1653,7 @@ void receive_query(struct listener *listen, time_t now) if (m >= 1) { #ifdef HAVE_DUMPFILE - dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, daemon->port); + dump_packet_udp(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, listen->fd); #endif send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, m, &source_addr, &dst_addr, if_index); @@ -1669,7 +1669,7 @@ void receive_query(struct listener *listen, time_t now) if (m >= 1) { #ifdef HAVE_DUMPFILE - dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, daemon->port); + dump_packet_udp(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, listen->fd); #endif #if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS) if (local_auth) @@ -1695,7 +1695,7 @@ void receive_query(struct listener *listen, time_t now) if (m >= 1) { #ifdef HAVE_DUMPFILE - dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, daemon->port); + dump_packet_udp(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, listen->fd); #endif #if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS) if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask)) @@ -203,7 +203,7 @@ void icmp6_packet(time_t now) int opt_sz; #ifdef HAVE_DUMPFILE - dump_packet(DUMP_RA, (void *)packet, sz, (union mysockaddr *)&from, NULL, -1); + dump_packet_icmp(DUMP_RA, (void *)packet, sz, (union mysockaddr *)&from, NULL); #endif /* look for link-layer address option for logging */ @@ -560,7 +560,7 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad } #ifdef HAVE_DUMPFILE - dump_packet(DUMP_RA, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL, (union mysockaddr *)&addr, -1); + dump_packet_icmp(DUMP_RA, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL, (union mysockaddr *)&addr); #endif while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base, diff --git a/src/rfc3315.c b/src/rfc3315.c index 866b8b8..947bf04 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -2214,7 +2214,7 @@ int relay_upstream6(int iface_index, ssize_t sz, fromsock.in6.sin6_flowinfo = 0; fromsock.in6.sin6_scope_id = 0; - dump_packet(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), &fromsock, &to, 0); + dump_packet_udp(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), &fromsock, &to, -1); } #endif send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0); @@ -97,7 +97,7 @@ void tftp_request(struct listener *listen, time_t now) return; #ifdef HAVE_DUMPFILE - dump_packet(DUMP_TFTP, (void *)packet, len, (union mysockaddr *)&peer, NULL, TFTP_PORT); + dump_packet_udp(DUMP_TFTP, (void *)packet, len, (union mysockaddr *)&peer, NULL, listen->tftpfd); #endif /* Can always get recvd interface for IPv6 */ @@ -488,7 +488,7 @@ void tftp_request(struct listener *listen, time_t now) send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), packet, len, &peer, &addra, if_index); #ifdef HAVE_DUMPFILE - dump_packet(DUMP_TFTP, (void *)packet, len, NULL, (union mysockaddr *)&peer, TFTP_PORT); + dump_packet_udp(DUMP_TFTP, (void *)packet, len, NULL, (union mysockaddr *)&peer, transfer->sockfd); #endif if (is_err) @@ -610,7 +610,7 @@ void check_tftp_listeners(time_t now) while(retry_send(sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer)))); #ifdef HAVE_DUMPFILE - dump_packet(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&peer, TFTP_PORT); + dump_packet_udp(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&peer, transfer->sockfd); #endif } } @@ -650,7 +650,7 @@ void check_tftp_listeners(time_t now) send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), daemon->packet, len, &transfer->peer, &transfer->source, transfer->if_index); #ifdef HAVE_DUMPFILE - dump_packet(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&transfer->peer, TFTP_PORT); + dump_packet_udp(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&transfer->peer, transfer->sockfd); #endif } |