Rufen Sie die IP-Adresse einer Schnittstelle unter Linux ab

Lesezeit: 8 Minuten

Benutzeravatar von leeeroy
leeroy

Wie bekomme ich die IPv4 Adresse einer Schnittstelle unter Linux aus C-Code?

Zum Beispiel möchte ich die IP-Adresse (falls vorhanden) eth0 zugewiesen bekommen.

Benutzeravatar von Filip Ekberg
Philipp Ekberg

Versuche dies:

#include <stdio.h>
#include <unistd.h>
#include <string.h> /* for strncpy */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>

int
main()
{
 int fd;
 struct ifreq ifr;

 fd = socket(AF_INET, SOCK_DGRAM, 0);

 /* I want to get an IPv4 IP address */
 ifr.ifr_addr.sa_family = AF_INET;

 /* I want IP address attached to "eth0" */
 strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1);

 ioctl(fd, SIOCGIFADDR, &ifr);

 close(fd);

 /* display result */
 printf("%s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));

 return 0;
}

Das Codebeispiel stammt aus hier.

  • Warum gibt es einen Segmentierungsfehler?

    – Benutzer138126

    26. März 2013 um 11:13 Uhr

  • Wenn Sie sich ändern SIOCGIFADDR zu SIOCGIFNETMASKkönnen Sie die Netzmaske der Schnittstelle abrufen.

    – Craig McQueen

    4. April 2014 um 2:23 Uhr

  • Es lohnt sich, den Rückgabewert von zu überprüfen ioctl()und wenn es nicht Null ist, überprüfen Sie den Wert von errno.

    – Craig McQueen

    4. April 2014 um 2:49 Uhr

  • Kein Bedarf für IFNAMSIZ-1sondern nur IFNAMSIZ wird genügen. strncpy verwendet das letzte Byte, um die Zeichenfolge im Falle eines Überlaufs zu beenden.

    – zapstern

    16. November 2016 um 9:01 Uhr

  • @zapstar Ich glaube nicht, dass das richtig ist. Von dem strncpy manpage: Warnung: Wenn sich unter den ersten n Bytes von src kein Null-Byte befindet, wird die in dest platzierte Zeichenfolge nicht nullterminiert.

    – Mark Smith

    4. April 2017 um 10:15 Uhr


Zusätzlich zu der von Filip demonstrierten ioctl()-Methode können Sie sie verwenden getifaddrs(). Am Ende der Manpage befindet sich ein Beispielprogramm.

  • getifaddrs scheint sehr umfassend zu sein. Andere Methoden geben nur die primäre oder erste Adresse pro Schnittstelle an.

    – MarkR

    17. Februar 2010 um 22:00 Uhr

  • Ich habe keine Verbindung zu eth0, wenn ich die andere Methode verwende, wird 128.226.115.183 ausgegeben, was falsch ist. Diese Methode zeigt jedoch, dass es keine Verbindung auf eth0 gibt, die eine zuverlässige Ausgabe liefert

    – Angs

    14. Juli 2013 um 10:47 Uhr

Benutzeravatar von sjsam
sjsam

Wenn Sie nach einer Adresse (IPv4) der spezifischen Schnittstelle suchen, sagen Sie WLAN0 dann versuchen Sie diesen Code, der verwendet getifaddrs():

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
    struct ifaddrs *ifaddr, *ifa;
    int family, s;
    char host[NI_MAXHOST];

    if (getifaddrs(&ifaddr) == -1) 
    {
        perror("getifaddrs");
        exit(EXIT_FAILURE);
    }


    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 
    {
        if (ifa->ifa_addr == NULL)
            continue;  

        s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);

        if((strcmp(ifa->ifa_name,"wlan0")==0)&&(ifa->ifa_addr->sa_family==AF_INET))
        {
            if (s != 0)
            {
                printf("getnameinfo() failed: %s\n", gai_strerror(s));
                exit(EXIT_FAILURE);
            }
            printf("\tInterface : <%s>\n",ifa->ifa_name );
            printf("\t  Address : <%s>\n", host); 
        }
    }

    freeifaddrs(ifaddr);
    exit(EXIT_SUCCESS);
}

Sie können ersetzen WLAN0 mit eth0 für Ethernet u siehe für lokales Loopback.

Die Struktur und detaillierte Erläuterungen zu den verwendeten Datenstrukturen konnten gefunden werden hier.

Um mehr über verknüpfte Listen in C zu erfahren, klicken Sie hier Seite wird ein guter Ausgangspunkt sein.

  • warum wir brauchen getnameinfo?

    – abhiarora

    14. Juli 2020 um 15:00 Uhr

  • @abhiarora Aus dem Dokument – es konvertiert eine Socket-Adresse auf protokollunabhängige Weise in einen entsprechenden Host und Dienst. Beachten Sie, dass der Wert der host Der später gedruckte Parameter wird innerhalb der geliefert getnameinfo Funktion.

    – sjsam

    14. Juli 2020 um 17:58 Uhr


  • Warum ifa->ifa_addr == NULL ist nicht genug? Ich bin mir nicht sicher, warum wir brauchen getnameinfo da ifa_addr eine interne Adresse ist.

    – abhiarora

    15. Juli 2020 um 4:08 Uhr

Meine 2 Cent: Derselbe Code funktioniert auch bei iOS:

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>



#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    showIP();
}



