Annotation of embedaddon/dnsmasq/src/dump.c, revision 1.1.1.1

1.1       misho       1: /* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
                      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: 
                     21: static u32 packet_count;
                     22: 
                     23: /* https://wiki.wireshark.org/Development/LibpcapFileFormat */
                     24: struct pcap_hdr_s {
                     25:         u32 magic_number;   /* magic number */
                     26:         u16 version_major;  /* major version number */
                     27:         u16 version_minor;  /* minor version number */
                     28:         u32 thiszone;       /* GMT to local correction */
                     29:         u32 sigfigs;        /* accuracy of timestamps */
                     30:         u32 snaplen;        /* max length of captured packets, in octets */
                     31:         u32 network;        /* data link type */
                     32: };
                     33: 
                     34: struct pcaprec_hdr_s {
                     35:         u32 ts_sec;         /* timestamp seconds */
                     36:         u32 ts_usec;        /* timestamp microseconds */
                     37:         u32 incl_len;       /* number of octets of packet saved in file */
                     38:         u32 orig_len;       /* actual length of packet */
                     39: };
                     40: 
                     41: 
                     42: void dump_init(void)
                     43: {
                     44:   struct stat buf;
                     45:   struct pcap_hdr_s header;
                     46:   struct pcaprec_hdr_s pcap_header;
                     47: 
                     48:   packet_count = 0;
                     49:   
                     50:   if (stat(daemon->dump_file, &buf) == -1)
                     51:     {
                     52:       /* doesn't exist, create and add header */
                     53:       header.magic_number = 0xa1b2c3d4;
                     54:       header.version_major = 2;
                     55:       header.version_minor = 4;
                     56:       header.thiszone = 0;
                     57:       header.sigfigs = 0;
                     58:       header.snaplen = daemon->edns_pktsz + 200; /* slop for IP/UDP headers */
                     59:       header.network = 101; /* DLT_RAW http://www.tcpdump.org/linktypes.html */
                     60: 
                     61:       if (errno != ENOENT ||
                     62:          (daemon->dumpfd = creat(daemon->dump_file, S_IRUSR | S_IWUSR)) == -1 ||
                     63:          !read_write(daemon->dumpfd, (void *)&header, sizeof(header), 0))
                     64:        die(_("cannot create %s: %s"), daemon->dump_file, EC_FILE);
                     65:     }
                     66:   else if ((daemon->dumpfd = open(daemon->dump_file, O_APPEND | O_RDWR)) == -1 ||
                     67:           !read_write(daemon->dumpfd, (void *)&header, sizeof(header), 1))
                     68:     die(_("cannot access %s: %s"), daemon->dump_file, EC_FILE);
                     69:   else if (header.magic_number != 0xa1b2c3d4)
                     70:     die(_("bad header in %s"), daemon->dump_file, EC_FILE);
                     71:   else
                     72:     {
                     73:       /* count existing records */
                     74:       while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 1))
                     75:        {
                     76:          lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR);
                     77:          packet_count++;
                     78:        }
                     79:     }
                     80: }
                     81: 
                     82: void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst)
                     83: {
                     84:   struct ip ip;
                     85:   struct ip6_hdr ip6;
                     86:   int family;
                     87:   struct udphdr {
                     88:     u16 uh_sport;               /* source port */
                     89:     u16 uh_dport;               /* destination port */
                     90:     u16 uh_ulen;                /* udp length */
                     91:     u16 uh_sum;                 /* udp checksum */
                     92:   } udp;
                     93:   struct pcaprec_hdr_s pcap_header;
                     94:   struct timeval time;
                     95:   u32 i, sum;
                     96:   void *iphdr;
                     97:   size_t ipsz;
                     98:   int rc;
                     99:   
                    100:   if (daemon->dumpfd == -1 || !(mask & daemon->dump_mask))
                    101:     return;
                    102:   
                    103:   /* So wireshark can Id the packet. */
                    104:   udp.uh_sport = udp.uh_dport = htons(NAMESERVER_PORT);
                    105: 
                    106:   if (src)
                    107:     family = src->sa.sa_family;
                    108:   else
                    109:     family = dst->sa.sa_family;
                    110: 
                    111:   if (family == AF_INET6)
                    112:     {
                    113:       iphdr = &ip6;
                    114:       ipsz = sizeof(ip6);
                    115:       memset(&ip6, 0, sizeof(ip6));
                    116:       
                    117:       ip6.ip6_vfc = 6 << 4;
                    118:       ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
                    119:       ip6.ip6_nxt = IPPROTO_UDP;
                    120:       ip6.ip6_hops = 64;
                    121: 
                    122:       if (src)
                    123:        {
                    124:          memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ);
                    125:          udp.uh_sport = src->in6.sin6_port;
                    126:        }
                    127:       
                    128:       if (dst)
                    129:        {
                    130:          memcpy(&ip6.ip6_dst, &dst->in6.sin6_addr, IN6ADDRSZ);
                    131:          udp.uh_dport = dst->in6.sin6_port;
                    132:        }
                    133:             
                    134:       /* start UDP checksum */
                    135:       for (sum = 0, i = 0; i < IN6ADDRSZ; i+=2)
                    136:        {
                    137:          sum += ip6.ip6_src.s6_addr[i] + (ip6.ip6_src.s6_addr[i+1] << 8) ;
                    138:          sum += ip6.ip6_dst.s6_addr[i] + (ip6.ip6_dst.s6_addr[i+1] << 8) ;
                    139:          
                    140:        }
                    141:     }
                    142:   else
                    143:     {
                    144:       iphdr = &ip;
                    145:       ipsz = sizeof(ip);
                    146:       memset(&ip, 0, sizeof(ip));
                    147:       
                    148:       ip.ip_v = IPVERSION;
                    149:       ip.ip_hl = sizeof(struct ip) / 4;
                    150:       ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len); 
                    151:       ip.ip_ttl = IPDEFTTL;
                    152:       ip.ip_p = IPPROTO_UDP;
                    153:       
                    154:       if (src)
                    155:        {
                    156:          ip.ip_src = src->in.sin_addr;
                    157:          udp.uh_sport = src->in.sin_port;
                    158:        }
                    159: 
                    160:       if (dst)
                    161:        {
                    162:          ip.ip_dst = dst->in.sin_addr;
                    163:          udp.uh_dport = dst->in.sin_port;
                    164:        }
                    165:       
                    166:       ip.ip_sum = 0;
                    167:       for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
                    168:        sum += ((u16 *)&ip)[i];
                    169:       while (sum >> 16)
                    170:        sum = (sum & 0xffff) + (sum >> 16);  
                    171:       ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
                    172:       
                    173:       /* start UDP checksum */
                    174:       sum = ip.ip_src.s_addr & 0xffff;
                    175:       sum += (ip.ip_src.s_addr >> 16) & 0xffff;
                    176:       sum += ip.ip_dst.s_addr & 0xffff;
                    177:       sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
                    178:     }
                    179:   
                    180:   if (len & 1)
                    181:     ((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
                    182: 
                    183:   udp.uh_sum = 0;
                    184:   udp.uh_ulen = htons(sizeof(struct udphdr) + len);
                    185:   sum += htons(IPPROTO_UDP);
                    186:   sum += htons(sizeof(struct udphdr) + len);
                    187:   for (i = 0; i < sizeof(struct udphdr)/2; i++)
                    188:     sum += ((u16 *)&udp)[i];
                    189:   for (i = 0; i < (len + 1) / 2; i++)
                    190:     sum += ((u16 *)packet)[i];
                    191:   while (sum >> 16)
                    192:     sum = (sum & 0xffff) + (sum >> 16);
                    193:   udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
                    194: 
                    195:   rc = gettimeofday(&time, NULL);
                    196:   pcap_header.ts_sec = time.tv_sec;
                    197:   pcap_header.ts_usec = time.tv_usec;
                    198:   pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
                    199:   
                    200:   if (rc == -1 ||
                    201:       !read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) ||
                    202:       !read_write(daemon->dumpfd, iphdr, ipsz, 0) ||
                    203:       !read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0) ||
                    204:       !read_write(daemon->dumpfd, (void *)packet, len, 0))
                    205:     my_syslog(LOG_ERR, _("failed to write packet dump"));
                    206:   else
                    207:     my_syslog(LOG_INFO, _("dumping UDP packet %u mask 0x%04x"), ++packet_count, mask);
                    208: 
                    209: }
                    210: 
                    211: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>