全部博文(298)
分类: 系统运维
2011-04-07 14:57:43
(17)Unix路由套接字
注:所以文章红色字体代表需要特别注意和有问题还未解决的地方,蓝色字体表示需要注意的地方
1. 本文所介绍的程序平台
由于linux下面路由套接字接口与unix下面不一致 所以一下内容没有验证。
2. 路由套接字
Uinx系统集成了路由的功能,它包含相应的路由数据库可提供路由信息,用户可以使用命令方式来增加、修改、删除路由表中的项目,也可以只查看路由表中的信息。除此外,应用程序可以使用路由套接字实现对路由表的读/写操作。应用程序通过写操作把消息发送给路由子系统以增加或删除路由:通过读操作接收从路由子系统发送来的路由信息。
在实际应用中,路由的修改常常是由网络管理员通过系统命令来完成的,而应用程序一般只需要系统提供路由信息。
3. 创建路由套接字
3.1格式:
int sockfd;
sockfd=socket(AF_ROUTE,SOCK_RAW,0);
通信域为AF_ROUTE,它只能支持原始套接字,只有超级用户才能创建这个套接字。
3.2 读写路由套接字
创建路由套接字后,与其他套接字一样,可以调用read()或者write()函数进行读写,但是由于系统内核是根据应用程序写入的消息来完成对路由信息的提供和修改的,因此,与其他套接字不同,写入和读出的数据都是有固定的格式的,例如:为了增加路由消息类型为RTM_ADD;为了获取路由,消息类型为RTM_GET;
路由套接字在
RTM_ADD增加路由
RTM_DELETE删除路由
RTM_CHANG改变路由
RTM_GET获取路由
RTM_MISS查询路由失败
3.2 通过路由套接字发送和接收的消息结构:
通过路由套接**换的结构有3个类型,分别如下:
struct rt_msghdr { //from net/route.h
u_short rtm_msglen; // to skip over non-understood messages
u_char rtm_version; //future binary compatibility
u_char rtm_type; //message type
u_short rtm_index; //index for associated ifp
int rtm_flags; //flags, incl. kern &message, e.g. , DONE
int rtm_addrs; //bitmask indentifying sockaddrs in msg
pid_t rtm_pid; // identify sender
int rtm_seq; // for sender to identify action
int rtm_errno; // why failed
int rtm_use; // from rtentry
u_long rtm_inits; // which metrics we are initializing
struct rt_metrics rtm_rmx; //metrics themselves
};
struct if_msghdr { // from net/if.h
u_short ifm_msglen; // to skip over non-understood messages
u_char ifm_version; // future binary compatibility
u_char ifm_type; // message type
int ifam_addrs; // like rtm_addrs
int ifam_flags; // value of ifa_flags
u_short ifam_index; // index for associated ifp
int ifam_metric; // value of ifa_metric
};
struct ifa_msghdr { //from net/if.h
u_short ifam_msglen; // to skip over non-understood messages
u_char ifam_version; // future binary compatibility
u_char ifam_type; // message type
int ifam_addrs; // like rtm_addrs
int ifam_flags; // value of ifa_flags
u_short ifam_index; // index for associated ifp
int ifam_metric; // value of ifa_metric
};
每个结构有相同的三个成员,本消息的长度, 版本和类型。类型是表一所示的第一列中的
常值之一。长度成员允许应用进程跳过不理解的消息类型。
rtm_addrs, ifm_addrs和ifam_addrs这3个成员是数位掩码(bitmask),指明本消息后跟的套
接口地址结构是8个可能选择中的那几个。下表给出了在
数位掩码 |
数组下标 |
套接口地址结构包含 | ||
常值 |
数值 |
常值 |
数字 | |
RTA_DST RTA_GATEWAY RTA_NETMASK RTA_GENMASK RTA_IFP RTA_IFA RTA_AUTHOR RTA_BRD |
0x01 0x02 0x04 0x08 0x10 0x20 0x40 0x80 |
RTAX_DST RTAX_GATEWAY RTAX_NETMASK RTAX_GENMASK RTAX_IFP RTAX_IFA RTAX_AUTHOR FTAX_BRD |
0 1 2 3 4 5 6 7 |
目的地址 网关地址 网络掩码 克隆掩码 接口名字 接口地址 重定向原创者 广播或点到点目的地址 |
|
|
RTAX_MAX |
8 |
最大元素数目 |
当存在多个套接口地址结构时,它们总是按照表中所示顺序排列。
3.3 路由套接字实例(注意该实例未验证)
n #include
n #include
n #include
n #include
n #include
n #include
n #include
n #include
n #include
n void cp_rtaddrs(int,sockaddr_in *,sockaddr_in **); /*此函数用于将收到的套接字地址拷入套接字地址数据rt_info中。*/
n #define BUFLEN (sizeof(rt_msghdr)+512) /*消息缓冲区的长度*/
n #define SEQ 1234 /*消息序号*/
n int main(int argc,char **argv)
n {
n int sockfd;
n char *buf;
n pit_t pid;
n ssize_t n;
n struct rt_msghdr *rtm;
n struct sockaddr_in *sa, *rt_info[RTA_NUMBITS];
n struct sockaddr_in *sin;
n if(argc!=2){
n printf("usage:%s
n exit(0);
n }
n sockfd=socket(AF_ROUTE,SOCK_RAW,0); /*创建路由套接字*/
n if(sockfd==-1){
n perror("socket error");
n exit(1);
n }
n buf=(char*) calloc(1,BUFLEN); /*分配缓冲区*/
n rtm=(rt_msghdr*)buf;
n rtm->rtm_msglen=sizeof(rt_msghdr)+sizeof(sockaddr_in); /*消息长度*/
n rtm->rtm_version=RTM_VERSION; /*版本号*/
n rtm->rtm_type=RTM_GET; /* 消息类型*/
n rtm->rtm_addrs=RTA_DST; /*位屏蔽字*/
n rtm->rtm_pid=pid=getpid(); /*进程号*/
n rtm->rtm_seq=SEQ; /*序号*/
n sin=(sockaddr_in *) (rtm+1); /*将目的地址填入跟在消息头后的套接字地址项中。*/
n sin->sin_family=AF_INET;
n inet_pton(AF_INET,argv[1],&sin->sin_addr);
n write(sockfd,rtm,rtm->rtm_msglen); /*发送RTM_GET消息给路由套接字*/
n /*通个循环读取路由套接字中的消息,直到读到类型为RTM_GET、序号为SEQ、进程ID为当前进程ID的消息,表明该消息是所发消息的回应。*/
n do {
n n=read(sockfd,rtm,BUFLEN);
n }while(rtm->rtm_type!=RTM_GET||rtm->rtm_seq!=SEQ||rtm->rtm_pid!=pid);
n sa=(sockaddr_in*) (rtm+1);
n cp_rtaddrs(rtm->rtm_addrs,sa,rt_info); /*将读取的套接字地址拷入数组rt_info中。*/
n if((sa=rt_info[RTA_DST])!=NULL) /*如果存在目的地址项*/
n printf("dest:%s\n",inet_ntoa(sa->sin_addr));
n if((sa=rt_info[RTA_GATEWAY])!=NULL) /*如果存在网关地址项*/
n printf("gateway:%s\n",inet_ntoa(sa->sin_addr));
n
n if((sa=rt_info[RTA_NETMASK])!=NULL) /*如果存在网络掩码地址项*/
n printf("netmask:%s\n",inet_ntoa(sa->sin_addr));
n exit(0);
n }
n /*以下函数实现依次检查位屏蔽字,如果某项存在,则拷入对应项目,否则填入NULL。*/
n void cp_rtaddrs(int addrs,struct sockaddr_in *sa,struct sockaddr_in **rt_info)
n {
n int i;
n for(i=0;i
n if(addrs&(1<
n rt_info[i]=sa;
n sa++;
n }
n else
n rt_info[i]=NULL;
n }
n }