void showIP()
{
    struct ifaddrs *ifaddr, *ifa;
    int family, s;
    char host[NI_MAXHOST];

    if (getifaddrs(&ifaddr) == -1)
    {
        perror("getifaddrs");
        exit(EXIT_FAILURE);
    }


    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
    {
        if (ifa->ifa_addr == NULL)
            continue;

        s=getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);

        if( /*(strcmp(ifa->ifa_name,"wlan0")==0)&&( */ ifa->ifa_addr->sa_family==AF_INET) // )
        {
            if (s != 0)
            {
                printf("getnameinfo() failed: %s\n", gai_strerror(s));
                exit(EXIT_FAILURE);
            }
            printf("\tInterface : <%s>\n",ifa->ifa_name );
            printf("\t  Address : <%s>\n", host);
        }
    }

    freeifaddrs(ifaddr);
}


@end

Ich habe einfach den Test gegen wlan0 entfernt, um Daten zu sehen. ps Sie können “Familie” entfernen

Benutzeravatar von George
George

Ich war kürzlich in derselben Ausgabe, und dies ist der Code, den ich mir ausgedacht habe, und er funktioniert. Stellen Sie sicher, dass Sie den Namen der Netzwerkschnittstelle genau so verwenden, wie Sie ihn haben (könnte “eth0” oder ein anderer sein).

muss prüfen ob ifconfigBefehl, um den Schnittstellennamen abzurufen und in C zu verwenden.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <linux/if.h>
#include <errno.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
    

void extract_ipaddress()
    {
        //create an ifreq struct for passing data in and out of ioctl
        struct ifreq my_struct;
     
        //declare and define the variable containing the name of the interface
        char *interface_name="enp0s3";   //a very frequent interface name is "eth0";
     
        //the ifreq structure should initially contains the name of the interface to be queried. Which should be copied into the ifr_name field.
        //Since this is a fixed length buffer, one should ensure that the name does not cause an overrun
        size_t interface_name_len=strlen(interface_name);
     
        if(interface_name_len<sizeof(my_struct.ifr_name))
        {
            memcpy(my_struct.ifr_name,interface_name,interface_name_len);
            my_struct.ifr_name[interface_name_len]=0;
        }
        else
        {
            perror("Copy name of interface to ifreq struct");
            printf("The name you provided for the interface is too long...\n");
        }
     
        //provide an open socket descriptor with the address family AF_INET
        /* ***************************************************************
         * All ioctl call needs a file descriptor to act on. In the case of SIOCGIFADDR this must refer to a socket file descriptor. This socket must be in the address family that you wish to obtain (AF_INET for IPv4)
         * ***************************************************************
         */
     
        int file_descriptor=socket(AF_INET, SOCK_DGRAM,0);
     
        if(file_descriptor==-1)
        {
            perror("Socket file descriptor");
            printf("The construction of the socket file descriptor was unsuccessful.\n");
            return -1;
        }
     
        //invoke ioctl() because the socket file descriptor exists and also the struct 'ifreq' exists
        int myioctl_call=ioctl(file_descriptor,SIOCGIFADDR,&my_struct);
     
        if (myioctl_call==-1)
        {
            perror("ioctl");
            printf("Ooops, error when invoking ioctl() system call.\n");
            close(file_descriptor);
            return -1;
        }
     
        close(file_descriptor);
     
        /* **********************************************************************
         * If this completes without error , then the hardware address of the interface should have been returned in the  'my_struct.ifr_addr' which is types as struct sockaddr_in.
         * ***********************************************************************/
     
      //extract the IP Address (IPv4) from the my_struct.ifr_addr which has the type 'ifreq'
     
        /* *** Cast the returned address to a struct 'sockaddr_in' *** */
        struct sockaddr_in * ipaddress= (struct sockaddr_in *)&my_struct.ifr_addr;
       /* *** Extract the 'sin_addr' field from the data type (struct) to obtain a struct 'in_addr' *** */
      printf("IP Address is %s.\n", inet_ntoa(ipaddress->sin_addr));

    }

Benutzeravatar von eshenhu
eshenhu

Wenn Sie die Binärgröße nicht stört, können Sie iproute2 als Bibliothek verwenden.

iproute2-as-lib

Vorteile:

  • Es ist nicht erforderlich, den Socket-Layer-Code zu schreiben.
  • Mehr oder sogar mehr Informationen über Netzwerkschnittstellen können abgerufen werden. Gleiche Funktionalität mit den iproute2-Tools.
  • Einfache API-Schnittstelle.

Nachteile:

  • Die Größe der iproute2-as-lib-Bibliothek ist groß. ~500kb.

Ich habe einen ziemlich einfachen Weg gefunden, IP zu bekommen, indem ich den Bash-Befehl ausnutze:

hostname -I

aber wenn Sie “hostname -I” verwenden, wird das Ergebnis nativ auf dem Bildschirm gedruckt. Wir müssen “popen()” verwenden, um das Ergebnis auszulesen und in einer Zeichenfolge zu speichern. Hier ist C-Code:

#include <stdio.h> // popen
#include "ip_common_def.h"

const char * get_ip()
{
    // Read out "hostname -I" command output
    FILE *fd = popen("hostname -I", "r");
    if(fd == NULL) {
    fprintf(stderr, "Could not open pipe.\n");
    return NULL;
    }
    // Put output into a string (static memory)
    static char buffer[IP_BUFFER_LEN];
    fgets(buffer, IP_BUFFER_LEN, fd);

    // Only keep the first ip.
    for (int i = 0; i < IP_BUFFER_LEN; ++i)
    {
        if (buffer[i] == ' ')
        {
            buffer[i] = '\0';
            break;
        }
    }

    char *ret = malloc(strlen(buffer) + 1);
    memcpy(ret, buffer, strlen(buffer));
    ret[strlen(buffer)] = '\0';
    printf("%s\n", ret);
    return ret;
}

1417220cookie-checkRufen Sie die IP-Adresse einer Schnittstelle unter Linux ab

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy