在ANSI C中获取用于给定ip的网关

我像疯了似的环顾四周,但没有得到真正的答案。 我有一个例子,但这取决于个人自己的图书馆,所以不太好。

起初我想获得接口的默认网关,但由于不同的IP可以以不同的方式路由,我很快就明白我想要的是通过使用AF_ROUTE套接字和rtm_type RTM_GET来获得用于给定目标IP的网关。 有没有人有一个例子,我实际上最终得到一个包含网关IP(或MAC地址)的字符串? 网关条目似乎是hex,但也编码在/ proc / net / route中,我猜AF_ROUTE套接字得到它的信息(但我通过内核)。

提前完成

和ps我刚刚开始使用堆栈溢出,我必须说,你们所有人都很棒! 快速回复和好的回复! 你是我最好的朋友;)

这是特定于操作系统的,没有统一的(或ANSI C)API。

假设Linux,最好的方法是解析/ proc / net / route,查找Destination为00000000的条目,默认网关在Gateway列中,您可以在其中读取网关IP地址的hex表示(大endian,我相信)

如果你想通过更具体的API调用来做到这一点,你将不得不经历一些箍,这是一个示例程序:

 #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #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; } 

也许这是一个非常古老的问题,但我有同样的问题,我找不到更好的结果。 最后,我用这些代码解决了我的问题,它有一些变化。 所以我决定分享它。

 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); } 

我决定采用“快速而肮脏”的方式开始,并使用netstat -rm/proc/net/route读出ip。

我以为我会分享我的function…但请注意,它有一些错误,并且很可能你可以帮我找到它,我会编辑它没有错误。 该函数采用像eth0这样的iface名称,并返回该iface使用的网关的ip。

 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; } 

这个函数的问题是当我将pclose留在那里时会导致内存损坏。 但是如果我删除了pclose调用它会起作用(但这不是一个好的解决方案,因为流将保持打开状态..呵呵)。 因此,如果有人能够发现错误,我将使用正确的版本编辑该function。 我不是C大师,对所有内存摆弄有点困惑;)