#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
static struct packet_type pt;
static int proto_handler(struct sk_buff * skb, struct net_device * dev1,
struct packet_type * pktype, struct net_device * dev2)
{
struct ethhdr * eth = eth_hdr(skb);
struct iphdr * ip = ip_hdr(skb);
printk("%pM -> %pM\n", eth->h_source, eth->h_dest);
printk("%pI4 -> %pI4\n", &ip->saddr, &ip->daddr);
return NF_ACCEPT;
}
int sniff_init(void)
{
pt.type = htons(ETH_P_IP);
pt.func = proto_handler;
dev_add_pack(&pt);
return 0;
}
void sniff_exit(void)
{
dev_remove_pack(&pt);
}
module_init(sniff_init);
module_exit(sniff_exit);
MODULE_LICENSE("GPL");
커널 모듈로 패킷을 캡쳐하는 세번째 방법으로는 새로운 프로토콜 핸들러를 등록하는 방식이다.
dev_add_pack()이라는 함수를 이용하여 새로운 프로토콜 핸들러를 등록 할 수 있는데, 먼저 아래의 구조체를 적절히 초기화 해야 한다.
struct packet_type {
__be16 type; /* This is really htons(ether_type). */
struct net_device *dev; /* NULL is wildcarded here */
int (*func) (struct sk_buff *,
struct net_device *,
struct packet_type *,
struct net_device *);
bool (*id_match)(struct packet_type *ptype,
struct sock *sk);
void *af_packet_priv;
struct list_head list;
};
type은 big endian이므로 htons()로 변환해서 초기화 해야하며,
type으로는 ETH_P_ 로 시작하는 것만 해야한다.
프로토콜을 처리할 함수는 func와 같은 형식으로 선언 및 정의해야 한다.
넷 필터에 경우 프로토콜이 NFPROTO_INET인 경우 이더넷 헤더를 볼 수 없다.
디캡슐레이션 후 넘어오기 때문이다.
그러나 위 방법에서는 이더넷 헤더 부터 볼 수 있다.
끝으로 모듈을 해제 할 때에는 dev_remove_pack()을 호출하여 등록한 핸들러를 해제 해주어야 한다.
'리눅스 커널 > 네트워크' 카테고리의 다른 글
promiscuous mode (0) | 2021.10.24 |
---|---|
DHCP (0) | 2021.10.24 |
Kernel hooking packet capture (0) | 2021.10.24 |
Raw socket outgoing packet capture (0) | 2021.10.24 |
Raw socket incoming packet capture (0) | 2021.10.24 |