-1

I'm trying to get my own ip addres with C. The idea is to get the output of "ifconfig", put it in a .txt file and extract the inet and the inet6 values. I stack trying to write the ifconfig output in the .txt file:

#include <stdio.h>
#include <stdlib.h>
#include <string>
int main ()
{
    char command[1000];
    strcpy(command, "ifconfig"); 
    system(command);

    FILE *fp = fopen("textFile.txt", "ab+");

    //... how to write the output of 'system(command)' in the textFile.txt?

    fclose(fp);

    //... how to scraping a file .text in C  ???

    return 0;
}

Thank you for any help and suggestion, Stefano

Stefano
  • 60
  • 1
  • 1
  • 7
  • 1
    Assuming you're using linux, have a look at http://stackoverflow.com/questions/2283494/get-ip-address-of-an-interface-on-linux – Sander De Dycker Mar 21 '17 at 15:42
  • Again, assuming you're using Linux, check this [C: Run a System Command and Get Output?](http://stackoverflow.com/questions/646241/c-run-a-system-command-and-get-output). You'll also want to check the originals, for anything new. – Wade Tyler Mar 21 '17 at 15:44
  • How do you expect that to work with DHCP/zeroconf? XY problem. EIther get the IP from your interface or some other portable way. – too honest for this site Mar 21 '17 at 15:45
  • yes indeed, Ubuntu 16.04. Thank you. – Stefano Mar 21 '17 at 15:45
  • I suspect the screen-scraping tag doesn't belong here. Just a high-level suggestion.. once you programatically determine a way to get the IP addr of your interface, there's no point in writing that to a file, then reading from that file to do your parsing. Just do your parsing in memory once you get it, and write the info to a file if you still want to do that. – yano Mar 21 '17 at 15:49

2 Answers2

0

You actually want to use system calls to accomplish this - rather than running the ifconfig command.

There's a similar question here for Linux: using C code to get same info as ifconfig

(Since ifconfig is a Linux command, I'm assuming you're asking about Linux).

The general gist was to use the ioctl() system call.

Otherwise, you'll be forking your process to split it into two, creating a pipe from the output of the child to the input of the parent, and calling exec on the child in order to replace it with "ifconfig". Then, you'll have to parse the string if you want to get anything useful out of it.

Community
  • 1
  • 1
Anish Goyal
  • 2,469
  • 8
  • 16
0

In Linux, use man 7 netdevice describes the interface you can use, as Anish Goyal already answered.

This is very simple and robust, and uses very little resources (since it is just a few syscalls). Unfortunately, it is Linux specific, and makes the code nonportable.

It is possible to do this portably. I describe the portable option here, because the Linux-specific one is rather trivial. Although the approach is quite complicated for just obtaining the local host IP addresses, the pattern is surprisingly often useful, because it can hide system-specific quirks, while easily allowing system administrators to customize the behaviour.

The idea for a portable solution is that you use a small helper program or shell script to obtain the information, and have it output the information in some easy-to-parse format to your main program. If your application is named yourapp, it is common to install such helpers in /usr/lib/yourapp/, say /usr/lib/yourapp/local-ip-addresses.

Personally, I'd recommend using a shell script (so that system admins can trivially edit the helpers if they need to customize the behaviour), and an output format where each interface is on its own line, fields separated by spaces, perhaps

inet interface-name ipv4-address [ hostname ]*
inet6 interface-name ipv6-address [ hostname ]*

i.e. first token specifies the address family, second token the interface name, third the address, optionally followed by the hostnames or aliases corresponding to that address.

As to the helper program/shell script itself, there are two basic approaches:

  1. One-shot

    For example, parsing LANG=C LC_ALL=C ip address output in Linux. The program/script will exit after the addresses have been printed.

  2. Continuous

    The program/script will print the ip address information, but instead of exiting, it will run as long as the pipe stays open, providing updates if interfaces are taken down or come up.

    In Linux, a program/script could use DBUS or NetworkManager to wait for such events; it would not need to poll (that is, repeatedly check the command output).

