socket(AF_PACKET, SOCK_RAW, protocol) 或建立一個通訊端點後回傳 file descriptor。SOCK_RAW 是收送整個 L2 封包,SOCK_DGRAM 則不包括 L2 header。protocol 是指定要收的 Ether Type (需轉成 network endian),如果所有 Ether Type 都收的話用 htons(ETH_P_ALL)。
socket(AF_PACKET, SOCK_DGRAM, protocol)
預設所有網路界面都收,可用 bind() 綁定界面。收的封包包括 unicast 及 broadcast,用 setsockopt(<fd>, SOL_PACKET, <optname>, <optval>, <optlen>) 修改是否接收其它 MAC 位址的封包。
- PACKET_ADD_MEMBERSHIP, PACKET_DROP_MEMBERSHIP:
- PACKET_MR_PROMISC:不做 MAC address 過濾
- PACKET_MR_MULTICAST:增減 multicast 位址
- PACKET_MR_ALLMULTI:接收所有 multicast
int da_filter(int sk, const unsigned char *mac)
{
struct sock_filter code[] = {
/* tcpdump -dd ether dst 12:34:56:78:9a:bc or broadcast
* (000) ld [2]
* (001) jeq #0x56789abc jt 2 jf 4
* (002) ldh [0]
* (003) jeq #0x1234 jt 7 jf 8
* (004) jeq #0xffffffff jt 5 jf 8
* (005) ldh [0]
* (006) jeq #0xffff jt 7 jf 8
* (007) ret #65535
* (008) ret #0
*/
{ 0x20, 0, 0, 0x00000002 },
{ 0x15, 0, 2, 0x56789abc },
{ 0x28, 0, 0, 0x00000000 },
{ 0x15, 3, 4, 0x00001234 },
{ 0x15, 0, 3, 0xffffffff },
{ 0x28, 0, 0, 0x00000000 },
{ 0x15, 0, 1, 0x0000ffff },
{ 0x6, 0, 0, 0x0000ffff },
{ 0x6, 0, 0, 0x00000000 },
};
code[3].k = (mac[0]<<8)+mac[1];
code[1].k = (mac[2]<<24)+(mac[3]<<16)+(mac[4]<<8)+mac[5];
struct sock_fprog bpf = {
.len = sizeof(code)/sizeof(code[0]),
.filter = code,
};
if ((ret = setsockopt(sk, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))))
printf("setsockopt error: %s\n", strerror(errno));
return ret;
}
透過 SO_DETACH_FILTER
或 socket 關閉時移除。改變需要先移除舊的,如果新的加入失敗會沿用舊的。SO_LOCK_FILTER 選項鎖定 attached 的過濾碼,不能移除或改變。| 收封包 | 送封包 |
|---|---|
| read(fd, buf, len) | write(fd, buf, len) |
| recv(fd, buf, len, flags) | send(fd, buf, len, flags) |
| recvfrom(fd, buf, len, flags, addr, addrlen) | sendto(fd, buf, len, flags, addr, addrlen) |
| recvmsg(fd, msg, flags) | sendmsg(fd, msg, flags) |
如果要用 write 或 send 送封包,需要先綁定網路界面,不然不知道要從哪個界面送。
| bind | send | receive | |
|---|---|---|---|
| family | v | v | ? |
| protocol | v | - | ? |
| ifindex | v | v | ? |
| hatype | - | - | v |
| pktype | - | - | v |
| halen | - | v | ? |
| addr[8] | - | v | ? |
註:
- 也可以用其它方式收 L2 封包,例如 netif_receive_skb() 的 rx_handler
參考來源
沒有留言:
張貼留言