VIDEOCUBE
네트워크명령어 [ ping ] 분석 본문
GitLab 활용하기 편에서 ping 소스를 업로드 해놓았다.
새로 Branches 를 생성하자
개발서버에 접속하자
root@linux-01:/data/source/ping> git fetch
Username for 'http://git.videocube.lab': pluto90k
Password for 'http://pluto90k@git.videocube.lab':
http://git.videocube.lab/network/ping URL에서
* [새로운 브랜치] develop -> origin/develop
develop 모드로 전환한 후
root@linux-01:/data/source/ping> git checkout develop
develop 브랜치가 리모트의 develop 브랜치를 (origin에서) 따라가도록 설정되었습니다.
새로 만든 'develop' 브랜치로 전환합니다
root@linux-01:/data/source/ping> git branch -a
* develop
master
remotes/origin/develop
remotes/origin/master
vi src/ping.c
//icmp 지원 여부를 확인한다
if (!(proto = getprotobyname("icmp"))) {
(void)fprintf(stderr, "ping: unknown protocol icmp.\n");
exit(2);
}
//소켓을 생성한다
if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
if (errno==EPERM) {
fprintf(stderr, "ping: ping must run as root\n");
}
else perror("ping: socket");
exit(2);
}
//옵션 세팅
while ((ch = getopt(argc, argv, "I:LRc:dfh:i:l:np:qrs:t:v")) != EOF)
{.....[하위 기술함 ]..}
if(inet_aton(target, &to->sin_addr))
{//IP
printf("IP : %s\n", target);
hostname = target;
}
else
{//HOST NAME ==> FIND IP
printf("HostByName : %s\n", target);
hp = gethostbyname(target);
if (!hp) {
(void)fprintf(stderr,
"ping: unknown host %s\n", target);
exit(2);
}
to->sin_family = hp->h_addrtype;
if (hp->h_length > (int)sizeof(to->sin_addr)) {
hp->h_length = sizeof(to->sin_addr);
}
memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
(void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
hostname = hnamebuf;
printf("IP : %s\n", inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr));
}
//소켓 옵션
setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&hold, sizeof(hold));
(void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold));
//실제 PING 을 발송하는 부분 preload [ l옵션으로 미리 몇개의 ping 을 날린 후 1초마다 인터벌로 호출하도록 한다. ]
while (preload--) /* fire off them quickies */
pinger();
//F 옵션이 있을 경우 처리 [ 패킷이 목적 디바이스에 완전히 전달되도록 보장 ]
if ((options & F_FLOOD) == 0)
catcher(0); /* start things going */
for (;;) {
struct sockaddr_in from;
register int cc;
size_t fromlen;
if (options & F_FLOOD) {
//실제 PING 을 발송하는 부분
pinger();
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
fdmask = 1 << s;
//입출력 다중화
if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL, (fd_set *)NULL, &timeout) < 1)
continue;
}
fromlen = sizeof(from);
//응답
if ((cc = recvfrom(s, (char *)packet, packlen, 0, (struct sockaddr *)&from, &fromlen)) < 0) {
if (errno == EINTR)
continue;
perror("ping: recvfrom");
continue;
}
pr_pack((char *)packet, cc, &from);
if (npackets && nreceived >= npackets)
break;
}
finish(0);
옵션을 살펴보자
switch(ch) {
case 'c':
전송(및 수신)되는 Count 변수에서 표시하는 반향 요청의 수를 지정합니다.
npackets = atoi(optarg);
if (npackets <= 0) {
(void)fprintf(stderr,
"ping: bad number of packets to transmit.\n");
exit(2);
}
break;
case 'd':
소켓 레벨 디버깅을 시작합니다.
options |= F_SO_DEBUG;
break;
case 'f':
//Flood ping
전송된 모든 ECHO_REQUEST에 대해 .(마침표)가 인쇄되는 한편, 수신된 모든 ECHO_REPLY에 대해 백스페이스가 인쇄됩니다. 이는 삭제 중인 패킷의 수에 대한 신속한 표시를 제공합니다. 루트 사용자만 이 옵션을 사용할 수 있습니다.
-i 옵션과 같이 사용안됨
if (!am_i_root) {
(void)fprintf(stderr,
"ping: %s\n", strerror(EPERM));
exit(2);
}
options |= F_FLOOD;
setbuf(stdout, NULL);
break;
case 'i':
각 패킷의 전송 간에 Wait 변수에서 지정하는 시간(초 단위) 동안 대기
-f 옵션과 같이 사용안됨
interval = atoi(optarg);
if (interval <= 0) {
(void)fprintf(stderr,
"ping: bad timing interval.\n");
exit(2);
}
options |= F_INTERVAL;
break;
case 'l':
일반 작동 모드에 진입하기 전에 가급적 빨리 Preload 변수에서 지정하는 수의 패킷을 전송합니다
if (!am_i_root) {
(void)fprintf(stderr,
"ping: %s\n", strerror(EPERM));
exit(2);
}
preload = atoi(optarg);
if (preload < 0) {
(void)fprintf(stderr,
"ping: bad preload value.\n");
exit(2);
}
break;
case 'n': IP 만 보임
숫자 출력만 지정합니다. 호스트 주소에 대한 기호 이름의 검사를 시도하지 않습니다 |
options |= F_NUMERIC;
break;
case 'p':
전송한 패킷을 채우기 위한 최대 16 'pad' 바이트를 지정합니다.
이는 네트워크의 데이터 관련 문제를 진단하는 데 유용합니다. 예를 들어, -p ff는 패킷을 모두 1로 채움
options |= F_PINGFILLED;
fill(datap, optarg);
break;
case 'q':
완료된 행만 출력합니다
options |= F_QUIET;
break;
case 'R':
레코드 라우트 옵션을 지정합니다. -R 플래그는 ECHO_REQUEST 패킷의 RECORD_ROUTE 옵션을 포함하며, 리턴된 패킷의 라우트 버퍼를 표시합니다.
주: IP 헤더는 9개의 해당 라우트를 수용할 만한 정도의 크기입니다. 또한 많은 호스트와 게이트웨이는 이 옵션을 무시합니다.
options |= F_RROUTE;
break;
case 'r':
라우팅 테이블을 무시하고 접속된 네트워크에 있는 호스트에 직접 전송합니다. Host가 직접 연결된 네트워크에 없으면 ping 명령이 오류 메시지를 생성합니다. 이 옵션은 더 이상 해당 라우트가 없는 인터페이스를 통해 로컬 호스트의 ping을 실행하는 데 사용될 수 있습니다.
options |= F_SO_DONTROUTE;
break;
case 's':
전송될 데이터 바이트의 수를 지정합니다. 디폴트는 56이며, 8바이트의 ICMP 헤더 데이터와 결합되는 경우에 이는 64 ICMP 데이터 바이트로 변환됩니다.
datalen = atoi(optarg);
if (datalen > MAXPACKET) {
(void)fprintf(stderr,
"ping: packet size too large.\n");
exit(2);
}
if (datalen <= 0) {
(void)fprintf(stderr,
"ping: illegal packet size.\n");
exit(2);
}
break;
case 'v':
반향 응답과 함께 수신된 ICMP 패킷을 나열하는 상세 출력을 요청합니다. [ 되는지 확인이 안됨 ] |
options |= F_VERBOSE;
break;
case 'L':
멀티캐스트 Ping에 대해 로컬 루프백을 사용하지 않습니다.
moptions |= MULTICAST_NOLOOP;
loop = 0;
break;
case 't':
멀티캐스트 패킷의 활동 시간이 ttl초임을 지정합니다.
moptions |= MULTICAST_TTL;
i = atoi(optarg);
if (i < 0 || i > 255) {
printf("ttl %u out of range\n", i);
exit(2);
}
ttl = i;
break;
case 'I':
지정하는 인터페이스가 송신 IPv4 멀티캐스트에 사용됨을 지정합니다
moptions |= MULTICAST_IF;
{
int i1, i2, i3, i4;
char junk;
if (sscanf(optarg, "%u.%u.%u.%u%c",
&i1, &i2, &i3, &i4, &junk) != 4) {
printf("bad interface address '%s'\n",
optarg);
exit(2);
}
ifaddr.s_addr = (i1<<24)|(i2<<16)|(i3<<8)|i4;
ifaddr.s_addr = htonl(ifaddr.s_addr);
}
break;
default:
usage();
}
ICMP 구조
Type : 8bit
Code : 8bit
CheckSum : 16bit
Optional Data : n bit
------------------------------------------------------
register struct icmphdr *icp;
icp = (struct icmphdr *)outpack;
icp->icmp_type = ICMP_ECHO;
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_seq = ntransmitted++;
icp->icmp_id = ident; /* ID */
참고 문서 : https://www.ibm.com/support/knowledgecenter/ko/ssw_aix_71/com.ibm.aix.cmds4/ping.htm
'분석' 카테고리의 다른 글
[MPEG TS] 구조 분석 (0) | 2018.01.02 |
---|---|
HLS ( Http Live Streaming ) 분석하기 (4) | 2017.12.12 |
[MP4] 파일 미디어 샘플과 시간 정보를 구하는 방법 (0) | 2017.11.29 |
[MP4] 분석 하기 | MPEG-4 파트 14 | MP4Box 설치 (5) | 2017.11.26 |
네트워크 명령어 [ ping ] (0) | 2017.11.20 |