File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / dump.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:02:07 2023 UTC (9 months, 1 week ago) by misho
Branches: dnsmasq, MAIN
CVS tags: v8_2p1, HEAD
Version 8.2p1

    1: /* dnsmasq is Copyright (c) 2000-2022 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: #include <netinet/icmp6.h>
   22: 
   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);
   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: 
   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)
  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;
  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);
  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: 
  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:       
  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: 	{
  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])) ; 
  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;
  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: 	}
  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:       
  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;
  232:     }
  233:   
  234:   if (len & 1)
  235:     ((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
  236: 
  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;
  256: 
  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:     
  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) ||
  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);
  290:   else
  291:     my_syslog(LOG_INFO, _("dumping packet %u mask 0x%04x"), ++packet_count, mask);
  292: 
  293: }
  294: 
  295: #endif

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