Annotation of embedaddon/dnsmasq/src/dump.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
1.1 misho 2:
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.
7:
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.
12:
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/>.
15: */
16:
17: #include "dnsmasq.h"
18:
19: #ifdef HAVE_DUMPFILE
20:
1.1.1.2 ! misho 21: #include <netinet/icmp6.h>
! 22:
1.1 misho 23: static u32 packet_count;
1.1.1.2 ! misho 24: static void do_dump_packet(int mask, void *packet, size_t len,
! 25: union mysockaddr *src, union mysockaddr *dst, int port, int proto);
1.1 misho 26:
27: /* https://wiki.wireshark.org/Development/LibpcapFileFormat */
28: struct pcap_hdr_s {
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 */
36: };
37:
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 */
43: };
44:
45:
46: void dump_init(void)
47: {
48: struct stat buf;
49: struct pcap_hdr_s header;
50: struct pcaprec_hdr_s pcap_header;
51:
52: packet_count = 0;
53:
54: if (stat(daemon->dump_file, &buf) == -1)
55: {
56: /* doesn't exist, create and add header */
57: header.magic_number = 0xa1b2c3d4;
58: header.version_major = 2;
59: header.version_minor = 4;
60: header.thiszone = 0;
61: header.sigfigs = 0;
62: header.snaplen = daemon->edns_pktsz + 200; /* slop for IP/UDP headers */
63: header.network = 101; /* DLT_RAW http://www.tcpdump.org/linktypes.html */
64:
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);
69: }
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);
75: else
76: {
77: /* count existing records */
78: while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 1))
79: {
80: lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR);
81: packet_count++;
82: }
83: }
84: }
85:
1.1.1.2 ! misho 86: void dump_packet_udp(int mask, void *packet, size_t len,
! 87: union mysockaddr *src, union mysockaddr *dst, int fd)
! 88: {
! 89: union mysockaddr fd_addr;
! 90: socklen_t addr_len = sizeof(fd_addr);
! 91:
! 92: if (daemon->dumpfd != -1 && (mask & daemon->dump_mask))
! 93: {
! 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;
! 100:
! 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)
! 104: {
! 105: if (!src)
! 106: src = &fd_addr;
! 107:
! 108: if (!dst)
! 109: dst = &fd_addr;
! 110: }
! 111:
! 112: do_dump_packet(mask, packet, len, src, dst, port, IPPROTO_UDP);
! 113: }
! 114: }
! 115:
! 116: void dump_packet_icmp(int mask, void *packet, size_t len,
! 117: union mysockaddr *src, union mysockaddr *dst)
! 118: {
! 119: if (daemon->dumpfd != -1 && (mask & daemon->dump_mask))
! 120: do_dump_packet(mask, packet, len, src, dst, -1, IPPROTO_ICMP);
! 121: }
! 122:
! 123: static void do_dump_packet(int mask, void *packet, size_t len,
! 124: union mysockaddr *src, union mysockaddr *dst, int port, int proto)
1.1 misho 125: {
126: struct ip ip;
127: struct ip6_hdr ip6;
128: int family;
129: struct udphdr {
130: u16 uh_sport; /* source port */
131: u16 uh_dport; /* destination port */
132: u16 uh_ulen; /* udp length */
133: u16 uh_sum; /* udp checksum */
134: } udp;
135: struct pcaprec_hdr_s pcap_header;
136: struct timeval time;
137: u32 i, sum;
138: void *iphdr;
139: size_t ipsz;
140: int rc;
1.1.1.2 ! misho 141:
! 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);
1.1 misho 148:
149: if (src)
150: family = src->sa.sa_family;
151: else
152: family = dst->sa.sa_family;
153:
154: if (family == AF_INET6)
155: {
156: iphdr = &ip6;
157: ipsz = sizeof(ip6);
158: memset(&ip6, 0, sizeof(ip6));
159:
160: ip6.ip6_vfc = 6 << 4;
161: ip6.ip6_hops = 64;
162:
1.1.1.2 ! misho 163: if ((ip6.ip6_nxt = proto) == IPPROTO_UDP)
! 164: ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
! 165: else
! 166: {
! 167: proto = ip6.ip6_nxt = IPPROTO_ICMPV6;
! 168: ip6.ip6_plen = htons(len);
! 169: }
! 170:
1.1 misho 171: if (src)
172: {
173: memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ);
174: udp.uh_sport = src->in6.sin6_port;
175: }
176:
177: if (dst)
178: {
179: memcpy(&ip6.ip6_dst, &dst->in6.sin6_addr, IN6ADDRSZ);
180: udp.uh_dport = dst->in6.sin6_port;
181: }
182:
183: /* start UDP checksum */
184: for (sum = 0, i = 0; i < IN6ADDRSZ; i+=2)
185: {
1.1.1.2 ! misho 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])) ;
1.1 misho 188: }
189: }
190: else
191: {
192: iphdr = &ip;
193: ipsz = sizeof(ip);
194: memset(&ip, 0, sizeof(ip));
195:
196: ip.ip_v = IPVERSION;
197: ip.ip_hl = sizeof(struct ip) / 4;
198: ip.ip_ttl = IPDEFTTL;
1.1.1.2 ! misho 199:
! 200: if ((ip.ip_p = proto) == IPPROTO_UDP)
! 201: ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len);
! 202: else
! 203: {
! 204: ip.ip_len = htons(sizeof(struct ip) + len);
! 205: proto = ip.ip_p = IPPROTO_ICMP;
! 206: }
1.1 misho 207:
208: if (src)
209: {
210: ip.ip_src = src->in.sin_addr;
211: udp.uh_sport = src->in.sin_port;
212: }
213:
214: if (dst)
215: {
216: ip.ip_dst = dst->in.sin_addr;
217: udp.uh_dport = dst->in.sin_port;
218: }
219:
220: ip.ip_sum = 0;
221: for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
222: sum += ((u16 *)&ip)[i];
223: while (sum >> 16)
224: sum = (sum & 0xffff) + (sum >> 16);
225: ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
226:
1.1.1.2 ! misho 227: /* start UDP/ICMP checksum */
1.1 misho 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;
232: }
233:
234: if (len & 1)
235: ((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
236:
1.1.1.2 ! misho 237: if (proto == IPPROTO_UDP)
! 238: {
! 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);
! 245:
! 246: udp.uh_sum = 0;
! 247: udp.uh_ulen = htons(sizeof(struct udphdr) + len);
! 248:
! 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];
! 253: while (sum >> 16)
! 254: sum = (sum & 0xffff) + (sum >> 16);
! 255: udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
1.1 misho 256:
1.1.1.2 ! misho 257: pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
! 258: }
! 259: else
! 260: {
! 261: /* ICMP - ICMPv6 packet is a superset of ICMP */
! 262: struct icmp6_hdr *icmp = packet;
! 263:
! 264: /* See comment in UDP code above. */
! 265: sum += htons(proto);
! 266: sum += htons(len);
! 267:
! 268: icmp->icmp6_cksum = 0;
! 269: for (i = 0; i < (len + 1) / 2; i++)
! 270: sum += ((u16 *)packet)[i];
! 271: while (sum >> 16)
! 272: sum = (sum & 0xffff) + (sum >> 16);
! 273: icmp->icmp6_cksum = (sum == 0xffff) ? sum : ~sum;
! 274:
! 275: pcap_header.incl_len = pcap_header.orig_len = ipsz + len;
! 276: }
! 277:
1.1 misho 278: rc = gettimeofday(&time, NULL);
279: pcap_header.ts_sec = time.tv_sec;
280: pcap_header.ts_usec = time.tv_usec;
281:
282: if (rc == -1 ||
283: !read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) ||
284: !read_write(daemon->dumpfd, iphdr, ipsz, 0) ||
1.1.1.2 ! misho 285: (proto == IPPROTO_UDP && !read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0)) ||
1.1 misho 286: !read_write(daemon->dumpfd, (void *)packet, len, 0))
287: my_syslog(LOG_ERR, _("failed to write packet dump"));
1.1.1.2 ! misho 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);
1.1 misho 290: else
1.1.1.2 ! misho 291: my_syslog(LOG_INFO, _("dumping packet %u mask 0x%04x"), ++packet_count, mask);
1.1 misho 292:
293: }
294:
295: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>