天天看點

socket綁定指定網卡發包

socket綁定指定網卡發包

  • SO_BINDTODEVICE

網絡程式設計中有時明明用eth0的位址來bind一個udp套接口, 可是發出去的包卻是從eht1走的, 在網上找到這麼一段話解釋該問題:

在多 IP/網卡主機上,UDP 包/協定會自動根據路由最優來選擇從哪個網卡發資料包出去,即使你在此之前把該 SOCKET 綁定到了另一個網卡上。這樣一來,如果你執行了綁定,則在 UDP 包中所代表的源 IP 字段可能不是你的資料包真正發出的位址。

比如:你有兩個網卡分别為:A—192.168.1.100; B-192.168.2.100; mask-255.255.255.0

此時你如果将一 UDP 套接字 S 綁定到了 A 上,但是要發的目的位址為 192.168.2.110,這時包實際是從網卡 B 上發出去的(根據路由最優原則),但在標頭的結構裡面,由于 BIND 的緣故,可能指向的源位址為 A。這樣源 IP 位址就産生了與實際不相符的錯誤。

要解決這種問題, 可以把套接字綁定到一個指定的網絡裝置, “eth0”, "ppp0"等.

示例1

int sock;
struct ifreq ifr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
memset(&ifr, 0x00, sizeof(ifr));
strncpy(ifr.ifr_name, "eth0", strlen("eth0"));
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr));      

示例2

int sock;
struct sockaddr_ll sl;
struct ifreq ifr;
sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IPV6));
memset(&sl, 0x00, sizeof(sl));
memset(&ifr, 0x00, sizeof(ifr));
sl.sll_family = AF_PACKET;
sl.sll_protocol = htons(ETH_P_IPV6);
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));
ioctl(fd, SIOCGIFINDEX, &ifr);
sl.sll_ifindex = ifr.ifr_ifindex;
bind(fd, (struct sockaddr *)&sl, sizeof(sl));      
int sock;
struct sockaddr addr;
sock = socket(PF_PACKET, SOCK_PACKET, ETH_P_IP);
memset(&addr, 0x00, sizeof(addr));
addr.sa_family = PF_PACKET;
strncpy(addr.sa_data, "eth0", sizeof(addr.sa_data));
bind(sock, &addr, sizeof(addr));      

SO_BINDTODEVICE