Thread: Extracting and comparing DNS servers from a .txt file

  1. #1
    Registered User
    Join Date
    May 2020
    Posts
    39

    Extracting and comparing DNS servers from a .txt file

    I've already gotten my code to obtain the best option (lower integer as time of response) out of different IP's stored in a .txt file, line after the other with line breaks between them. Now, I've to do the same off a redirected .txt file with different DNS servers surrounded by strings of text. I just need going through the file and taking the average time of response in order to compare recursively and print the winner. That's my previous code, made for a "line after line" approach, without need to browse through character strings:


    Code:
    int best_response = 0;
    char best_ip[sizeof(ipresp)] = "";
    int best_valid = 0;
    responses = fopen("ips_responden.txt", "r");
    if (responses != NULL)
    {
        while (fgets(ipresp, sizeof(ipresp), responses))
        {
            int response1 = velocidad_media(ipresp);
            if (!best_valid || response1 < best_response) {
                best_response = response1;
                strcpy(best_ip, ipresp);
                best_valid = 1;
            }
        }
        printf("\n\n    Average time: %d ms.\n", best_response);
        printf("    Best IP: %s", best_ip);
    }
    My redirected .txt file would look like this:


    Code:
    Configuraci˘n para la interfaz "Ethernet" 
    Servidores DNS configurados a trav‚s de DHCP: 80.10.11.220 
    80.11.43.220 
    Registrar con el sufijo: Solo el principal

    And I'd need to go through the DNS servers only, like the aforementioned code but being able to filter. What I'm working on is this following piece of code:


    Code:
    char term = "DNS", line[500];
    char target = ":", result[100];
    
    FILE* dns = fopen("dns.txt", "r");
        while (fgets(line, sizeof line, dns)) {
            if (strstr(line, term)) {
                strchr(result, target);
            }
                strcpy(result);
            }
        printf("String copied: %s", result);
        }
    fclose(dns);
    Still not working. My idea would be put the pointer to a line where "DNS" was to be found and start reading from the ":" on. But I'm not sure about how to extract the whole DNS server (maybe taking into consideration that it's always following the XX.XX.XX.XXX format would be helpful) and iterate through the file in order to implement the extraction to the code block I've pasted before.

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,629
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <inttypes.h>
     
    #define FRM_SCN "%" SCNu32 ".%" SCNu32 ".%" SCNu32 ".%" SCNu32
    #define FRM_PRI "%" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32
     
    void print_ip(uint32_t ip)
    {
        printf(FRM_PRI "\n", ip >> 24 & 0xff,
                             ip >> 16 & 0xff,
                             ip >>  8 & 0xff,
                             ip       & 0xff);
    }
     
    int main()
    {
        FILE *in = fopen("input.txt", "r");
     
        char line[1024];
        while (fgets(line, sizeof line, in))
        {
            uint32_t a, b, c, d;
     
            // get index to first digit in the line, or to '\0' if none
            unsigned digit = strcspn(line, "0123456789");
     
            if (line[digit]
                && sscanf(line + digit, FRM_SCN, &a, &b, &c, &d) == 4
                && a < 256 && b < 256 && c < 256 && d < 256)
                {
                    // 32-bit ip's can be stored in uint32_t
                    uint32_t ip = a << 24 | b << 16 | c << 8 | d;
                    print_ip(ip);
     
                    // Or you can store it in a string
                    char ip_str[20];
                    sprintf(ip_str, FRM_PRI, a, b, c, d);
                    printf("%s\n\n", ip_str);
                }
        }
     
        fclose(in);
     
        return 0;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    May 2020
    Posts
    39
    Hey John, thanks a lot once again for your response.
    Many concepts escaping my understanding there, so it's a bit of copying/pasting blindly this time. I guess I just need to modify that "input.txt" to "dns.txt" (the file where I store the redirected info) and just choose one of the blocks, either storing in string or uint32_t, right?

    What would ip_str store, though? Just the DNS string?

    Anyway, FRM_PRI (on the "void print_ip" function) expects a parenthesis or it won't let me compile. I don't know if I missed something while declaring it...

    https://cboard.cprogramming.com/imag...AASUVORK5CYII=
    Last edited by JSteel; 05-19-2020 at 03:19 AM. Reason: Compiling error

  4. #4
    Registered User
    Join Date
    Dec 2017
    Posts
    1,629
    It may have been overly-complicated (showing two different ways and using inttypes).
    How about this.
    Code:
    #include <stdio.h>
    #include <string.h>
     
    int main()
    {
        FILE *in = fopen("input.txt", "r");
     
        char line[1024];
        while (fgets(line, sizeof line, in))
        {
            unsigned a, b, c, d;
     
            // get index to first digit in the line, or to '\0' if none
            unsigned digit = strcspn(line, "0123456789");
     
            if (line[digit] // if digit is not index of '\0'
                // and if we're able to read 4 unsigned ints with dots between them
                && sscanf(line + digit, "%u.%u.%u.%u, &a, &b, &c, &d) == 4
                // and if all the values are in range
                && a < 256 && b < 256 && c < 256 && d < 256)
                {
                    // then reconstruct the string from the unsigned ints
                    char ip_str[20];
                    sprintf(ip_str, "%u.%u.%u.%u, a, b, c, d);
     
                    // Now ip_str has the ip as a string.
                    // Do whatever you want with it.
                    printf("%s\n", ip_str);
                }
        }
     
        fclose(in);
     
        return 0;
    }
    A little inaccuracy saves tons of explanation. - H.H. Munro

  5. #5
    Registered User
    Join Date
    May 2020
    Posts
    39
    Thanks a lot for your response again. Didn't compile well so I just added some ending commas and initialized the variables a, b, c and d. Don't know if I did it well, since it crashes when implementing it to my own code. That's how it looks (I'd already declared "line" as global variable). I also added my own touch, and surely messed up, trying to make it look cleaner and, instead of fopen, using _popen with "str" variable (which should store the command used to print the DNS servers therefore giving me the same results without redirecting any extra .txt file). What do you think about it?

    Code:
        FILE* dns = _popen(str, "r");
        while (fgets(line, sizeof line, dns))
        {
            unsigned a = 0, b = 0, c = 0, d = 0;
    
            // get index to first digit in the line, or to '\0' if none
            unsigned digit = strcspn(line, "0123456789");
    
            if (line[digit] // if digit is not index of '\0'
                // and if we're able to read 4 unsigned ints with dots between them
                && sscanf(line + digit, "%u.%u.%u.%u, &a, &b, &c, &d") == 4
                // and if all the values are in range
                && a < 256 && b < 256 && c < 256 && d < 256)
            {
                // then reconstruct the string from the unsigned ints
                char ip_str[20];
                sprintf(ip_str, "%u.%u.%u.%u, a, b, c, d");
    
                // Now ip_str has the ip as a string.
                // Do whatever you want with it.
                printf("%s\n", ip_str);
            }
        }
    
        fclose(dns);

  6. #6
    Registered User
    Join Date
    Dec 2017
    Posts
    1,629
    I didn't test it and forgot some closing double-quotes.
    But you put them in the wrong place.
    Note that you should probably use _pclose to close a FILE* opened with _popen.
    Code:
    FILE* dns = _popen(str, "r");
    while (fgets(line, sizeof line, dns))
    {
        unsigned a = 0, b = 0, c = 0, d = 0;
     
        // get index to first digit in the line, or to '\0' if none
        unsigned digit = strcspn(line, "0123456789");
     
        if (line[digit] // if digit is not index of '\0'
            // and if we're able to read 4 unsigned ints with dots between them
            && sscanf(line + digit, "%u.%u.%u.%u", &a, &b, &c, &d) == 4
            // and if all the values are in range
            && a < 256 && b < 256 && c < 256 && d < 256)
        {
            // then reconstruct the string from the unsigned ints
            char ip_str[20];
            sprintf(ip_str, "%u.%u.%u.%u", a, b, c, d);
     
            // Now ip_str has the ip as a string.
            // Do whatever you want with it.
            printf("%s\n", ip_str);
        }
    }
     
    _pclose(dns);
    A little inaccuracy saves tons of explanation. - H.H. Munro

  7. #7
    Registered User
    Join Date
    May 2020
    Posts
    39
    Works as a charm, mate! Thanks again!
    Now I'm in a different problem:

    Code:
                    printf("\n\DNS: %s\n", ip_str);
                    int dns_s1 = velocidad_media(ip_str);
                    printf("Average time of response: %s ms.\n", dns_s1);
    I want "dns_s1" to store the average time of response when pinging the DNS server. If you remember my previous annoyance, I did so successfully via the following function:

    Code:
    int velocidad_media(const char* ip)
    {
        const char* const Delim = "Media = ";
        printf("\nExtrayendo velocidad media de %s", ip);
    
        char cmd[64];
        sprintf(cmd, "ping %s", ip);
        FILE* p = _popen(cmd, "r");
        char line[256];
        while (fgets(line, sizeof(line), p))
        {
            char* s = NULL;
            if ((s = strstr(line, Delim)) != NULL)
            {
                _pclose(p);
                return atoi(s + strlen(Delim));
            }
        }
        _pclose(p);
    
        return 0;
    }
    ... but this time, with the new variable ip_str it crashes. I don't know the logic to it whatsoever, can you find it?

  8. #8
    Registered User
    Join Date
    May 2020
    Posts
    39
    Got it!

    Code:
                    printf("Average time of response: %s ms.\n", dns_s1);
    How foolish of me printing an int with %s!

  9. #9
    Registered User
    Join Date
    May 2020
    Posts
    39
    Now, almost there...

    Trying to pick the DNS server that coincides with the lower average time value. This worked well with my IP block:

    Code:
            int best_response = 0;
            char best_ip[sizeof(ipresp)] = "";
            int best_valid = 0;
            responses = fopen("ips_responden.txt", "r");
            if (responses != NULL)
            {
                while (fgets(ipresp, sizeof(ipresp), responses))
                {
                    int response1 = velocidad_media(ipresp);
                    if (!best_valid || response1 < best_response) {
                        best_response = response1;
                        strcpy(best_ip, ipresp);
                        best_valid = 1;
                    }
                }
                printf("\n\n    Velocidad de respuesta media: %d ms.\n", best_response);
                printf("\n    IP seleccionada: %s", best_ip);
            }
    So I'm trying to mimic it with the new approach given by your help, but after compiling it won't print a thing:

    Code:
            FILE* dns = _popen(str, "r");
            while (fgets(line, sizeof line, dns))
            {
                unsigned a = 0, b = 0, c = 0, d = 0;
                unsigned digit = strcspn(line, "0123456789");
    
                if (line[digit]
                    && sscanf(line + digit, "%u.%u.%u.%u", &a, &b, &c, &d) == 4
                    && a < 256 && b < 256 && c < 256 && d < 256)
                {                char ip_str[20];
                    sprintf(ip_str, "%u.%u.%u.%u", a, b, c, d);
    
                    int best_response_dns = 0;
                    char best_dns[sizeof(ip_str)] = "";
                    int best_valid_dns = 0;
                    dns = fopen(str, "r");
                    if (dns != NULL)
                    {
                        while (fgets(ip_str, sizeof ip_str, dns)) 
                        {
                            int dns_s1 = velocidad_media(ip_str);
                            if (!best_valid_dns || dns_s1 < best_response_dns) {
                                best_response_dns = dns_s1;
                                strcpy(best_dns, ip_str);
                                best_valid_dns = 1;
                            }
                        }
                        printf("\n    DNS seleccionada: %s\n", best_dns);
                        printf("\n    Velocidad media: %d ms.\n", best_response_dns);
                    }
                }
                _pclose(dns);
            }
    I guess some trivial mistakes are going on but cannot find them!

  10. #10
    Registered User
    Join Date
    Dec 2017
    Posts
    1,629
    As usual, I don't understand what you are trying to do. The code doesn't make sense to me and you've never really been able to explain what in the world you are trying to do overall. I'm lost. It's frustrating.

    Is this one program or more than one?
    What is it's purpose?
    What exactly does the input (from all sources if more than one) look like?
    What exactly do you want the output to be?
    A little inaccuracy saves tons of explanation. - H.H. Munro

  11. #11
    Registered User
    Join Date
    May 2020
    Posts
    39
    Yes, sorry. I've tried to simplify working in different modules now.

    First one should export to dns_responden.txt those DNS servers. Working fine so far:

    Code:
    void extraerDNS() {
    
        FILE* responsesdns = fopen("dns_responden.txt", "w");
        FILE* dns = _popen(str, "r");
        while (fgets(line, sizeof line, dns))
        {
        unsigned a = 0, b = 0, c = 0, d = 0;
        unsigned digit = strcspn(line, "0123456789");
    
        if (line[digit]
            && sscanf(line + digit, "%u.%u.%u.%u", &a, &b, &c, &d) == 4
            && a < 256 && b < 256 && c < 256 && d < 256)
        {
            char ip_str[20];
            sprintf(ip_str, "%u.%u.%u.%u", a, b, c, d);
            fprintf(responsesdns, "%s\n", ip_str);
        }
    }
    
    _pclose(dns);
    }
    dns_responden.txt looks like this, format-wise (fictional DNS servers):

    Code:
    80.51.41.651
    80.08.21.229
    Now, back to my main, the backbone of my program, where I had implemented previous help to ping through different IP's (also from a redirected .txt file, namely ips_responden.txt):

    Code:
            FILE* responses = fopen("ips_responden.txt", "w");
            while (fgets(ch, sizeof(ch), fp))
            {
                printf("\n    Lanzando ping a %s", ch);
                sprintf(ping_cmd, "ping %s", ch);
                FILE* f = _popen(ping_cmd, "r");
                while (fgets(line, sizeof line, f)) {
                    if (strstr(line, term)) {
                        fprintf(responses, "%s", ch);
                    }
                }
                fclose(f);
            }
            fclose(responses);
            fclose(fp);
    
            int best_response = 0;
            char best_ip[sizeof(ipresp)] = "";
            int best_valid = 0;
            responses = fopen("ips_responden.txt", "r");
            if (responses != NULL)
            {
                while (fgets(ipresp, sizeof(ipresp), responses))
                {
                    int response1 = velocidad_media(ipresp);
                    if (!best_valid || response1 < best_response) {
                        best_response = response1;
                        strcpy(best_ip, ipresp);
                        best_valid = 1;
                    }
                }
                printf("\n\n    Velocidad de respuesta media: %d ms.\n", best_response);
                printf("\n    IP seleccionada: %s", best_ip);
            }
            extraerDNS();
    This came in hefty to compare among IP's, keeping the lower value as best_response and its corresponding IP as best_ip. The latter phase of my program involves almost the same, but considerably shorter since I don't need to ping before in order to select among those which respond.
    As you can see, this final line invoked this new module, i.e. redirects the DNS servers to the .txt file.

    I'm implementing the following block immediately afterwards just to be able to compare between them, too, and be able to print the "winner" as well. First off, I'll open the redirected .txt to be able to do the rest:

    Code:
            FILE* responsesdns = fopen("dns_responden.txt", "r");
            int best_response_dns = 0;
            char best_dns[sizeof(ip_str)] = "";
            int best_valid_dns = 0;
            if (responsesdns != NULL)
            {
                while (fgets(ip_str, sizeof(ip_str), responsesdns))
                {
                    int dns1 = velocidad_media(ip_str);
                    if (!best_valid_dns || dns1 < best_response_dns) {
                        best_response_dns = dns1;
                        strcpy(best_dns, ip_str);
                        best_valid_dns = 1;
                    }
                }
                printf("\n\n    Velocidad de respuesta media: %d ms.\n", best_response_dns);
                printf("\n    DNS seleccionada: %s", best_dns);
            }
    ... but it doesn't print a thing. In fact, I'm getting just a "0" for best_response_dns and a null value for best_dns. I don't know how to fix it.

    Does this make more sense now?
    Please forgive my sloppy approach. As you can see, I'm just learning the basics and it's too frustrating as well. And your help is much appreciated, mind you.
    Last edited by JSteel; 05-21-2020 at 11:23 AM.

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Are you sure velocidad_media is working correctly with the input from fgets? Recall that fgets stores the newline from reading the line at the end of the string if there is space for it.

    best_response_dns sounds like a poor name because it sounds like the same kind of thing as best_dns. I'd rename it to best_response_time.

    best_valid_dns sounds badly named too. It has nothing to do with the best valid dns... rather, it is a flag as to whether the first IP address in the list has been processed. This means that you need to check this flag before you blindly start printing anything.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Registered User
    Join Date
    May 2020
    Posts
    39
    Hey laserlight! Thanks for your input. True about the names but, as with the rest of the code, I just wanted to transpose the previous block with slightly different nomenclature in order to avoid mixing variables. Also, didn't put much thought to this fact but, as I'm needing help from others, I'm working in a much more understandable way now. My apologies in this regard for making things difficult.

    As for the velocidad_media function, sure, it gets the average time of IP's in the previous block (the one involving variable ipresp instead of ip_str), so I don't know how would it be affecting this time. Once again, maybe you're right and I'm not getting it straight at all. But I think I've kept the same syntax and structure and it's so weird it's not working this time. I'm really lost on it.

    In short: I'd want to access the "dns_responden.txt" file and read, line by line, using the velocidad_media function for each line, and storing just the resulting lowest value of the bunch, and I'd done well with IP's but it seems weird this time is not working at all.

  14. #14
    Registered User
    Join Date
    May 2020
    Posts
    39
    Update: I've tried out, through a different file and folder (where I've copied the same dns_responden.txt file) the following code, in order to follow laserlight's signature hint. Compiles and works perfect, the way I want it to do:

    Code:
    #define _CRT_SECURE_NO_WARNINGS
    
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int velocidad_media(const char* ip)
    {
        const char* const Delim = "Media = ";
        printf("\nExtrayendo velocidad media de %s", ip);
    
        char cmd[64];
        sprintf(cmd, "ping %s", ip);
        FILE* p = _popen(cmd, "r");
        char line[256];
        while (fgets(line, sizeof(line), p))
        {
            char* s = NULL;
            if ((s = strstr(line, Delim)) != NULL)
            {
                _pclose(p);
                return atoi(s + strlen(Delim));
            }
        }
        _pclose(p);
    
        return 0;
    }
    
    void main()
    {
        FILE* responsesdns = fopen("dns_responden.txt", "r");
        int best_response_time = 0;
        char ip_str[100], best_dns[sizeof(ip_str)] = "";
        int best_valid_dns = 0;
        if (responsesdns != NULL)
        {
            while (fgets(ip_str, sizeof(ip_str), responsesdns))
            {
                int dns1 = velocidad_media(ip_str);
                if (!best_valid_dns || dns1 < best_response_time) {
                    best_response_time = dns1;
                    strcpy(best_dns, ip_str);
                    best_valid_dns = 1;
                }
            }
            printf("\n\n    Velocidad de respuesta media: %d ms.\n", best_response_time);
            printf("\n    DNS seleccionada: %s", best_dns);
        }
    }
    Now, implementing it to my program, I've created the mediaDNS() module, just copied/pasted from the previous main:

    Code:
    void mediaDNS()
    {
        FILE* responsesdns = fopen("dns_responden.txt", "r");
        int best_response_time = 0;
        char ip_str[100], best_dns[sizeof(ip_str)] = "";
        int best_valid_dns = 0;
        if (responsesdns != NULL)
        {
            while (fgets(ip_str, sizeof(ip_str), responsesdns))
            {
                int dns1 = velocidad_media(ip_str);
                if (!best_valid_dns || dns1 < best_response_time) {
                    best_response_time = dns1;
                    strcpy(best_dns, ip_str);
                    best_valid_dns = 1;
                }
            }
            printf("\n\n    Velocidad de respuesta media: %d ms.\n", best_response_time);
            printf("\n    DNS seleccionada: %s", best_dns);
        }
    }
    I'm invoking it just inside the program's main, just after extracting the DNS servers to the redirected file (extraerDNS module), both inside and outside its loop...:

    Code:
            int best_response = 0;
            char best_ip[sizeof(ipresp)] = "";
            int best_valid = 0;
            responses = fopen("ips_responden.txt", "r");
            if (responses != NULL)
            {
                while (fgets(ipresp, sizeof(ipresp), responses))
                {
                    int response1 = velocidad_media(ipresp);
                    if (!best_valid || response1 < best_response) {
                        best_response = response1;
                        strcpy(best_ip, ipresp);
                        best_valid = 1;
                    }
                }
                printf("\n\n    Velocidad de respuesta media: %d ms.\n", best_response);
                printf("\n    IP seleccionada: %s", best_ip);
                fclose(responses);
                extraerDNS();
            }
            mediaDNS();
    And nothing. Well, it gives me a 0 for best_response and null value for best_ip. I can't understand what's happening between both approaches.
    Last edited by JSteel; 05-22-2020 at 04:24 AM.

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by JSteel
    I just wanted to transpose the previous block with slightly different nomenclature in order to avoid mixing variables.
    When you start getting worried about "mixing variables", it means that it is time to break your function into smaller functions that each does one thing and does it well.

    Quote Originally Posted by JSteel
    As for the velocidad_media function, sure, it gets the average time of IP's in the previous block (the one involving variable ipresp instead of ip_str), so I don't know how would it be affecting this time. Once again, maybe you're right and I'm not getting it straight at all. But I think I've kept the same syntax and structure and it's so weird it's not working this time. I'm really lost on it.
    Then don't assume. Test! Write unit tests that throw various input at the function and see if it returns what you expect it to return, whether a valid value or an error code. In more advanced unit testing, you would mock the DNS servers so that for a known mock IP address, the mocked DNS server waits for some time that you know in advance and hence can check if the time returned is in range of that known time.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help extracting JPG from .WAV file
    By MattJunior in forum C++ Programming
    Replies: 15
    Last Post: 07-20-2017, 06:16 AM
  2. Extracting Data from txt File
    By BonaviaFx in forum C Programming
    Replies: 1
    Last Post: 01-13-2015, 05:10 AM
  3. Extracting and comparing numbers
    By .C-Man. in forum C++ Programming
    Replies: 47
    Last Post: 03-01-2011, 08:45 AM
  4. extracting file names
    By cathal in forum C Programming
    Replies: 1
    Last Post: 08-19-2004, 08:57 AM

Tags for this Thread