2013-03-27 60 views
3

我看到這個問題:Linux C: how to know the default interface for internet access?,但它建議解析命令的輸出,這是我不想做的事情。我也檢查了它的源代碼並完全丟失了。如何在linux中找到默認的網絡接口?

任何人都可以給我一個片段,這將做到這一點?我想要的只是接口名稱。


這是我目前(非工作)來源爲功能代碼,使用libmnl:

bool get_default_interface(std::string* interface_name) { 
    char buf[MNL_SOCKET_BUFFER_SIZE]; 
    struct nlmsghdr* nlh = mnl_nlmsg_put_header(buf); 
    struct ifinfomsg* ifm = (ifinfomsg*) mnl_nlmsg_get_payload(nlh); 
    int len = nlh->nlmsg_len; 
    struct rtmsg* r = (rtmsg*) NLMSG_DATA(nlh); 
    struct rtattr* rta = RTM_RTA(r); 
    struct nlattr* tb[IFLA_MAX + 1] = {}; 
    mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb); 
    //struct rtnexthop* nh = (rtnexthop*) RTA_DATA(tb[RTA_MULTIPATH]); 
    if (r->rtm_dst_len) { 
      return false; 
    } 
    std::cout << mnl_attr_get_str(tb[IFLA_IFNAME]) << std::endl; 
    *interface_name = mnl_attr_get_str(tb[IFLA_IFNAME]); 
    return true; 
} 

正如你所知道的,我是新來這個。

+0

爲什麼你堅持認識接口而不是簡單地使用默認值? – 2013-03-27 21:31:11

+0

@ ott--,我只想禁用網絡接口(以便用戶無法訪問互聯網),但爲此,我需要知道要禁用的接口。 – MiJyn 2013-03-27 21:35:32

回答

2

這應該做。我從「Bob」here中拿走了它,並且冒險添加一對丟失的包含並修改輸出。基本上你打開一個套接字來查詢路由,並且默認接口是與空目的地地址相關的接口。

該代碼適用於我的64位Linux。

> Destination  Gateway   Interface  Source 
> 0.0.0.0   192.168.0.1  eth1   *.*.*.* 
>         ^^^^^ here it is! 
> 127.0.0.0  *.*.*.*   lo    *.*.*.* 
> ... 


#include <asm/types.h> 
#include <netinet/ether.h> 
#include <netinet/in.h> 
#include <net/if.h> 
#include <stdio.h> 
#include <sys/socket.h> 
#include <sys/ioctl.h> 
#include <linux/netlink.h> 
#include <linux/rtnetlink.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 
#include <stdio.h> 

#define BUFSIZE 8192 

struct route_info{ 
     u_int dstAddr; 
     u_int srcAddr; 
     u_int gateWay; 
     char ifName[IF_NAMESIZE]; 
}; 

int readNlSock(int sockFd, char *bufPtr, int seqNum, int pId) { 
     struct nlmsghdr *nlHdr; 
     int readLen = 0, msgLen = 0; 
     do { 
       /* Receive 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((0 == NLMSG_OK(nlHdr, readLen)) || (NLMSG_ERROR == nlHdr->nlmsg_type)) 
       { 
         perror("Error in received packet"); 
         return -1; 
       } 
       /* Check if it is the last message */ 
       if (NLMSG_DONE == nlHdr->nlmsg_type) 
       { 
         break; 
       } 
       /* Else move the pointer to buffer appropriately */ 
       bufPtr += readLen; 
       msgLen += readLen; 
       /* Check if its a multi part message; return if it is not. */ 
       if (0 == (nlHdr->nlmsg_flags & NLM_F_MULTI)) { 
         break; 
       } 
     } while((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId)); 
     return msgLen; 
} 

char *ntoa(int addr) 
{ 
     static char buffer[18]; 
     sprintf(buffer, "%d.%d.%d.%d", 
       (addr & 0x000000FF)  , 
       (addr & 0x0000FF00) >> 8, 
       (addr & 0x00FF0000) >> 16, 
       (addr & 0xFF000000) >> 24); 
     return buffer; 
} 
/* For printing the routes. */ 
void printRoute(struct route_info *rtInfo) 
{ 
     /* Print Destination address */ 
     printf("%s\t", rtInfo->dstAddr ? ntoa(rtInfo->dstAddr) : "0.0.0.0 "); 

     /* Print Gateway address */ 
     printf("%s\t", rtInfo->gateWay ? ntoa(rtInfo->gateWay) : "*.*.*.*"); 

     /* Print Interface Name */ 
     printf("%s\t", rtInfo->ifName); 

     /* Print Source address */ 
     printf("%s\n", rtInfo->srcAddr ? ntoa(rtInfo->srcAddr) : "*.*.*.*"); 

     if (0 == rtInfo->dstAddr) { 
       printf("\t\t\t^^^^^ here it is!\n"); 
     } 

} 

/* For parsing the route info returned */ 
void parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo) 
{ 
     struct rtmsg *rtMsg; 
     struct rtattr *rtAttr; 
     int rtLen; 
     char *tempBuf = NULL; 

     tempBuf = (char *)malloc(100); 
     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 = *(u_int *)RTA_DATA(rtAttr); 
           break; 
         case RTA_PREFSRC: 
           rtInfo->srcAddr = *(u_int *)RTA_DATA(rtAttr); 
           break; 
         case RTA_DST: 
           rtInfo->dstAddr = *(u_int *)RTA_DATA(rtAttr); 
           break; 
       } 
     } 
     printRoute(rtInfo); 
     free(tempBuf); 
} 

int main() 
{ 
     struct nlmsghdr *nlMsg; 
     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: "); 

     /* Initialize the buffer */ 
     memset(msgBuf, 0, BUFSIZE); 

     /* point the header and the msg structure pointers into the buffer */ 
     nlMsg = (struct nlmsghdr *)msgBuf; 

     /* 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)); 
     // ADDED BY BOB 
     /* THIS IS THE NETTSTAT -RL code I commented out the printing here and in parse routes */ 
     printf("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); 
     return 0; 
} 
+0

謝謝,這個工程! – MiJyn 2013-03-27 22:34:56

0

那麼關於Linux的好處是,幾乎所有東西都是開源的。其中包括源代碼ifConfig。如果您不想調用遠程進程,您可以輕鬆地與您的項目集成。

ifConfig Usage

+0

它是否有找到_default_網絡接口的方法? – MiJyn 2013-03-27 21:09:05

+0

我不確定你的默認定義是什麼,但ifConfig是linux網絡中的一個標準,因此很可能你正在尋找它的東西已經在那裏實現了 – 2013-03-27 21:24:54

+0

看起來並不像它。我的意思是「默認」,是這樣的:http://stackoverflow.com/a/10513738/999400(檢查第一個命令的輸出) – MiJyn 2013-03-27 21:30:17

相關問題