/* * ** dnsmap - DNS Network Mapper by pagvac * ** Copyright (C) 2010 gnucitizen.org * ** * ** This program is free software; you can redistribute it and/or modify * ** it under the terms of the GNU General Public License as published by * ** the Free Software Foundation; either version 2 of the License, or * ** (at your option) any later version. * ** * ** This program is distributed in the hope that it will be useful, * ** but WITHOUT ANY WARRANTY; without even the implied warranty of * ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * ** GNU General Public License for more details. * ** * ** You should have received a copy of the GNU General Public License * ** along with this program; if not, write to the Free Software * ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "dnsmap.h" // built-in subdomains list and define macros // function prototypes unsigned short int wildcarDetect(char *, char *); unsigned short int dodelay(unsigned short int); unsigned short int isPrivateIP(char *); unsigned short int isValidDomain(char *); unsigned short int usesOpenDNS(char *); unsigned short int isIPblacklisted(char *); int main(int argc, char *argv[]) { unsigned short int i=0, j=0, k=0, l=0, found=0, ipCount=0, filtIPcount=0, milliseconds=10, intIPcount=0, wordlist=FALSE, txtResults=FALSE, csvResults=FALSE, delay=TRUE, filter=FALSE; unsigned long int start=0, end=0; char dom[MAXSTRSIZE]={'\0'}, csvResultsFilename[MAXSTRSIZE]={'\0'}, txtResultsFilename[MAXSTRSIZE]={'\0'}, wordlistFilename[MAXSTRSIZE]={'\0'}, ipstr[INET_ADDRSTRLEN]={'\0'}, wildcardIpStr[INET_ADDRSTRLEN]={'\0'}, filterIPs[5][INET_ADDRSTRLEN]={{'\0'}}, invalidTldIpstr[INET_ADDRSTRLEN]={'\0'}; void *addr; char *ipver, *strP; struct hostent *h; // start of IPv6 stuff struct addrinfo hints, *res, *p; int status; char ipv6str[INET6_ADDRSTRLEN]; memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET6; // AF_INET or AF_INET6 to force version hints.ai_socktype = SOCK_STREAM; // end of IPv6 stuff FILE *fpWords,*fpCsvLogs,*fpTxtLogs; time_t now; struct tm *ts; char timestampBuf[18]; printf("%s", BANNER); // get the current time now = time(NULL); // timestamp format: yyyy_mm_dd_hhmmss ts = localtime(&now); strftime(timestampBuf, sizeof(timestampBuf), "%Y_%m_%d_%H%M%S", ts); // start of *primitive* input validation // ideally more work should be spent on this! if(argc==1) { printf("%s%s", USAGE, EXAMPLES); exit(1); } else if(argc%2==1 && argc>2) { printf("%s%s", USAGE, EXAMPLES); exit(1); } for(i=0;argv[1][i];++i) // convert domain to lower case argv[1][i]=(tolower(argv[1][i])); #if DEBUG printf("domain: %s\n", argv[1]); #endif if(!isValidDomain(argv[1])) { printf("%s", DOMAINERR); exit(1); } for(i=0;iMAXSTRSIZE) { printf("%s",INPUTERR); exit(1); } } // end of simple input validation /* else if ((h=gethostbyname(argv[1])) == NULL) { // get the host info herror("gethostbyname"); exit(1); } */ start=(int)time(NULL); #if DEBUG printf("start time: %d\n", (int)start); #endif // parse options for(i=0;i300000) { // delay must be between 1 ms and 5 minutes printf("%s", DELAYINPUTERR); exit(1); } delay=TRUE; milliseconds=atoi(argv[(i+1)]); } // filter out user-provided IP(s) if(!strcmp(argv[i],"-i")) { for(filtIPcount=1,j=0;argv[i+1][j]!='\0';++j) if(argv[i+1][j]==',') ++filtIPcount; #if DEBUG printf("%d IP(s) to filter found\nParsing ...\n", filtIPcount); #endif if(filtIPcount<=5) { printf(FILTERMSG); strP=strtok(argv[i+1],","); for(j=0;strP;) { if(strlen(strP)=1) printf(DELAYMSG); printf("%s", "\n"); for(i=0;i<(sizeof(sub)/MAXSUBSIZE);++i) { //skipResolve=FALSE; strncpy(dom,sub[i],MAXSTRSIZE-strlen(dom)-1); strncat(dom,".",MAXSTRSIZE-strlen(dom)-1);//TEST strncat(dom,argv[1],MAXSTRSIZE-strlen(dom)-1); #if DEBUG printf("brute-forced domain: %s\n",dom); #endif // ipv6 code modded from www.kame.net status = getaddrinfo(dom, NULL, &hints, &res); if ((status=getaddrinfo(dom, NULL, &hints, &res))==0) { printf("%s\n", dom); ++found; if(txtResults) fprintf(fpTxtLogs, "%s\n", dom); if(csvResults) fprintf(fpCsvLogs, "%s", dom); for(p=res,k=0;p;p=p->ai_next,++k) { if (p->ai_family==AF_INET6) { // IPv6 struct sockaddr_in6 *ipv6=(struct sockaddr_in6 *)p->ai_addr; addr = &(ipv6->sin6_addr); ipver = "IPv6"; } // convert the IP to a string and print it: inet_ntop(p->ai_family, addr, ipv6str, sizeof ipv6str); printf("%s address #%d: %s\n",ipver,k+1,ipv6str); ++ipCount; if(txtResults) fprintf(fpTxtLogs,"%s address #%d: %s\n",ipver,k+1,ipv6str); if(csvResults) fprintf(fpCsvLogs,",%s", ipv6str); } printf("%s", "\n"); if(txtResults) fprintf(fpTxtLogs,"\n"); if(csvResults) fprintf(fpCsvLogs,"\n"); freeaddrinfo(res); // free the linked list } // end of if conditional h=gethostbyname(dom); //sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[0])),"%s"); //for(j=0;h->h_addr_list[j];++j) { // sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[j])),"%s"); // if(isIPblacklisted(ipstr)) { // skipResolve=TRUE; // break; // } //} //if(h && !skipResolve) { //if(h && !isIPblacklisted(ipstr)) { if(h && !isIPblacklisted(inet_ntoa(*((struct in_addr *)h->h_addr_list[0])))) { for(j=0;h->h_addr_list[j];++j) { sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[j])),"%s"); for(k=0;kh_addr_list[j+1]) ++j; else break; } } // END OF TEST //if(strcmp(wildcardIpStr,ipstr) && strcmp(filterIpStr,ipstr)) { if(strcmp(wildcardIpStr,ipstr) && filter==FALSE) { if(j==0) { ++found; printf("%s\n", dom); if(txtResults) fprintf(fpTxtLogs, "%s\n", dom); if(csvResults) fprintf(fpCsvLogs, "%s", dom); } printf("[%d] %s : %s\n", j+1,dom,ipstr); ++ipCount; if(isPrivateIP(ipstr)) { //if(isPrivateIP(inet_ntoa(*((struct in_addr *)h->h_addr_list[j])))) { printf("%s",INTIPWARN); ++intIPcount; } if(!strcmp(ipstr,"127.0.0.1") && strcmp(wildcardIpStr,ipstr)) { //if(!strcmp(inet_ntoa(*((struct in_addr *)h->h_addr_list[j])), //"127.0.0.1")) printf("%s",SAMESITEXSSWARN); } if(txtResults) { //fprintf(fpCsvLogs,",%s", // inet_ntoa(*((struct in_addr *)h->h_addr_list[j]))); fprintf(fpTxtLogs,"IP address #%d: %s\n", j+1, ipstr); if(isPrivateIP(ipstr) && strcmp(wildcardIpStr,ipstr)) fprintf(fpTxtLogs,"%s",INTIPWARN); if(!strcmp(ipstr,"127.0.0.1") && strcmp(wildcardIpStr,ipstr)) fprintf(fpTxtLogs,"%s",SAMESITEXSSWARN); } if(csvResults && strcmp(wildcardIpStr,ipstr)) fprintf(fpCsvLogs,",%s",ipstr); } } //if(strcmp(wildcardIpStr,ipstr) && strcmp(filterIpStr,ipstr)) { if(strcmp(wildcardIpStr,ipstr) && filter==FALSE) { printf("%s", "\n"); if(txtResults) fprintf(fpTxtLogs,"%s","\n"); if(csvResults) fprintf(fpCsvLogs,"%s","\n"); } filter=FALSE; } // user wants delay between DNS requests? if(delay) dodelay(milliseconds); } if(txtResults) fclose(fpTxtLogs); if(csvResults) fclose(fpCsvLogs); } // read subdomains from wordlist file else if(wordlist) { // openDNS detection if(usesOpenDNS(invalidTldIpstr)) printf("%s",OPENDNSMSG); // wildcard detection wildcarDetect(argv[1],wildcardIpStr); if(strcmp(invalidTldIpstr,wildcardIpStr)) printf(WILDCARDWARN); fpWords=fopen(wordlistFilename, "r"); if(fpWords) { printf(EXTERNALMSG); if(milliseconds>=1) printf(DELAYMSG); printf("%s","\n"); while(!feof(fpWords)) { //strncpy(dom,"",MAXSTRSIZE-strlen(dom)-1); for(i=0;iai_next,++k) { void *addr; char *ipver; if (p->ai_family==AF_INET6) { // IPv6 struct sockaddr_in6 *ipv6=(struct sockaddr_in6 *)p->ai_addr; addr = &(ipv6->sin6_addr); ipver = "IPv6"; } // convert the IP to a string and print it: inet_ntop(p->ai_family, addr, ipv6str, sizeof ipv6str); printf("%s address #%d: %s\n",ipver,k+1,ipv6str); ++ipCount; if(txtResults) fprintf(fpTxtLogs,"%s address #%d: %s\n",ipver,k+1,ipv6str); if(csvResults) fprintf(fpCsvLogs,",%s", ipv6str); } printf("%s", "\n"); if(txtResults) fprintf(fpTxtLogs,"\n"); if(csvResults) fprintf(fpCsvLogs,"\n"); freeaddrinfo(res); // free the linked list // ipv6 code modded from www.kame.net } // end of if conditional h=gethostbyname(dom); if(h && !isIPblacklisted(inet_ntoa(*((struct in_addr *)h->h_addr_list[0])))) { for(j=0;h->h_addr_list[j];++j) { sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[j])),"%s"); //TEST for(k=0;kh_addr_list[j+1]) ++j; else break; } } // END OF TEST //if(strcmp(wildcardIpStr,ipstr) && strcmp(filterIpStr,ipstr)) { if(strcmp(wildcardIpStr,ipstr) && filter==FALSE) { if(j==0) { ++found; printf("%s\n",dom); if(txtResults) { //fprintf(fpCsvLogs,"%s",dom); fprintf(fpTxtLogs,"%s\n",dom); } if(csvResults) { //fprintf(fpCsvLogs,"%s",dom); fprintf(fpCsvLogs,"%s",dom); } } printf("IP address #%d: %s\n",j+1,ipstr); ++ipCount; if(isPrivateIP(ipstr) && strcmp(wildcardIpStr,ipstr)) { printf("%s",INTIPWARN); ++intIPcount; } if(!strcmp(ipstr,"127.0.0.1") && strcmp(wildcardIpStr,ipstr)) printf("%s",SAMESITEXSSWARN); if(txtResults && strcmp(wildcardIpStr,ipstr)) { fprintf(fpTxtLogs,"IP address #%d: %s\n",j+1,ipstr); if(isPrivateIP(ipstr)) fprintf(fpTxtLogs,"%s",INTIPWARN); if(!strcmp(ipstr,"127.0.0.1")) fprintf(fpTxtLogs,"%s",SAMESITEXSSWARN); } if(csvResults && strcmp(wildcardIpStr,ipstr)) fprintf(fpCsvLogs,",%s",ipstr); } } //if(strcmp(wildcardIpStr,ipstr) && strcmp(filterIpStr,ipstr)) { if(strcmp(wildcardIpStr,ipstr) && filter==FALSE) { printf("%s", "\n"); if(txtResults) fprintf(fpTxtLogs,"%s","\n"); if(csvResults) fprintf(fpCsvLogs,"%s","\n"); } filter=FALSE; } // user wants delay between DNS requests? if(delay) dodelay(milliseconds); } // end while() loop fclose(fpWords); } else { printf(OPENFILEERR); exit(1); } if(txtResults) fclose(fpTxtLogs); if(csvResults) fclose(fpCsvLogs); } printf(RESULTSMSG4); if(intIPcount>=1) printf(RESULTSMSG1); if(txtResults) printf(RESULTSMSG2); if(csvResults) printf(RESULTSMSG5); end=(int)time(NULL); printf(RESULTSMSG3); return 0; } // return true if domain wildcards are enabled unsigned short int wildcarDetect(char *dom, char *ipstr) { char strTmp[30]={'\0'},s[MAXSTRSIZE]={'\0'}; unsigned short int i=0,n=0,max=0; struct hostent *h; srand(time(NULL)); max=rand()%20; // max should be between 10 and 20 if(max<10) max=max+(10-max); // generate up to random 20 digits-long subdomain // e.g. 06312580442146732554 for(i=0;ih_addr_list[i];++i) { */ //sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[i])),"%s"); sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[0])),"%s"); #if DEBUG printf("wildcard domain\'s IP address: %s\n",ipstr); #endif return TRUE; } else return FALSE; } // return number of milliseconds delayed unsigned short int dodelay(unsigned short int maxmillisecs) { unsigned short int n=0; srand(time(NULL)); n=rand()%maxmillisecs; ++n; maxmillisecs=n; #if DEBUG printf("sleeping %d milliseconds ...\n",maxmillisecs); #endif usleep(maxmillisecs*1000); return maxmillisecs; } // return true if IP addr is internal (RFC1918) unsigned short int isPrivateIP(char *ip) { char classB[][8]={"172.16.","172.17.","172.18.","172.19.", "172.20.","172.21.","172.22.","172.23.","172.24.", "172.25.","172.26.","172.27.","172.28.","172.29.", "172.30.","172.31."}; unsigned short int i=0,j=0; size_t len = strlen(ip); // shortest: 0.0.0.0 - 8 chars inc \0 // longest: 255.255.255.255 - 16 chars inc \0 if(len<8 || len>16) return 0; // ip addr must have three period signs for(i=0,j=0;i6)) // tld must be between 2-6 char. e.g. .museum, .uk return FALSE; // valid domain can only contain digits, letters, dot (.) and dash symbol (-) len = strlen(d); for(i=0;i= '0' && d[i] <= '9') && !(d[i] >= 'a' && d[i] <= 'z') && !(d[i] >= 'A' && d[i] <= 'Z') && !(d[i] >= '-' && d[i] <= '.')) return 0; } srand(time(NULL)); max=rand()%20; // max should be between 10 and 20 if(max<10) max=max+(10-max); // generate up to random 20 digits-long subdomain // e.g. 06312580442146732554 for(i=0;ih_addr_list[j];++j) inet_ntoa(*((struct in_addr *)h->h_addr_list[j])); if(j>1) { #if DEBUG printf("wildcard domain\'s number of IP address(es): %d" " (this causes dnsmap to produce false positives)\n",j); #endif return FALSE; } } return TRUE; } // return true if IP is blacklisted, false otherwise unsigned short int isIPblacklisted(char *ip) { int i; // add you own blacklisted IP addresses here if dnsmap is producing false positives. // this could be caused by your ISP returning a captive portal search page when // when requesting invalid domains on your browser char ips[][INET_ADDRSTRLEN]={ "81.200.64.50", "67.215.66.132", "1.2.3.4", "0.0.0.0" // add your false positive IPs here }; //for(i=0;ips[i];++i) { for(i=0;i<(sizeof(ips)/INET_ADDRSTRLEN);++i) { if(!strcmp(ips[i],ip)) return TRUE; } return FALSE; } // return true if usage of public DNS server is detected // Note: right now this function only detects openDNS, but might be // updated in the future to detect other common public DNS servers unsigned short int usesOpenDNS(char *ipstr) { char strTmp[30]={'\0'}, s[MAXSTRSIZE]={'\0'}, dummyLTD[4]={"xyz"}/*, ipstr[INET_ADDRSTRLEN]={'\0'}*/; char ips[][INET_ADDRSTRLEN]={"67.215.65.132"}; unsigned short int i=0,j=0,n=0,max=0; struct hostent *h; srand(time(NULL)); max=rand()%20; // max should be between 10 and 20 if(max<10) max=max+(10-max); // generate up to random 20 digits-long subdomain // e.g. 06312580442146732554 for(i=0;ih_addr_list[i];++i) { sprintf(ipstr,inet_ntoa(*((struct in_addr *)h->h_addr_list[i])),"%s"); #if DEBUG printf("public DNS server\'s default IP address #%d: %s\n",i+1,ipstr); #endif for(j=0;i<(sizeof(ips)/INET_ADDRSTRLEN);++j) { if(!strcmp(ips[i],ipstr)) return TRUE; } } return TRUE; } else return FALSE; }