diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2022-01-29 15:55:04 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2022-01-29 15:55:04 +0000 |
commit | fc664d114d6e11ced4912b746f18d543f662066b (patch) | |
tree | a63e55fe3a3d0074cc7fb79737b42b3b78bb62c0 | |
parent | c6d4c33d612c26f7d7518bef301a448a143b0a58 (diff) | |
download | dnsmasq-fc664d114d6e11ced4912b746f18d543f662066b.tar.gz |
Extend packet-dump system to DHCP and TFTP.
-rw-r--r-- | man/dnsmasq.8 | 2 | ||||
-rw-r--r-- | src/dhcp.c | 35 | ||||
-rw-r--r-- | src/dhcp6.c | 33 | ||||
-rw-r--r-- | src/dnsmasq.h | 22 | ||||
-rw-r--r-- | src/dump.c | 5 | ||||
-rw-r--r-- | src/forward.c | 40 | ||||
-rw-r--r-- | src/rfc3315.c | 12 | ||||
-rw-r--r-- | src/tftp.c | 23 |
8 files changed, 120 insertions, 52 deletions
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 0d53474..398c2c6 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. +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. .TP .B --add-mac[=base64|text] Add the MAC address of the requestor to DNS queries which are @@ -177,11 +177,16 @@ void dhcp_packet(time_t now, int pxe_fd) if ((sz = recv_dhcp_packet(fd, &msg)) == -1 || (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))) return; - - #if defined (HAVE_LINUX_NETWORK) + +#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); +#endif + +#if defined (HAVE_LINUX_NETWORK) if (ioctl(fd, SIOCGSTAMP, &tv) == 0) recvtime = tv.tv_sec; - + if (msg.msg_controllen >= sizeof(struct cmsghdr)) for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO) @@ -455,6 +460,14 @@ void dhcp_packet(time_t now, int pxe_fd) #elif defined(HAVE_BSD_NETWORK) else { +#ifdef HAVE_DUMPFILE + dest.sin_addr.s_addr = (ntohs(mess->flags) & 0x8000) ? INADDR_BROADCAST : 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); +#endif + send_via_bpf(mess, iov.iov_len, iface_addr, &ifr); return; } @@ -463,6 +476,11 @@ void dhcp_packet(time_t now, int pxe_fd) #ifdef HAVE_SOLARIS_NETWORK setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index)); #endif + +#ifdef HAVE_DUMPFILE + dump_packet(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL, + (union mysockaddr *)&dest, daemon->dhcp_server_port); +#endif while(retry_send(sendmsg(fd, &msg, 0))); @@ -1114,6 +1132,17 @@ static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, to.in.sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; } +#ifdef HAVE_DUMPFILE + { + union mysockaddr fromsock; + 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); + } +#endif + send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0); if (option_bool(OPT_LOG_OPTS)) diff --git a/src/dhcp6.c b/src/dhcp6.c index 9831255..a343740 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -119,6 +119,11 @@ void dhcp6_packet(time_t now) if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1) return; +#ifdef HAVE_DUMPFILE + dump_packet(DUMP_DHCPV6, (void *)daemon->dhcp_packet.iov_base, sz, + (union mysockaddr *)&from, NULL, DHCPV6_SERVER_PORT); +#endif + for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo) { @@ -137,6 +142,11 @@ 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); +#endif + while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, save_counter(-1), 0, (struct sockaddr *)&from, sizeof(from)))); @@ -144,7 +154,7 @@ void dhcp6_packet(time_t now) else { struct dhcp_bridge *bridge, *alias; - + for (tmp = daemon->if_except; tmp; tmp = tmp->next) if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name)) return; @@ -161,7 +171,7 @@ void dhcp6_packet(time_t now) memset(&parm.fallback, 0, IN6ADDRSZ); memset(&parm.ll_addr, 0, IN6ADDRSZ); memset(&parm.ula_addr, 0, IN6ADDRSZ); - + /* If the interface on which the DHCPv6 request was received is an alias of some other interface (as specified by the --bridge-interface option), change parm.ind so that we look @@ -199,13 +209,13 @@ void dhcp6_packet(time_t now) context->current = context; memset(&context->local6, 0, IN6ADDRSZ); } - + for (relay = daemon->relay6; relay; relay = relay->next) relay->current = relay; if (!iface_enumerate(AF_INET6, &parm, complete_context6)) return; - + if (daemon->if_names || daemon->if_addrs) { @@ -233,7 +243,7 @@ void dhcp6_packet(time_t now) /* May have configured relay, but not DHCP server */ if (!daemon->doing_dhcp6) return; - + lease_prune(NULL, now); /* lose any expired leases */ port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback, @@ -246,11 +256,16 @@ void dhcp6_packet(time_t now) if (port != 0) { from.sin6_port = htons(port); - while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, - save_counter(-1), 0, (struct sockaddr *)&from, - sizeof(from)))); + +#ifdef HAVE_DUMPFILE + dump_packet(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), + NULL, (union mysockaddr *)&from, DHCPV6_SERVER_PORT); +#endif + + while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, + save_counter(-1), 0, (struct sockaddr *)&from, sizeof(from)))); } - + /* These need to be called _after_ we send DHCPv6 packet, since lease_update_file() may trigger sending an RA packet, which overwrites our buffer. */ lease_update_file(now); diff --git a/src/dnsmasq.h b/src/dnsmasq.h index f37d7b1..a921f7d 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -690,14 +690,17 @@ struct hostsfile { }; /* packet-dump flags */ -#define DUMP_QUERY 0x0001 -#define DUMP_REPLY 0x0002 -#define DUMP_UP_QUERY 0x0004 -#define DUMP_UP_REPLY 0x0008 -#define DUMP_SEC_QUERY 0x0010 -#define DUMP_SEC_REPLY 0x0020 -#define DUMP_BOGUS 0x0040 -#define DUMP_SEC_BOGUS 0x0080 +#define DUMP_QUERY 0x0001 +#define DUMP_REPLY 0x0002 +#define DUMP_UP_QUERY 0x0004 +#define DUMP_UP_REPLY 0x0008 +#define DUMP_SEC_QUERY 0x0010 +#define DUMP_SEC_REPLY 0x0020 +#define DUMP_BOGUS 0x0040 +#define DUMP_SEC_BOGUS 0x0080 +#define DUMP_DHCP 0x1000 +#define DUMP_DHCPV6 0x2000 +#define DUMP_TFTP 0x8000 /* DNSSEC status values. */ #define STAT_SECURE 0x10000 @@ -1794,7 +1797,8 @@ 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); +void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, + union mysockaddr *dst, unsigned short port); #endif /* domain-match.c */ @@ -79,7 +79,8 @@ void dump_init(void) } } -void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst) +void dump_packet(int mask, void *packet, size_t len, + union mysockaddr *src, union mysockaddr *dst, unsigned short port) { struct ip ip; struct ip6_hdr ip6; @@ -101,7 +102,7 @@ void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, unio return; /* So wireshark can Id the packet. */ - udp.uh_sport = udp.uh_dport = htons(NAMESERVER_PORT); + udp.uh_sport = udp.uh_dport = htons(port); if (src) family = src->sa.sa_family; diff --git a/src/forward.c b/src/forward.c index d9633f5..c17541b 100644 --- a/src/forward.c +++ b/src/forward.c @@ -146,20 +146,6 @@ static void server_send(struct server *server, int fd, sa_len(&server->addr)))); } -#ifdef HAVE_DNSSEC -static void server_send_log(struct server *server, int fd, - const void *header, size_t plen, int dumpflags, - unsigned int logflags, char *name, char *arg, - unsigned short type) -{ -#ifdef HAVE_DUMPFILE - dump_packet(dumpflags, (void *)header, (size_t)plen, NULL, &server->addr); -#endif - log_query_mysockaddr(logflags, name, &server->addr, arg, type); - server_send(server, fd, header, plen, 0); -} -#endif - static int domain_no_rebind(char *domain) { struct rebind_domain *rbd; @@ -524,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); + dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &srv->addr, daemon->port); #endif /* Keep info in case we want to re-send this packet */ @@ -854,7 +840,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header, #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); + header, (size_t)plen, &forward->sentto->addr, NULL, daemon->port); #endif } @@ -963,9 +949,13 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header, if (option_bool(OPT_CONNTRACK)) set_outgoing_mark(orig, fd); #endif - server_send_log(server, fd, header, nn, DUMP_SEC_QUERY, - F_NOEXTRA | F_DNSSEC | F_SERVER, daemon->keyname, - STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0); + +#ifdef HAVE_DUMPFILE + dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr, daemon->port); +#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; } @@ -1057,7 +1047,7 @@ void reply_query(int fd, time_t now) #ifdef HAVE_DUMPFILE dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY, - (void *)header, n, &serveraddr, NULL); + (void *)header, n, &serveraddr, NULL, daemon->port); #endif /* log_query gets called indirectly all over the place, so @@ -1261,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); + dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source, daemon->port); #endif #if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS) @@ -1576,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); + dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL, daemon->port); #endif #ifdef HAVE_CONNTRACK @@ -1659,7 +1649,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); + dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, daemon->port); #endif send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, m, &source_addr, &dst_addr, if_index); @@ -1675,7 +1665,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); + dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, daemon->port); #endif #if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS) if (local_auth) @@ -1701,7 +1691,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); + dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, daemon->port); #endif #if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS) if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask)) diff --git a/src/rfc3315.c b/src/rfc3315.c index a286395..6c55672 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -2176,6 +2176,18 @@ void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, } } +#ifdef HAVE_DUMPFILE + { + union mysockaddr fromsock; + fromsock.in6.sin6_port = htons(DHCPV6_SERVER_PORT); + fromsock.in6.sin6_addr = from.addr6; + fromsock.sa.sa_family = AF_INET6; + 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); + } +#endif send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0); if (option_bool(OPT_LOG_OPTS)) @@ -95,6 +95,10 @@ void tftp_request(struct listener *listen, time_t now) if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2) return; + +#ifdef HAVE_DUMPFILE + dump_packet(DUMP_TFTP, (void *)packet, len, (union mysockaddr *)&peer, NULL, TFTP_PORT); +#endif /* Can always get recvd interface for IPv6 */ if (!check_dest) @@ -482,6 +486,10 @@ 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); +#endif if (is_err) free_transfer(transfer); @@ -600,6 +608,10 @@ void check_tftp_listeners(time_t now) prettyprint_addr(&peer, daemon->addrbuff); len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff, NULL); 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); +#endif } } } @@ -634,9 +646,14 @@ void check_tftp_listeners(time_t now) } if (len != 0) - send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), daemon->packet, len, - &transfer->peer, &transfer->source, transfer->if_index); - + { + 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); +#endif + } + if (endcon || len == 0) { strcpy(daemon->namebuff, transfer->file->filename); |