About

Having a large file containing DNS names line-by-line (such as spam domains), the task is to check whether each domain-name can be resolved. The code below can be compiled with:

gcc checkdns.c -lpthread -o checkdns

and the resulting program can be executed, by taking a file containing domains line-by-line as parameter and the number of threads to use. For example:

./checkdns -d domains.txt -t 50

will read the file domains.txt and create 50 resolver threads. Any domain that resolves properly will be spat out on stdout whereas failing domains will silently be suppressed.

Code

checkdns.c
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3      //
//  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
///////////////////////////////////////////////////////////////////////////
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <pthread.h>
#include <string.h>
#include <netdb.h>
 
int active_workers = 0;
 
void *check(void *host)
{
    struct hostent *ent = gethostbyname(host);
    if (!ent || strlen(ent->h_name) == 0)
	goto release;
    fprintf(stdout, "%s\n", ent->h_name);
    fflush(stdout);
  release:
    --active_workers;
}
 
int main(int argc, char **argv)
{
    pthread_t *threads;
    int max_workers = 1;
    int i;
 
    char **domains;
    int domaincount = 0;
    char **nameservers;
    int nameservercount = 0;
 
    FILE *fp;
    size_t len = 0;
    ssize_t read;
    char *line;
 
    while ((i = getopt(argc, argv, "d:t:")) != -1) {
	switch (i) {
	case 't':
	    max_workers = atoi(optarg);
	    threads =
		(pthread_t *) malloc(max_workers * sizeof(pthread_t));
	    break;
	case 'd':
	    if ((fp = fopen(optarg, "r")) == NULL) {
		fprintf(stderr, "cannot open domains file\n");
		return 1;
	    }
	    domains = (char **) malloc(sizeof(char **));
	    while ((read = getline(&line, &len, fp)) != -1) {
		domains[domaincount] =
		    (char *) malloc(read * sizeof(char));
		strncpy(domains[domaincount], line, read - 1);
		domains =
		    (char **) realloc(domains,
				      ++domaincount * sizeof(char **) +
				      sizeof(domains));
	    }
	    break;
	default:
	    fprintf(stderr,
		    "syntax: %s <-d domains.txt> <-t number>\n");
	    return 1;
	}
    }
 
    if(domaincount == 0) {
        fprintf(stderr,
		    "syntax: %s <-d domains.txt> <-t number>\n");
        return 1;
    }
 
    --domaincount;
    do {
      wind:
	if (active_workers >= max_workers) {
	    usleep(100);
	    goto wind;
	}
	i = max_workers - 1;
	do {
	    pthread_create(&threads[i], NULL, check,
			   (void *) domains[domaincount--]);
	    ++active_workers;
	}
	while (--i > -1);
    }
    while (domaincount > 0);
 
    return 0;
}