1 /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/icmp6.h>
23 static u32 packet_count;
24 static void do_dump_packet(int mask, void *packet, size_t len,
25 union mysockaddr *src, union mysockaddr *dst, int port, int proto);
27 /* https://wiki.wireshark.org/Development/LibpcapFileFormat */
29 u32 magic_number; /* magic number */
30 u16 version_major; /* major version number */
31 u16 version_minor; /* minor version number */
32 u32 thiszone; /* GMT to local correction */
33 u32 sigfigs; /* accuracy of timestamps */
34 u32 snaplen; /* max length of captured packets, in octets */
35 u32 network; /* data link type */
38 struct pcaprec_hdr_s {
39 u32 ts_sec; /* timestamp seconds */
40 u32 ts_usec; /* timestamp microseconds */
41 u32 incl_len; /* number of octets of packet saved in file */
42 u32 orig_len; /* actual length of packet */
49 struct pcap_hdr_s header;
50 struct pcaprec_hdr_s pcap_header;
54 if (stat(daemon->dump_file, &buf) == -1)
56 /* doesn't exist, create and add header */
57 header.magic_number = 0xa1b2c3d4;
58 header.version_major = 2;
59 header.version_minor = 4;
62 header.snaplen = daemon->edns_pktsz + 200; /* slop for IP/UDP headers */
63 header.network = 101; /* DLT_RAW http://www.tcpdump.org/linktypes.html */
65 if (errno != ENOENT ||
66 (daemon->dumpfd = creat(daemon->dump_file, S_IRUSR | S_IWUSR)) == -1 ||
67 !read_write(daemon->dumpfd, (void *)&header, sizeof(header), 0))
68 die(_("cannot create %s: %s"), daemon->dump_file, EC_FILE);
70 else if ((daemon->dumpfd = open(daemon->dump_file, O_APPEND | O_RDWR)) == -1 ||
71 !read_write(daemon->dumpfd, (void *)&header, sizeof(header), 1))
72 die(_("cannot access %s: %s"), daemon->dump_file, EC_FILE);
73 else if (header.magic_number != 0xa1b2c3d4)
74 die(_("bad header in %s"), daemon->dump_file, EC_FILE);
77 /* count existing records */
78 while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 1))
80 lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR);
86 void dump_packet_udp(int mask, void *packet, size_t len,
87 union mysockaddr *src, union mysockaddr *dst, int fd)
89 union mysockaddr fd_addr;
90 socklen_t addr_len = sizeof(fd_addr);
92 if (daemon->dumpfd != -1 && (mask & daemon->dump_mask))
94 /* if fd is negative it carries a port number (negated)
95 which we use as a source or destination when not otherwise
96 specified so wireshark can ID the packet.
97 If both src and dst are specified, set this to -1 to avoid
98 a spurious getsockname() call. */
99 int port = (fd < 0) ? -fd : -1;
101 /* fd >= 0 is a file descriptor and the address of that file descriptor is used
102 in place of a NULL src or dst. */
103 if (fd >= 0 && getsockname(fd, (struct sockaddr *)&fd_addr, &addr_len) != -1)
112 do_dump_packet(mask, packet, len, src, dst, port, IPPROTO_UDP);
116 void dump_packet_icmp(int mask, void *packet, size_t len,
117 union mysockaddr *src, union mysockaddr *dst)
119 if (daemon->dumpfd != -1 && (mask & daemon->dump_mask))
120 do_dump_packet(mask, packet, len, src, dst, -1, IPPROTO_ICMP);
123 static void do_dump_packet(int mask, void *packet, size_t len,
124 union mysockaddr *src, union mysockaddr *dst, int port, int proto)
130 u16 uh_sport; /* source port */
131 u16 uh_dport; /* destination port */
132 u16 uh_ulen; /* udp length */
133 u16 uh_sum; /* udp checksum */
135 struct pcaprec_hdr_s pcap_header;
142 /* if port != -1 it carries a port number
143 which we use as a source or destination when not otherwise
144 specified so wireshark can ID the packet.
145 If both src and dst are specified, set this to -1 to avoid
146 a spurious getsockname() call. */
147 udp.uh_sport = udp.uh_dport = htons(port < 0 ? 0 : port);
150 family = src->sa.sa_family;
152 family = dst->sa.sa_family;
154 if (family == AF_INET6)
158 memset(&ip6, 0, sizeof(ip6));
160 ip6.ip6_vfc = 6 << 4;
163 if ((ip6.ip6_nxt = proto) == IPPROTO_UDP)
164 ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
167 proto = ip6.ip6_nxt = IPPROTO_ICMPV6;
168 ip6.ip6_plen = htons(len);
173 memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ);
174 udp.uh_sport = src->in6.sin6_port;
179 memcpy(&ip6.ip6_dst, &dst->in6.sin6_addr, IN6ADDRSZ);
180 udp.uh_dport = dst->in6.sin6_port;
183 /* start UDP checksum */
184 for (sum = 0, i = 0; i < IN6ADDRSZ; i+=2)
186 sum += ntohs((ip6.ip6_src.s6_addr[i] << 8) + (ip6.ip6_src.s6_addr[i+1])) ;
187 sum += ntohs((ip6.ip6_dst.s6_addr[i] << 8) + (ip6.ip6_dst.s6_addr[i+1])) ;
194 memset(&ip, 0, sizeof(ip));
197 ip.ip_hl = sizeof(struct ip) / 4;
198 ip.ip_ttl = IPDEFTTL;
200 if ((ip.ip_p = proto) == IPPROTO_UDP)
201 ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len);
204 ip.ip_len = htons(sizeof(struct ip) + len);
205 proto = ip.ip_p = IPPROTO_ICMP;
210 ip.ip_src = src->in.sin_addr;
211 udp.uh_sport = src->in.sin_port;
216 ip.ip_dst = dst->in.sin_addr;
217 udp.uh_dport = dst->in.sin_port;
221 for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
222 sum += ((u16 *)&ip)[i];
224 sum = (sum & 0xffff) + (sum >> 16);
225 ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
227 /* start UDP/ICMP checksum */
228 sum = ip.ip_src.s_addr & 0xffff;
229 sum += (ip.ip_src.s_addr >> 16) & 0xffff;
230 sum += ip.ip_dst.s_addr & 0xffff;
231 sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
235 ((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
237 if (proto == IPPROTO_UDP)
239 /* Add Remaining part of the pseudoheader. Note that though the
240 IPv6 pseudoheader is very different to the IPv4 one, the
241 net result of this calculation is correct as long as the
242 packet length is less than 65536, which is fine for us. */
243 sum += htons(IPPROTO_UDP);
244 sum += htons(sizeof(struct udphdr) + len);
247 udp.uh_ulen = htons(sizeof(struct udphdr) + len);
249 for (i = 0; i < sizeof(struct udphdr)/2; i++)
250 sum += ((u16 *)&udp)[i];
251 for (i = 0; i < (len + 1) / 2; i++)
252 sum += ((u16 *)packet)[i];
254 sum = (sum & 0xffff) + (sum >> 16);
255 udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
257 pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
261 /* ICMP - ICMPv6 packet is a superset of ICMP */
262 struct icmp6_hdr *icmp = packet;
264 /* See comment in UDP code above. */
268 icmp->icmp6_cksum = 0;
269 for (i = 0; i < (len + 1) / 2; i++)
270 sum += ((u16 *)packet)[i];
272 sum = (sum & 0xffff) + (sum >> 16);
273 icmp->icmp6_cksum = (sum == 0xffff) ? sum : ~sum;
275 pcap_header.incl_len = pcap_header.orig_len = ipsz + len;
278 rc = gettimeofday(&time, NULL);
279 pcap_header.ts_sec = time.tv_sec;
280 pcap_header.ts_usec = time.tv_usec;
283 !read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) ||
284 !read_write(daemon->dumpfd, iphdr, ipsz, 0) ||
285 (proto == IPPROTO_UDP && !read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0)) ||
286 !read_write(daemon->dumpfd, (void *)packet, len, 0))
287 my_syslog(LOG_ERR, _("failed to write packet dump"));
288 else if (option_bool(OPT_EXTRALOG))
289 my_syslog(LOG_INFO, _("%u dumping packet %u mask 0x%04x"), daemon->log_display_id, ++packet_count, mask);
291 my_syslog(LOG_INFO, _("dumping packet %u mask 0x%04x"), ++packet_count, mask);