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>