[예전게시판백업]ping.c
os/Linux 2004. 2. 2. 03:28 |간단히 icmp로 장난치다가 ping도 만들어 봤습니다.
완전한 ping구현은 난이도상 공개해봤자 별로 초보분들에게는 도움이 될거 같지 않아서
어설픈 단계까지만 구현하였습니다. (Seq만 검사하는 것)
사실 이거가지고 linux.co.kr에 엄청난 ping을 잠시 걸어봤는데 8%정도 에러가 나네요. 제가 있는 곳에서는...
참고로 원래는 Packet 을 보낸는곳과 받는곳이 따로 비동기적으로 움직여야 할거라
판단되었지만 간단하게 하려고 합친거니까 분석 다 하신분덜은 그렇게 바꿔보세요.
- 주의사항
반드시 root유저만이 이것을 정상적으로 실행가능합니다.
또는 root실행권한을 실행퍼미션에 주어야 합니다.
일반 유저는 원래 ping기능을 사용할수 없나봅니다. 왜냐하면 RAW socket이니까~
- 컴파일 방법
bash# gcc -Wall -Werror -s -O2 -o ping ping.c
============= [ 절취선: ping.c ] =======================
/*
Copyright (c) Information Equipment co.,LTD.
Code by JaeHyuk Cho <mailto: minzkn@infoeq.co.kr >
- Simple is best ! (Sequence number check ping)
2003.1.20
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
static int __MZ_ICMP_CheckSum__(void *s_Buffer, int s_Size)
{
int s_Return = 0;
if(s_Size & 1)s_Return += (int)((*(unsigned char *)s_Buffer)++);
s_Size >>= 1;
while(s_Size-- > 0)s_Return += (int)(*(((unsigned short *)s_Buffer)++));
if(s_Size == 1)s_Return += (int)(*(unsigned char *)(s_Buffer));
s_Return = (s_Return >> 16) + (s_Return & 0xFFFF);
s_Return += (s_Return >> 16);
return((~s_Return) & 0xffff);
}
int CORE_Ping(const char *s_HostName, unsigned int s_Index, unsigned int s_TimeOut)
{
int s_Return = (-1), s_Socket, s_SendBytes, s_RecvBytes, s_IsSelect;
struct protoent *s_ProtoEntry;
struct hostent *s_HostEntry;
struct sockaddr_in s_PingAddress, s_FromAddress;
socklen_t s_FromAddressLength;
struct icmp *s_ICMP;
struct iphdr *s_IPHeader;
unsigned char s_ICMP_Packet[ 60 + 76 + 56 ]; /* Packet assembly */
fd_set s_FD;
struct timeval s_TimeVal;
s_HostEntry = gethostbyname(s_HostName);
if(s_HostEntry)
{
memset((void *)(&s_PingAddress), 0, sizeof(s_PingAddress));
s_PingAddress.sin_family = AF_INET;
memcpy((void *)(&s_PingAddress.sin_addr), s_HostEntry->h_addr, sizeof(s_PingAddress.sin_addr));
memset((void *)(&s_ICMP_Packet[0]), 0, sizeof(s_ICMP_Packet));
s_ICMP = (struct icmp *)(&s_ICMP_Packet[0]);
s_ICMP->icmp_type = ICMP_ECHO;
s_ICMP->icmp_seq = s_Index;
s_ICMP->icmp_id = getpid() & 0xffff;
gettimeofday((struct timeval *)(&s_ICMP_Packet[8]), (void *)0);
s_ICMP->icmp_cksum = __MZ_ICMP_CheckSum__((void *)(&s_ICMP_Packet[0]), sizeof(s_ICMP_Packet));
s_ProtoEntry = getprotobyname("icmp");
s_Socket = socket(AF_INET, SOCK_RAW, s_ProtoEntry ? s_ProtoEntry->p_proto : 1);
setuid(getuid()); /* Who are you ? */
if(s_Socket >= 0)
{
s_SendBytes = sendto(s_Socket, (void *)(&s_ICMP_Packet[0]), sizeof(s_ICMP_Packet),
MSG_NOSIGNAL, /* Ignore broken pipe */
(struct sockaddr *)(&s_PingAddress), sizeof(s_PingAddress));
if(s_SendBytes == sizeof(s_ICMP_Packet))
{
memset((void *)(&s_FromAddress), 0, sizeof(s_FromAddress));
s_FromAddressLength = sizeof(s_FromAddress);
memset((void *)(&s_ICMP_Packet[0]), 0, sizeof(s_ICMP_Packet));
s_TimeVal.tv_sec = s_TimeOut, s_TimeVal.tv_usec = 0;
FD_ZERO(&s_FD); FD_SET(s_Socket, &s_FD);
s_IsSelect = select(s_Socket + 1, &s_FD, (fd_set *)0, (fd_set *)0, &s_TimeVal);
if(s_IsSelect > 0 && FD_ISSET(s_Socket, &s_FD) != 0)
{
s_RecvBytes = recvfrom(s_Socket, (void *)(&s_ICMP_Packet[0]), sizeof(s_ICMP_Packet),
MSG_NOSIGNAL, /* Ignore broken pipe */
(struct sockaddr *)(&s_FromAddress), (socklen_t *)(&s_FromAddressLength));
}
else s_RecvBytes = 0;
if(s_RecvBytes >= 76)
{
s_IPHeader = (struct iphdr *)(&s_ICMP_Packet[0]);
s_ICMP = (struct icmp *)(&s_ICMP_Packet[ s_IPHeader->ihl << 2 ]);
if(s_ICMP->icmp_type == ICMP_ECHOREPLY)
{
/* TODO:
Packet check sum need
Time compute
Duplicate packet check
Send packet & Recv packet -> Two thread or alarm
*/
s_Return = (int)s_ICMP->icmp_seq;
}
}
}
close(s_Socket);
}
}
return(s_Return);
}
int main(int s_Argc, char *s_Argv[])
{
int s_Return, s_Check, s_Index, s_ErrorCount, s_IsError, s_Count;
fprintf(stdout, "MZ_Ping v0.0.1 - Code by JaeHyuk Cho < minzkn@infoeq.co.kr >\n\n");
if(s_Argc > 1)
{
s_ErrorCount = 0, s_Index = 1;
if(s_Argc > 2)sscanf(s_Argv[2], "%i", &s_Count);
else s_Count = 8;
do
{
s_Check = CORE_Ping(s_Argv[1], s_Index /* Request sequence number */, 4u /* Timeout 4 second */);
if(s_Check != s_Index)s_ErrorCount++, s_IsError = 1;
else s_IsError = 0;
fprintf(stdout, "Ping[%s]: %s (Seq %d->%d) - ERR=%d\n",
s_Argv[1], s_IsError == 0 ? "OK" : "LOSS", s_Index, s_Check, s_ErrorCount);
usleep(10000);
}while(s_Index++ < s_Count);
fprintf(stdout, "Total %d%% loss.\n", s_ErrorCount * 100 / s_Index);
s_Return = s_ErrorCount;
}
else
{
fprintf(stdout, "usage: ping <host> <count>\n");
s_Return = 0;
}
return(s_Return);
}
/* End of source */
완전한 ping구현은 난이도상 공개해봤자 별로 초보분들에게는 도움이 될거 같지 않아서
어설픈 단계까지만 구현하였습니다. (Seq만 검사하는 것)
사실 이거가지고 linux.co.kr에 엄청난 ping을 잠시 걸어봤는데 8%정도 에러가 나네요. 제가 있는 곳에서는...
참고로 원래는 Packet 을 보낸는곳과 받는곳이 따로 비동기적으로 움직여야 할거라
판단되었지만 간단하게 하려고 합친거니까 분석 다 하신분덜은 그렇게 바꿔보세요.
- 주의사항
반드시 root유저만이 이것을 정상적으로 실행가능합니다.
또는 root실행권한을 실행퍼미션에 주어야 합니다.
일반 유저는 원래 ping기능을 사용할수 없나봅니다. 왜냐하면 RAW socket이니까~
- 컴파일 방법
bash# gcc -Wall -Werror -s -O2 -o ping ping.c
============= [ 절취선: ping.c ] =======================
/*
Copyright (c) Information Equipment co.,LTD.
Code by JaeHyuk Cho <mailto: minzkn@infoeq.co.kr >
- Simple is best ! (Sequence number check ping)
2003.1.20
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
static int __MZ_ICMP_CheckSum__(void *s_Buffer, int s_Size)
{
int s_Return = 0;
if(s_Size & 1)s_Return += (int)((*(unsigned char *)s_Buffer)++);
s_Size >>= 1;
while(s_Size-- > 0)s_Return += (int)(*(((unsigned short *)s_Buffer)++));
if(s_Size == 1)s_Return += (int)(*(unsigned char *)(s_Buffer));
s_Return = (s_Return >> 16) + (s_Return & 0xFFFF);
s_Return += (s_Return >> 16);
return((~s_Return) & 0xffff);
}
int CORE_Ping(const char *s_HostName, unsigned int s_Index, unsigned int s_TimeOut)
{
int s_Return = (-1), s_Socket, s_SendBytes, s_RecvBytes, s_IsSelect;
struct protoent *s_ProtoEntry;
struct hostent *s_HostEntry;
struct sockaddr_in s_PingAddress, s_FromAddress;
socklen_t s_FromAddressLength;
struct icmp *s_ICMP;
struct iphdr *s_IPHeader;
unsigned char s_ICMP_Packet[ 60 + 76 + 56 ]; /* Packet assembly */
fd_set s_FD;
struct timeval s_TimeVal;
s_HostEntry = gethostbyname(s_HostName);
if(s_HostEntry)
{
memset((void *)(&s_PingAddress), 0, sizeof(s_PingAddress));
s_PingAddress.sin_family = AF_INET;
memcpy((void *)(&s_PingAddress.sin_addr), s_HostEntry->h_addr, sizeof(s_PingAddress.sin_addr));
memset((void *)(&s_ICMP_Packet[0]), 0, sizeof(s_ICMP_Packet));
s_ICMP = (struct icmp *)(&s_ICMP_Packet[0]);
s_ICMP->icmp_type = ICMP_ECHO;
s_ICMP->icmp_seq = s_Index;
s_ICMP->icmp_id = getpid() & 0xffff;
gettimeofday((struct timeval *)(&s_ICMP_Packet[8]), (void *)0);
s_ICMP->icmp_cksum = __MZ_ICMP_CheckSum__((void *)(&s_ICMP_Packet[0]), sizeof(s_ICMP_Packet));
s_ProtoEntry = getprotobyname("icmp");
s_Socket = socket(AF_INET, SOCK_RAW, s_ProtoEntry ? s_ProtoEntry->p_proto : 1);
setuid(getuid()); /* Who are you ? */
if(s_Socket >= 0)
{
s_SendBytes = sendto(s_Socket, (void *)(&s_ICMP_Packet[0]), sizeof(s_ICMP_Packet),
MSG_NOSIGNAL, /* Ignore broken pipe */
(struct sockaddr *)(&s_PingAddress), sizeof(s_PingAddress));
if(s_SendBytes == sizeof(s_ICMP_Packet))
{
memset((void *)(&s_FromAddress), 0, sizeof(s_FromAddress));
s_FromAddressLength = sizeof(s_FromAddress);
memset((void *)(&s_ICMP_Packet[0]), 0, sizeof(s_ICMP_Packet));
s_TimeVal.tv_sec = s_TimeOut, s_TimeVal.tv_usec = 0;
FD_ZERO(&s_FD); FD_SET(s_Socket, &s_FD);
s_IsSelect = select(s_Socket + 1, &s_FD, (fd_set *)0, (fd_set *)0, &s_TimeVal);
if(s_IsSelect > 0 && FD_ISSET(s_Socket, &s_FD) != 0)
{
s_RecvBytes = recvfrom(s_Socket, (void *)(&s_ICMP_Packet[0]), sizeof(s_ICMP_Packet),
MSG_NOSIGNAL, /* Ignore broken pipe */
(struct sockaddr *)(&s_FromAddress), (socklen_t *)(&s_FromAddressLength));
}
else s_RecvBytes = 0;
if(s_RecvBytes >= 76)
{
s_IPHeader = (struct iphdr *)(&s_ICMP_Packet[0]);
s_ICMP = (struct icmp *)(&s_ICMP_Packet[ s_IPHeader->ihl << 2 ]);
if(s_ICMP->icmp_type == ICMP_ECHOREPLY)
{
/* TODO:
Packet check sum need
Time compute
Duplicate packet check
Send packet & Recv packet -> Two thread or alarm
*/
s_Return = (int)s_ICMP->icmp_seq;
}
}
}
close(s_Socket);
}
}
return(s_Return);
}
int main(int s_Argc, char *s_Argv[])
{
int s_Return, s_Check, s_Index, s_ErrorCount, s_IsError, s_Count;
fprintf(stdout, "MZ_Ping v0.0.1 - Code by JaeHyuk Cho < minzkn@infoeq.co.kr >\n\n");
if(s_Argc > 1)
{
s_ErrorCount = 0, s_Index = 1;
if(s_Argc > 2)sscanf(s_Argv[2], "%i", &s_Count);
else s_Count = 8;
do
{
s_Check = CORE_Ping(s_Argv[1], s_Index /* Request sequence number */, 4u /* Timeout 4 second */);
if(s_Check != s_Index)s_ErrorCount++, s_IsError = 1;
else s_IsError = 0;
fprintf(stdout, "Ping[%s]: %s (Seq %d->%d) - ERR=%d\n",
s_Argv[1], s_IsError == 0 ? "OK" : "LOSS", s_Index, s_Check, s_ErrorCount);
usleep(10000);
}while(s_Index++ < s_Count);
fprintf(stdout, "Total %d%% loss.\n", s_ErrorCount * 100 / s_Index);
s_Return = s_ErrorCount;
}
else
{
fprintf(stdout, "usage: ping <host> <count>\n");
s_Return = 0;
}
return(s_Return);
}
/* End of source */