RAW Socket

강윤경·2023년 1월 31일
0

Network

목록 보기
17/17

RAW Socket?

  • 어느 특정한 프로토콜 용의 전송 계층 formatting 없이 인터넷 프로토콜 패킷을 직접적으로 송수신 가능하게 하는 소켓
  • 헤더 정보들에 대해 직접 제어 가능
  • RAW 소켓 사용 시 IP 헤더와 TCP 헤더 직접 제어 가능, 이를 모두 사용자 데이터로 취급하여 네트워크 계층에 어떤 종류의 헤더 사용 가능

RAW Socket 특징

  • 응용 계층과 전송 계층, 네트워크 계층에서 모두 접근 가능
  • 네트워크 계층 헤더와 전송 계층 헤더 직접 제어 가능
  • 네트워크 계층으로 전송되는 모든 패킷들을 모니터링 및 감지 가능
  • IP Segment에서 암호화된 악성 코드 존재 시, IP 계층에서 이를 필터링하지 못하여 문제가 발생할 수 있다.
  • 일반적으로 패킷의 목적지IP 주소가 자신의 IP 주소인 패킷만을 수신받지만 RAW 소켓은 IP주소나 포트주소가 다르더라도 물리 계층인 인터넷 디바이스 드라이버에서 오는 모든 패킷을 수신받아 확인 가능

RAW Socket 흐름도

RAW Socket 생성

sock = socket(AF_INET, SOCK_RAW, PROTOCOL);
  • AF_INET : 프로토콜 체계
  • SOCK_RAW : RAW Socket 생성
  • PROTOCOL
    • TCP : IPPROTO_TCP
    • UDP : IPPROTO_UDP
    • ICMP : IPPROTO_ICMP
  • 소켓 옵션 변경
    int value = 1
    setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&value, siezof(value));
    • IP_HDRINCL : 해당 옵션을 설정하지 않을 시 IP 헤더는 커널이 생성
    • IP, TCP 헤더 모두 설정하기 위해서는 사용할 프로토콜 명시, IP_HDRINCL 옵션 설정 필수

RAW Socket Programming

  • RAW Socket을 icmp protocol로 설정하여 ping프로그램 생성
  • 예제 코드
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <netinet/in_systm.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <netinet/ip_icmp.h>
    #include <signal.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <sys/time.h>
    
    void sig_alrm(int);
    void send_msg(void);
    void handlePing(void);
    unsigned short cksum_in(unsigned short *, int);
    void tv_sub(struct timeval *, struct timeval *);
    
    struct timeval * tvsend, tvrecv;
    int sd;
    pid_t pid;
    int nsent = 0;
    
    struct sockaddr_in sasend;
    struct sockaddr_in sarecv;
    int salen;
    
    int main(int argc, char *argv[]){
    	if(argc != 2){
    		printf("usage : ping domain_name\n");
    		exit(-1);
    	}
    
    	bzero((char *)&sasend, sizeof(sasend));
    	sasend.sin_family = AF_INET;
    	sasend.sin_addr.s_addr = inet_addr(argv[1]);
    	salen = sizeof(sasend);
    
    	pid = getpid() & 0xffff;
    
    	handlePing();
    
    	return 0;
    }
    
    void handlePing(void) {
    	int len, hlen, icmplen;
    	struct timeval tval;
    	char buf[1500];
    
    	fd_set readfd;
    	struct iphdr *iph;
    	struct icmp *icmp;
    
    	double rtt;
    
    	signal(SIGALRM, sig_alrm);
    
    	if((sd=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
    		printf("socket open error\n");
    		exit(-1);
    	}
    
    	sig_alrm(SIGALRM);
    
    	for(;;) {
    		if((len = recvfrom(sd, buf, sizeof(buf), 0, NULL, NULL)) < 0){
    			printf("read error\n");
    			exit(-1);
    		}
    
    		iph = (struct iphdr *)buf;
    		hlen = iph->ihl * 4;
    
    		if(iph->protocol != IPPROTO_ICMP)
    			return;
    
    		if(iph->saddr == sasend.sin_addr.s_addr){
    			icmp = (struct icmp *)(buf + hlen);
    			icmplen = len - hlen;
    
    			if(icmp->icmp_type == ICMP_ECHOREPLY){
    				if(icmp->icmp_id != pid)
    					return;
    
    				gettimeofday(&tvrecv, NULL);
    				tvsend = (struct timeval *)icmp->icmp_data;
    				tv_sub(&tvrecv, tvsend);
    
    				rtt = tvrecv.tv_sec * 1000.0 + tvrecv.tv_usec / 1000.0;
    				
    				printf("%d byte from ** : seq = %u, ttl = %d, rtt = %.3f ms \n", icmplen, icmp->icmp_seq, iph->ttl, rtt);
    			}
    		}
    	}
    }
    
    void sig_alrm(int signo){
    	send_msg();
    
    	alarm(1);
    	return;
    }
    
    void send_msg(void){
    	int len;
    	struct icmp *icmp;
    	char sendbuf[1500];
    	int datalen = 56;
    
    	icmp = (struct icmp *)sendbuf;
    
    	icmp->icmp_type = ICMP_ECHO;
    	icmp->icmp_code = 0;
    	icmp->icmp_id = pid;
    	icmp->icmp_seq = nsent++;
    	memset(icmp->icmp_data, 0xa5, datalen);
    
    	gettimeofday((struct timeval *)icmp->icmp_data, NULL);
    
    	len = 8 + datalen;
    	icmp->icmp_cksum = 0;
    	icmp->icmp_cksum = cksum_in((unsigned short *)icmp, len);
    
    	sendto(sd, sendbuf, len, 0, (struct sockaddr *)&sasend, len);
    }
    
    void tv_sub(struct timeval *out, struct timeval *in){
    	if((out->tv_usec -= in->tv_usec) < 0) {
    		--out->tv_sec;
    		out->tv_usec += 100000;
    	}
    	out->tv_sec -= in->tv_sec;
    }
    
    unsigned short cksum_in(unsigned short *addr, int len)
    {
    	unsigned long sum = 0;
    	unsigned short answer = 0;
    	unsigned short *w = addr;
    	int nleft = len;
    
    	while (nleft > 1) {
    		sum += *w++;
    		if (sum & 0x80000000)
    			sum = (sum & 0xffff) + (sum >> 16);
    		nleft -= 2;
    	}
    
    	if (nleft == 1) {
    		*(unsigned char *)(&answer) = *(unsigned char *)w;
    		sum += answer;
    	}
    
    	while (sum >> 16)
    		sum = (sum & 0xffff) + (sum >> 16);
    
    	return(sum == 0xffff) ? sum : ~sum;
    }
  • 결과

    RAW Socket Programming 실행 중 socket open 실패 시 관리자 권한으로 실행

0개의 댓글