首页 > 代码库 > 《网络编程》路由套接字

《网络编程》路由套接字

概述

        Unix 系统集成了路由功能,它包含相应的路由数据库可提供的路由信息,用户可以通过命令方式来增加、修改以及删除路由表中的项目,也可以只查看路由表的信息。在创建套接字时,可以通过指定参数 AF_ROUTE 域创建路由套接字,路由套接字可以访问内核中路由子系统的接口信息。路由套接字上支持 3 种类型的操作:

  1. 进程通过写到路由套接字向内核发送消息;
  2. 进程通过读入路由套接字接收来自内核的消息;
  3. 进程调用 sysctl 函数获取路由表或列出所有已配置的接口;

数据链路地址结构

struct sockaddr_dl {
  uint8_t      sdl_len;
  sa_family_t  sdl_family;   /* AF_LINK */
  uint16_t     sdl_index;    /* system assigned index, if > 0 */
  uint8_t      sdl_type;     /* IFT_ETHER, etc. from <net/if_types.h> */
  uint8_t      sdl_nlen;     /* name length, starting in sdl_data[0] */
  uint8_t      sdl_alen;     /* link-layer address length */
  uint8_t      sdl_slen;     /* link-layer selector length */
  char         sdl_data[12]; /* minimum work area, can be larger;
                                contains i/f name and link-layer address */
};
/* 说明:
 * 其中 sdl_data成员包含名字和链路层地址;名字从sdl_data[0]开始,而且不以空字符结尾;
 * 链路层地址从sdl_data[sdl_nlen]开始;下面宏定义是返回指向链路层地址的指针:
 */
#define LLADDR(s)   ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))

读写路由套接字

        首先可以指定 AF_ROUTE 域  socket(AF_ROUTE,SOCK_RAW,0);创建路由套接字,它只能支持原始套接字,只有超级用户才能创建这个套接字。创建路由套接字后,与其他套接字一样,可以调用 read() 或 write() 函数进行读写,但是由于系统内核是根据应用程序写入的消息来完成对路由信息的提供和修改的,因此,与其他套接字不同,写入和读出的数据都是有固定的格式的,例如:为了增加路由消息类型为RTM_ADD;为了获取路由,消息类型为RTM_GET;路由套接字在 <net/route.h> 里面定义了相应的消息类型。具体参数可参照书本上的表格。


sysctl 函数

使用 sysctl 函数可以使不具有超级用户权限的程序能够获取路由表和接口列表信息,以下是该函数的定义:

/* 函数功能:检查路由表和接口列表;
 * 返回值:若成功则返回0,若出错则返回-1;
 * 函数原型:
 */
#include <sys/param.h>
#include <sys/sysctl.h>
int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
/* 说明:
 * 参数name是指定名字的一个整数数组,namelen是指定该数组中的元素数目,该数组中第一个元素指定请求定向到内核的某个子系统,接下来的元素逐渐细化指定该子系统的某个部分;
 * oldp指向提供内核存放值的缓冲区,oldlenp是值-结果参数,即指定缓冲区大小作为参数值输入,函数返回时,该值结果变为内核存放在该缓冲区的实际大小;
 * newp指向一个为newlen参数值的缓冲区,也可指定为空指针;
 *
 */


/*name 参数的第一个元素可取以下值:*/
/* Top-level names: */

enum
{
	CTL_KERN=1,		/* General kernel info and control */
	CTL_VM=2,		/* VM management */
	CTL_NET=3,		/* Networking */
	CTL_PROC=4,		/* removal breaks strace(1) compilation */
	CTL_FS=5,		/* Filesystems */
	CTL_DEBUG=6,		/* Debugging */
	CTL_DEV=7,		/* Devices */
	CTL_BUS=8,		/* Busses */
	CTL_ABI=9,		/* Binary emulation */
	CTL_CPU=10,		/* CPU stuff (speed scaling, etc) */
	CTL_ARLAN=254,		/* arlan wireless driver */
	CTL_S390DBF=5677,	/* s390 debug */
	CTL_SUNRPC=7249,	/* sunrpc debug */
	CTL_PM=9899,		/* frv power management */
	CTL_FRV=9898,		/* frv specific sysctls */
};
/* name 参数的第二个元素可取以下值:
 * (1)AF_INET     获取或设置影响网际网协议的变量;
 * (2)AF_LINK     获取或设置链路层信息;
 * (3)AF_ROUTE    返回路由表或接口列表信息;
 * (4)AF_UNSPEC   获取或设置一些套接字层变量;
 */
 /* 若name数组的第二个元素指定为AF_ROUTE时,第三个元素则是0,第四个元素则是一个地址族,第五个和第六个元素取值如下表; */



接口名字与索引函数

每个接口都有唯一的名字和唯一的正值索引。以下是接口名字和索引函数的定义:

/* 接口名字和索引函数 */

#include <net/if.h>
/* Convert an interface name to an index, and vice versa.  */
unsigned int if_nametoindex (const char *ifname);/* 若成功则返回正的接口索引,出错返回0 */
char *if_indextoname (unsigned int ifindex, char *ifname);/* 若成功则返回指向接口名字的指针,出错则返回NULL */

/* Return a list of all interfaces and their indices.  */
struct if_nameindex *if_nameindex (void);/* 若成功则返回非空指针,出错则返回NULL */

/* Free the data returned from if_nameindex.  */
void if_freenameindex (struct if_nameindex *ptr);
/* 说明:
 * if_nametoindex返回名为ifname的接口的索引;
 * if_indextoname对给定的ifindex返回一个指向其接口名的指针,ifname参数指向一个大小为IFNAMSIZ头文件中定义的缓冲区,
 * 调用者必须分配这个缓冲区以保存结果,成功时这个指针也是函数的返回值;
 * if_nameindex返回一个指向if_nameindex结构的数组的指针;
 */
/* 结构体if_nameindex 的定义 */
struct if_nameindex
  {
    unsigned int if_index;	/* 1, 2, ... */
    char *if_name;		/* null terminated name: "eth0", ... */
  };/* 结构成员内存空间由函数动态获取,并由函数if_freenameindex归还给系统 */



参考资料:

《Unix 网络编程》

《网络编程》路由套接字