#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "pktfilter.c"
int main(void)
{
int sock;
unsigned char buf[65536];
struct packet_mreq pm;
sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock < 0)
{
perror("socket error");
return -1;
}
memset(&pm, 0, sizeof(pm));
pm.mr_ifindex = 2; //normally, 1: lo, 2: ens33(or eth0)
pm.mr_type = PACKET_MR_PROMISC;
if (setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &pm, sizeof(pm)) < 0)
{
perror("setsockopt error");
close(sock);
return -1;
}
while (1)
{
int type;
int rcv_bytes = recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL);
if (rcv_bytes < 0)
break;
eth_handle((struct ethhdr *)buf);
}
close(sock);
return 0;
}
기본적으로 packet socket의 옵션은 SOL_PACKET 레벨의 setsockopt() 을 통해 변경 할 수 있다.
그리고 이 때 옵션으로 PACKET_ADD_MEMBERSHIP, PACKET_DROP_MEMBERSHIP에 사용되는 packet_mreq 구조체는 아래와 같이 정의되어 있다.
struct packet_mreq {
int mr_ifindex; //interface index
unsigned short mr_type; //수행할 action을 명시
unsigned short mr_alen; //주소 길이
unsigned char mr_address[8]; //물리계층 주소
};
type에는 4가지가 있다.
#define PACKET_MR_MULTICAST 0
#define PACKET_MR_PROMISC 1
#define PACKET_MR_ALLMULTI 2
#define PACKET_MR_UNICAST 3
먼저 PACKET_MR_MULTICAST 는 해당 소켓을 mr_address, mr_alen으로 명시된 물리계층의 멀티캐스트 그룹의 바인드시킨다. 그래서 해당 type을 설정할 경우 이 두 변수는 적절히 초기화되어야 한다.
PACKET_MR_ALLMULTI 는 인터페이스 도착하는 모든 멀티캐스트 패킷들을 수신하도록 해준다.
마지막으로 PACKET_MR_PROMISC 이다.
해당 type은 해당 socket을 promiscous mode로 전환시켜, 공유 매체내 모든 패킷을 수신하도록 하게 해준다.
즉, 같은 네트워크 상에 떠돌아 다니는 모든 패킷을 볼 수 있게 해준다는 의미이다.
우리가 인터넷 통신을 위해 게이트웨이로만 패킷을 보낸다고 하여도
해당 패킷은 같은 네트워크 내 모든 호스트들에게 전송된다.
그러나 시스템은 받은 패킷의 2계층 주소를 보고 필터링 하기 때문에 우리는 이 패킷을 일반적으로 볼 수 없는 것이다.
그러나 promiscous mode를 통해 이러한 패킷도 볼 수 있는 것이다.
'리눅스 커널 > 네트워크' 카테고리의 다른 글
Check Sum Layer 4 (0) | 2021.10.24 |
---|---|
netlink example (0) | 2021.10.24 |
DHCP (0) | 2021.10.24 |
Kernel handler packet capture (0) | 2021.10.24 |
Kernel hooking packet capture (0) | 2021.10.24 |