for() */ 패킷 처리 소스

Download Report

Transcript for() */ 패킷 처리 소스

Libpcap & Libnet
Sungjin OK
By PresenterMedia.com
ON TARGET
INDEX
BPF
Libpcap function
Libpcap API
Libpcap 예제
Libnet
Libnet 예제
ON TARGET
BPF 구조

Berkeley Packet Filter 구조
tcpdump
유저 프로세스들~
sniffer
ngrep
TCP, UDP
IP, ICMP, IGMP
필터 필터 필터
BPF 드라이버
복사 받은 패킷
보낸 패킷
Ethernet
device driver
ON TARGET
패킷 캡쳐

패킷을 캡쳐하는 순서
- 1. 네트웍 인터페이스 명칭 지정
- 2. 네트웍 인터페이스 디스크립터 얻음
- 3. 필터룰을 컴파일 시킴
- 4. 컴파일된 필터룰을 네트웍 인터페이스에 적용
- 5. 패킷을 모으고, 패킷에 따른 프로세싱
ON TARGET
Libpcap 사용

헤더파일을 포함시킴
#include <pcap.h>
/* or */
#include <pcap/pcap.h>

컴파일 방법
# gcc 소스.c -lpcap
/* version 0.2.6-9 */
ON TARGET
Libpcap function
Char* Pcap_lookdev();
Device = pcap_lookupdev(ebuf);
네트웍 장치를 가져오는 함수
가능한 장치중 가장 번호가 낮은 장치를 가져오게 된다
리눅스라면 eth0 같은
다른 장치를 통해 캡쳐하려면 직접 장치명을 써준다
Device = “wlan0”;
Pcap_t Pcap_open_live();
Pd = pcap_open_live(device, snlen, promiscuous, time, ebuf);
실제 기기를 사용할수 있도록 열어주는 함수
Device : 네트웍장치
Snlen : 패킷당 저장할 바이트크기 (실제 패킷에서 가져오고 싶은 크기)
Promiscuous : promiscuous 패킷의 저장 여부 1이면 저장 0이면 무시
Time : 패킷대기 시간
패킷이 버퍼로 전달될 때 바로 전달되는 것이 아님
명시한 시간을 넘겼을때 나 버퍼가 다 채워질경우만 전달됨
단위는 milliseconds
ON TARGET
Libpcap function
pcap_lookupnet(device, &localnet, &netmask, ebuf);
열려진 패킷 캡쳐 장치에 네트웍 주소와 서브넷 마스크를 넘겨주는 함수
성공 여부를 0 또는 -1로 리턴
localnet : 네트웍 주소(ip) 를 저장하기 위한 공간
Netmask : 서브넷 마스크를 저장하기 위한 공간
크기는 Uint32 정도로 구성(ipv4의 경우)
Pcap_compile(pd, &fcod, filter_rule, optimize, netmask);
우리가 원하는 패킷을 보기위해서는 필터를 거쳐야 한다
해당 필터룰(tcpdump 의 필터) 프로그램으로 사용하기 위해 컴파일 하는 과정
Struct bpf_program *fcod : 컴파일 결과
Filter_rule : tcpdump필터 룰을 따른 문자열
Int optimize : 최적화 여부
Netmask : 해당 장치의 netmask
ON TARGET
Libpcap function
Pcap_setfilter()
pcap_setfilter(pd, &fcode);
컴파일한 필터를 지정해 주는데 사용된다
pcap_datalink()
printer = lookup_printer(pcap_datalink(pd));
패킷 캡쳐 디바이스의 datalink계층의 종류를 넘겨 받아 이에 따른 적절한 함수포인터를 할당하게 됩니
다.
if (pcap_datalink (handle) == DLT_EN10MB)
{
wired = 1; /* ethernet link */
} else {
if (pcap_datalink (handle) == DLT_IEEE802_11_RADIO_AVS)
{
wired = 0; /* wireless */
} else {
fprintf (stderr, "I don't support this interface type!\n");
exit (1);
}
}
ON TARGET
Libpcap function
Pcap_loop()
pcap_loop(pd, packetcnt, printer, pcap_userdata)
실제 패킷을 잡아서 실행할 함수를 지정해 주는 함수
packetcnt의 수만큼 패킷을 잡아서 잡을 때 마다 해당 패킷을 printer가 포인터하는 함수에게 전
달하고 함수를 수행
packetcnt를 0으로 지정하면 무한대로 함수를 실행합니다.
Userdata : 핸들러 함수로 넘어갈 때의 데이터
Pcap_next()
함수형 포인터를 사용하지 않고 함수를 호출할 때마다 패킷을 리턴해주는 함수로 앞의 pcap_datalink()
와 pcap_loop()를 대체할 수 있습니다.
ON TARGET
Libpcap API 예제
pcap_t *pdevice;
char *device;
………
if (device == NULL) {
if ((device = pcap_lookupdev(err_buffer)) == NULL) {
perror(err_buffer);
exit(1);
}
}
…………
if ((pdevice = pcap_open_live(device, snaplen, PROMISCUOUS, to_ms, err_buffer))
== NULL) {
fprintf(stdout, "\nerror : pcap_open_live()\n");
perror(err_buffer);
exit(1);
}
ON TARGET
Libpcap API 예제
………………
struct bpf_program fcode;
………………
if (pcap_compile(pdevice, &fcode, filter_rule, 0, netmask) < 0) {
fprintf(stdout, "%s\n", pcap_geterr(pdevice));
exit(1);
유저 프로세스들~
}
tcpdump
sniffer
ngrep
if (pcap_setfilter(pdevice, &fcode) < 0) {
fprintf(stdout, "%s\n", pcap_geterr(pdevice));
exit(1);
}
필터 필터 필터
if (pcap_loop(pdevice, packetcnt, handler_pcap, pcap_userdata) < 0) {
BPF 드라이버
fprintf(stdout, "%s\n", pcap_geterr(pdevice));
exit(1);
}
ON TARGET
패킷 캡쳐 부분
#include <pcap/pcap.h>
#define PROMISCUOUS 1
/* 모든 패킷에 대하여 수신 모드 */
int main(int argc, char *argv[]) {
bpf_u_int32 localnet, netmask;
pcap_t *pdevice;
char *device = NULL;
char *filter_rule;
/* unsigned 32bit int */
/* 장치에 대한 정보가 저장될 구조체 */
/* 장치명 */
/* 필터룰 문자열 */
char err_buffer[PCAP_ERRBUF_SIZE];
struct pcap_stat ps;
/* pcap_stats() */
ON TARGET
패킷 캡쳐 부분
int snaplen = 1514; /* 버퍼에 캡쳐될 패킷 최대 크기를 결정 한다. */
int to_ms = 1000; /* 버퍼가 채워지길 기다리는 시간 (ms) */
int snapshotlen;
/* pcap_snapshot() 에서 리턴 값 */
int packetcnt = -1; /* 캡쳐될 패킷 카운트 default : 무한값 */
int datalink;
/* 데이터링크 타입 저장, pcap_datalink() */
unsigned char *pcap_userdata;
struct bpf_program fcode;
/* 컴파일된 필터룰이 저장될 구조체 */
filter_rule = argv[1];
/* ex) src host xxx.xxx.xxx.xxx and tcp port 80 */
이더넷 프레임
이더넷 헤더
14 bytes
IP 헤더
TCP 헤더
애플리케이션
데이타
46 ~ 1500 bytes
이더넷
트레일러
ON TARGET
패킷 캡쳐 부분
/* 장치 명칭이(eth0 or eth1...) 결정되지 않았을 경우에 자동으로 할당 한다. */
if (device == NULL) {
/* pcap_lookupnet(), pcap_open_live() 에서 사용될
네트웍 디바이스에 대한 포인터를 리턴한다. */
/* 함수 호출시 에러가 발생하면 NULL 이 리턴되며
errbuf 에 적절한 에러메세지가 담겨진다. */
if ((device = pcap_lookupdev(err_buffer)) == NULL) {
fprintf(stdout, "\nerror : pcap_lookupdev()\n");
perror(err_buffer);
exit(1);
}
}
ON TARGET
패킷 캡쳐 부분
/* 네트워크 상에서 패킷을 인식하기 위한 패킷 캡쳐 디스크립터를 얻는데 사용된다. */
/*
/*
/*
/*
/*
device 는 open 시킬 네트워크 디바이스를 가리키는 문자열 */
snaplen 는 캡쳐할 최대 바이트 수를 나타낸다. */
PROMISCUOUS 는 인터페이스가 PROMISCUOUS 모드 상태로 전환하기위한 값 */
to_ms 는 버퍼가 채워지길 기다리는 시간을 milliseconds 단위로 설정한 것이다. */
err_buffer 는 NULL 이 리턴될 경우 에러메세지가 저장된다. */
if ((pdevice = pcap_open_live(device, snaplen, PROMISCUOUS, to_ms, err_buffer))
== NULL) {
fprintf(stdout, "\nerror : pcap_open_live()\n");
perror(err_buffer);
exit(1);
}
ON TARGET
패킷 캡쳐 부분
/* pcap_open_live() 가 호출될때 지정된 snapshot 의 길이를 리턴한다. */
if ((snapshotlen = pcap_snapshot(pdevice)) > snaplen) {
fprintf(stdout, "\nerror : pcap_snapshot()\n");
fprintf(stdout, "%s\n", pcap_geterr(pdevice));
exit(1);
}
fprintf(stdout, "snapshotlen : %d\n", snapshotlen);
ON TARGET
패킷 캡쳐 부분
/* 네트워크 디바이스와 관계된 네트워크 넘버, 서브넷 마스크 등을 결정 */
/* localnet, netmask 는 각각 네트워크 넘버와 서브넷 마스크를 나타내고 bpf_u_int32
타입이다. */
/* 에러가 발생하면 1 을 리턴한다. */
if (pcap_lookupnet(device, &localnet, &netmask, err_buffer) < 0) {
fprintf(stdout, "\nerror : pcap_lookupnet()\n");
perror(err_buffer);
exit(1);
}
fprintf(stdout, "localnet : %s\n", inet_ntoa(localnet));
fprintf(stdout, "netmask : %s\n", inet_ntoa(netmask));
ON TARGET
패킷 캡쳐 부분
fprintf(stdout, "filter_rule = %s\n", filter_rule);
/* pcap_compile 함수는 filter_rule 문자열을 필터 프로그램에 컴파일 시킴 */
/* fcode 는 필터 프로그램의 포인터이다. struct bpf_program */
/* 네번째 인수인 0 는 optimize 로서 필터 프로그램의 결과 코드의 최적화를 조절 */
if (pcap_compile(pdevice, &fcode, filter_rule, 0, netmask) < 0) {
fprintf(stdout, "\nerror : pcap_compile()\n");
fprintf(stdout, "%s\n", pcap_geterr(pdevice));
exit(1);
}
필터 필터 필터
BPF 드라이버
ON TARGET
패킷 캡쳐 부분
/* 컴파일된 필터 프로그램을 지정한다. */
/* fcode 는 bpf_program struct 의 배열을 가리키는 포인터이다. */
/* 함수 실패시 -1 을 리턴하며, 성공시 0 이 리턴된다. */
if (pcap_setfilter(pdevice, &fcode) < 0) {
fprintf(stdout, "\nerror : pcap_setfilter()\n");
fprintf(stdout, "%s\n", pcap_geterr(pdevice));
exit(1);
}
유저 프로세스들~
tcpdump
sniffer
ngrep
필터 필터 필터
BPF 드라이버
ON TARGET
패킷 캡쳐 부분
/* 데이터링크의 타입을 구해온다. */
datalink = pcap_datalink(pdevice);
/* bpf.h 헤더파일 참조 */
/* 패킷을 모으고 프로세싱을 한다. */
/* packetcnt 는 캡쳐될 패킷의 갯수를 나타내며, -1 일때는 무한 루프, 0 이면 에러가
발생하거나 데이터의 끝일때까지 모든 패킷을 처리한다. */
/* pcap_userdata 는 u_char 형으로 사용자가 임의로 넣을 수 있다. */
/* handler_pcap 는 패킷을 처리할 핸들러 함수 이다. */
/* handler_pcap 로 네 번 째 인 수 인 pcap_userdata, pcap_pkthdr 구 조 체 에 대 한
포인터(실제 네트웍 헤더와 데이터의 첫부분을 가리킴), 패킷 데이터에 대한 u_char
형 포인터, 이상 3개의 인수가 전달 된다. */
if (pcap_loop(pdevice, packetcnt, handler_pcap, pcap_userdata) < 0) {
fprintf(stdout, "\nerror : pcap_loop()\n");
fprintf(stdout, "%s\n", pcap_geterr(pdevice));
exit(1);
}
ON TARGET
패킷 캡쳐 부분
/* 패킷 캡쳐가 시작된 이후부터 이 함수가 호출될 시점까지의 패킷 캡쳐의 통계치를
구한다. */
/* 두번째 인수 pcap_stat 구조체에 통계치를 저장한다. */
/* 실패시 -1 을 리턴한다. */
/* 단, 한번더 호출시 전 통계치는 리셋 */
if (pcap_stats(pdevice, &ps) < 0) {
fprintf(stdout, "\nerror : pcap_stats()\n");
fprintf(stdout, "%s\n", pcap_geterr(pdevice));
exit(1);
}
fprintf(stdout, "received : %u, dropped : %u\n", ps.ps_recv, ps.ps_drop);
/* 구조체 pcap 에 사용된 파일과 메모리를 해제한다. */
pcap_close(pdevice);
ON TARGET
Pcap_handler

pcap_handler
- 패킷을 수신시 패킷의 처리를 담당하는 함수
- pcap_loop() 함수에서 handler 함수명을 지정해 주어야 함
/* pcap_loop() 에 의해 패킷을 잡을 때마다 불리어지는 함수 */
void handler_pcap(unsigned char *user, const struct pcap_pkthdr *h,
const unsigned char *p) {
/* 사용자 인수 인 user, 패킷 데이터에 대한 u_char 형 포인터 p */
/* pcap_pkthdr 구조체에 대한 포인터 */
…………
return;
}
ON TARGET
패킷 처리

ethernet 헤더
- net/ehternet.h 중에서
/* 10Mb/s ethernet header */
struct ether_header {
u_int8_t ether_dhost[ETH_ALEN];
/* destination eth addr */
u_int8_t ether_shost[ETH_ALEN];
/* source ether addr */
u_int16_t ether_type;
/* packet type ID field */
};
이더넷 프레임
이더넷 헤더
14 bytes
IP 헤더
TCP 헤더
애플리케이션
데이타
이더넷
트레일러
ON TARGET
패킷 처리

IP 헤더
- netinet/ip.h 중에서
struct iphdr {
unsigned int version:4;
unsigned int ihl:4;
u_int8_t tos; /* type of service */
u_int16_t tot_len;
//전체의 길이
u_int16_t id;
u_int16_t frag_off;
/* 3-bit flags 포함 */
u_int8_t ttl;
u_int8_t protocol;
u_int16_t check;
IP 데이터그램
u_int32_t saddr;
u_int32_t daddr;
};
TCP 헤더
IP 헤더
20 bytes
애플리케이션
데이타
ON TARGET
패킷 처리

ICMP 헤더
- netinet/ip_icmp.h 중에서
struct icmp {
u_int8_t icmp_type;
u_int8_t icmp_code;
u_int16_t icmp_cksum;
/* type of message, see below */
/* type sub code */
/* ones complement checksum of struct */
union {
………….
}
ICMP 메세지
};
IP 헤더
ICMP 헤더
8 bytes
IP header of datagram
That generated error
UDP 헤더
ON TARGET
패킷 처리

TCP 헤더
- netinet/tcp.h 중에서
struct tcphdr {
u_int16_t source;
u_int16_t dest;
u_int32_t seq;
u_int32_t ack_seq;
u_int16_t doff:4; //header length
u_int16_t res1:4;
u_int16_t res2:2;
u_int16_t window;
u_int16_t check;
u_int16_t urg_ptr;
};
u_int16_t urg:1;
u_int16_t ack:1;
u_int16_t psh:1;
u_int16_t rst:1;
u_int16_t syn:1;
u_int16_t fin:1;
IP 헤더
TCP 세그먼트
TCP 헤더
20 bytes
TCP 데이터
ON TARGET
패킷 처리

UDP 헤더
- netinet/udp.h 중에서
struct udphdr {
u_int16_t
u_int16_t
u_int16_t
u_int16_t
};
source;
dest;
len;
check;
UDP 데이터그램
IP 헤더
UDP 헤더
8 bytes
UDP 데이터
ON TARGET
패킷 처리

ARP 헤더
- netinet/if_ether.h 중에서
struct ether_arp {
struct arphdr ea_hdr;
/* fixed-size header */
u_int8_t arp_sha[ETH_ALEN];
/* sender hardware address */
u_int8_t arp_spa[4];
/* sender protocol address */
u_int8_t arp_tha[ETH_ALEN];
/* target hardware address */
u_int8_t arp_tpa[4];
/* target protocol address */
};
ARP 리퀘스트/리플라이
이더넷 헤더
ARP 헤더
28 bytes
ON TARGET
패킷 처리 소스
#include <net/ethernet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
#include <netinet/if_ether.h>
/*
/*
/*
/*
/*
/*
이더넷 */
IP 헤더 */
TCP 헤더 */
UDP 헤더 */
ICMP 헤더 */
ARP 헤더 */
/* pcap_loop() 에 의해 패킷을 캡쳐할 때마다 불리어지는 함수 */
void handler_pcap(unsigned char *user, const struct pcap_pkthdr *h,
const unsigned char *p) {
/* 사용자 인수 인 user, 패킷 데이터에 대한 u_char 형 포인터 p */
/* pcap_pkthdr 구조체에 대한 포인터 */
ON TARGET
패킷 처리 소스
/* 헤더 구조체, netinet 폴더에 *.h 참조 */
struct ether_header *eh;
struct iphdr *iph;
struct tcphdr *tcph;
struct udphdr *udph;
struct icmp *icmph;
struct ether_arp *arph;
unsigned char *tcpdata;
unsigned char *udpdata;
unsigned char *icmpdata;
register int i, j;
/* for() */
/* net/ethernet.h 참조 */
ON TARGET
패킷 처리 소스
/* 이더넷 헤더 맵핑 */
eh = (struct ether_header *) p;
/* 데이터링크 레이어 */
/* ================== 데이터링크 레이어 ================== */
for (i = 0; i < ETH_ALEN; i++) {
/* ETH_ALEN = 6, linux/if_ether.h 참조 */
fprintf(stdout, "%02x", eh->ether_shost[i]); /* 출발지 MAC 주소 */
if (i != 5) {
fprintf(stdout, ":");
}
}
fprintf(stdout, " ----> ");
이더넷 프레임
이더넷 헤더
14 bytes
IP 헤더
TCP 헤더
애플리케이션
데이타
이더넷
트레일러
ON TARGET
패킷 처리 소스
for (i = 0; i < ETH_ALEN; i++) {
fprintf(stdout, "%02x", eh->ether_dhost[i]); /* 목적지 MAC 주소 */
if (i != 5) {
fprintf(stdout, ":");
}
}
fprintf(stdout, "\n");
fprintf(stdout, "Ether_type: %x\n", ntohs(eh->ether_type)); /* 16 비트 */
ON TARGET
패킷 처리 소스
/* IP 헤더 */
IP 데이터그램
IP 헤더
TCP 헤더
if (ntohs(eh->ether_type) == ETHERTYPE_IP) {
/* IP 헤더 맵핑 */
iph = (struct iphdr *) (sizeof(struct ether_header) + p);
/* IP 헤더로 포인터를 맞춤 */
20 bytes
/* ==================
IP 헤더
================== */
fprintf(stdout, "%s ---->", inet_ntoa(iph->saddr));
fprintf(stdout, "%s\n", inet_ntoa(iph->daddr));
fprintf(stdout, "Version:
%d\n", iph->version);
fprintf(stdout, "Header Length:
%d\n", iph->ihl);
fprintf(stdout, "Service:
%x\n", iph->tos);
애플리케이션
데이타
ON TARGET
패킷 처리 소스
fprintf(stdout, "Total Length:
fprintf(stdout, "Identification:
%d\n", ntohs(iph->tot_len));
%d\n", ntohs(iph->id));
fprintf(stdout, "RF:%d ", (ntohs(iph->frag_off) & 0x8000) >> 15);
fprintf(stdout, "DF:%d ", (ntohs(iph->frag_off) & 0x4000) >> 14);
fprintf(stdout, "MF:%d\n", (ntohs(iph->frag_off) & 0x2000) >> 14);
fprintf(stdout, "Fragmenting bits: %d\n", (ntohs(iph->frag_off) & 0x1fff) * 8);
fprintf(stdout, "Time to Live:
fprintf(stdout, "Protocol:
fprintf(stdout, "Checksum:
%d\n", iph->ttl);
%d\n", iph->protocol);
%d\n", ntohs(iph->check));
RF DF MF
Fragmenting bits
3 bits
13 bits
ON TARGET
패킷 처리 소스
/* TCP 헤더 */
if (iph->protocol == IPPROTO_TCP) {
/* netinet/in.h 참조 */
TCP 세그먼트
IP 헤더
TCP 헤더
TCP 데이터
/* TCP 헤더 맵핑 */
tcph = (struct tcphdr *) (sizeof(struct ether_header)20+bytes
(iph->ihl * 4) + p);
/* ==================
TCP 헤더
================== */
fprintf(stdout, "Source Port:
%d\n", ntohs(tcph->source));
fprintf(stdout, "Destination Port:
%d\n", ntohs(tcph->dest));
fprintf(stdout, "Sequence Number:
%u\n", ntohl(tcph->seq));
fprintf(stdout, "Acknowledgment Number: %u\n", ntohl(tcph->ack_seq));
fprintf(stdout, "Header Length:
%d\n", tcph->doff);
ON TARGET
패킷 처리 소스
fprintf(stdout, "Reserved1:%d ", tcph->res1);
fprintf(stdout, "Reserved2:%d\n", tcph->res2);
fprintf(stdout, "URG:%d ", tcph->urg);
fprintf(stdout, "ACK:%d ", tcph->ack);
fprintf(stdout, "PSH:%d ", tcph->psh);
fprintf(stdout, "RST:%d ", tcph->rst);
fprintf(stdout, "SYN:%d ", tcph->syn);
fprintf(stdout, "FIN:%d\n", tcph->fin);
fprintf(stdout, "Windows Size:
fprintf(stdout, "Checksum:
fprintf(stdout, "Urgent Pointer:
/* 플래그 */
%d\n", ntohs(tcph->window));
%d\n", ntohs(tcph->check));
%d\n", ntohs(tcph->urg_ptr));
ON TARGET
패킷 처리 소스
/* TCP 데이터 */
tcpdata = (unsigned char *) (p + sizeof(struct ether_header)
+ (iph->ihl * 4) + (tcph->doff * 4));
/* 포인터 조정 */
/* ================== TCP DATA(HEX) ================== */
j = 0;
for (i = (iph->ihl * 4) + (tcph->doff * 4); i <= ntohs(iph->tot_len) - 1; i++) {
fprintf(stdout, "%02x ", *(tcpdata++));
if ((++j % 16) == 0) {
fprintf(stdout, "\n");
}
TCP 세그먼트
}
fprintf(stdout, "\n");
IP 헤더
TCP 헤더
20 bytes
TCP 데이터
ON TARGET
패킷 처리 소스
/* ================== TCP DATA(char) ================== */
for (i = (iph->ihl * 4) + (tcph->doff * 4); i <= ntohs(iph->tot_len) - 1; i++) {
if ((*tcpdata == 0x0d) && (*(tcpdata + 1) == 0x0a)) {
fprintf(stdout, "\n");
tcpdata += 2;
i++;
continue;
}
if (*tcpdata >= ' ' && *tcpdata < 0x7f) {
/* 출력 못하는 문자 ‘.’ 대치 */
fprintf(stdout, ".");
}
else {
fprintf(stdout, "%c", *tcpdata);
}
tcpdata++;
}
ON TARGET
패킷 처리 소스
/* UDP 헤더 */
else if (iph->protocol == IPPROTO_UDP) {
/* netinet/in.h 참조 */
UDP 데이터그램
IP 헤더
UDP 헤더
UDP 데이터
/* UDP 헤더 맵핑 */
udph = (struct udphdr *) (p + sizeof(struct ether_header) + (iph->ihl * 4));
8 bytes
/* ==================
UDP 헤더
==================\n"); */
fprintf(stdout, "Source Port:
%d\n", ntohs(udph->source));
fprintf(stdout, "Destination Port:
%d\n", ntohs(udph->dest));
fprintf(stdout, "Length:
%d\n", ntohs(udph->len));
fprintf(stdout, "Checksum:
%d\n", ntohs(udph->check));
ON TARGET
패킷 처리 소스
/* UDP 데이터 */
udpdata = (unsigned char *) (p + sizeof(struct ether_header)
+ (iph->ihl * 4) + sizeof(struct udphdr));
/* 포인터 위치 시킴 */
/* ================== UDP DATA ================== */
/* TCP 의 데이터 부분과 동일 */
UDP 데이터그램
IP 헤더
UDP 헤더
8 bytes
UDP 데이터
ON TARGET
패킷 처리 소스
/* ICMP 헤더 */
else if (iph->protocol == IPPROTO_ICMP) {
/* netinet/in.h 참조 */
ICMP 메세지
IP 헤더
ICMP 데이터
ICMP 헤더
/* ICMP 헤더 맵핑 */
icmph = (struct icmp *) (p + sizeof(struct ether_header) + (iph->ihl * 4));
8 bytes
/* ICMP 헤더는 type 과 code 별로 여러가지 형태의 헤더가 나타난다. */
/* 아래는 default 이다. */
/* ==================
fprintf(stdout, "Type:
fprintf(stdout, "Code:
fprintf(stdout, "Checksum:
ICMP 헤더
================== */
%d\n", icmph->icmp_type);
%d\n", icmph->icmp_code);
%d\n", ntohs(icmph->icmp_cksum));
ON TARGET
패킷 처리 소스
/* ICMP 데이터 */
icmpdata = (unsigned char *) (p + sizeof(struct ether_header)
+ (iph->ihl * 4) + sizeof(struct icmp)); /* 포인터 위치 시킴 */
/* ================== ICMP DATA(HEX) ================== */
j = 0;
for (i = (iph->ihl * 4) + sizeof(struct icmp); i <= ntohs(iph->tot_len) - 1; i++) {
fprintf(stdout, "%02x ", *(icmpdata++));
if ((++j % 16) == 0) {
fprintf(stdout, "\n");
}
}
ICMP 메세지
fprintf(stdout, "\n");
}
IP 헤더
ICMP 헤더
8 bytes
ICMP 데이터
ON TARGET
패킷 처리 소스
/* ARP 헤더 */
else if (ntohs(eh->ether_type) == ETHERTYPE_ARP) {
ARP 리퀘스트/리플라이
/* ARP 헤더 맵핑 */
이더넷 헤더
arph = (struct ether_arp *) (p + sizeof(struct ether_header));
ARP 헤더
/* ==================
ARP 헤더
==================
*/
28 bytes
fprintf(stdout, "Hardware (Type): %d\n", ntohs(arph->ea_hdr.ar_hrd));
fprintf(stdout, "Protocol(Type):
%d\n", ntohs(arph->ea_hdr.ar_pro));
fprintf(stdout, "Hardware(Size):
%d\n", arph->ea_hdr.ar_hln);
fprintf(stdout, "Protocol(Size):
%d\n", arph->ea_hdr.ar_pln);
fprintf(stdout, "ARP opcode (command):
ntohs(arph->ea_hdr.ar_op));
%d\n",
ON TARGET
패킷 처리 소스
fprintf(stdout, "Sender Hardware(Ethernet) address: ");
for (i = 0; i < ETH_ALEN; i++) {
/* MAC 주소 나타내는 것과 동일 */
fprintf(stdout, "%02X", arph->arp_sha[i]);
if (i != 5) {
fprintf(stdout, ":");
/* XX:XX:XX:XX:XX:XX, 48 bits */
}
}
fprintf(stdout, "Sender Protocol(IP) address: ");
for (i = 0; i < 4; i++){
fprintf(stdout, "%d", arph->arp_spa[i]);
if (i != 3) {
fprintf(stdout, ".");
}
}
/* Target 부분, Sender 와 동일 */
ON TARGET
Libnet
Libnet
응용 프로그램이 패킷을 생성하여 보낼 수 있게 해주는 라이브러리
패킷 생성 과정
1. 네트워크의 초기화
2. 메모리의 초기화
3. 패킷의 생성
4. 패킷의 체크섬(Check Sum) 생성
5. 패킷의 투입 (Injection)
ON TARGET
Libnet 사용

헤더파일을 포함시킴
#include <libnet.h>

컴파일 방법
# gcc 소스.c -lnet
ON TARGET
Libnet
네트웍 초기화
네트웍 injection 인터페이스 갖고 오기
raw 소켓 인터페이스
적당한 프로토콜 (보통 IPPROTO_RAW)을 가지고 libnet_open_raw_socket()을
호출
이 호출은 커널에 libnet이 IP 헤더를 만들 것이라는 것을 알려주는
IP_HDRINCL이 찍혀진 raw 소켓을 리턴
링크-layer 인터페이스
적당한 디바이스 인자를 가지고 libnet_open_link_interface() 를 호출
이 함수는 링크-인터페이스 구조에 갈 준비가 되어 있는 포인터를 리턴
메모리 Allocation
패킷을 위한 메모리를 allocate 시킨다
방법은 libnet_init_packet()를 호출
raw 소켓 인터페이스를 사용하는 30바이트의 payload를 가진 간단한 TCP 패
킷을 위해서는 70바이트가 필요(IP 헤더 + TCP 헤더 + payload)
링크-layer 인터페이스를 사용하는 같은 패킷은 84바이트가 필요
(이더넷 헤더 + IP 헤더 + TCP 헤더 + payload).
메모리 작업이 끝나면, libnet_destroy_packet()를 호출하여 메모리를 놓아주
어야 한다.
ON TARGET
Libnet
패킷 생성
패킷은 모듈적으로 생성
각각의 프로토콜 layer에 각각에 맞는 libnet_build
함수에 대한 호출이 있다.
raw 소켓 에서는 libnet_build_ip()와
libnet_build_tcp()가 쓰임
링크-layer 에서는 libnet_build_Ethernet()이 쓰임.
패킷 생성 함수 호출의 순서는 중요하지 않다.
단지 이 함수들에 정확한 메모리 오프셋이 전달되는 것이
중요하다. (현재 버전에서는 tag로 처리)
 함수들은 패킷 버퍼에 패킷 헤더를 만들어야 한다. 그리
고 이것은 어떤 순서로도 될 수 있다.
ON TARGET
Libnet
ON TARGET
Libnet
패킷 버퍼는 libnet_init_packet()을 통해서 초기화
libnet_build_Ethernet()는 오프셋 0을 가진 버퍼의 맨 처음이 전달된다.
(이더넷 헤드는 패킷의 맨 앞에 만들어져야 하므로)
libnet_build_ip() 정확한 위치에 IP 헤더를 만들기 위해서 14바이트의 오
프셋이 전달받고,
 libnet_build_tcp() 은 이것보다 20바이트 뒤의 오프셋을 전달받는다.
패킷 체크섬
패킷 체크섬을 계산
(패킷이 어떤 종류의 IP 패킷이라고 가정할 때)
raw 소켓 인터페이스에서는 커널이 IP 체크섬을 다룰 것이므로 프로그래머는
transparent layer 체크섬만을 계산하면 된다. (패킷이 transparent layer를 가지고 있다고
가정할 때)
링크-layer 인터페이스에서는 IP 체크섬은 명확하게 계산되어야 한다.
체크섬은 패킷의 IP헤더에 대한 포인터를 받는 libnet_do_checksum()을 통해서 계
산된다.
ON TARGET
Libnet
패킷 Injection
네트웍에 패킷을 쓰는 것
raw 소켓 인터페이스에서는 libnet_write_ip()을 통해서 쓰고,
링크-layer 인터페이스에서는 libnet_write_link_layer()을 통해서 쓴다.
두 개의 함수 모두 씌여진 바이트 수를 리턴하고, 오류가 나면 -1을 리턴한다.
ON TARGET
Libnet 소스
소스 설명으로 대체
더 자세한 함수는
http://libnet.sourcearchive.com 참조
ON TARGET
THANK YOU