int main(int argc, char *argv[]) { /** * I've included some basic code for opening a socket in C, sending * a UDP packet, and then receiving a response (or timeout). You'll * need to fill in many of the details, but this should be enough to * get you started. */ // process the arguments if (argc != 3 && argc != 4) { printf("Usage: ./3600dns [-ns|-mx] @<server:port> <name>\n"); exit(-1); } char serverType = RECORDS; if (argc == 4) { if (!strcmp(argv[1],"-mx")) { serverType = MX; } else if (!strcmp(argv[1],"-ns")) { serverType = NS; } else { return -1; } argc = 1; } else { argc = 0; } // set the default port to 53 int port = 53; char* name = calloc(150,sizeof(char)); char* server = argv[argc+1] + 1; memcpy( name,argv[argc+2],strlen(argv[2]) ); char* offset = strchr(argv[argc+1], ':'); if (offset) { *offset = 0; port = atoi(offset + 1); } // construct the DNS request //Structure mallocs unsigned char* packetDNS = (unsigned char*)calloc(MAX_IP_PACKET_SIZE, sizeof(char)); if (!packetDNS) { return -1; } dnsheader* header = (dnsheader*)calloc(1, sizeof(dnsheader)); if (!header) { return -1; } dnsquestion* question = (dnsquestion*)calloc(1, sizeof(dnsquestion)); if (!question) { return -1; } dnsanswer* answer = (dnsanswer*)calloc(1, sizeof(dnsanswer)); if (!answer) { return -1; } //setup the header header->ID = htons(QUERY_ID); header->RD = ~(0); header->QDCOUNT = htons(0x0001); //setup the question, QNAME is added later switch (serverType) { case RECORDS: question->QTYPE = htons(0x0001); break; case MX: question->QTYPE = htons(MX); break; case NS: question->QTYPE = htons(NS); break; } question->QCLASS = htons(0x0001); int packetSize = 0; //copy header into packet memcpy( packetDNS, header, sizeof(dnsheader) ); packetSize += sizeof(dnsheader); //copy qname into packet int length = strlen(name); char* period = NULL; *( name + length ) = '.'; *( name + length + 1 ) = 0; while ( (period = strchr(name, '.')) != 0 ) { *period = 0; length = strlen(name); memcpy( packetDNS + packetSize, &length, 1 ); packetSize++; memcpy( packetDNS + packetSize, name, length); packetSize += length; name = period + 1; } //copy zero byte at end of qname char zeroByte = 0; memcpy( packetDNS + packetSize, &zeroByte, 1 ); packetSize++; //copy question into packet memcpy( packetDNS + packetSize, question, sizeof(dnsquestion) ); packetSize += sizeof(dnsquestion); // send the DNS request (and call dump_packet with your request) dump_packet( packetDNS, packetSize ); // first, open a UDP socket int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // next, construct the destination address struct sockaddr_in out; out.sin_family = AF_INET; out.sin_port = htons( (short) port ); out.sin_addr.s_addr = inet_addr(server); if (sendto(sock, packetDNS, packetSize, 0, (struct sockaddr*)&out, sizeof(out)) < 0) { printf("Error occured in sendto\n"); return -1; } //Clear question buffer to use for answer buffer in the future memset( packetDNS, 0, MAX_IP_PACKET_SIZE ); memset( question, 0, sizeof(dnsquestion) ); memset( header, 0, sizeof(dnsheader) ); packetSize = 0; // wait for the DNS reply (timeout: 5 seconds) struct sockaddr_in in; socklen_t in_len; // construct the socket set fd_set socks; FD_ZERO(&socks); FD_SET(sock, &socks); // construct the timeout struct timeval t; t.tv_sec = 5; t.tv_usec = 0; // wait to receive, or for a timeout if (select(sock + 1, &socks, NULL, NULL, &t)) { in_len = sizeof(in); int status; status = recvfrom(sock, packetDNS, MAX_IP_PACKET_SIZE, 0, (struct sockaddr*) &in, &in_len); if ( status < 0) { printf("%s in recvfrom\n",strerror(errno)); return -1; } if (!header) { return -1; } /*========================== Parse response HEADER ==========================*/ //Check header for consistency memcpy( header,packetDNS,sizeof(dnsheader) ); if ( ntohs(header->ID) != QUERY_ID || header->QR != 1 || header->RD != 1 || header->RA != 1 ) { printf("ERROR: Header mismatch\n"); return 1; } packetSize = sizeof(dnsheader); int numAnswers = ntohs(header->ANCOUNT); /*========================== Parse response QUESTION QNAME ==========================*/ unsigned char* qname = calloc(150, sizeof(char)); int len = parse_qname( packetDNS, qname, sizeof(dnsheader) ); if (!strcmp((char*)argv[2],(char*)qname+1)) { printf("ERROR: qname mismatch '%s'\n",qname); return -1; } packetSize += len; /*========================== Parse response QUESTION ==========================*/ memcpy( question, packetDNS+packetSize, sizeof(dnsquestion) ); if ( (ntohs(question->QTYPE) != RECORDS && ntohs(question->QTYPE) != MX && ntohs(question->QTYPE) != NS) || ntohs(question->QCLASS) != (1) ) { printf("ERROR: question mismatch\n"); return -1; } packetSize += sizeof(dnsquestion); /*========================== Parse response ANSWER QNAME ==========================*/ do { memset(qname,0,150); len = parse_qname(packetDNS,qname,packetSize); if (!strcmp((char*)argv[2],(char*)qname+1)) { printf("ERROR: answer qname mismatch '%s'\n",qname); return -1; } packetSize += len; /*========================== Parse response ANSWER ==========================*/ memcpy(answer,packetDNS+packetSize,sizeof(dnsanswer)); if ((ntohs(answer->TYPE) != RECORDS && ntohs(answer->TYPE) != CNAME && ntohs(answer->TYPE) != MX && ntohs(answer->TYPE) != NS) || ntohs(answer->CLASS) != 1 ) { printf("NOTFOUND\n"); return 1; } //Two bytes need to be subtracted from dnsanswer becasue padding was added packetSize += sizeof(dnsanswer) - 2; /*===================== Parse response RDATA =====================*/ unsigned char* rdata = calloc(150,sizeof(char)); short preference = 0; if ( ntohs(answer->TYPE) == RECORDS ) { parse_ip(packetDNS,rdata,packetSize); printf("IP\t%s",rdata); packetSize += ntohs(answer->RDLENGTH); } else if ( ntohs(answer->TYPE) == CNAME ) { len = parse_qname(packetDNS,rdata,packetSize); printf("CNAME\t%s",rdata); packetSize += len; } else if ( ntohs(answer->TYPE) == NS ) { len = parse_qname(packetDNS,rdata,packetSize); printf("NS\t%s",rdata); packetSize += len; } else if ( ntohs(answer->TYPE) == MX ) { memcpy(&preference,packetDNS+packetSize,sizeof(short)); packetSize+=sizeof(preference); preference = ntohs(preference); len = parse_qname(packetDNS,rdata,packetSize); printf("MX\t%s\t%d",rdata,preference); packetSize += len; } if ( header->AA) { printf("\tauth\n"); } else { printf("\tnonauth\n"); } numAnswers--; } while (numAnswers); } else { // a timeout occurred printf("NORESPONSE"); } // print out the result //dump_packet( packetDNS, packetSize); free(header); free(question); free(packetDNS); free(answer); return 0; }
static int dns_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct xt_dns *data = (struct xt_dns *)(*match)->data; switch (c) { case O_DNS_FLAG_QR: if (*flags & XT_DNS_FLAG_QR) { xtables_error(PARAMETER_PROBLEM, "Only one `--qr' allowed"); } data->qr = true; if (invert) { data->invflags |= XT_DNS_FLAG_QR; } *flags |= XT_DNS_FLAG_QR; break; case O_DNS_FLAG_OPCODE: if (*flags & XT_DNS_FLAG_OPCODE) { xtables_error(PARAMETER_PROBLEM, "Only one `--opcode' allowed"); } data->opcode = parse_opcode_flags(optarg); data->setflags |= XT_DNS_FLAG_OPCODE; if (invert) { data->invflags |= XT_DNS_FLAG_OPCODE; } *flags |= XT_DNS_FLAG_OPCODE; break; case O_DNS_FLAG_AA: if (*flags & XT_DNS_FLAG_AA) { xtables_error(PARAMETER_PROBLEM, "Only one `--aa' allowed"); } data->aa = true; if (invert) { data->invflags |= XT_DNS_FLAG_AA; } *flags |= XT_DNS_FLAG_AA; break; case O_DNS_FLAG_TC: if (*flags & XT_DNS_FLAG_TC) { xtables_error(PARAMETER_PROBLEM, "Only one `--tc' allowed"); } data->tc = true; if (invert) { data->invflags |= XT_DNS_FLAG_TC; } *flags |= XT_DNS_FLAG_TC; break; case O_DNS_FLAG_RD: if (*flags & XT_DNS_FLAG_RD) { xtables_error(PARAMETER_PROBLEM, "Only one `--rd' allowed"); } data->rd = true; if (invert) { data->invflags |= XT_DNS_FLAG_RD; } *flags |= XT_DNS_FLAG_RD; break; case O_DNS_FLAG_RA: if (*flags & XT_DNS_FLAG_RA) { xtables_error(PARAMETER_PROBLEM, "Only one `--ra' allowed"); } data->ra = true; if (invert) { data->invflags |= XT_DNS_FLAG_RA; } *flags |= XT_DNS_FLAG_RA; break; case O_DNS_FLAG_AD: if (*flags & XT_DNS_FLAG_AD) { xtables_error(PARAMETER_PROBLEM, "Only one `--ad' allowed"); } data->ad = true; if (invert) { data->invflags |= XT_DNS_FLAG_AD; } *flags |= XT_DNS_FLAG_AD; break; case O_DNS_FLAG_CD: if (*flags & XT_DNS_FLAG_CD) { xtables_error(PARAMETER_PROBLEM, "Only one `--cd' allowed"); } data->cd = true; if (invert) { data->invflags |= XT_DNS_FLAG_CD; } *flags |= XT_DNS_FLAG_CD; break; case O_DNS_FLAG_RCODE: if (*flags & XT_DNS_FLAG_RCODE) { xtables_error(PARAMETER_PROBLEM, "Only one `--rcode' allowed"); } data->rcode = parse_rcode_flags(optarg); data->setflags |= XT_DNS_FLAG_RCODE; if (invert) { data->invflags |= XT_DNS_FLAG_RCODE; } *flags |= XT_DNS_FLAG_RCODE; break; case O_DNS_FLAG_QNAME: if (*flags & XT_DNS_FLAG_QNAME) { xtables_error(PARAMETER_PROBLEM, "Only one `--qname' allowed"); } parse_qname(optarg, data->qname); data->setflags |= XT_DNS_FLAG_QNAME; if (invert) { data->invflags |= XT_DNS_FLAG_QNAME; } *flags |= XT_DNS_FLAG_QNAME; break; case O_DNS_FLAG_QTYPE: if (*flags & XT_DNS_FLAG_QTYPE) { xtables_error(PARAMETER_PROBLEM, "Only one `--qtype' allowed"); } data->qtype = htons(parse_qtype_flags(optarg)); data->setflags |= XT_DNS_FLAG_QTYPE; if (invert) { data->invflags |= XT_DNS_FLAG_QTYPE; } *flags |= XT_DNS_FLAG_QTYPE; break; case O_DNS_FLAG_RMATCH: if (*flags & XT_DNS_FLAG_RMATCH) { xtables_error(PARAMETER_PROBLEM, "Only one `--qtype' allowed"); } data->rmatch = true; if (invert) { data->invflags |= XT_DNS_FLAG_RMATCH; } *flags |= XT_DNS_FLAG_RMATCH; break; case O_DNS_FLAG_QNAME_MAXSIZE: if (*flags & XT_DNS_FLAG_QNAME_MAXSIZE) { xtables_error(PARAMETER_PROBLEM, "Only one `--maxsize' allowed"); } data->maxsize = atoi(optarg); if (invert) { data->invflags |= XT_DNS_FLAG_QNAME_MAXSIZE; } *flags |= XT_DNS_FLAG_QNAME_MAXSIZE; break; default: return 0; } return 1; }