Raw 소켓을 사용한 ping 프로그램 오류가 나요 ㅜㅜ
글쓴이: happyu_u / 작성시간: 수, 2009/06/10 - 6:12오전
생 소켓을 사용해서 ICMP 기반의 Ping 프로그램을 작성하고 있는데요..
실행하게 되면
recvfrom() error
not ICMP packet.
이 두문장이 계속해서 무한루프 됩니다ㅜㅜ
문제가 뭘까요?
대체 뭐가 잘못된건지 헤매고 있습니다...도와주세요
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <unistd.h> #include <sys/time.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <netinet/in.h> #include <netinet/in_systm.h> #define BUFSIZE 1500 char sendbuf[BUFSIZE], recvbuf[BUFSIZE]; int seqnum; pid_t pid; int sockfd; int datalen = 56; struct sockaddr_in dstaddr, srcaddr; int send_ping(); int print_ping(char *ipdata, int readlen); void sig_alrm(int); void tv_sub(struct timeval *, struct timeval *); uint16_t in_cksum(uint16_t *addr, int len); void error_print(char *); int main(int argc, char **argv){ int readlen, addrlen; if(argc!=2){ printf("Usage : %s ip_address \n", argv[0]); exit(1); } bzero(&srcaddr, sizeof(struct sockaddr)); bzero(&dstaddr, sizeof(struct sockaddr)); dstaddr.sin_family = AF_INET; dstaddr.sin_addr.s_addr = inet_addr(argv[1]); dstaddr.sin_port = htons(0); sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if(sockfd < 0) error_print("raw socket creation fail."); if(connect(sockfd, (struct sockaddr *)&dstaddr, sizeof(struct sockaddr))!=0 ) error_print("connect for raw socket fail."); pid = getpid() & 0xffff; signal(SIGALRM, sig_alrm); addrlen = sizeof(srcaddr); sig_alrm(SIGALRM); while(1){ readlen = recvfrom(sockfd, recvbuf, sizeof(recvbuf),0,(struct sockaddr *)&srcaddr, &addrlen); if(readlen < 0) error_print("recvfrom() error"); print_ping(recvbuf, readlen); } exit(0); } uint16_t in_cksum(uint16_t *addr, int len){ int nleft = len; uint32_t sum = 0; uint16_t *w = addr; uint16_t 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); } int send_ping(){ int len; struct icmp *icmp; icmp = (struct icmp *) sendbuf; bzero((char *)icmp, sizeof(struct icmp)); icmp->icmp_type = ICMP_ECHO; icmp->icmp_code = 0; icmp->icmp_id = pid; icmp->icmp_seq = seqnum++; memset(icmp->icmp_data, 0xa5, datalen); gettimeofday((struct timeval *)icmp->icmp_data,NULL); len = 8 + datalen; icmp->icmp_cksum = 0; icmp->icmp_cksum = in_cksum((u_short *) icmp, len); sendto(sockfd, sendbuf, len, 0, (struct sockaddr *)&dstaddr, sizeof(dstaddr)); } void sig_alrm(int signo){ send_ping(); alarm(2); return; } void tv_sub(struct timeval *out, struct timeval *in){ if ((out->tv_usec -= in->tv_usec) < 0){ --out->tv_sec; out->tv_sec += 1000000; } out->tv_sec -= in->tv_sec; } print_ping(char *ipdata, int recvsize){ int ip_headlen, icmp_len; double rtt; struct icmp *icmp; struct iphdr *ip; struct timeval *tvsend, tvrecv; char buf[512]; gettimeofday(&tvrecv, NULL); ip = (struct iphdr *) ipdata; ip_headlen = ip->ihl *4; if(ip->protocol != IPPROTO_ICMP){ printf("not ICMP packet.\n"); return; } icmp = (struct icmp *) (ipdata + ip_headlen); icmp_len = recvsize - ip_headlen; tvsend = (struct timeval *)icmp->icmp_data; tv_sub(&tvrecv, tvsend); rtt = tvrecv.tv_sec * 1000.0 + tvrecv.tv_usec / 1000.0; inet_ntop(AF_INET, (void *)&ip->saddr, buf, sizeof(buf)); printf("%d bytes recv from %s: seq = %u, ttl = %d, rtt = %.3fms\n", icmp_len, buf, icmp->icmp_seq, ip->ttl, rtt); } void error_print(char *message){ fputs(message, stderr); fputc('\n', stderr); exit; }
Forums:
음..
recvfrom 의 errno 를 한번 찍어보세요.
몇 가지 사소한 문법 에러가 있고, byte order 도 전혀 신경쓰지 않고 있기는 하지만..
정상적인 환경에서라면 그럭저럭 동작하는 코드입니다.
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
root 권한으로
root 권한으로 실행하니 소스 수정 없이 잘 되네요~
댓글 달기