Thread: gethostbyaddr() reverse lookups failing (???)

  1. #1
    Registered User
    Join Date
    Feb 2005
    Posts
    11

    gethostbyaddr() reverse lookups failing (???)

    Hey, I've got a script that I'm having trouble getting to work -- the idea of it is that it runs through a list/file of words and attempts to look each one up as a subdomain to the host you give the script as an argument.. in the code I have a reverse lookup option that does a gethostbyaddr() on the address returned by the original gethostbyname() (this is done if the reverse lookup flag is specific, of course). Anyway I've stripped down the code and left only what's needed to re-create the issue:

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <netdb.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    int checkDomain(char *);
    int wstrip(char *);
    int usage(char *);
    
    short reverse = 0, verbose = 0;
    
    int main(int argc, char *argv[])
    {
    FILE *list;
    char *sublist = NULL, *domain = NULL;
    char line[256], host[256];    /* if your sub/domain is > 256 chars youre a gay or up to no good */
    int opt;
    
        if(argc < 2) {
            usage(argv[0]);
        }
        
        while((opt = getopt(argc, argv, "hs:rv")) != -1) {
            switch(opt) {
                case 'h':
                    usage(argv[0]);
                    break;
                case 's':
                    sublist = optarg;
                    break;
                case 'r':
                    reverse = 1;
                    break;
                case 'v':
                    verbose = 1;
                    break;
                default:
                    usage(argv[0]);
            }
        }
        
        domain = argv[argc-1];
        wstrip(domain);
    
        if(sublist == NULL) {
            fprintf(stderr, "Error: no subdomain list specified. Use -h for help.\n");
            return -1;
        }
        
        if((list = fopen(sublist, "r")) == NULL) {
            fprintf(stderr, "Error: failed to open subdomain list\n");
            return -1;
        }
    
        printf("\ndomain: %s ...\n\n", domain);
        
        checkDomain(domain);
              
        while(!feof(list)) {
            fgets(line, sizeof(line), list);
            
            if((line[0] == '#') || (line[0] == '\n'))
                continue;
    
            wstrip(line);
            snprintf(host, sizeof(host), "%s.%s", line, domain);
            checkDomain(host);
        }
        
        printf("\ncomplete ...\n");
         
        fclose(list);
    
    return 0;
    }       
    int checkDomain(char *domain)
    {
    unsigned long addr;
    
        struct hostent *hent;
        
        if((hent = gethostbyname(domain)) == NULL) {
            if(verbose == 1) {
                if(h_errno != HOST_NOT_FOUND) {
                    herror(domain);
                }
            }
            return 0;
        }
        addr = inet_ntoa(*((struct in_addr *)hent->h_addr));
        
        printf("%-24s %-25s", domain, addr);
        
        if(reverse == 1) {     
            if((hent = gethostbyaddr((char *)addr, sizeof((char *)addr), AF_INET)) != NULL) {
                printf("(%s)\n", (char *)hent->h_name);
            }else{
                printf("(reverse lookup failed)\n");
            }
        }else{
            printf("\n");
        }
    
    return 0;
    }   
    int wstrip(char *str)
    {
    int i = 0, n;
    
        while((str[i] == ' ') || (str[i] == '\t')) {
            i++;
        }
        if(i > 0) {
            for(n = 0; n < strlen(str); n++) {
                str[n] = str[n+i];
            }
            str[n] = '\0';
        }
            
        i = strlen(str)-1;
        while((str[i] == ' ') || (str[i] == '\t') || (str[i] == '\n')) {
            i--;
        }
        if(i < (strlen(str)-1)) {
            str[i++] = '\0';
        }
    
    return 0;
    }
    int usage(char *arg)
    {
        fprintf(stderr, "test - dns domain guessing script\n");
        fprintf(stderr, "usage: %s [opts[args]]\n", arg);
        fprintf(stderr, "-s <domain list>\n");
        fprintf(stderr, "-r enable reverse lookups\n");
        fprintf(stderr, "-h help\n");
        fprintf(stderr, "-v verbose mode\n");
        exit(0);
    }
    for testing purposes, save the following as, well, anything, and use it as your <domain list>:

    Code:
    # example subdomain list
    
    www
    home
    ftp
    ns1
    shop
    shopping
    buy
    stores
    store
    secure
    forums
    beta
    example output:

    Code:
    code@devdeb ~
    $ ./subscan -s example.lst -r amazon.com
    
    domain: amazon.com ...
    
    amazon.com               207.171.163.90           (reverse lookup failed)
    www.amazon.com           207.171.163.90           (reverse lookup failed)
    home.amazon.com          207.171.163.90           (reverse lookup failed)
    ftp.amazon.com           207.171.165.22           (reverse lookup failed)
    ns1.amazon.com           207.171.178.132          (reverse lookup failed)
    shop.amazon.com          207.171.166.23           (reverse lookup failed)
    shopping.amazon.com      207.171.166.23           (reverse lookup failed)
    buy.amazon.com           207.171.166.23           (reverse lookup failed)
    stores.amazon.com        207.171.166.23           (reverse lookup failed)
    store.amazon.com         207.171.166.23           (reverse lookup failed)
    secure.amazon.com        207.171.163.91           (reverse lookup failed)
    forums.amazon.com        207.171.163.18           (reverse lookup failed)
    beta.amazon.com          207.171.181.17           (reverse lookup failed)
    
    complete ...
    
    code@devdeb ~
    $
    so... yeah... obviously gethostbyaddr() keeps returning NULL, justifying the "(reverse lookup failed)" but I can't figure out why it's doing this, or how to fix it. I've tried it with dozens of domains so i know the domain itself isn't an issue. *shrug* I have the feeling it's something small that I'm overlooking. I dont know, help appreciated.

  2. #2
    Registered User
    Join Date
    Apr 2005
    Posts
    134
    Hi,

    The problem I think is

    Code:
    sizeof((char *)addr)
    in gethostbyaddr() call. It should be length of the IP address. What you are passing is the sizeof the pointer which is just 4 bytes (assuming 32-bit address).

    You need to use,

    Code:
    strlen(addr)
    Thanks,

  3. #3
    Registered User
    Join Date
    Feb 2005
    Posts
    11
    Hrmm... nope didn't work. Thanks for trying though ... anyone else?

  4. #4
    Gawking at stupidity
    Join Date
    Jul 2004
    Location
    Oregon, USA
    Posts
    3,218
    Did you bother trying to see why it was failing? #include <errno.h> and change:
    Code:
    printf("(reverse lookup failed)\n");
    to:
    Code:
    printf("(reverse lookup failed: %s)\n", strerror(errno));
    That's a very very simple preliminary debugging tool.
    If you understand what you're doing, you're not learning anything.

  5. #5
    Registered User
    Join Date
    Apr 2005
    Posts
    134
    Hi,

    whether it worked or not is a different problem. But that was the correct way of sending the length, for your code.

    Now, the reason it is not working could be that the DNS server for the domain is not configured with Reverse lookup zone or it may not have a PTR record (used for reverse lookup for domain name) for the IP address that you are using to query. If PTR record is not there in DNS server the it will return nothing. This will cause NULL.

    My suggestion is try the program first with the local DNS server which you can manage. Create some dummy domains and add some hosts with PTR records. Test your program with that domain.
    There is windows/unix based test tool library called "netwox" which can simulate a simple DNS server. It can return only one record (A and/or PTR) when you query it. I had a similar program written myself. I tested with many sites but it did not work. Finally I tested it using this tool and it worked.

    Simple way to test if the reverse lookup will work or not for the current IP is to ping it with "-a" option. If you see the domain name resolved then your program will work for that IP address else it won't.

    For e.g I have a program A which resolved Domain name to IP address using gethostbyname()

    [root@linux snoopy]# ./host1 www.cisco.com
    Hostname: www.cisco.com
    host[1]: 198.133.219.25
    [root@linux snoopy]#
    when I used the IP to ping using -a option I get following .

    D:\>ping -a 198.133.219.25

    Pinging www.cisco.com [198.133.219.25] with 32 bytes of data:

    Reply from 198.133.219.25: bytes=32 time=2ms TTL=121
    Request timed out.
    Reply from 198.133.219.25: bytes=32 time=1ms TTL=121
    Reply from 198.133.219.25: bytes=32 time=1ms TTL=121

    Ping statistics for 198.133.219.25:
    Packets: Sent = 4, Received = 3, Lost = 1 (25% loss),
    Approximate round trip times in milli-seconds:
    Minimum = 1ms, Maximum = 2ms, Average = 1ms
    Check the first line after the ping command. It says pinging to "www.cisco.com". This means that the DNS server for site has a PTR record for that IP.

    If I try the same thing with www.hotmail.com, I get following result.

    D:\>ping -a 206.24.222.120

    Pinging 206.24.222.120 with 32 bytes of data:

    Reply from 206.24.222.120: bytes=32 time=11ms TTL=53
    Reply from 206.24.222.120: bytes=32 time=11ms TTL=53
    Reply from 206.24.222.120: bytes=32 time=11ms TTL=53
    Reply from 206.24.222.120: bytes=32 time=11ms TTL=53

    Ping statistics for 206.24.222.120:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
    Approximate round trip times in milli-seconds:
    Minimum = 11ms, Maximum = 11ms, Average = 11ms
    This means, no PTR record for this IP is available on DNS.

    HTH.

  6. #6
    Registered User
    Join Date
    Mar 2004
    Posts
    536
    Quote Originally Posted by Uncle Rico
    Code:
            if((hent = gethostbyaddr((char *)addr, sizeof((char *)addr), AF_INET)) != NULL)
    so... yeah... obviously gethostbyaddr() keeps returning NULL, justifying the "(reverse lookup failed)" but I can't figure out why it's doing this, or how to fix it. I've tried it with dozens of domains so i know the domain itself isn't an issue. *shrug* :confused: I have the feeling it's something small that I'm overlooking. I dont know, help appreciated.
    The stuff pointed to by the first argument of gethostbyaddr is not a string, it is a struct in_addr (the four binary bytes of the ip address in network order for ipv4). You could use inet_aton() to do the conversion from the string to the binary bytes. (The second argument is the length of the struct --- 4 in this case.)

    The following works for me

    Code:
        if(reverse == 1) {     
            struct in_addr iaddr;
            inet_aton(addr, &iaddr);
                
            if((hent = gethostbyaddr((const void *)&iaddr, sizeof(iaddr), AF_INET)) != NULL) {
                printf("(%s)\n", (char *)hent->h_name);
            } 
            else {
                printf("(reverse lookup failed)\n");
            }
        }else{
            printf("\n");
        }
    As a matter of style, I would normally put the declaration for iaddr at the beginning of the function, but I wanted to illustrate with as little change to your code as possible.

    The addr that you are using (for the result of inet_ntoa()) should be pointer to char. If you got a warning about "assignment makes int from pointer" about the inet_ntoa() line, it means that you should #include <arpa/inet.h> to get the prototype for inet_ntoa(). (And for inet_aton(), now.)

    Regards,

    Dave

    (Might be more appropriately posted on the Networking forum.)
    Last edited by Dave Evans; 08-18-2005 at 05:48 PM.

  7. #7
    Registered User
    Join Date
    Apr 2005
    Posts
    134
    Quote Originally Posted by Dave Evans
    The stuff pointed to by the first argument of gethostbyaddr is not a string, it is a struct in_addr
    Not really, This is the man page definition of gethostbyaddr() on my linux PC,

    Code:
    struct hostent *gethostbyaddr(const char *addr, int len, int type);
    Although as per OP, he is not passing char *, which I realized just now. The variable "addr" should be of type "char *" and NOT "unsigned long". My last post still stands correct about PTR record.

    Function inet_ntoa() returns an ascii string containing the IP address in dotted decimal format as required by gethostbyaddr(). Perhaps, you should pay more attention to the complier warnings.

  8. #8
    Registered User
    Join Date
    Mar 2004
    Posts
    536
    Quote Originally Posted by nkhambal
    Not really, This is the man page definition of gethostbyaddr() on my linux PC,

    Code:
    struct hostent *gethostbyaddr(const char *addr, int len, int type);
    Although as per OP, he is not passing char *, which I realized just now. The variable "addr" should be of type "char *" and NOT "unsigned long". My last post still stands correct about PTR record.

    Function inet_ntoa() returns an ascii string containing the IP address in dotted decimal format as required by gethostbyaddr(). Perhaps, you should pay more attention to the complier warnings.
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <netdb.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    int checkDomain(char *);
    int wstrip(char *);
    int usage(char *);
    
    short reverse = 0, verbose = 0;
    
    int main(int argc, char *argv[])
    {
    FILE *list;
    char *sublist = NULL, *domain = NULL;
    char line[256], host[256];
    int opt;
    
        if(argc < 2) {
            usage(argv[0]);
        }
        
        while((opt = getopt(argc, argv, "hs:rv")) != -1) {
            switch(opt) {
                case 'h':
                    usage(argv[0]);
                    break;
                case 's':
                    sublist = optarg;
                    break;
                case 'r':
                    reverse = 1;
                    break;
                case 'v':
                    verbose = 1;
                    break;
                default:
                    usage(argv[0]);
            }
        }
        
        domain = argv[argc-1];
        wstrip(domain);
    
        if(sublist == NULL) {
            fprintf(stderr, "Error: no subdomain list specified. Use -h for help.\n");
            return -1;
        }
        
        if((list = fopen(sublist, "r")) == NULL) {
            fprintf(stderr, "Error: failed to open subdomain list\n");
            return -1;
        }
    
        printf("\ndomain: %s ...\n\n", domain);
        
        checkDomain(domain);
              
        while(!feof(list)) {
            fgets(line, sizeof(line), list);
            
            if((line[0] == '#') || (line[0] == '\n'))
                continue;
    
            wstrip(line);
            snprintf(host, sizeof(host), "%s.%s", line, domain);
            checkDomain(host);
        }
        
        printf("\ncomplete ...\n");
         
        fclose(list);
    
    return 0;
    }       
    int checkDomain(char *domain)
    {
    /* unsigned long addr; */
    char *addr;
    
        struct hostent *hent;
        
        if((hent = gethostbyname(domain)) == NULL) {
            if(verbose == 1) {
                if(h_errno != HOST_NOT_FOUND) {
                    herror(domain);
                }
            }
            return 0;
        }
        addr = inet_ntoa(*((struct in_addr *)hent->h_addr));
        
        printf("%-24s %-25s", domain, addr);
        if(reverse == 1) {     
            struct in_addr iaddr;
            inet_aton(addr, &iaddr);
                
            if((hent = gethostbyaddr((const void *)&iaddr, sizeof(iaddr), AF_INET)) != NULL) {
                printf("(%s)\n", (char *)hent->h_name);
            } 
            else {
                printf("(reverse lookup failed)\n");
            }
        }else{
            printf("\n");
        }
    
        
    
    return 0;
    }   
    int wstrip(char *str)
    {
    int i = 0, n;
    
        while((str[i] == ' ') || (str[i] == '\t')) {
            i++;
        }
        if(i > 0) {
            for(n = 0; n < strlen(str); n++) {
                str[n] = str[n+i];
            }
            str[n] = '\0';
        }
            
        i = strlen(str)-1;
        while((str[i] == ' ') || (str[i] == '\t') || (str[i] == '\n')) {
            i--;
        }
        if(i < (strlen(str)-1)) {
            str[i++] = '\0';
        }
    
    return 0;
    }
    int usage(char *arg)
    {
        fprintf(stderr, "test - dns domain guessing script\n");
        fprintf(stderr, "usage: %s [opts[args]]\n", arg);
        fprintf(stderr, "-s <domain list>\n");
        fprintf(stderr, "-r enable reverse lookups\n");
        fprintf(stderr, "-h help\n");
        fprintf(stderr, "-v verbose mode\n");
        exit(0);
    }

    Windows XP with cygwin gcc (gcc version 3.3.1)

    with gcc -Wall -pedantic z.c

    no errors, no warnings.



    With the following command line (example.txt is the one supplied in the original post).

    a -s example.txt -r yahoo.com
    My output
    domain: yahoo.com ...

    yahoo.com 216.109.112.135 (w2.rc.vip.dcn.yahoo.com)
    www.yahoo.com 216.109.118.79 (p16.www.dcn.yahoo.com)
    home.yahoo.com 216.109.112.135 (w2.rc.vip.dcn.yahoo.com)
    ns1.yahoo.com 66.218.71.63 (ns1.yahoo.com)
    shop.yahoo.com 216.109.112.135 (w2.rc.vip.dcn.yahoo.com)
    shopping.yahoo.com 216.109.126.171 (pdb3.shop.vip.dcn.yahoo.com)
    stores.yahoo.com 66.163.161.45 (html3.store.vip.sc5.yahoo.com)
    store.yahoo.com 66.163.161.45 (html3.store.vip.sc5.yahoo.com)
    beta.yahoo.com 66.94.234.13 (w2.rc.vip.scd.yahoo.com)

    complete ...
    Regards,

    Dave
    Last edited by Dave Evans; 08-19-2005 at 10:21 AM.

  9. #9
    Registered User
    Join Date
    Feb 2005
    Posts
    11
    Very good you guys have been a huge help! Thanks!!

  10. #10
    Registered User
    Join Date
    Mar 2004
    Posts
    536

    A bug in wstrip()

    Quote Originally Posted by nkhambal
    Not really, This is the man page definition of gethostbyaddr() on my linux PC,

    Code:
    struct hostent *gethostbyaddr(const char *addr, int len, int type);
    Although as per OP, he is not passing char *, which I realized just now. The variable "addr" should be of type "char *" and NOT "unsigned long". My last post still stands correct about PTR record.

    Function inet_ntoa() returns an ascii string containing the IP address in dotted decimal format as required by gethostbyaddr(). Perhaps, you should pay more attention to the complier warnings.
    Notice what I wrote:

    Quote Originally Posted by Dave Evans
    The stuff pointed to by the first argument of gethostbyaddr is not a string, it is a struct in_addr (the four binary bytes of the ip address in network order for ipv4).
    I chose my words carefully. I didn't say that the variable type of the argument has to be a pointer to a struct, I said that the stuff pointed to is a struct with the binary bytes. Note also, that I used a cast on the &iaddr to make sure the compiler didn't complain. I don't like to use casts just for the heck of it, and I could have made iaddr an array of four chars, thus eliminating compiler warning messages, but the way I did it will remind me what the argument really is on that day in the far future (like, maybe, next Tuesday) that I revisit this little example.

    The man page shows function prototypes (and therefore the types of the arguments), but doesn't actually tell us anything about the nature of the the arguments to the functions. I don't just make this stuff up, you know. I looked here: Opengroup gethostbyaddr()

    Where I found this:
    The addr argument of gethostbyaddr() shall be an in_addr structure when type is AF_INET. It contains a binary format (that is, not null-terminated) address in network byte order.

    I do not (and did not) dispute your claim about PTR. As a matter of fact, if I run the program on cisco.com, I get this:

    domain: cisco.com ...

    cisco.com 198.133.219.25 (www.cisco.com)
    www.cisco.com 198.133.219.25 (www.cisco.com)
    home.cisco.com 171.70.67.175 (wwwin-pool5.cisco.com)
    ftp.cisco.com 198.133.219.27 (ftp-sj.cisco.com)
    ns1.cisco.com 128.107.241.185 (ns1.cisco.com)
    shop.cisco.com 198.133.219.23 (redirect.cisco.com)
    secure.cisco.com 171.71.40.99 (secure.cisco.com)
    forums.cisco.com 204.69.199.39 (forums.cisco.com)
    beta.cisco.com 198.133.219.35 (beta.cisco.com)

    complete ...
    When I run it on hotmail.com, I get
    domain: hotmail.com ...

    hotmail.com 64.4.33.7 (hotmail.kz)
    www.hotmail.com 66.35.214.30 (reverse lookup failed)
    ns1.hotmail.com 216.200.206.140 (reverse lookup failed)

    complete ...
    Thus verifying your assertions, but also pointing out that the program (with my minor modification) works as desired.


    Now the real reason for this post: When I tried it on my Linux box, it failed. The reason had nothing to do with the gethost... stuff, but because there is a bug in the wstrip() function in case the example.txt file was created by a text editor that has '\n' instead of '\r''\n' at the end of each line.

    I fixed the wstrip function so that it works regardless of the end-of-line stuff and now everything works on Linux and Windows. (The OP didn't ask about wstrip(), and neither did anyone else, so I will refrain from submitting a solution for that little problem. If someone wants to start a new thread about wstrip(), OK. I really think this thread --- about the gethostbyaddr() --- should have been on the Networking forum anyhow.)



    Regards,

    Dave

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem with my reverse function and its output!
    By Matus in forum C Programming
    Replies: 4
    Last Post: 04-29-2008, 08:33 PM
  2. a reverse function
    By AngKar in forum C Programming
    Replies: 20
    Last Post: 04-27-2006, 10:35 PM
  3. Using reverse iterators in algorithms
    By 0rion in forum C++ Programming
    Replies: 1
    Last Post: 02-27-2006, 03:19 AM
  4. initializes all components of failing to false
    By romeoz in forum C++ Programming
    Replies: 21
    Last Post: 08-01-2003, 09:30 PM
  5. Replies: 7
    Last Post: 03-18-2003, 03:32 PM