Linux下網關地址的擷取__Linux

來源:互聯網
上載者:User
Linux的網關資訊儲存在路由表中,擷取網關實際上就是路由表的查詢。

 使用者空間擷取網關地址

有兩種方法,一個是從/proc/net/route中讀取,這是最簡單,最直接的,route命令就是這麼做的,可以參考net-tools包中route的源碼實現。

另一種是用Netlink來實現。利用NETLINK_ROUTE(rtnetlink.c: Routing netlink socket interface)的RTM_GETROUTE指令尋找路由,這是從網上找的代碼,在Debian (2.6.26核心)下測試通過。

#include <arpa/inet.h>  //for in_addr   #include <linux/rtnetlink.h>    //for rtnetlink   #include <net/if.h> //for IF_NAMESIZ, route_info   #include <stdlib.h> //for malloc(), free()   #include <string.h> //for strstr(), memset()      #include <string>      #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{       //收到核心的應答       if((readLen = recv(sockFd, bufPtr, BUFSIZE - msgLen, 0)) < 0)       {         perror("SOCK READ: ");         return -1;       }             nlHdr = (struct nlmsghdr *)bufPtr;       //檢查header是否有效       if((NLMSG_OK(nlHdr, readLen) == 0) || (nlHdr->nlmsg_type == NLMSG_ERROR))       {         perror("Error in recieved packet");         return -1;       }                    if(nlHdr->nlmsg_type == NLMSG_DONE)        {         break;       }       else       {                  bufPtr += readLen;         msgLen += readLen;       }                    if((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0)        {                 break;       }     } while((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId));     return msgLen;   }   //分析返回的路由資訊   void parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo,char *gateway)   {     struct rtmsg *rtMsg;     struct rtattr *rtAttr;     int rtLen;     char *tempBuf = NULL;     struct in_addr dst;     struct in_addr gate;          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;          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;      }     }     dst.s_addr = rtInfo->dstAddr;     if (strstr((char *)inet_ntoa(dst), "0.0.0.0"))     {       printf("oif:%s",rtInfo->ifName);       gate.s_addr = rtInfo->gateWay;       sprintf(gateway, (char *)inet_ntoa(gate));       printf("%s\n",gateway);       gate.s_addr = rtInfo->srcAddr;       printf("src:%s\n",(char *)inet_ntoa(gate));       gate.s_addr = rtInfo->dstAddr;       printf("dst:%s\n",(char *)inet_ntoa(gate));      }     free(tempBuf);     return;   }      int get_gateway(char *gateway)   {    struct nlmsghdr *nlMsg;    struct rtmsg *rtMsg;    struct route_info *rtInfo;    char msgBuf[BUFSIZE];        int sock, len, msgSeq = 0;       if((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)    {     perror("Socket Creation: ");     return -1;    }            memset(msgBuf, 0, BUFSIZE);            nlMsg = (struct nlmsghdr *)msgBuf;    rtMsg = (struct rtmsg *)NLMSG_DATA(nlMsg);            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.            if(send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0){     printf("Write To Socket Failed…\n");     return -1;    }            if((len = readNlSock(sock, msgBuf, msgSeq, getpid())) < 0) {     printf("Read From Socket Failed…\n");     return -1;    }        rtInfo = (struct route_info *)malloc(sizeof(struct route_info));    for(;NLMSG_OK(nlMsg,len);nlMsg = NLMSG_NEXT(nlMsg,len)){     memset(rtInfo, 0, sizeof(struct route_info));     parseRoutes(nlMsg, rtInfo,gateway);    }    free(rtInfo);    close(sock);    return 0;   }      int main()   {       char buff[256];       get_gateway(buff);       return 0;   }  

  核心空間擷取網關地址

使用者空間的實現,其本質上是核心空間的支援,因此核心空間擷取應該更直接點。我參考了NETLINK_ROUTE中的實現來做,即執行一個從本機IP到外網IP的路由查詢,獲得的路由記錄中自然包括網關地址,主要用到ip_route_output_key()函數。下面是My Code:

…   extern struct net init_net;   …   inline void printIP(__u32 uip)   {       printk(NIPQUAD_FMT,NIPQUAD(uip));   }   …   int xxxxxx()   {       …       int err;       struct rtable * rt = NULL;       struct flowi fl = {           .nl_u = {               .ip4_u = {                   .daddr = 0,                   .saddr = 0,                   .tos = 0,               },           },           .oif = 0,       };       fl.nl_u.ip4_u.daddr = in_aton("182.168.1.1");       fl.nl_u.ip4_u.saddr = in_aton("192.168.0.186");       err = ip_route_output_key(&init_net, &rt, &fl);       if(rt)       {           if(rt->idev&&rt->idev->dev&&rt->idev->dev->name)               printk(" if:%s\n",rt->idev->dev->name);           printk(" gw:");           printIP(rt->rt_gateway);           printk("\n dst:");           printIP(rt->rt_dst);           printk("\n src:");           printIP(rt->rt_src);           printk("\n");       }       else           printk("rt = NULL!\n");       …   }  
 暫時只找到這種實現方式,有新的發現再來更新:) March 18th,2009 | Category: Software Development 原文地址: http://www.penna.cn/blog/?p=255
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.