A shell script has the extra benefit that it can support multiple distributions, even operating systems (across POSIX systems at least), at the same time. Such scripts often have a similar outline:

#!/bin/sh
export LANG=C LC_ALL=C
case "$(uname -s)" in

  Linux)
    if [ -x /bin/ip ]; then
        /bin/ip -o address | awk \
           '/^[0-9]*:/ {
                addr = $4
                sub(/\/.*$/, "", addr)
                printf "%s %s %s\n", $3, $2, addr
            }'
        exit 0
    elif [ -x /sbin/ifconfig ]; then
        /sbin/ifconfig | awk \
           'BEGIN {
                RS = "[\t\v\f\r ]*\n"
                FS = "[\t\v\f ]+"
            }
            /^[0-9A-Za-z]/ {
                iface = $1
            }
            /^[\t\v\f ]/ {
                if (length(iface) > 0)
                    for (i = 1; i < NF-1; i++)
                        if ($i == "inet") {
                            addr = $(i+1)
                            sub(/^addr:/, "", addr)
                            printf "inet %s %s\n", iface, addr
                        } else
                        if ($i == "inet6") {
                            addr = $(i+2)
                            sub(/\/.*$/, "", addr)
                            printf "inet6 %s %s\n", iface, addr
                        }
            }'
        exit 0

    fi
    ;;

  # Other systems?

esac

printf 'Cannot determine local IP addresses!\n'
exit 1

The script sets the locale to C/POSIX, so that the output of external commands will be in the default locale (in English and so on). uname -s provides the kernel name (Linux for Linux), and further checks can be done using e.g. the [ shell command.

I only implemented the scriptlet for Linux, because that's the machine I'm on right now. (Both ip and ifconfig alternatives work on my machine, and provide the same output -- although you cannot expect to get the interfaces in any specific order.)

The situations where a sysadmin might need to edit this particular helper script includes as-yet-unsupported systems, systems with new core tools, and systems that have interfaces that should be excluded from normal interface lists (say, those connected to a internal sub-network that are reserved for privileged purposes like DNS, file servers, backups, LDAP, and so on).

In the C application, you simply execute the external program or shell script using popen("/usr/lib/yourapp/local-ip-addresses", "r"), which provides you a FILE * that you can read as if it was a file (except you cannot seek or rewind it). After you have read everything from the pipe, pclose() the handle:

#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

/* ... */

    FILE   *in;
    char   *line_ptr = NULL;
    size_t  line_size = 0;
    ssize_t line_len;
    int     status;

    in = popen("/usr/lib/myapp/local-ip-addresses", "r");
    if (!in) {
        fprintf(stderr, "Cannot determine local IP addresses: %s.\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    while (1) {

        line_len = getline(&line_ptr, &line_size, in);
        if (line_len < 1)
            break;

        /* Parse line_ptr */

    }

    free(line_ptr);
    line_ptr = NULL;
    line_size = 0;

    if (ferror(in) || !feof(in)) {
        pclose(in);
        fprintf(stderr, "Read error while obtaining local IP addresses.\n");
        exit(EXIT_FAILURE);
    }

    status = pclose(in);
    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
        fprintf(stderr, "Helper utility /usr/lib/myapp/local-ip-addresses failed to obtain local IP addresses.\n");
        exit(EXIT_FAILURE);
    }

I omitted the parsing code, because there are so many alternatives -- strtok(), sscanf(), or even a custom function that splits the line into tokens (and populates an array of pointers) -- and my own preferred option is the least popular one (last one, a custom function).

While the code needed for just this task is almost not worth the while, applications that use this approach tend to use several of such helpers. Then, of course, it makes sense to choose the piped data format in a way that allows easy parsing, but supports all use cases. The amortized cost is then much easier to accept, too.

Community
  • 1
  • 1
Nominal Animal
  • 34,734
  • 4
  • 49
  • 79