Commit 6b173352 authored by Simon Kelley's avatar Simon Kelley

Add packet-dump debugging facility.

parent 07ed585c
...@@ -17,6 +17,12 @@ version 2.80 ...@@ -17,6 +17,12 @@ version 2.80
Fix DHCP broken-ness when --no-ping AND --dhcp-sequential-ip Fix DHCP broken-ness when --no-ping AND --dhcp-sequential-ip
are set. Thanks to Daniel Miess for help with this. are set. Thanks to Daniel Miess for help with this.
Add a facilty to store DNS packets sent/recieved in a
pcap-format file for later debugging. The file location
is given by the --dumpfile option, and a bitmap controlling
which packets should be dumped is given by the --dumpmask
option.
version 2.79 version 2.79
Fix parsing of CNAME arguments, which are confused by extra spaces. Fix parsing of CNAME arguments, which are confused by extra spaces.
......
...@@ -76,7 +76,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \ ...@@ -76,7 +76,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \ helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \ dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \ domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
poll.o rrfilter.o edns0.o arp.o crypto.o poll.o rrfilter.o edns0.o arp.o crypto.o dump.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h dns-protocol.h radv-protocol.h ip6addr.h
......
...@@ -10,7 +10,8 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \ ...@@ -10,7 +10,8 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \ dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c auth.c ipset.c domain.c \ radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c \ dnssec.c dnssec-openssl.c blockdata.c tables.c \
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c crypto.c loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
crypto.c dump.c
LOCAL_MODULE := dnsmasq LOCAL_MODULE := dnsmasq
......
...@@ -647,6 +647,13 @@ V4 mapped IPv6 addresses, which have a representation like ::ffff:1.2.3.4 are ha ...@@ -647,6 +647,13 @@ V4 mapped IPv6 addresses, which have a representation like ::ffff:1.2.3.4 are ha
The address range can be of the form The address range can be of the form
<ip address>,<ip address> or <ip address>/<netmask> in both forms of the option. <ip address>,<ip address> or <ip address>/<netmask> in both forms of the option.
.TP .TP
.B --dumpfile=<path/to/file>
Specify the location of a pcap-format file which dnsmasq uses to dump copies of network packets for debugging purposes. If the file exists when dnsmasq starts, it is not deleted; new packets are added to the end.
.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.
.TP
.B --add-mac[=base64|text] .B --add-mac[=base64|text]
Add the MAC address of the requestor to DNS queries which are Add the MAC address of the requestor to DNS queries which are
forwarded upstream. This may be used to DNS filtering by the upstream forwarded upstream. This may be used to DNS filtering by the upstream
......
...@@ -117,6 +117,9 @@ HAVE_AUTH ...@@ -117,6 +117,9 @@ HAVE_AUTH
HAVE_DNSSEC HAVE_DNSSEC
include DNSSEC validator. include DNSSEC validator.
HAVE_DUMPFILE
include code to dump packets to a libpcap-format file for debugging.
HAVE_LOOP HAVE_LOOP
include functionality to probe for and remove DNS forwarding loops. include functionality to probe for and remove DNS forwarding loops.
...@@ -132,6 +135,7 @@ NO_DHCP6 ...@@ -132,6 +135,7 @@ NO_DHCP6
NO_SCRIPT NO_SCRIPT
NO_LARGEFILE NO_LARGEFILE
NO_AUTH NO_AUTH
NO_DUMPFILE
NO_INOTIFY NO_INOTIFY
these are available to explicitly disable compile time options which would these are available to explicitly disable compile time options which would
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
...@@ -164,6 +168,7 @@ RESOLVFILE ...@@ -164,6 +168,7 @@ RESOLVFILE
#define HAVE_AUTH #define HAVE_AUTH
#define HAVE_IPSET #define HAVE_IPSET
#define HAVE_LOOP #define HAVE_LOOP
#define HAVE_DUMPFILE
/* Build options which require external libraries. /* Build options which require external libraries.
...@@ -363,6 +368,10 @@ HAVE_SOCKADDR_SA_LEN ...@@ -363,6 +368,10 @@ HAVE_SOCKADDR_SA_LEN
#undef HAVE_LOOP #undef HAVE_LOOP
#endif #endif
#ifdef NO_DUMPFILE
#undef HAVE_DUMPFILE
#endif
#if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY) #if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY)
#define HAVE_INOTIFY #define HAVE_INOTIFY
#endif #endif
...@@ -451,8 +460,11 @@ static char *compile_opts = ...@@ -451,8 +460,11 @@ static char *compile_opts =
#ifndef HAVE_INOTIFY #ifndef HAVE_INOTIFY
"no-" "no-"
#endif #endif
"inotify"; "inotify "
#ifndef HAVE_DUMPFILE
"no-"
#endif
"dumpfile";
#endif #endif
......
...@@ -366,7 +366,16 @@ int main (int argc, char **argv) ...@@ -366,7 +366,16 @@ int main (int argc, char **argv)
else else
daemon->inotifyfd = -1; daemon->inotifyfd = -1;
#endif #endif
if (daemon->dump_file)
#ifdef HAVE_DUMPFILE
dump_init();
else
daemon->dumpfd = -1;
#else
die(_("Packet dumps not available: set HAVE_DUMP in src/config.h"), NULL, EC_BADCONF);
#endif
if (option_bool(OPT_DBUS)) if (option_bool(OPT_DBUS))
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
{ {
...@@ -1424,6 +1433,11 @@ static void async_event(int pipe, time_t now) ...@@ -1424,6 +1433,11 @@ static void async_event(int pipe, time_t now)
if (daemon->runfile) if (daemon->runfile)
unlink(daemon->runfile); unlink(daemon->runfile);
#ifdef HAVE_DUMPFILE
if (daemon->dumpfd != -1)
close(daemon->dumpfd);
#endif
my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM")); my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
flush_log(); flush_log();
......
...@@ -119,6 +119,9 @@ typedef unsigned long long u64; ...@@ -119,6 +119,9 @@ typedef unsigned long long u64;
#include <net/if_arp.h> #include <net/if_arp.h>
#include <netinet/in_systm.h> #include <netinet/in_systm.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#ifdef HAVE_IPV6
#include <netinet/ip6.h>
#endif
#include <netinet/ip_icmp.h> #include <netinet/ip_icmp.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <syslog.h> #include <syslog.h>
...@@ -598,6 +601,16 @@ struct hostsfile { ...@@ -598,6 +601,16 @@ struct hostsfile {
unsigned int index; /* matches to cache entries for logging */ unsigned int index; /* matches to cache entries for logging */
}; };
/* 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
/* DNSSEC status values. */ /* DNSSEC status values. */
#define STAT_SECURE 1 #define STAT_SECURE 1
...@@ -1020,14 +1033,14 @@ extern struct daemon { ...@@ -1020,14 +1033,14 @@ extern struct daemon {
unsigned int duid_enterprise, duid_config_len; unsigned int duid_enterprise, duid_config_len;
unsigned char *duid_config; unsigned char *duid_config;
char *dbus_name; char *dbus_name;
char *dump_file;
int dump_mask;
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry; unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
#ifdef OPTION6_PREFIX_CLASS #ifdef OPTION6_PREFIX_CLASS
struct prefix_class *prefix_classes; struct prefix_class *prefix_classes;
#endif #endif
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
struct ds_config *ds; struct ds_config *ds;
int dnssec_no_time_check;
int back_to_the_future;
char *timestamp_file; char *timestamp_file;
#endif #endif
...@@ -1040,6 +1053,8 @@ extern struct daemon { ...@@ -1040,6 +1053,8 @@ extern struct daemon {
char *workspacename; /* ditto */ char *workspacename; /* ditto */
char *rr_status; /* flags for individual RRs */ char *rr_status; /* flags for individual RRs */
int rr_status_sz; int rr_status_sz;
int dnssec_no_time_check;
int back_to_the_future;
#endif #endif
unsigned int local_answer, queries_forwarded, auth_answer; unsigned int local_answer, queries_forwarded, auth_answer;
struct frec *frec_list; struct frec *frec_list;
...@@ -1094,6 +1109,10 @@ extern struct daemon { ...@@ -1094,6 +1109,10 @@ extern struct daemon {
char *addrbuff; char *addrbuff;
char *addrbuff2; /* only allocated when OPT_EXTRALOG */ char *addrbuff2; /* only allocated when OPT_EXTRALOG */
#ifdef HAVE_DUMPFILE
/* file for packet dumps. */
int dumpfd;
#endif
} *daemon; } *daemon;
/* cache.c */ /* cache.c */
...@@ -1588,3 +1607,9 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe ...@@ -1588,3 +1607,9 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
/* arp.c */ /* arp.c */
int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now); int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now);
int do_arp_script_run(void); 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);
#endif
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
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
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_DUMPFILE
static u32 packet_count;
/* https://wiki.wireshark.org/Development/LibpcapFileFormat */
struct pcap_hdr_s {
u32 magic_number; /* magic number */
u16 version_major; /* major version number */
u16 version_minor; /* minor version number */
u32 thiszone; /* GMT to local correction */
u32 sigfigs; /* accuracy of timestamps */
u32 snaplen; /* max length of captured packets, in octets */
u32 network; /* data link type */
};
struct pcaprec_hdr_s {
u32 ts_sec; /* timestamp seconds */
u32 ts_usec; /* timestamp microseconds */
u32 incl_len; /* number of octets of packet saved in file */
u32 orig_len; /* actual length of packet */
};
void dump_init(void)
{
struct stat buf;
struct pcap_hdr_s header;
struct pcaprec_hdr_s pcap_header;
packet_count = 0;
if (stat(daemon->dump_file, &buf) == -1)
{
/* doesn't exist, create and add header */
header.magic_number = 0xa1b2c3d4;
header.version_major = 2;
header.version_minor = 4;
header.thiszone = 0;
header.sigfigs = 0;
header.snaplen = daemon->edns_pktsz + 200; /* slop for IP/UDP headers */
header.network = 101; /* DLT_RAW http://www.tcpdump.org/linktypes.html */
if (errno != ENOENT ||
(daemon->dumpfd = creat(daemon->dump_file, S_IRUSR | S_IWUSR)) == -1 ||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), 0))
die(_("cannot create %s: %s"), daemon->dump_file, EC_FILE);
}
else if ((daemon->dumpfd = open(daemon->dump_file, O_APPEND | O_RDWR)) == -1 ||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), 1) ||
header.magic_number != 0xa1b2c3d4)
die(_("cannot access %s: %s"), daemon->dump_file, EC_FILE);
else
{
/* count existing records */
while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 1))
{
lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR);
packet_count++;
}
}
}
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst)
{
struct ip ip;
#ifdef HAVE_IPV6
struct ip6_hdr ip6;
int family;
#endif
struct udphdr {
u16 uh_sport; /* source port */
u16 uh_dport; /* destination port */
u16 uh_ulen; /* udp length */
u16 uh_sum; /* udp checksum */
} udp;
struct pcaprec_hdr_s pcap_header;
struct timeval time;
u32 i, sum;
void *iphdr;
size_t ipsz;
int rc;
if (daemon->dumpfd == -1 || !(mask & daemon->dump_mask))
return;
/* So wireshark can Id the packet. */
udp.uh_sport = udp.uh_dport = htons(NAMESERVER_PORT);
#ifdef HAVE_IPV6
if (src)
family = src->sa.sa_family;
else
family = dst->sa.sa_family;
if (family == AF_INET6)
{
iphdr = &ip6;
ipsz = sizeof(ip6);
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 (src)
{
memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ);
udp.uh_sport = src->in6.sin6_port;
}
if (dst)
{
memcpy(&ip6.ip6_dst, &dst->in6.sin6_addr, IN6ADDRSZ);
udp.uh_dport = dst->in6.sin6_port;
}
/* start UDP checksum */
for (sum = 0, i = 0; i < IN6ADDRSZ; i++)
sum += ((u16 *)&ip6.ip6_src)[i];
}
else
#endif
{
iphdr = &ip;
ipsz = sizeof(ip);
memset(&ip, 0, sizeof(ip));
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 (src)
{
ip.ip_src = src->in.sin_addr;
udp.uh_sport = src->in.sin_port;
}
if (dst)
{
ip.ip_dst = dst->in.sin_addr;
udp.uh_dport = dst->in.sin_port;
}
ip.ip_sum = 0;
for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
sum += ((u16 *)&ip)[i];
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
/* start UDP checksum */
sum = ip.ip_src.s_addr & 0xffff;
sum += (ip.ip_src.s_addr >> 16) & 0xffff;
sum += ip.ip_dst.s_addr & 0xffff;
sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
}
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;
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) ||
!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);
}
#endif
...@@ -508,6 +508,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -508,6 +508,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (errno == 0) if (errno == 0)
{ {
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &start->addr);
#endif
/* Keep info in case we want to re-send this packet */ /* Keep info in case we want to re-send this packet */
daemon->srv_save = start; daemon->srv_save = start;
daemon->packet_len = plen; daemon->packet_len = plen;
...@@ -769,7 +773,7 @@ void reply_query(int fd, int family, time_t now) ...@@ -769,7 +773,7 @@ void reply_query(int fd, int family, time_t now)
#endif #endif
header = (struct dns_header *)daemon->packet; header = (struct dns_header *)daemon->packet;
if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR)) if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
return; return;
...@@ -796,6 +800,12 @@ void reply_query(int fd, int family, time_t now) ...@@ -796,6 +800,12 @@ void reply_query(int fd, int family, time_t now)
if (!(forward = lookup_frec(ntohs(header->id), hash))) if (!(forward = lookup_frec(ntohs(header->id), hash)))
return; return;
#ifdef HAVE_DUMPFILE
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
(void *)header, n, &serveraddr, NULL);
#endif
/* log_query gets called indirectly all over the place, so /* log_query gets called indirectly all over the place, so
pass these in global variables - sorry. */ pass these in global variables - sorry. */
daemon->log_display_id = forward->log_id; daemon->log_display_id = forward->log_id;
...@@ -934,6 +944,11 @@ void reply_query(int fd, int family, time_t now) ...@@ -934,6 +944,11 @@ void reply_query(int fd, int family, time_t now)
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
!option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC), !option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
NULL, NULL); NULL, NULL);
#ifdef HAVE_DUMPFILE
if (status == STAT_BOGUS)
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
header, (size_t)n, &serveraddr, NULL);
#endif
} }
/* Can't validate, as we're missing key data. Put this /* Can't validate, as we're missing key data. Put this
...@@ -1060,6 +1075,11 @@ void reply_query(int fd, int family, time_t now) ...@@ -1060,6 +1075,11 @@ void reply_query(int fd, int family, time_t now)
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
} }
#endif #endif
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr);
#endif
while (retry_send(sendto(fd, (char *)header, nn, 0, while (retry_send(sendto(fd, (char *)header, nn, 0,
&server->addr.sa, &server->addr.sa,
sa_len(&server->addr)))); sa_len(&server->addr))));
...@@ -1114,8 +1134,8 @@ void reply_query(int fd, int family, time_t now) ...@@ -1114,8 +1134,8 @@ void reply_query(int fd, int family, time_t now)
bogusanswer = 1; bogusanswer = 1;
} }
} }
#endif #endif
/* restore CD bit to the value in the query */ /* restore CD bit to the value in the query */
if (forward->flags & FREC_CHECKING_DISABLED) if (forward->flags & FREC_CHECKING_DISABLED)
header->hb4 |= HB4_CD; header->hb4 |= HB4_CD;
...@@ -1141,6 +1161,11 @@ void reply_query(int fd, int family, time_t now) ...@@ -1141,6 +1161,11 @@ void reply_query(int fd, int family, time_t now)
nn = resize_packet(header, nn, NULL, 0); nn = resize_packet(header, nn, NULL, 0);
} }
#endif #endif
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &forward->source);
#endif
send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn, send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
&forward->source, &forward->dest, forward->iface); &forward->source, &forward->dest, forward->iface);
} }
...@@ -1394,7 +1419,11 @@ void receive_query(struct listener *listen, time_t now) ...@@ -1394,7 +1419,11 @@ void receive_query(struct listener *listen, time_t now)
pass these in global variables - sorry. */ pass these in global variables - sorry. */
daemon->log_display_id = ++daemon->log_id; daemon->log_display_id = ++daemon->log_id;
daemon->log_source_addr = &source_addr; daemon->log_source_addr = &source_addr;
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
#endif
if (extract_request(header, (size_t)n, daemon->namebuff, &type)) if (extract_request(header, (size_t)n, daemon->namebuff, &type))
{ {
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
......
...@@ -161,6 +161,8 @@ struct myoption { ...@@ -161,6 +161,8 @@ struct myoption {
#define LOPT_TFTP_MTU 349 #define LOPT_TFTP_MTU 349
#define LOPT_REPLY_DELAY 350 #define LOPT_REPLY_DELAY 350
#define LOPT_RAPID_COMMIT 351 #define LOPT_RAPID_COMMIT 351
#define LOPT_DUMPFILE 352
#define LOPT_DUMPMASK 353
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
...@@ -327,6 +329,8 @@ static const struct myoption opts[] = ...@@ -327,6 +329,8 @@ static const struct myoption opts[] =
{ "dhcp-ttl", 1, 0 , LOPT_DHCPTTL }, { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
{ "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY }, { "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
{ "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT }, { "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT },
{ "dumpfile", 1, 0, LOPT_DUMPFILE },
{ "dumpmask", 1, 0, LOPT_DUMPMASK },
{ NULL, 0, 0, 0 } { NULL, 0, 0, 0 }
}; };
...@@ -500,6 +504,8 @@ static struct { ...@@ -500,6 +504,8 @@ static struct {
{ LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL }, { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
{ LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL }, { LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL },
{ LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL }, { LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL },
{ LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
{ LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
{ 0, 0, NULL, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
...@@ -1811,6 +1817,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -1811,6 +1817,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(_("bad MX target")); ret_err(_("bad MX target"));
break; break;
case LOPT_DUMPFILE: /* --dumpfile */
daemon->dump_file = opt_string_alloc(arg);
break;
case LOPT_DUMPMASK: /* --dumpmask */
daemon->dump_mask = strtol(arg, NULL, 0);
break;
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
case 'l': /* --dhcp-leasefile */ case 'l': /* --dhcp-leasefile */
daemon->lease_file = opt_string_alloc(arg); daemon->lease_file = opt_string_alloc(arg);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment