«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

VIDEOCUBE

네트워크명령어 [ ping ] 분석 본문

분석

네트워크명령어 [ ping ] 분석

라떼청년 2017. 11. 23. 00:55

 

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

 

 

 

 

 

 

 

 

 

 

반응형
Comments