鏈路層原始套接字編程-總結

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協議裏沒有設置這個字段的地方。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章