File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / dump.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:56:46 2021 UTC (3 years, 3 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    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>