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 권한으로 실행하니 소스 수정 없이 잘 되네요~
댓글 달기