Example #1
0
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;
}
Example #2
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;
}