Linux下网关地址的获取
2012-02-08 12:31
1716 查看
Linux的网关信息保存在路由表中,获取网关实际上就是路由表的查询。
用户空间获取网关地址
有两种方法,一个是从/proc/net/route中读取,这是最简单,最直接的,route命令就是这么做的,可以参考net-tools包中route的源码实现。
另一种是用Netlink来实现。利用NETLINK_ROUTE(rtnetlink.c: Routing netlink socket interface)的RTM_GETROUTE指令查找路由,这是从网上找的代码,在Debian (2.6.26内核)下测试通过。
内核空间获取网关地址
用户空间的实现,其本质上是内核空间的支持,因此内核空间获取应该更直接点。我参考了NETLINK_ROUTE中的实现来做,即执行一个从本机IP到外网IP的路由查询,获得的路由记录中自然包括网关地址,主要用到ip_route_output_key()函数。下面是我的代码:
暂时只找到这种实现方式,有新的发现再来更新:)
March 18th,2009 | Category:Software Development
原文地址:http://www.penna.cn/blog/?p=255
用户空间获取网关地址
有两种方法,一个是从/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()函数。下面是我的代码:
… 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
相关文章推荐
- linux编程获取网关地址
- Linux 获取网关地址
- Linux下如何在进程中获取虚拟地址对应的物理地址【转】
- JAVA Window、Linux 获取实际IP地址
- 怎么在LINUX里安装和配置DNS服务。还有IP地址、网关、DNS地址
- linux c获取mac地址
- linux 下获取默认网关的方法
- Linux下获取调用堆栈地址
- Linux下如何在进程中获取虚拟地址对应的物理地址
- linux学习之修改IP地址、网关地址、DNS
- linux_下IP、网关、DNS地址配置
- Linux下获取CPUID、硬盘序列号与MAC地址
- linux下程序设计-获取本机MAC地址
- linux编程获取本机IP地址的三种方法
- Linux下获取系统的IP,子网掩码,网关,MAC和配置文件的修改
- linux编程获取本机IP地址
- java(jdk1.4、jdk1.6)获取mac地址的方法(winxp、win2003、win7、linux)
- qt获取IP、网关地址
- C++获取本地mac地址和网关mac地址方法
- Linux下获取公网IP地址