programming - usando el código C para obtener la misma información que ifconfig
socket tcp c linux (6)
Así es como obtengo MAC y MTU en mi código:
void getMACAddress(std::string _iface,unsigned char MAC[6]) {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
struct ifreq ifr;
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name , _iface.c_str() , IFNAMSIZ-1);
ioctl(fd, SIOCGIFHWADDR, &ifr);
for(unsigned int i=0;i<6;i++)
MAC[i] = ifr.ifr_hwaddr.sa_data[i];
ioctl(fd, SIOCGIFMTU, &ifr);
close(fd);
printf("MTU: %d/n",ifr.ifr_mtu);
printf("MAC:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x/n",MAC[0],MAC[1],MAC[2],MAC[3],MAC[4],MAC[5]);
}
¿Hay alguna forma en Linux, usando código C, para obtener la misma información que devolvería "ifconfig eth0"? Me interesan cosas como la dirección IP, el estado del enlace y la dirección MAC.
Aquí hay un ejemplo de salida de ifconfig:
eth0 Link encap:Ethernet HWaddr 00:0F:20:CF:8B:42
inet addr:217.149.127.10 Bcast:217.149.127.63 Mask:255.255.255.192
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2472694671 errors:1 dropped:0 overruns:0 frame:0
TX packets:44641779 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1761467179 (1679.8 Mb) TX bytes:2870928587 (2737.9 Mb)
Interrupt:28
Hay un enfoque más simple. copiado de http://man7.org/linux/man-pages/man3/getifaddrs.3.html
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_link.h>
int main(int argc, char *argv[])
{
struct ifaddrs *ifaddr, *ifa;
int family, s, n;
char host[NI_MAXHOST];
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
/* Walk through linked list, maintaining head pointer so we
can free list later */
for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
if (ifa->ifa_addr == NULL)
continue;
family = ifa->ifa_addr->sa_family;
/* Display interface name and family (including symbolic
form of the latter for the common families) */
printf("%-8s %s (%d)/n",
ifa->ifa_name,
(family == AF_PACKET) ? "AF_PACKET" :
(family == AF_INET) ? "AF_INET" :
(family == AF_INET6) ? "AF_INET6" : "???",
family);
/* For an AF_INET* interface address, display the address */
if (family == AF_INET || family == AF_INET6) {
s = getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
host, NI_MAXHOST,
NULL, 0, NI_NUMERICHOST);
if (s != 0) {
printf("getnameinfo() failed: %s/n", gai_strerror(s));
exit(EXIT_FAILURE);
}
printf("/t/taddress: <%s>/n", host);
} else if (family == AF_PACKET && ifa->ifa_data != NULL) {
struct rtnl_link_stats *stats = (struct rtnl_link_stats *)ifa->ifa_data;
printf("/t/ttx_packets = %10u; rx_packets = %10u/n"
"/t/ttx_bytes = %10u; rx_bytes = %10u/n",
stats->tx_packets, stats->rx_packets,
stats->tx_bytes, stats->rx_bytes);
}
}
freeifaddrs(ifaddr);
exit(EXIT_SUCCESS);
}
Sí, ifconfig
sí mismo está escrito en C. :) Ver: http://cvsweb.netbsd.org/bsdweb.cgi/src/sbin/ifconfig/ifconfig.c?rev=1.169&content-type=text/x-cvsweb-markup
Do man netdevice
para ver los detalles (en Linux). Utiliza la ioctl()
sistema ioctl()
.
Una forma de llegar al fondo de problemas como este, especialmente en los casos en que no se tiene una fuente, es muy strace .
Le proporciona una lista de todas las llamadas al sistema realizadas por cualquier programa que pase, junto con sus argumentos y valores devueltos. Si su programa solo descarga información y se cierra en lugar de ejecutarse durante un tiempo prolongado, puede ser bastante sencillo hacer que un hombre haga todas las llamadas al sistema que ve para que le proporcionen la información que está buscando.
Cuando corro
strace ifconfig
Algunas de las llamadas interesantes son:
open("/proc/net/dev", O_RDONLY) = 6
seguido de un montón de ioctls, corroborando la respuesta de @ payne:
ioctl(5, SIOCGIFFLAGS, {ifr_name="eth0", ifr_flags=IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST}) = 0
ioctl(5, SIOCGIFHWADDR, {ifr_name="eth0", ifr_hwaddr=84:2b:2b:b7:9e:6d}) = 0
ioctl(5, SIOCGIFMETRIC, {ifr_name="eth0", ifr_metric=0}) = 0
ioctl(5, SIOCGIFMTU, {ifr_name="eth0", ifr_mtu=1500}) = 0
Una forma simple es usar la función popen, ver: http://pubs.opengroup.org/onlinepubs/009696899/functions/popen.html
Use algo como:
FILE *fp;
char returnData[64];
fp = popen("/sbin/ifconfig eth0", "r");
while (fgets(returnData, 64, fp) != NULL)
{
printf("%s", returnData);
}
pclose(fp);
void parse_ioctl(const char *ifname)
{
printf("%s/n", "scarf rosari...");
int sock;
struct ifreq ifr;
struct sockaddr_in *ipaddr;
char address[INET_ADDRSTRLEN];
size_t ifnamelen;
/* copy ifname to ifr object */
ifnamelen = strlen(ifname);
if (ifnamelen >= sizeof(ifr.ifr_name)) {
printf("error :%s/n", ifr.ifr_name);
return ;
}
memcpy(ifr.ifr_name, ifname, ifnamelen);
ifr.ifr_name[ifnamelen] = ''/0'';
/* open socket */
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock < 0) {
printf("error :%s/n", "unable to open socket..");
return;
}
/* process mac */
if (ioctl(sock, SIOCGIFHWADDR, &ifr) != -1) {
printf("Mac address: %02x:%02x:%02x:%02x:%02x:%02x/n",
(unsigned char)ifr.ifr_hwaddr.sa_data[0],
(unsigned char)ifr.ifr_hwaddr.sa_data[1],
(unsigned char)ifr.ifr_hwaddr.sa_data[2],
(unsigned char)ifr.ifr_hwaddr.sa_data[3],
(unsigned char)ifr.ifr_hwaddr.sa_data[4],
(unsigned char)ifr.ifr_hwaddr.sa_data[5]);
}
/* process mtu */
if (ioctl(sock, SIOCGIFMTU, &ifr) != -1) {
printf("MTU: %d/n", ifr.ifr_mtu);
}
/* die if cannot get address */
if (ioctl(sock, SIOCGIFADDR, &ifr) == -1) {
close(sock);
return;
}
/* process ip */
ipaddr = (struct sockaddr_in *)&ifr.ifr_addr;
if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
printf("Ip address: %s/n", address);
}
/* try to get broadcast */
if (ioctl(sock, SIOCGIFBRDADDR, &ifr) != -1) {
ipaddr = (struct sockaddr_in *)&ifr.ifr_broadaddr;
if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
printf("Broadcast: %s/n", address);
}
}
/* try to get mask */
if (ioctl(sock, SIOCGIFNETMASK, &ifr) != -1) {
ipaddr = (struct sockaddr_in *)&ifr.ifr_netmask;
if (inet_ntop(AF_INET, &ipaddr->sin_addr, address, sizeof(address)) != NULL) {
printf("Netmask: %s/n", address);
}
}
close(sock);
}
uso:
parse_ioctl("eth0");