链路层原始套接字编程-总结

来源:互联网 发布:c语言求逻辑表达式格式 编辑:程序博客网 时间:2024/06/16 05:06
1、链路层原始套接字创建方法:socket(PF_PACKET, SOCK_RAW, htons(protocol)),其中protocal参数为关心的协议类型。
2、默认情况下网卡只处理目的地址是本机网卡地址的包,可通过设置混杂模式,使网卡将收到的所有包(包括组播和广播)都转发给操作系统。代码如下:
    struct ifreq    ifr;
    strcpy(ifr.ifr_name, if_name);
    ioctl(fd, SIOCGIFFLAGS, &ifr);
    ifr.ifr_flags |= IFF_PROMISC;
    ioctl(fd, SIOCSIFFLAGS, &ifr);
3、对于多网卡系统,操作系统在收包时不区分是从哪个网卡收到的,统一转发给用户进程socket,特别的,当用户进程创建了原始套接字socket,那么操作系统在转发消息时,将从网卡收到的buf复制给所有的、关心的原始套接字(原因是操作系统不知道怎么区分不同的原始套接字的包)。
4、可通过bind函数将创建的原始套接字绑定到指定的addr,addr的实际类型为struct sockaddr_ll,绑定时需要设置sll_family,sll_protocol,sll_ifindex这几个参数。其中,sll_ifindex为指定的接口名称的索引,可通过ioctl函数获取ioctl(fd, SIOCGIFINDEX, &ifr);
  int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  struct sockaddr_ll{
    unsigned short int sll_family;
    unsigned short int sll_protocol;
    int sll_ifindex;
    unsigned short int sll_hatype;
    unsigned char sll_pkttype;
    unsigned char sll_halen;
    unsigned char sll_addr[8];
  };
5、sendto函数在发送链路层数据时,需要自己组织buf内容,包括以太网头和协议内容。其中dest_addr参数必须设置,与应用层sendto函数指定目的地址不同,链路层发送时需要指定将buf从本机的哪个网卡发送出去。同样,实际类型为struct sockaddr_ll,只需要设置sll_ifindex参数即可。
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
6、recvfrom函数在接收数据时,如果本机的任意一个网卡设置了混杂模式,那么这个函数都能收到链路层包,除非sockfd采用bind函数绑定了网卡。如果绑定的网卡设置了混杂模式,则只能收到发往本网卡包(包括组播包和广播包等)。其中,src_addr为发送包的源地址。
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
7、应用层socket通过(源IP、源端口、目的IP、目的端口)四元组来确定socket对应的进程,操作系统在转发包时能够确定唯一的进程ID;而原始套接字socket没有端口的概念,所以只能通过(源IP、目的IP)或(源MAC、目的MAC)二元组来区分不同的进程。ping程序通过在协议字段里添加进程ID来区分;而Y1731协议里没有设置这个字段的地方。

0 0
原创粉丝点击