summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2022-01-29 15:55:04 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2022-01-29 15:55:04 +0000
commitfc664d114d6e11ced4912b746f18d543f662066b (patch)
treea63e55fe3a3d0074cc7fb79737b42b3b78bb62c0
parentc6d4c33d612c26f7d7518bef301a448a143b0a58 (diff)
downloaddnsmasq-fc664d114d6e11ced4912b746f18d543f662066b.tar.gz
Extend packet-dump system to DHCP and TFTP.
-rw-r--r--man/dnsmasq.82
-rw-r--r--src/dhcp.c35
-rw-r--r--src/dhcp6.c33
-rw-r--r--src/dnsmasq.h22
-rw-r--r--src/dump.c5
-rw-r--r--src/forward.c40
-rw-r--r--src/rfc3315.c12
-rw-r--r--src/tftp.c23
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
diff --git a/src/dhcp.c b/src/dhcp.c
index cdea79e..de766c1 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -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 */
diff --git a/src/dump.c b/src/dump.c
index 14365d8..4aae008 100644
--- a/src/dump.c
+++ b/src/dump.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))
diff --git a/src/tftp.c b/src/tftp.c
index b82d89d..bdf37a3 100644
--- a/src/tftp.c
+++ b/src/tftp.c
@@ -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);