mausezahn: use getopt_long instead of getopt
[netsniff-ng.git] / staging / dns.c
blob83227e25c1cf23aa5f5c64825c9c8cf478df3832
1 /*
2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008 Herbert Haas
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12 * details.
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
21 ////////////////////////////////////////////////////////////////////
23 // DNS: Only UDP-based here
24 //
25 ////////////////////////////////////////////////////////////////////
27 #include "mz.h"
28 #include "cli.h"
31 #define MZ_DNS_HELP \
32 "| DNS type: Send Domain Name System Messages.\n" \
33 "|\n" \
34 "| Generally there are two interesting general DNS messages: queries and answers. The easiest\n" \
35 "| way is to use the following syntax:\n" \
36 "|\n" \
37 "| query|q = <name>[:<type>] ............. where type is per default \"A\"\n" \
38 "| (and class is always \"IN\")\n" \
39 "|\n" \
40 "| answer|a = [<type>:<ttl>:]<rdata> ...... ttl is per default 0.\n" \
41 "| = [<type>:<ttl>:]<rdata>/[<type>:<ttl>:]<rdata>/...\n" \
42 "|\n" \
43 "| Note: If you only use the 'query' option then a query is sent. If you additonally add\n" \
44 "| an 'answer' option then an answer is sent.\n" \
45 "|\n" \
46 "| Examples: \n" \
47 "|\n" \
48 "| q = www.xyz.com\n" \
49 "| q = www.xyz.com, a=192.168.1.10\n" \
50 "| q = www.xyz.com, a=A:3600:192.168.1.10\n" \
51 "| q = www.xyz.com, a=CNAME:3600:abc.com/A:3600:192.168.1.10\n" \
52 "|\n" \
53 "| Note: <type> can be: A, CNAME, or any integer\n" \
54 "|\n" \
55 "|\n" \
56 "| OPTIONAL parameter hacks: (if you don't know what you do this might cause invalid packets)\n" \
57 "|\n" \
58 "| Parameter Description query / reply)\n" \
59 "| -------------------------------------------------------------------------------------\n" \
60 "|\n" \
61 "| request/response|reply ..... flag only request / n.a. \n" \
62 "| id ......................... packet id (0-65535) random / random\n" \
63 "| opcode (or op) ............. accepts values 0..15 or one of std / 0 \n" \
64 "| these keywords: \n" \
65 "| = std ................... Standard Query\n" \
66 "| = inv ................... Inverse Query\n" \
67 "| = sts ................... Server Status Request\n" \
68 "| aa or !aa .................. Authoritative Answer UNSET / SET\n" \
69 "| tc or !tc .................. Truncation UNSET / UNSET\n" \
70 "| rd or !rd .................. Recursion Desired SET / SET\n" \
71 "| ra or !ra .................. Recursion Available UNSET / SET\n" \
72 "| z .......................... Reserved (takes values 0..7) 0 / 0 \n" \
73 "| (z=2...authenticated)\n" \
74 "| rcode ...................... Response Code (0..15); interesting 0 / 0 \n" \
75 "| values are:\n" \
76 "| = 0 ...................... No Error Condition\n" \
77 "| = 1 ...................... Unable to interprete query due to format error\n" \
78 "| = 2 ...................... Unable to process due to server failure\n" \
79 "| = 3 ...................... Name in query does not exist\n" \
80 "| = 4 ...................... Type of query not supported\n" \
81 "| = 5 ...................... Query refused\n" \
82 "|\n" \
83 "| Count values (values 0..65535) will be set automatically! You should not set these\n" \
84 "| values manually except you are interested in invalid packets.\n" \
85 "| qdcount (or qdc) ........... Number of entries in question section 1 / 1\n" \
86 "| ancount (or anc) ........... Number of RRs in answer records section 0 / 1\n" \
87 "| nscount (or nsc) ........... Number of name server RRs in authority 0 / 0\n" \
88 "| records section\n" \
89 "| arcount (or arc) ........... Number of RRs in additional records section 0 / 0\n" \
90 "\n"
92 static u_int8_t gbuf[MAX_PAYLOAD_SIZE]; // This is only a generic global buffer to handover data more easily
93 static u_int32_t gbuf_s;
95 int dns_get_query (char* argval);
96 int dns_get_answer (char* argval);
100 // Note: I do NOT use libnet here (had problems with bugs there...)
101 int create_dns_packet(void)
104 char *token, *tokenptr, argval[MAX_PAYLOAD_SIZE];
106 int i=0,j=0;
108 unsigned char *x;
109 u_int16_t tmp;
112 // 16 bit values:
113 u_int8_t
114 dns_id0 =0, // DNS packet ID
115 dns_id1 =0,
116 dns_flags0 =0, // consists of the flags below
117 dns_flags1 =0,
118 dns_num_q0 =0, // number of questions
119 dns_num_q1 =0,
120 dns_num_ans0 =0, // number of answer resource records
121 dns_num_ans1 =0,
122 dns_num_aut0 =0, // number of authority resource records
123 dns_num_aut1 =0,
124 dns_num_add0 =0, // number of additional resource records
125 dns_num_add1 =0,
126 dns_type0 =0,
127 dns_type1 =0;
130 // bit fields for dns_flags1: Q/R(1), OPCODE(4), AA(1), TC(1), RD(1)
131 // bit fields for dns_flags0: RA(1), Z(3), RCODE(4)
132 u_int8_t
133 dns_flags_qr, // 1 bit
134 dns_flags_opcode, // 4 bits
135 dns_flags_aa, // 1 bit
136 dns_flags_tc, // 1 bit
137 dns_flags_rd, // 1 bit
138 // ---- next byte -----
139 dns_flags_ra, // 1 bit
140 dns_flags_z, // 3 bits
141 dns_flags_rcode; // 4 bits
144 u_int8_t
145 dns_packet[MAX_PAYLOAD_SIZE], // finally the whole packet with all sections
146 section[MAX_PAYLOAD_SIZE]; // contains only a section (intermediately)
147 u_int32_t
148 dns_packet_s;
152 if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==DNS) )
154 if (mz_port)
156 cli_print(gcli, "%s", MZ_DNS_HELP);
157 return -1;
159 else
161 fprintf(stderr,"\n"
162 MAUSEZAHN_VERSION
163 "\n%s", MZ_DNS_HELP);
164 exit(0);
169 // general defaults:
170 // TODO: define globals in case dns is called by external functions!)
171 // MOST SAFEST AND EASIEST METHOD: define tx.dns_xxxx for default-initialization
173 dns_id0 = 0x42; // dns_id0 = (u_int8_t) ( ((float) rand()/RAND_MAX)*255);
174 dns_id1 = 0x42;
176 dns_flags_qr = 0; // request
177 dns_flags_opcode = 0; // 'standard query' (also for response!)
179 dns_type0 = 1; // A record
180 dns_type1 = 0;
183 i=0;
186 /////////////////////////////////////////////////////////////////////////////////
187 // Evaluate CLI parameters:
190 // Handle the query //
192 if ( (getarg(tx.arg_string,"query", argval)==1) ||
193 (getarg(tx.arg_string,"q", argval)==1) )
196 (void) dns_get_query (argval); // returns the length in byte dns_num_q0=1;
198 // copy the result from gbuf to our local buffer 'section':
199 for (j=0;j<gbuf_s;j++)
201 section[j]=gbuf[j];
204 i = gbuf_s;
206 // Set defaults if not already set by callee.
207 // !! But ONLY set these if there is no additional answer section
208 // !! because then the answer section should set the defaults !!!
209 if ( (getarg(tx.arg_string,"answer", NULL)==0) && // no answer
210 (getarg(tx.arg_string,"a", NULL)==0) )
212 if (!tx.dp) tx.dp = 53;
213 if (!tx.sp) tx.sp = 42000;
217 // These are the defaults for a query:
218 dns_flags_aa = 1; // authoritative answer
219 dns_flags_tc = 0; // not truncated
220 dns_flags_rd = 1; // recursion desired
221 dns_flags_ra = 0; // recursion available
222 dns_flags_z = 0; // FYI: if 010 = 2 = authenticated
223 dns_flags_rcode = 0; // no errors
224 dns_num_q0 = 1; // number of questions
229 // Handle the answer:
231 // answer|a = <name>[:<type>[:<class>]]/[<ttl>:]<rdata>\n"
232 if ( (getarg(tx.arg_string,"answer", argval)==1) ||
233 (getarg(tx.arg_string,"a", argval)==1) )
236 // In case there are multiple answer sections seperate them with / or |
237 token = strtok_r(argval,"/|",&tokenptr);
240 //then the corresponding answer section:
241 //first create a pointer to the <name>:
242 section[i]=0xc0; // a pointer always starts with MSB=11xxxxxx xxxxxxx = 0xc0
243 i++;
244 section[i]=0x0c; // this number always points to the first query entry
245 i++;
246 //then add rdata
247 dns_num_ans0 += dns_get_answer (token);
248 //NOTE: 'i' points to the next free byte in section[] (see the query handling above)
249 for (j=0;j<gbuf_s;j++)
251 section[j+i]=gbuf[j];
253 i=i+gbuf_s; // so 'i' again points to the next free byte in section[]
254 } while ( (token = strtok_r(NULL,"/|",&tokenptr))!=NULL);
256 if (!tx.sp) tx.sp = 53;
257 if (!tx.dp) tx.dp = 42000; // should be set by user
258 dns_flags_qr = 1; // response
259 dns_flags_aa = 0; // no authoritative answer
260 dns_flags_tc = 0; // not truncated
261 dns_flags_rd = 1; // recursion desired
262 dns_flags_ra = 0; // recursion not available
263 dns_flags_z = 0; // FYI: if 010 = 2 = authenticated
264 dns_flags_rcode = 0; // no errors
269 // *** NOTE ***
270 // Now 'i' contains the number of DNS payload bytes = valid bytes in section[]
274 ///////////////////////////////////////////////////////////////////////////////////////////////
275 // Now let's handle the optional other commands, if some user really changed them...
279 if (getarg(tx.arg_string,"id",argval)==1)
281 tmp = (u_int16_t) str2int (argval);
282 x = (unsigned char*) &tmp;
284 dns_id1 = *x;
285 x++;
286 dns_id0 = *x;
290 if ( (getarg(tx.arg_string,"opcode", argval)==1) || (getarg(tx.arg_string,"op", argval)==1))
292 if (strncmp(argval,"std",3)==0) // standard query
294 dns_flags_opcode = 0;
296 else if (strncmp(argval,"inv",3)==0) // inverse query
298 dns_flags_opcode = 1;
300 else if (strncmp(argval,"sts",3)==0) // status server request
302 dns_flags_opcode = 2;
304 else // specified as integer
306 dns_flags_opcode = (u_int8_t) str2int (argval);
307 if (dns_flags_opcode > 15)
309 if (!quiet)
311 fprintf(stderr, "mz/dns: [Warning] Opcode cannot exceed 15 => will reduce to 15!\n");
313 dns_flags_opcode = 15;
321 if (getarg(tx.arg_string,"aa",NULL)==1)
323 dns_flags_aa = 1;
326 if (getarg(tx.arg_string,"!aa",NULL)==1)
328 dns_flags_aa = 0;
331 if (getarg(tx.arg_string,"tc",NULL)==1)
333 dns_flags_tc = 1;
336 if (getarg(tx.arg_string,"!tc",NULL)==1)
338 dns_flags_tc = 0;
341 if (getarg(tx.arg_string,"rd",NULL)==1)
343 dns_flags_rd = 1;
346 if (getarg(tx.arg_string,"!rd",NULL)==1)
348 dns_flags_rd = 0;
351 if (getarg(tx.arg_string,"ra",NULL)==1)
353 dns_flags_ra = 1;
356 if (getarg(tx.arg_string,"!ra",NULL)==1)
358 dns_flags_ra = 0;
361 if (getarg(tx.arg_string,"z", argval)==1)
363 dns_flags_z = (u_int8_t) str2int (argval);
364 if (dns_flags_z > 7)
366 if (!quiet)
368 fprintf(stderr, "mz/dns: [Warning] z cannot exceed 7 => will reduce to 7!\n");
370 dns_flags_z = 7;
376 if (getarg(tx.arg_string,"rcode", argval)==1)
378 dns_flags_rcode = (u_int8_t) str2int (argval);
379 if (dns_flags_rcode > 15)
381 if (!quiet)
383 fprintf(stderr, "mz/dns: [Warning] rcode cannot exceed 15 => will reduce to 15!\n");
385 dns_flags_rcode = 7;
390 if ( (getarg(tx.arg_string,"qdcount", argval)==1) ||
391 (getarg(tx.arg_string,"qdc", argval)==1) ||
392 (getarg(tx.arg_string,"qc", argval)==1) )
395 tmp = (u_int16_t) str2int (argval);
396 x = (unsigned char*) &tmp;
397 dns_num_q1 = *x;
398 x++;
399 dns_num_q0 = *x;
402 if ( (getarg(tx.arg_string,"ancount", argval)==1) ||
403 (getarg(tx.arg_string,"anc", argval)==1) )
405 tmp = (u_int16_t) str2int (argval);
406 x = (unsigned char*) &tmp;
407 dns_num_ans1 = *x;
408 x++;
409 dns_num_ans0 = *x;
412 if ( (getarg(tx.arg_string,"nscount", argval)==1) ||
413 (getarg(tx.arg_string,"nsc", argval)==1) )
415 tmp = (u_int16_t) str2int (argval);
416 x = (unsigned char*) &tmp;
417 dns_num_aut1 = *x;
418 x++;
419 dns_num_aut0 = *x;
422 if ( (getarg(tx.arg_string,"arcount", argval)==1) ||
423 (getarg(tx.arg_string,"arc", argval)==1) )
425 tmp = (u_int16_t) str2int (argval);
426 x = (unsigned char*) &tmp;
427 dns_num_add1 = *x;
428 x++;
429 dns_num_add0 = *x;
433 // End of optional parameter handling
435 ///////////////////////////////////////////////////////////////////////////////////////////////
440 /////////////////////////////////////////////////////////
441 // Now put all together i. e. create the UDP payload
443 // bit fields for dns_flags1: Q/R(1), OPCODE(4), AA(1), TC(1), RD(1)
444 // bit fields for dns_flags0: RA(1), Z(3), RCODE(4)
446 // 7 6 5 4 3 2 1 0
447 // +--+--+--+--+--+--+--+--+
448 // |QR| OPCODE |AA|TC|RD|
449 // +--+--+--+--+--+--+--+--+
452 // 7 6 5 4 3 2 1 0
453 // +--+--+--+--+--+--+--+--+
454 // |RA| Z | RCODE |
455 // +--+--+--+--+--+--+--+--+
458 //// Flags: MSB
459 dns_flags_qr <<= 7;
460 dns_flags1 |= dns_flags_qr;
462 dns_flags_opcode <<= 3;
463 dns_flags1 |= dns_flags_opcode;
465 dns_flags_aa <<= 2;
466 dns_flags1 |= dns_flags_aa;
468 dns_flags_tc <<= 1;
469 dns_flags1 |= dns_flags_tc;
471 dns_flags1 |= dns_flags_rd;
473 //// Flags: LSB
475 dns_flags_ra <<= 7;
476 dns_flags0 |= dns_flags_ra;
478 dns_flags_z <<= 4;
479 dns_flags0 |= dns_flags_z;
481 dns_flags0 |= dns_flags_rcode;
483 //// Add header bytes to dns_packet:
485 dns_packet[0]=dns_id1;
486 dns_packet[1]=dns_id0;
488 dns_packet[2]=dns_flags1;
489 dns_packet[3]=dns_flags0;
491 dns_packet[4]=dns_num_q1;
492 dns_packet[5]=dns_num_q0;
494 dns_packet[6]=dns_num_ans1;
495 dns_packet[7]=dns_num_ans0;
497 dns_packet[8]=dns_num_aut1;
498 dns_packet[9]=dns_num_aut0;
500 dns_packet[10]=dns_num_add1;
501 dns_packet[11]=dns_num_add0;
503 //// Add sections to dns_packet:
506 for (j=0; j<i; j++)
508 dns_packet[12+j] = section[j];
512 //////////////////////////////////////////////////////////
514 dns_packet_s = i+12;
515 tx.udp_payload_s = dns_packet_s;
517 // copy the dns_paylod to the udp_payload
519 for (j=0; j<tx.udp_payload_s; j++)
521 tx.udp_payload[j] = dns_packet[j];
524 tx.udp_len = 8 + tx.udp_payload_s;
526 return dns_packet_s;
531 ////////////////////////////////////////////////////////////////////////////////////////////
532 // Accepts a string like "www.perihel.at:A" or "www.perihel.at"
533 // and creates a valid query section using the global gbuf[] and gbuf_s
535 // query|q = <name>[:<type>]\n"
536 // Return value:
537 // number of queries (currently only 1 query accepted,
538 // hence return value is 1 on success or 0 upon failure
540 int dns_get_query(char* argval)
542 char *token, *field, *saveptr1=NULL, *saveptr2=NULL;
543 int i,j, cnt;
544 u_int16_t tmp;
545 unsigned char *x;
547 i=0;
549 // now get first field: <name>
550 field = strtok_r(argval, ":", &saveptr1);
552 // decompose <name> into labels:
553 token = strtok_r(field, ".", &saveptr2);
555 do // loop through all labels
557 cnt = strlen(token);
558 gbuf[i] = cnt;
559 i++;
560 for (j=i; j<(i+cnt);j++)
562 gbuf[j] = *token;
563 token++;
565 i+=cnt;
567 } while ( (token = strtok_r(NULL, ".", &saveptr2)) != NULL);
569 gbuf[i]=0x00;
570 i++; // (always point to next empty byte)
573 // lets see if <type> has also been specified:
574 if ( (field = strtok_r(NULL, ":", &saveptr1)) !=NULL)
576 if ( (strncmp(field, "A",1)==0) || (strncmp(field, "a",1)==0) )
578 tmp = 1;
580 else
582 tmp = (u_int16_t) str2int (field);
585 x = (unsigned char*) &tmp;
587 gbuf[i] = *(x+1);
588 i++;
589 gbuf[i] = *x;
590 i++;
592 else // use default type=A
594 gbuf[i] = 0x00; i++;
595 gbuf[i] = 0x01; i++;
598 // finally add the class=IN:
599 gbuf[i] = 0x00; i++;
600 gbuf[i] = 0x01; i++;
602 // this is the number of used bytes:
603 gbuf_s = i;
605 //////// TEST
607 for (j=0; j<i; j++)
609 printf("%02x \n",gbuf[j]);
611 printf("i=%u\n",i);
614 return 1;
623 // Given a label (e. g. www.google.com) creates correct bytes in *buf
624 // and returns number of bytes created.
625 // NOTE: Label MUST NOT be longer than 512 characters.
627 int dns_process_label(char* label, u_int8_t *buf)
629 char *saveptr=NULL, *token;
630 int i=0, j=0, cnt=0, avoid_buffer_overflow=0;
632 token = strtok_r(label, ".", &saveptr);
634 do // loop through all labels
636 cnt = strlen(token);
637 i++;
638 *buf = cnt;
639 buf++;
640 avoid_buffer_overflow++;
641 for (j=0; j<cnt ;j++)
643 *buf = *token;
644 buf++;
645 avoid_buffer_overflow++;
646 if (avoid_buffer_overflow == 512) return 512;
647 token++;
649 i+=cnt;
651 } while ( (token = strtok_r(NULL, ".", &saveptr)) != NULL);
652 *buf=0x00;
653 i++; // number of total bytes written
654 return i;
661 // Accepts a valid triple of type:ttl:rdata and writes anything in gbuf[] and gbuf_s.
663 // Syntax examples:
665 // CNAME:3600:abc.com => Depending on type the rdata must be handled differently
666 // A:86400:192.168.1.33 => Up to 3 parameters
667 // A:192.168.1.33 => TTL may be omitted, then TTL=0
668 // 192.168.1.44 => Single parameter can only be an A record
670 // Other TYPES than A and CNAME are currently not supported and therefore the user must
671 // specify RDATA in hex.
674 int dns_get_answer(char* argval)
676 char *field, *saveptr1=NULL;
677 char field1[512], field2[512], field3[512];
678 int i, len, num_params;
679 u_int16_t TYPE=1; // A
680 u_int8_t *ptrTYPE;
681 u_int32_t TTL=0;
682 u_int8_t *ptrTTL;
683 u_int16_t RDLEN;
684 u_int8_t *ptrRDLEN;
685 u_int8_t rdata[512];
687 field1[0]='\0';
688 field2[0]='\0';
689 field3[0]='\0';
691 len = strlen (argval);
693 // determine number of occurences of ':'
694 num_params=1;
695 for (i=0; i<len; i++)
697 if (argval[i]==':') num_params++;
699 if (num_params>3) return 0; // Error!
701 // now get the fields (type, ttl, rdata)
702 field = strtok_r(argval, ":", &saveptr1);
703 strncpy(field1, field, 512);
704 if (num_params>1) // 2 or 3
706 field = strtok_r(NULL, ":", &saveptr1);
707 strncpy(field2, field, 512);
708 if (num_params==3)
710 field = strtok_r(NULL, ":", &saveptr1);
711 strncpy(field3, field, 512);
716 // Now we have all parameters in field1, field2, and field3.
717 // But field2 and/or field3 might be empty.
719 switch (num_params)
721 case 1: // only RDATA specified
722 strncpy(field3, field1, 512);
723 strcpy(field1, "A");
724 strcpy(field2, "0");
725 break;
726 case 2: // TYPE and RDATA
727 strncpy(field3, field2, 512);
728 strcpy(field2, "0");
729 break;
732 //CHECK:
733 //printf("fields: [%s] [%s] [%s]\n",field1,field2,field3);
735 //////////////////////////////////////////////////////////////////////
736 // Now create the whole answer section: Type, Class, TTL, RDLEN, RDATA
738 //// TYPE
739 if ( (strcmp(field1,"CNAME")==0) ||
740 (strcmp(field1,"cname")==0) )
742 TYPE=5;
743 gbuf[0]=0x00;
744 gbuf[1]=0x05;
746 else if ( (strcmp(field1,"A")==0) ||
747 (strcmp(field1,"a")==0) )
749 TYPE=1;
750 gbuf[0]=0x00;
751 gbuf[1]=0x01;
753 else // type must be given as number
755 TYPE = (u_int16_t) str2int(field1);
756 ptrTYPE = (u_int8_t*) &TYPE;
757 gbuf[0]=*(ptrTYPE+1);
758 gbuf[1]=*(ptrTYPE);
762 //// CLASS = IN = 0x00 01
763 gbuf[2]= 0x00; gbuf[3]=0x01;
765 //// TTL
766 TTL = (u_int32_t) str2int(field2);
767 ptrTTL = (u_int8_t*) &TTL;
768 gbuf[4]= *(ptrTTL+3);
769 gbuf[5]= *(ptrTTL+2);
770 gbuf[6]= *(ptrTTL+1);
771 gbuf[7]= *(ptrTTL+0);
774 //// RDLEN and RDATA
775 if (TYPE==1) // A
777 RDLEN = num2hex(field3, rdata); // should be 4 if IP address
778 if (RDLEN!=4)
780 fprintf(stderr," mz/dns_get_answer: [WARNING] RDATA of A record should contain an IPv4 address (4 bytes).\n");
783 else if (TYPE==5) // CNAME
785 RDLEN = dns_process_label (field3, rdata);
786 if (RDLEN==0)
788 fprintf(stderr," mz/dns_get_answer: [WARNING] RDATA must contain a domain name.\n");
791 else // Any other type
793 RDLEN = str2hex(field3, rdata, 512); // should be 4 if IP address
796 ptrRDLEN = (u_int8_t*) &RDLEN;
797 gbuf[8] = *(ptrRDLEN+1);
798 gbuf[9] = *(ptrRDLEN+0);
801 // finally write rdata
802 for (i=0; i<RDLEN; i++)
804 gbuf[10+i] = rdata[i];
806 gbuf_s = 10+RDLEN;
808 //////// TEST
810 for (i=0; i<gbuf_s; i++)
812 printf("%02x \n",gbuf[i]);
814 printf("i=%u\n",i);
817 return 1;