Under Construction
Abfragen der IP-Adresse für ein Netzwerk-Interface (SIOCGIFADDR)
Mit dem Kommando SIOCGIFADDR (/usr/include/sys/ioctl.h) lässt sich die IP-Adresse für ein Netzwerk-Interface ermitteln. Für die Informationen wird die Struktur ifreq aus /usr/include/net/if.h verwendet:
/*
* Interface request structure used for socket
* ioctl's. All interface ioctl's must have parameter
* definitions which begin with ifr_name. The
* remainder may be interface specific.
*/
struct ifreq {
#ifndef IFNAMSIZ /* Also in net_if.h */
#define IFNAMSIZ 16
#endif
char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
__ulong32_t ifru_flags;
int ifru_metric;
caddr_t ifru_data;
u_short ifru_site6;
__ulong32_t ifru_mtu;
int ifru_obaudrate;
uint64_t ifru_baudrate;
int ifru_checksum_offload[2];
} ifr_ifru;
#define ifr_addr ifr_ifru.ifru_addr /* address */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */
#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
#define ifr_flags ifr_ifru.ifru_flags /* flags */
#define ifr_metric ifr_ifru.ifru_metric /* metric */
#define ifr_data ifr_ifru.ifru_data /* for use by interface */
#define ifr_site6 ifr_ifru.ifru_site6 /* IPv6 site index */
#define ifr_mtu ifr_ifru.ifru_mtu /* mtu of interface */
#define ifr_isno ifr_ifru.ifru_data /* pointer to if_netopts */
#define ifr_baudrate ifr_ifru.ifru_baudrate /* baudrate of interface */
#define ifr_obaudrate ifr_ifru.ifru_obaudrate /* OLD baudrate of interface */
#define ifr_checksum_offload ifr_ifru.ifru_checksum_offload[1] /* checksum offload active or not */
};
Der Name des Netzwerk-Interfaces muss in ifr_name vor dem Aufruf von ioctl(2) abgesspeichert werden. Der ioctl(2) liefert dann die IP-Addresse über ifru_addr (Union ifr_ifru) in der Struktur sockaddr zurück. Die generische sockaddr Struktur ist in /usr/include/sys/socket.h und /usr/include/netinet/in.h definiert:
struct sockaddr {
uchar_t sa_len; /* total length */
sa_family_t sa_family; /* address family */
char sa_data[14]; /* actually longer; address value */
};
Für den Fall einer IP-Adresse ist die Adreß-Familie AF_INET und die zugehörige spezifische Socket-Adreß-Struktur ist sockaddr_in (definiert in /usr/include/netinet/in.h):
/*
* Socket address, internet style.
*/
struct sockaddr_in {
uchar_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
uchar_t sin_zero[8];
};
Die IP-Adresse ist dann im Feld sin_addr abgespeichert.
Das folgende kleine Beispiel-Programm demonstriert die Verwendung von SIOCGIFADDR:
$ cat get_ip.c
/*
* Copyright (c) 2021 by PowerCampus 01 GmbH
*/
#include <sys/ioctl.h> // SIOCGIFADDR
#include <sys/socket.h> // socket()
#include <netinet/in.h> // sockaddr, sockaddr_in
#include <net/if.h> // ifreq
#include <arpa/inet.h> // inet_ntoa()
#include <errno.h> // errno, perror()
#include <unistd.h> // ioctl(), close()
#include <stdio.h> // fprintf()
#include <stdlib.h> // exit()
#include <string.h> //strncpy()
int main( int argc , char** argv )
{
int sd;
int ret;
sockaddr_in* addr;
// 1. Provide buffer for the request.
struct ifreq req;
// 2. Store interface name in ifr_name.
strncpy(req.ifr_name,argv[1],IFNAMSIZ);
// 3. Create datagram socket for address family Inet.
sd = socket(AF_INET,SOCK_DGRAM,0);
if ( sd == -1 )
{
perror("get_ip");
exit(errno);
}
// 4. Call ioctl with command SIOCGIFADDR.
ret = ioctl(sd,SIOCGIFADDR,&req);
if ( ret == -1 )
{
perror("get_ip");
exit(errno);
}
// 5. (optional) Ensure that returned socket address is for Inet.
if ( req.ifr_addr.sa_family != AF_INET )
{
fprintf(stderr,"get_ip: unexpected address family\n");
exit(EAFNOSUPPORT); // may be there is a better error number for this case
}
// 6. Print IP-Address.
addr = (struct sockaddr_in*)&(req.ifr_addr);
printf("IP: %s\n",inet_ntoa(addr->sin_addr));
// 7. Close socket descriptor
close(sd);
return 0;
}
$
Das Programm erwartet beim Aufruf den Namen eines Netzwerk-Interfaces als Argument und gibt dann für dieses Interface die IP-Adresse aus.
Das Programm kann z.B. mit dem GNU C-Compiler übersetzt werden:
$ gcc -o get_ip get_ip.c
$
Ein kleiner Test mit den Netzwerk-Interfaces lo0 und en0 zeigt, dass das Programm funktioniert:
$ get_ip lo0
IP: 127.0.0.1
$ get_ip en0
IP: 192.168.170.250
$