C   24
dnsudp
Guest on 16th March 2023 01:23:56 PM


  1. include  <stdio.h>
  2. #include  <sys/types.h>
  3. #include  <sys/socket.h>
  4. #include  <netinet/in.h>
  5. #include  <arpa/inet.h>
  6.  
  7. #include  <stdio.h>
  8. #include  <strings.h> // bzero
  9. #include  <string.h>  // strncpy
  10. #include  <stdlib.h>  // exit
  11. #include  <unistd.h>  // close
  12.  
  13. #include <stdint.h>   // uint8_t
  14.  
  15. int print_dns_name(char *, char *);
  16.  
  17. #define SERV_PORT   53
  18. #define SERV_HOST_ADDR  "129.170.170.2"
  19.  
  20. // Pasted from Wireshark's Analyze > Follow > UDP stream > "C arrays"
  21. //  This represents the UDP DNS payload for an NS query for cs.dartmouth.edu
  22. //  as generated by "dig ns cs.dartmouth.edu"
  23. char req[] = {
  24.      0xa8, 0x3c, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
  25.      0x00, 0x00, 0x00, 0x00, 0x02, 0x63, 0x73, 0x09,
  26.      0x64, 0x61, 0x72, 0x74, 0x6d, 0x6f, 0x75, 0x74,
  27.      0x68, 0x03, 0x65, 0x64, 0x75, 0x00, 0x00, 0x02,
  28.      0x00, 0x01 };
  29.  
  30. #define MAX_MSG 1500
  31.  
  32. // DNS header with fixed-width fields
  33. //   See http://unixwiz.net/techtips/iguide-kaminsky-dns-vuln.html for images.
  34. typedef struct dns_resp_hdr {
  35.      uint16_t tx_id;
  36.      uint8_t  flags[2];
  37.      uint16_t n_q;
  38.      uint16_t n_a;
  39.      uint16_t n_auth;
  40.      uint16_t n_add;
  41. } dns_resp_hdr_t;
  42.  
  43. int main(argc, argv)
  44. int     argc;
  45. char    *argv[];
  46. {
  47.      int sockfd;
  48.      struct sockaddr_in serv_addr;
  49.  
  50.      char buff[1500];
  51.      int n, i;
  52.  
  53.      uint16_t type, class, data_len;
  54.      uint32_t ttl;
  55.  
  56.      dns_resp_hdr_t *r;
  57.  
  58.      char *p;
  59.  
  60.      /*
  61.       * Fill in the structure "serv_addr" with the address of the
  62.       * server that we want to connect with.
  63.       */
  64.      
  65.      bzero((char *) &serv_addr, sizeof(serv_addr));
  66.      serv_addr.sin_family      = AF_INET;
  67.      serv_addr.sin_addr.s_addr = inet_addr(SERV_HOST_ADDR);
  68.      serv_addr.sin_port        = htons(SERV_PORT);
  69.      
  70.      /*
  71.       * Open a UDP socket (a "datagram" socket, i.e., UDP; recall that TCP was SOCK_STREAM).
  72.       */
  73.      
  74.      if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
  75.           perror("udp client: can't open DGRAM socket");
  76.           exit(1);
  77.      }
  78.  
  79.      /*
  80.       * Connect to the server. Unlike TCP, no packets are sent; only kernel's
  81.       *  data structures are filled in, so that next time you write/send to
  82.       *  this socket, the IP/UDP packet knows where to go.
  83.       */
  84.      
  85.      if (connect(sockfd, (struct sockaddr *) &serv_addr,
  86.                  sizeof(serv_addr)) < 0){
  87.           perror("udp client: can't connect to server");
  88.           exit(1);
  89.      }
  90.      
  91.      // Compare with sendto(), which does not need connect() above, because
  92.      //   it specifies the sockaddr with every datagram.
  93.      if( (n = write(sockfd, (void*) req, sizeof(req))) < 0 ){
  94.           perror("udp client: write error");
  95.           exit(1);
  96.      }
  97.      
  98.      // Compare with recvfrom, which does not need a connect() either.
  99.      n = recv(sockfd, (void*) buff, MAX_MSG, 0);
  100.      if( n < 0 ){
  101.           perror("Truncated response received.");
  102.           goto out;
  103.      }
  104.  
  105.      // This is the key to our parsing of the header: the struct gives us a "mask" for memory accesses.
  106.      r = (dns_resp_hdr_t *) buff;
  107.      printf( "Response length: %d\n", n );
  108.  
  109.      // Print packet in hex
  110.      for (i = 0; i < n; i++) {
  111.           printf("%02X%s", (uint8_t)buff[i], (i + 1)%16 ? " " : "\n");
  112.      }
  113.      printf("\n");
  114.  
  115.      // Printing out the fixed-length parts of the common DNS header:
  116.      printf("tx_id 0x%x, flags %02X %02X, questions %d, answers %d, authorities %d, additional %d\n",
  117.             ntohs(r->tx_id), r->flags[0], r->flags[1], ntohs(r->n_q), ntohs(r->n_a), ntohs(r->n_auth), ntohs(r->n_add) );
  118.      
  119.      p = buff + sizeof(dns_resp_hdr_t);
  120.  
  121.      // Print queries
  122.      for( i = 0 ; i < ntohs(r->n_q); i++ ){
  123.           // parse RR starting from name
  124.           printf( "Query RR name: " );    
  125.           p += print_dns_name( p, buff );
  126.          
  127.           // then print type and class
  128.           type = ntohs( *(uint16_t *)p );
  129.           p += 2;
  130.           class = ntohs (*(uint16_t *)p );
  131.           p += 2;
  132.           printf( "  type %d, class %d\n", type, class );
  133.      }  
  134.      // Print answers
  135.      for( i = 0 ; i < ntohs(r->n_a); i++ ){
  136.           // parse RR starting from name
  137.           printf( "Answer RR name: " );    
  138.           p += print_dns_name(p, buff);
  139.  
  140.           type = ntohs( *(uint16_t *)p );
  141.           p += 2;
  142.           class = ntohs (*(uint16_t *)p );
  143.           p += 2;
  144.           printf( "  type %d, class %d\n", type, class );
  145.  
  146.           ttl = ntohl( *(uint32_t *)p );
  147.           p += 4;
  148.  
  149.           data_len = ntohs( *(uint16_t *)p );
  150.           p += 2;
  151.           printf( "  ttl %d, data_len %d ", ttl, data_len );
  152.  
  153.           // Data interpretation varies by type
  154.           if( type == 1 && data_len == 4){
  155.                printf( " %s\n", inet_ntoa( *(struct in_addr*) p ));
  156.                p += 4;
  157.           }
  158.           else if( type == 2 ){
  159.                print_dns_name( p, buff );
  160.           }
  161.           else{
  162.                printf( "WARN: don't know how to parse RR data for type %d length %d\n", type, data_len);
  163.           }
  164.          
  165.           p += data_len;
  166.  
  167.      } // done printing answers
  168.      for( i = 0 ; i < ntohs(r->n_auth); i++ ){
  169.           printf( "Skipping authority RR: not implemented\n");
  170.      }
  171.      for( i = 0 ; i < ntohs(r->n_add); i++ ){
  172.           printf( "Skipping additional RR: not implemented\n");
  173.      }
  174.  
  175. out:
  176.      close(sockfd);
  177.      return 0;
  178. }
  179.  
  180. /*
  181.  * Args: pointer to a DNS-encoded name (or backreference), pointer to
  182.  *   the start of the DNS payload (to resolve backreferences).
  183.  * Returns: the number of bytes occupied by the name, to skip over.
  184.  */
  185. int print_dns_name(char *p, char *buff)
  186. {
  187.      char *p0 = p;
  188.      int8_t len  = *(uint8_t*)p;
  189.      p++;
  190.  
  191.      // write out parts of the name from this record
  192.      while( len > 0 ){
  193.           fwrite( p, len, 1, stdout );
  194.           printf(".");
  195.           p += len;
  196.           len = *(uint8_t*)p;
  197.           p++;
  198.      }
  199.      // at this point we either hit len==0 (the end of name)
  200.      //  or a negative back-pointer
  201.  
  202.      if( len < 0 ){ // back-pointer, starts with 0xc0
  203.           uint16_t offset;
  204.           offset = ntohs(*(uint16_t *)(p-1)) & ~0xc000;  // scan back one byte
  205.           printf( "<backref offset %d>", offset );
  206.           print_dns_name( buff+offset, buff ); // ignore return value
  207.           printf("\n");
  208.           p += 1; // skip offset
  209.      }
  210.  
  211.      return p-p0;
  212. }

Raw Paste

Login or Register to edit or fork this paste. It's free.