redes - Obteniendo una puerta de enlace para usar para una ip dada en ANSI C
gateway significado (3)
Decidí ir a la manera "rápida y sucia" de comenzar y leer la ip de /proc/net/route
usando netstat -rm
.
Pensé que iba a compartir mi función ... Sin embargo, tenga en cuenta que hay un error y, tal vez, pueda ayudarme a encontrarlo y lo editaré para que no tenga fallas. La función toma un nombre de iface como eth0
y devuelve la ip de la puerta de enlace utilizada por ese iface.
char* GetGatewayForInterface(const char* interface) {
char* gateway = NULL;
FILE* fp = popen("netstat -rn", "r");
char line[256]={0x0};
while(fgets(line, sizeof(line), fp) != NULL)
{
/*
* Get destination.
*/
char* destination;
destination = strndup(line, 15);
/*
* Extract iface to compare with the requested one
* todo: fix for iface names longer than eth0, eth1 etc
*/
char* iface;
iface = strndup(line + 73, 4);
// Find line with the gateway
if(strcmp("0.0.0.0 ", destination) == 0 && strcmp(iface, interface) == 0) {
// Extract gateway
gateway = strndup(line + 16, 15);
}
free(destination);
free(iface);
}
pclose(fp);
return gateway;
}
El problema con esta función es que cuando salgo de pclose allí, se produce un fallo de memoria dañada. Pero funciona si elimino la llamada pclose (pero esa no sería una buena solución porque la secuencia permanecería abierta ... jeje). Entonces, si alguien puede detectar el error, editaré la función con la versión correcta. No soy un gurú de C y me confunde un poco acerca de todos los problemas con la memoria;)
He mirado a mi alrededor como loca, pero no recibo una respuesta real. Tengo un ejemplo, pero eso depende de la biblioteca de los individuos, así que no es muy bueno.
Al principio, quería obtener la puerta de enlace predeterminada de una interfaz, pero como las distintas direcciones IP podían enrutarse de manera diferente, comprendí rápidamente que lo que quiero es que la puerta de enlace se use para una IP de destino determinada utilizando un socket AF_ROUTE
y el rtm_type RTM_GET
. ¿Alguien tiene un ejemplo donde realmente termine con una cadena que contiene las puertas de enlace IP (o dirección mac)? La entrada de la puerta de enlace parece estar en hexadecimal, pero también está codificada en / proc / net / route, donde creo que el socket AF_ROUTE
obtiene la información de (pero a través del kernel, supongo).
Gracias de antemano
y ps, acabo de empezar a usar el desbordamiento de pila y debo decir, ¡todos ustedes son geniales! ¡Respuestas rápidas y buenas! Ustedes son mis nuevos mejores amigos;)
Esto es específico del sistema operativo, no hay una API unificada (o ANSI C) para esto.
Suponiendo que Linux, la mejor manera es simplemente analizar / proc / net / route, busque la entrada donde Destino es 00000000, la puerta de enlace predeterminada se encuentra en la columna Puerta de enlace, donde puede leer la representación hexadecimal de la dirección IP de la puerta de enlace (en grande endian, creo
Si quieres hacer esto a través de llamadas API más específicas, tendrás que pasar por muchos problemas, aquí hay un programa de ejemplo:
#include <netinet/in.h>
#include <net/if.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define BUFSIZE 8192
char gateway[255];
struct route_info {
struct in_addr dstAddr;
struct in_addr srcAddr;
struct in_addr gateWay;
char ifName[IF_NAMESIZE];
};
int readNlSock(int sockFd, char *bufPtr, int seqNum, int pId)
{
struct nlmsghdr *nlHdr;
int readLen = 0, msgLen = 0;
do {
/* Recieve response from the kernel */
if ((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0) {
perror("SOCK READ: ");
return -1;
}
nlHdr = (struct nlmsghdr *) bufPtr;
/* Check if the header is valid */
if ((NLMSG_OK(nlHdr, readLen) == 0)
|| (nlHdr->nlmsg_type == NLMSG_ERROR)) {
perror("Error in recieved packet");
return -1;
}
/* Check if the its the last message */
if (nlHdr->nlmsg_type == NLMSG_DONE) {
break;
} else {
/* Else move the pointer to buffer appropriately */
bufPtr += readLen;
msgLen += readLen;
}
/* Check if its a multi part message */
if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) {
/* return if its not */
break;
}
} while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId));
return msgLen;
}
/* For printing the routes. */
void printRoute(struct route_info *rtInfo)
{
char tempBuf[512];
/* Print Destination address */
if (rtInfo->dstAddr.s_addr != 0)
strcpy(tempBuf, inet_ntoa(rtInfo->dstAddr));
else
sprintf(tempBuf, "*.*.*.*/t");
fprintf(stdout, "%s/t", tempBuf);
/* Print Gateway address */
if (rtInfo->gateWay.s_addr != 0)
strcpy(tempBuf, (char *) inet_ntoa(rtInfo->gateWay));
else
sprintf(tempBuf, "*.*.*.*/t");
fprintf(stdout, "%s/t", tempBuf);
/* Print Interface Name*/
fprintf(stdout, "%s/t", rtInfo->ifName);
/* Print Source address */
if (rtInfo->srcAddr.s_addr != 0)
strcpy(tempBuf, inet_ntoa(rtInfo->srcAddr));
else
sprintf(tempBuf, "*.*.*.*/t");
fprintf(stdout, "%s/n", tempBuf);
}
void printGateway()
{
printf("%s/n", gateway);
}
/* For parsing the route info returned */
void parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo)
{
struct rtmsg *rtMsg;
struct rtattr *rtAttr;
int rtLen;
rtMsg = (struct rtmsg *) NLMSG_DATA(nlHdr);
/* If the route is not for AF_INET or does not belong to main routing table
then return. */
if ((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN))
return;
/* get the rtattr field */
rtAttr = (struct rtattr *) RTM_RTA(rtMsg);
rtLen = RTM_PAYLOAD(nlHdr);
for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen)) {
switch (rtAttr->rta_type) {
case RTA_OIF:
if_indextoname(*(int *) RTA_DATA(rtAttr), rtInfo->ifName);
break;
case RTA_GATEWAY:
rtInfo->gateWay.s_addr= *(u_int *) RTA_DATA(rtAttr);
break;
case RTA_PREFSRC:
rtInfo->srcAddr.s_addr= *(u_int *) RTA_DATA(rtAttr);
break;
case RTA_DST:
rtInfo->dstAddr .s_addr= *(u_int *) RTA_DATA(rtAttr);
break;
}
}
//printf("%s/n", inet_ntoa(rtInfo->dstAddr));
if (rtInfo->dstAddr.s_addr == 0)
sprintf(gateway, (char *) inet_ntoa(rtInfo->gateWay));
//printRoute(rtInfo);
return;
}
int main()
{
struct nlmsghdr *nlMsg;
struct rtmsg *rtMsg;
struct route_info *rtInfo;
char msgBuf[BUFSIZE];
int sock, len, msgSeq = 0;
/* Create Socket */
if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
perror("Socket Creation: ");
memset(msgBuf, 0, BUFSIZE);
/* point the header and the msg structure pointers into the buffer */
nlMsg = (struct nlmsghdr *) msgBuf;
rtMsg = (struct rtmsg *) NLMSG_DATA(nlMsg);
/* Fill in the nlmsg header*/
nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); // Length of message.
nlMsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table .
nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump.
nlMsg->nlmsg_seq = msgSeq++; // Sequence of the message packet.
nlMsg->nlmsg_pid = getpid(); // PID of process sending the request.
/* Send the request */
if (send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0) {
printf("Write To Socket Failed.../n");
return -1;
}
/* Read the response */
if ((len = readNlSock(sock, msgBuf, msgSeq, getpid())) < 0) {
printf("Read From Socket Failed.../n");
return -1;
}
/* Parse and print the response */
rtInfo = (struct route_info *) malloc(sizeof(struct route_info));
//fprintf(stdout, "Destination/tGateway/tInterface/tSource/n");
for (; NLMSG_OK(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len)) {
memset(rtInfo, 0, sizeof(struct route_info));
parseRoutes(nlMsg, rtInfo);
}
free(rtInfo);
close(sock);
printGateway();
return 0;
}
Tal vez esta sea una pregunta muy antigua pero tuve el mismo problema y no puedo encontrar un mejor resultado. Finalmente resolví mi problema con estos códigos que tiene algunos cambios. Así que decido compartirlo.
char* GetGatewayForInterface(const char* interface)
{
char* gateway = NULL;
char cmd [1000] = {0x0};
sprintf(cmd,"route -n | grep %s | grep ''UG[ /t]'' | awk ''{print $2}''", interface);
FILE* fp = popen(cmd, "r");
char line[256]={0x0};
if(fgets(line, sizeof(line), fp) != NULL)
gateway = string(line);
pclose(fp);
}