alix apu asa auswahl backup bewegung bom buecher c cfengine checklisten cisco computernetz debian dvcs ebtables email epub fairphone2 fedora firewall fossilscm grep hardware i2c iproute ipsec iptables ipv6 kalender kpartx latex laufen lighttpd linux lua lur monotone mount mysql openvpn openwrt pac paketfilter perl postfix programmieren proxy pxelinux python qubes-os rezension rfc rpm rs232 schreiben script seriell shell software stehen sysadmin syslog systemd troubleshoot ubuntu uci vcs virtualbox virtuell vpn wine xen

C-Schnipsel: IP-Adressen einlesen und ausgeben

Wenn ich Netzwerkprogramme in C schreibe, kommt irgendwann der Wunsch auf, IP-Adressen auszugeben oder einzulesen. Sei es, dass ich einen Logeintrag mit einer Adresse schreiben will, oder eine Adresse aus einer Konfigurationsdatei einlesen.

Traditionell kamen dann oft inet_ntoa(), inet_aton() oder ähnliche Funktionen zum Einsatz. Insbesondere die beiden erwähnten Funktionen haben aber den Nachteil, dass sie sich nur für IPv4-Adressen eignen. Damit sind sie für neue Programme überholt und bei der Wartung vorhandener Programme ergibt sich vielleicht die Möglichkeit sie zu ersetzen.

Dafür bieten sich die beiden Funktionen inet_ntop() und inet_pton() an.

IP-Adressen in Text umwandeln

#include <arpa/inet.h>

const char *inet_ntop(int af, const void *src,
                      char *dst, socklen_t size);

Die Funktion inet_ntop() wandelt eine IPv4- oder IPv6-Adresse aus einer Socketstruktur in die entsprechende Textdarstellung um.

Dazu übergebe ich die folgenden Parameter:

  • af - die Protokollfamilie: AF_INET für IPv4 oder AF_INET6 für IPv6,

  • src - die Socketstruktur mit der Adresse: einen Zeiger auf struct in_addr bei IPv4 oder einen Zeiger auf struct in6_addr bei IPv6,

  • dst - einen Puffer, der groß genug ist, die Textdarstellung aufzunehmen,

  • size - die Größe des Puffers (die Konstante INET6_ADDRSTRLEN ist groß genug für IPv4 und IPv6).

In Beej's Guide to Network Programming fand ich eine Hilfsfunktion, die mir einiges an Tipparbeit abnimmt, wenn ich Adressen aus einer struct sockaddr ausgeben will:

char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen) {
    switch(sa->sa_family) {
        case AF_INET:
             inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
                       s, maxlen);
             break;

        case AF_INET6:
             inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
                       s, maxlen);
             break;

        default:
             strncpy(s, "Unknown AF", maxlen);
             return NULL;
    }
    return s;
}

Ich übergebe dieser Funktion einen Zeiger auf die struct sockaddr, außerdem einen Zeichenpuffer und dessen Länge. Zurück erhalte ich einen Zeiger auf eben diesen Puffer mit der Textdarstellung der Adresse oder NULL.

IP-Adressen von Text nach Binär umwandeln

#include <arpa/inet.h>

int inet_pton(int af, const char *src, void *dst);

Die Funktion inet_pton() wandelt die Textdarstellung einer IPv4- oder IPv6-Adresse in eine Socketstruktur, die ich in einem Programm verwenden kann, um.

Dazu übergebe ich die folgenden Parameter:

  • af - die Protokollfamilie: AF_INET für IPv4 oder AF_INET6 für IPv6,

  • src - die Textdarstellung, für IPv4 im Dotted-Decimal-Format ddd.ddd.ddd.ddd, für IPv6 in einer der gängigen Darstellungen,

  • dst - ein Zeiger auf struct in_addr bei AF_INET oder ein Zeiger auf struct in6_addr bei AF_INET6.

Die Funktion inet_pton() macht keine DNS-Anfrage, das heißt ich muss eine IP-Adresse im C-String übergeben. Will ich automatisch Hostadressen auflösen, kann ich auf getaddrinfo() zurückgreifen. Diese Funktion erläutere ich vielleicht in einem anderen Artikel.

Beispielprogramm

Das folgende Programm mag als Beispiel für die Verwendung von inet_pton() und inet_ntop() dienen. Es nimmt eine IPv6- oder IPv4-Adresse als Parameter in der Kommandozeile, wandelt diese in die entsprechende Binärstruktur und wieder zurück und gibt schließlich den konvertierten Text aus:

/*
 * inet_pton-inet_ntop.c
 * Copyright (C) 2018 Mathias Weidner <mathias@mamawe.net>
 *
 * Distributed under terms of the MIT license.
 *
 * see also: http://beej.us/guide/bgnet/
 *
 * This programs takes either an IPv6 or an IPv4 address on the command
 * line and prints. Default is IPv6, to switch to IPv4 use the command
 * line option -4.
 */

#include <arpa/inet.h>

#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void usage(const char * prog) {
    fprintf(stderr,"Usage: %s [-4] address\n", prog);
    exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {
    int opt, result, flag = AF_INET6;
    struct sockaddr_storage addr = {};
    char string[INET6_ADDRSTRLEN] = "";

    while ((opt = getopt(argc, argv, "4")) != -1) {
        switch(opt) {
        case '4':
            flag = AF_INET;
            break;
        default:
            usage(argv[0]);
        }
    }
    if (optind >= argc) {
        usage(argv[0]);
    }
    if(0 >= (result = inet_pton(flag, argv[optind], &addr))) {
        if (0 == result) {
            fprintf(stderr,"Error: %s is not a valid address\n",
                    argv[optind]);
        }
        else {
            fprintf(stderr,"Error: unknown family: %d\n", flag);
        }
        exit(EXIT_FAILURE);
    }
    if (NULL == inet_ntop(flag, &addr, string, sizeof(string))) {
        perror("inet_ntop");
        exit(EXIT_FAILURE);
    }
    printf("%s\n", string);
    exit(EXIT_SUCCESS);
}

Ressourcen:

Ein guter Anlaufpunkt für Netzwerkprogrammierung ist das Buch von W. Richard Stevens: UNIX Network Programming, Volume 1, Networking APIs: Sockets and XTI.

Etwas neuer, dafür bei weitem nicht so umfangreich ist Beej's Guide to Network Programming, zu finden unter http://beej.us/guide/bgnet/. Eine deutsche Übersetzung gibt es unter der Adresse http://www.tobscore.com/socket-programmierung-in-c/.

Posted 2018-05-11 Tags:

Fehlersuche in IPsec VPN: Fragen
Posted 2018-04-26
Rezension: Threat Modeling: Designing for Security
Posted 2018-03-23
Ein Pure-Perl-Modul für PCAP-Dateien
Posted 2018-02-25
Im Trüben fischen in den ASA Logs
Posted 2018-01-22
Half-managed IPsec-VPN ist wie ...
Posted 2017-12-13
Kalender 2018
Posted 2017-12-08
Die serielle Schnittstelle bei Linux
Posted 2017-11-07
Mit pacparser die Proxy-Konfiguration testen
Posted 2017-10-06
Backup mit duply
Posted 2017-08-30