· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
ICMP

ICMP

°³¿ä


ICMP (Internet Control Message Protocol)

  • ICMP´Â ´ÙÀ½°ú °°ÀÌ IP datagram °ú ÇÔ²² ±¸¼ºµÈ ¸ð½ÀÀ» ¶ç°í ÀÖ´Ù.
    <- IP datagram ->
    IP header ICMP message

  • ICMP message
    0 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
    8bit Type 8bit Code 16bit Checksum
    (Type°ú Code¿¡ µû¶ó¼­ ´Ù¸¥ Çü½ÄÀ» °®´Â ºÎºÐ)

  • ICMP message Type and Code (Âü°í: [http]http://www.iana.org/assignments/icmp-parameters[])
    Type Code Name Reference
    0 0 Echo Reply (RFC792)
    1 - Unassigned (JBP)
    2 - Unassigned (JBP)
    3 Destination Unreachable (RFC792)
    0 Net Unreachable
    1 Host Unreachable
    2 Protocol Unreachable
    3 Port Unreachable
    4 Fragmentation Needed and Don't Fragment was Set
    5 Source Route Failed
    6 Destination Network Unknown
    7 Destination Host Unknown
    8 Source Host Isolated
    9 Communication with Destination Network is Administratively Prohibited
    10 Communication with Destination Host is Administratively Prohibited
    11 Destination Network Unreachable for Type of Service
    12 Destination Host Unreachable for Type of Service
    4 0 Source Quench (RFC792)
    5 Redirect (RFC792)
    0 Redirect Datagram for the Network (or subnet)
    1 Redirect Datagram for the Host
    2 Redirect Datagram for the Type of Service and Network
    3 Redirect Datagram for the Type of Service and Host
    6 Alternate Host Address (JBP)
    0 Alternate Address for Host
    7 - Unassigned (JBP)
    8 0 Echo (RFC792)
    9 0 Router Advertisement (RFC1256)
    10 0 Router Selection (RFC1256)
    11 Time Exceeded (RFC792)
    0 Time to Live exceeded in Transit
    1 Fragment Reassembly Time Exceeded
    12 Parameter Problem (RFC792)
    0 Pointer indicates the error
    1 Missing a Required Option
    2 Bad Length
    13 0 Timestamp (RFC792)
    14 0 Timestamp Reply (RFC792)
    15 0 Information Request (RFC792)
    16 0 Information Reply (RFC792)
    17 0 Address Mask Request (RFC950)
    18 0 Address Mask Reply (RFC950)
    19 - Reserved (for Security) (Solo)
    20-29 - Reserved (for Robustness Experiment) (ZSu)
    30 - Traceroute (RFC1393)
    31 - Datagram Conversion Error (RFC1475)
    32 - Mobile Host Redirect (David Johnson)
    33 - IPv6 Where-Are-You (Bill Simpson)
    34 - IPv6 I-Am-Here (Bill Simpson)
    35 - Mobile Registration Request (Bill Simpson)
    36 - Mobile Registration Reply (Bill Simpson)
    37-255 - Reserved (JBP)
    • Type ¿¡ µû¶ó¼­ ÀϺδ Code¸¦ Ãß°¡ÀûÀ¸·Î ÇÊ¿äÇϰųª ÇÊ¿äÇÏÁö ¾Ê´Ù.

  • ICMP checksum (¾ö¹ÐÈ÷´Â Internet checksum À̶ó°í ºÎ¸£¸ç RFC1071 ¿¡ ±× ±¸Çö¹æ¹ýÀÌ ¸í½ÃµÇ¾î ÀÖ´Ù.)
    #define def_mzping_icmp_optimize (1) /* 0=ÀÌ·ÐÀû±¸Çö, 1=ÃÖÀûÈ­±¸Çö */
    static unsigned int mzping_icmp_checksum(const void *s_data, size_t s_size)
    {
     /*
       s_resultÀÇ º¯¼öÇüÀÌ unsigned int·Î »ç¿ëÇÏ¿´Áö¸¸ ¾ö°ÝÇÏ°Ô´Â 32bit Á¤¼öÇüÀ» »ç¿ëÇØ¾ß ÇÑ´Ù.
       ¸¸¾à unsigned int°¡ 32bit Á¤¼öÇüÀÌ ¾Æ´Ñ °æ¿ì ÀÌ´Â À߸øµÈ ±¸ÇöÀÌ µÊÀ» ÁÖÀÇÇØ¾ß ÇÑ´Ù.
     */
        register unsigned int s_result = 0u;

        while(s_size > ((size_t)1)) {
    #if def_mzping_icmp_optimize == (0)
            s_result += (unsigned int)(ntohs(*((const unsigned short int *)s_data)));
    #else
            s_result += (unsigned int)(*((const unsigned short int *)s_data));
    #endif
            s_data = ((const unsigned short int *)s_data) + ((size_t)1);
            s_size -= (size_t)2;
        }

        if(s_size > ((size_t)0)) {
            s_result += (unsigned int)(*((const unsigned char *)s_data));
        }

    #if def_mzping_icmp_optimize == (0)
        while(s_result > 0xffffu) {
            s_result = (s_result >> 16) + (s_result & 0xffffu);
        }
    #else
        s_result = (s_result >> 16) + (s_result & 0xffffu);
        s_result += s_result >> 16;
    #endif

    #if def_mzping_icmp_optimize == (0)
        return(htons((~s_result) & 0xffffu));
    #else
        return((~s_result) & 0xffffu);
    #endif
    }


  • ICMP echo request and reply
    0 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
    8bit Type (8 or 0) 8bit Code 16bit Checksum
    Identifier Sequence number
    Variable data

  • ICMP address mask request and replay
    0 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
    8bit Type (17 or 18) 8bit Code 16bit Checksum
    Identifier Sequence number
    32bit subnet mask

  • ICMP timestamp request and replay
    0 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
    8bit Type (13 or 14) 8bit Code 16bit Checksum
    Identifier Sequence number
    32bit originate timestamp
    32bit receive timestamp
    32bit transmit timestamp

¿¹Á¦¼Ò½º

/*
 Copyright (C) JAEHYUK CHO
 All rights reserved.

 Author: JaeHyuk Cho <minzkn@minzkn.com>

 Tiny ping example source
*/

/* need for "struct addrinfo" */
#if 1L && (!defined(_POSIX_SOURCE))
# define _POSIX_SOURCE                                               (1L)
#endif

#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>

#define def_mzping_icmp_optimize (1)

#define def_mzping_icmp_min_packet_size (1 + 1 + 2 + 2 + 2) /* type(1) + code(1) + checksum(2) + identifier(2) + sequence_number(2) */

static unsigned int mzping_icmp_checksum(const void *s_data, size_t s_size);
static unsigned int mzping_ts32_us(void);
static int mzping_icmp_v4(int s_socket, const char *s_hostname, const char *s_address_string, struct addrinfo *s_addrinfo, int s_sequence_number, int s_timeout);
static int mzping_icmp_v6(int s_socket, const char *s_hostname, const char *s_address_string, struct addrinfo *s_addrinfo, int s_sequence_number, int s_timeout);

int mzping(const char *s_hostname, int s_count);

int main(int s_argc, char **s_argv);

static unsigned int mzping_icmp_checksum(const void *s_data, size_t s_size)
{
    register unsigned int s_result = 0u;

    while(s_size > ((size_t)1)) {
#if def_mzping_icmp_optimize == (0)
        s_result += (unsigned int)(ntohs(*((const unsigned short int *)s_data)));
#else
        s_result += (unsigned int)(*((const unsigned short int *)s_data));
#endif
        s_data = ((const unsigned short int *)s_data) + ((size_t)1);
        s_size -= (size_t)2;
    }

    if(s_size > ((size_t)0)) {
        s_result += (unsigned int)(*((const unsigned char *)s_data));
    }

#if def_mzping_icmp_optimize == (0)
    while(s_result > 0xffffu) {
        s_result = (s_result >> 16) + (s_result & 0xffffu);
    }
#else
    s_result = (s_result >> 16) + (s_result & 0xffffu);
    s_result += s_result >> 16;
#endif

#if def_mzping_icmp_optimize == (0)
    return(htons((~s_result) & 0xffffu));
#else
    return((~s_result) & 0xffffu);
#endif
}

static unsigned int mzping_ts32_us(void)
{
    struct timeval s_timeval;

    (void)gettimeofday((struct timeval *)(&s_timeval), (void *)0);

    return((s_timeval.tv_sec * 1000000u) + s_timeval.tv_usec);
}

static int mzping_icmp_v4(int s_socket, const char *s_hostname, const char *s_address_string, struct addrinfo *s_addrinfo, int s_sequence_number, int s_timeout)
{
    int s_result, s_check, s_myid;
    unsigned char s_packet[ (20 + 40) + (def_mzping_icmp_min_packet_size + 4) ];
    size_t s_packet_size;
    ssize_t s_send_bytes;
    size_t s_ip_header_size;
    fd_set s_fd_rx;
    struct timeval s_timeval;
    ssize_t s_recv_bytes;
    socklen_t s_socklen_in;
    struct sockaddr_in s_sockaddr_in;

    s_result = (-1);
    s_myid = (int)(getpid() & 0xffff);

    s_packet_size = (size_t)0;
    s_packet[s_packet_size] = 8u; /* ICMP_ECHO */
    s_packet_size += (size_t)1;
    s_packet[s_packet_size] = 0u; /* code */
    s_packet_size += (size_t)1;
    *((unsigned short int *)(&s_packet[s_packet_size])) = 0u; /* checksum */
    s_packet_size += (size_t)2;
    *((unsigned short int *)(&s_packet[s_packet_size])) = htons(s_myid); /* identifier */
    s_packet_size += (size_t)2;
    *((unsigned short int *)(&s_packet[s_packet_size])) = htons(s_sequence_number); /* sequence number */
    s_packet_size += (size_t)2;
#if def_mzping_icmp_optimize == (0)
    *((unsigned int *)(&s_packet[8])) = htonl(mzping_ts32_us()); /* optional: time stamp */
#else
    *((unsigned int *)(&s_packet[8])) = (unsigned int)mzping_ts32_us(); /* optional: time stamp */
#endif
    s_packet_size += (size_t)4;

    /* do checksum */
    *((unsigned short int *)(&s_packet[2])) = mzping_icmp_checksum((const void *)(&s_packet[0]), s_packet_size); /* checksum */

    s_send_bytes = sendto(s_socket, (const void *)(&s_packet[0]), s_packet_size, MSG_NOSIGNAL,
        (struct sockaddr *)s_addrinfo->ai_addr, s_addrinfo->ai_addrlen);
    if(s_send_bytes != ((ssize_t)s_packet_size)) {
        (void)fprintf(stderr, "send: can not send %ld/%lu\n", (long)s_send_bytes, (unsigned long)sizeof(s_packet));
        return(-1);
    }

l_need_echoreply:;
    FD_ZERO(&s_fd_rx);
    FD_SET(s_socket, &s_fd_rx);
    s_timeval.tv_sec = s_timeout / 1000;
    s_timeval.tv_usec = (s_timeout % 1000) * 1000;
    s_check = select(s_socket + 1, (fd_set *)(&s_fd_rx), (fd_set *)0, (fd_set *)0, (struct timeval *)(&s_timeval));
    if(s_check == (-1)) {
        perror("select");
        return(-1);
    }
    if(s_check == 0) {
        (void)fprintf(stderr, "select: timeout\n");
        return(-1);
    }
    if(FD_ISSET(s_socket, &s_fd_rx) == 0) {
        (void)fprintf(stderr, "select: is not set\n");
        return(-1);
    }

    s_socklen_in = (socklen_t)sizeof(s_sockaddr_in);
    s_recv_bytes = recvfrom(s_socket, (void *)(&s_packet[0]), sizeof(s_packet), MSG_NOSIGNAL, (struct sockaddr *)(&s_sockaddr_in), (socklen_t *)(&s_socklen_in));
    if(s_recv_bytes == ((ssize_t)(-1))) {
        perror("recvfrom");
        return(-1);
    }

    s_ip_header_size = ((size_t)((s_packet[0] >> 0) & 0x0fu)) << 2;
    if(s_recv_bytes < (s_ip_header_size + s_packet_size)) {
        /* (void)fprintf(stderr, "too small packet\n"); */
        goto l_need_echoreply;
    }

    if(ntohs(*((unsigned short int *)(&s_packet[s_ip_header_size + 4]))) != s_myid) {
        /* (void)fprintf(stderr, "not my ping\n"); */
        goto l_need_echoreply;
    }

    if(s_packet[s_ip_header_size] == 8u /* ICMP_ECHO */) { /* maybe localhost loopback case */
        goto l_need_echoreply;
    }

    if(s_packet[s_ip_header_size] == 0u /* ICMP_ECHOREPLY */) {
        unsigned int s_trip_time;
        s_result = (int)ntohs(*((unsigned short int *)(&s_packet[s_ip_header_size + 1 + 1 + 2 + 2])));
#if def_mzping_icmp_optimize == (0)
        s_trip_time = mzping_ts32_us() - ntohl(*((unsigned int *)(&s_packet[s_ip_header_size + def_mzping_icmp_min_packet_size])));
#else
        s_trip_time = mzping_ts32_us() - (*((unsigned int *)(&s_packet[s_ip_header_size + def_mzping_icmp_min_packet_size])));
#endif
        (void)fprintf(stdout, "%ld bytes from %s (%s): icmp_seq=%d ttl=%u time=%u.%03u ms;\n",
            (unsigned long)(s_recv_bytes - (s_ip_header_size)),
            s_hostname,
            s_address_string,
            s_result,
            (unsigned int)s_packet[8],
            s_trip_time / 1000u,
            s_trip_time % 1000u);
    }

    return(s_result);
}

static int mzping_icmp_v6(int s_socket, const char *s_hostname, const char *s_address_string, struct addrinfo *s_addrinfo, int s_sequence_number, int s_timeout)
{
    int s_result, s_check, s_myid;
    unsigned char s_packet[ (def_mzping_icmp_min_packet_size + 4) ];
    size_t s_packet_size;
    ssize_t s_send_bytes;

    fd_set s_fd_rx;
    struct timeval s_timeval;
    ssize_t s_recv_bytes;
    socklen_t s_socklen_in;
    struct sockaddr_in s_sockaddr_in;

    s_result = (-1);
    s_myid = (int)(getpid() & 0xffff);

    s_packet_size = (size_t)0;
    s_packet[s_packet_size] = 128u; /* ICMP6_ECHO_REQUEST */
    s_packet_size += (size_t)1;
    s_packet[s_packet_size] = 0u; /* code */
    s_packet_size += (size_t)1;
    *((unsigned short int *)(&s_packet[s_packet_size])) = 0u; /* checksum */
    s_packet_size += (size_t)2;
    *((unsigned short int *)(&s_packet[s_packet_size])) = htons(s_myid); /* identifier */
    s_packet_size += (size_t)2;
    *((unsigned short int *)(&s_packet[s_packet_size])) = htons(s_sequence_number); /* sequence number */
    s_packet_size += (size_t)2;
#if def_mzping_icmp_optimize == (0)
    *((unsigned int *)(&s_packet[8])) = htonl(mzping_ts32_us()); /* optional: time stamp */
#else
    *((unsigned int *)(&s_packet[8])) = (unsigned int)mzping_ts32_us(); /* optional: time stamp */
#endif
    s_packet_size += (size_t)4;

    /* do checksum */
    *((unsigned short int *)(&s_packet[2])) = mzping_icmp_checksum((const void *)(&s_packet[0]), s_packet_size); /* checksum */

    s_send_bytes = sendto(s_socket, (const void *)(&s_packet[0]), s_packet_size, MSG_NOSIGNAL,
        (struct sockaddr *)s_addrinfo->ai_addr, s_addrinfo->ai_addrlen);
    if(s_send_bytes != ((ssize_t)s_packet_size)) {
        (void)fprintf(stderr, "send: can not send %ld/%lu\n", (long)s_send_bytes, (unsigned long)sizeof(s_packet));
        return(-1);
    }

l_need_echoreply:;
    FD_ZERO(&s_fd_rx);
    FD_SET(s_socket, &s_fd_rx);
    s_timeval.tv_sec = s_timeout / 1000;
    s_timeval.tv_usec = (s_timeout % 1000) * 1000;
    s_check = select(s_socket + 1, (fd_set *)(&s_fd_rx), (fd_set *)0, (fd_set *)0, (struct timeval *)(&s_timeval));
    if(s_check == (-1)) {
        perror("select");
        return(-1);
    }
    if(s_check == 0) {
        (void)fprintf(stderr, "select: timeout\n");
        return(-1);
    }
    if(FD_ISSET(s_socket, &s_fd_rx) == 0) {
        (void)fprintf(stderr, "select: is not set\n");
        return(-1);
    }

    s_socklen_in = (socklen_t)sizeof(s_sockaddr_in);
    s_recv_bytes = recvfrom(s_socket, (void *)(&s_packet[0]), sizeof(s_packet), MSG_NOSIGNAL, (struct sockaddr *)(&s_sockaddr_in), (socklen_t *)(&s_socklen_in));
    if(s_recv_bytes == ((ssize_t)(-1))) {
        perror("recvfrom");
        return(-1);
    }

    if(s_recv_bytes < s_packet_size) {
        /* (void)fprintf(stderr, "too small packet\n"); */
        goto l_need_echoreply;
    }

    if(ntohs(*((unsigned short int *)(&s_packet[4]))) != s_myid) {
        /* (void)fprintf(stderr, "not my ping\n"); */
        goto l_need_echoreply;
    }

    if(s_packet[0] == 128u /* ICMP6_ECHO_REQUEST */) {
        goto l_need_echoreply;
    }

    if(s_packet[0] == 129u /* ICMP6_ECHO_REPLY */) {
        unsigned int s_trip_time;
        s_result = (int)ntohs(*((unsigned short int *)(&s_packet[1 + 1 + 2 + 2])));
#if def_mzping_icmp_optimize == (0)
        s_trip_time = mzping_ts32_us() - ntohl(*((unsigned int *)(&s_packet[def_mzping_icmp_min_packet_size])));
#else
        s_trip_time = mzping_ts32_us() - (*((unsigned int *)(&s_packet[def_mzping_icmp_min_packet_size])));
#endif
        (void)fprintf(stdout, "%ld bytes from %s (%s): icmp_seq=%d ttl=%u time=%u.%03u ms;\n",
            (unsigned long)s_recv_bytes,
            s_hostname,
            s_address_string,
            s_result,
            (unsigned int)0u /* TODO: Hops limit here */,
            s_trip_time / 1000u,
            s_trip_time % 1000u);
    }

    return(s_result);
}

int mzping(const char *s_hostname, int s_count)
{
    int s_sequence_number = 0, s_check, s_socket;
    struct addrinfo *s_addrinfo_result;
    struct addrinfo s_addrinfo_hints;
    struct addrinfo *s_addrinfo;
    char s_address_string[ 64 ];

    /* resolv name */
    (void)memset((void *)(&s_addrinfo_hints), 0, sizeof(s_addrinfo_hints));
    s_addrinfo_hints.ai_socktype = SOCK_RAW;
    s_addrinfo_hints.ai_family = AF_UNSPEC;
    s_check = getaddrinfo(s_hostname, (const char *)0, (const struct addrinfo *)(&s_addrinfo_hints), (struct addrinfo **)(&s_addrinfo_result));
    if(s_check != 0) {
        (void)fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(s_check));
        return(-1);
    }

    do {
        s_sequence_number++;

        for(s_addrinfo = s_addrinfo_result;s_addrinfo != ((struct addrinfo *)0);s_addrinfo = s_addrinfo->ai_next) {
            if(s_addrinfo->ai_family == AF_INET) { /* ICMP */
                struct sockaddr_in *s_in;

                s_socket = socket(s_addrinfo->ai_family, SOCK_RAW, IPPROTO_ICMP);
                if(s_socket == (-1)) {
                    perror("socket");
                    continue;
                }

                s_in = (struct sockaddr_in *)s_addrinfo->ai_addr;
                inet_ntop(s_addrinfo->ai_family, (const void *)(&s_in->sin_addr), (char *)(&s_address_string[0]), (socklen_t)sizeof(s_address_string));

                s_check = mzping_icmp_v4(s_socket, s_hostname, (const char *)(&s_address_string[0]), s_addrinfo, s_sequence_number, 20000);
                close(s_socket);
            }
            else if(s_addrinfo->ai_family == AF_INET6) { /* ICMPv6 */
                struct sockaddr_in6 *s_in6;

                s_socket = socket(s_addrinfo->ai_family, SOCK_RAW, IPPROTO_ICMPV6);
                if(s_socket == (-1)) {
                    perror("socket");
                    continue;
                }

                s_in6 = (struct sockaddr_in6 *)s_addrinfo->ai_addr;
                inet_ntop(s_addrinfo->ai_family, (const void *)(&s_in6->sin6_addr), (char *)(&s_address_string[0]), (socklen_t)sizeof(s_address_string));

                s_check = mzping_icmp_v6(s_socket, s_hostname, (const char *)(&s_address_string[0]), s_addrinfo, s_sequence_number, 20000);
                close(s_socket);
            }
        }

        (void)sleep(1);
    }while(s_sequence_number < s_count);

    freeaddrinfo((struct addrinfo *)s_addrinfo_result);

    return(1);

}

int main(int s_argc, char **s_argv)
{
    int s_count = 4;

    (void)fprintf(stdout, "mzping v0.0.2 - Code by JaeHyuk Cho <minzkn@minzkn.com>\n");

    if(s_argc <= 1) {
        (void)fprintf(stdout, "usage: %s <host> <count>\n", (char *)s_argv[0]);

        /* (void)mzping("localhost", s_count); */

        return(EXIT_SUCCESS);
    }

    if(s_argc >= 3) {
        if(sscanf(s_argv[2], "%i", &s_count) != 1) {
            perror("count");
            return(EXIT_FAILURE);
        }
    }

    (void)setuid(getuid());
    (void)mzping(s_argv[1], s_count);

    return(EXIT_SUCCESS);
}

/* vim: set expandtab: */
/* End of source */



ID
Password
Join
Expect a letter from a friend who will ask a favor of you.


sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2015-02-06 16:15:18
Processing time 0.0164 sec