当前位置:   article > 正文

ICMP报文_icmp报文发送实例

icmp报文发送实例

有关ICMP的内容在此不做阐述,仅说下ICMP报文何时会发送(ping除外),ICMP报文中的数据又是什么,如何处理接收到的ICMP报文

何时产生ICMP

当发送一段udp报文到一个不可达的机器,或者ttl耗尽,或者MTU大于在某处路由的mtu,此时均会收到ICMP报文。上述所说均是常见例子,分别对应3,3;11,0;3,4

ICMP数据

携带的正是你发送的UDP数据,会将其原原本本的发送回来,其中会包含IP层的数据
如下是通过wireshark捕获的3,3报文。此时由于客户端的突然关闭,但是路由链路还存在,故主机回收到此udp,然而程序退出,故回复了ICMP报文
在这里插入图片描述
下面分别是udp报文和ICMP报文

// udp数据
1f 40 d1 27 00 1c 2d 20
21 00 00 29 78 7e a0 a2 74 09 b9 7a 00 10 00 00 98 6a 48 23

// ICMP报文
03 03 96 ec 00 00 00 00 	// ICMP头部,以下是数据部分
45 68 00 30 7f 8b 40 00 35 11 2c 08 31 ** ** dc c0 a8 14 55 // IP头部 **是屏蔽了公网IP
1f 40 d1 27 00 1c 2d 20		// udp头部
21 00 00 29 78 7e a0 a2 74 09 b9 7a 00 10 00 00 98 6a 48 23 // udp数据
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
ICMP报文处理

1、设置套接字

int on = 1;
setsockopt(fd, SOL_IP, IP_RECVERR, &on, sizeof(on); // 仅限IPv4
  • 1
  • 2

2、通过poll/epoll返回 POLLERR/EPOLLERR后读取消息

unsigned char vec_buf[4096], ancillary_buf[4096];
struct iovec iov = {vec_buf, sizeof(vec_buf)};
struct sockaddr_in remote;
struct msghdr msg;
ssize_t len;
struct cmsghdr *cmsg;
struct sock_extended_err *e;
struct sockaddr *icmp_addr;
struct sockaddr_in *icmp_sin;

memset(&msg, 0, sizeof(msg));
msg.msg_name = &remote;
msg.msg_namelen = sizeof(remote);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;
msg.msg_control = ancillary_buf;
msg.msg_controllen = sizeof(ancillary_buf);

EINTR_LOOP(len, recvmsg(udpfd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT));
if (len < 0) {
    if (errno != EAGAIN || errno != EWOULDBLOCK) {
        LOGE("recvmsg error. [%d,%s]", errno, strerror(errno));
    }
    break;
}
// 收到几个ICMP就循环几次。可通过man 3 cmsg查看详情
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
    if (cmsg->cmsg_type != IP_RECVERR) {
        LOGD("Unhandled errqueue type: %d\n", cmsg->cmsg_type);
        continue;
    }

    if (cmsg->cmsg_level != SOL_IP) {
        LOGD("Unhandled errqueue level: %d\n", cmsg->cmsg_level);
        continue;
    }

    LOGD("errqueue: IP_RECVERR, SOL_IP, len %zd\n", cmsg->cmsg_len);

    if (remote.sin_family != AF_INET) {
        LOGD("Address family is %d, not AF_INET. Ignoring\n", remote.sin_family);
        continue;
    }

    LOGD("Remote host: %s:%d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));

    e = (struct sock_extended_err *)CMSG_DATA(cmsg);
    if (!e) {
        LOGD("errqueue: sock_extended_err is NULL?\n");
        continue;
    }
    if (e->ee_origin != SO_EE_ORIGIN_ICMP) {
        LOGD("errqueue: Unexpected origin: %d\n", e->ee_origin);
        continue;
    }

    LOGD("    ee_errno:  %d\n", e->ee_errno);
    LOGD("    ee_origin: %d\n", e->ee_origin);
    LOGD("    ee_type:   %d\n", e->ee_type);
    LOGD("    ee_code:   %d\n", e->ee_code);
    LOGD("    ee_info:   %d\n", e->ee_info); // discovered MTU for EMSGSIZE errors
    LOGD("    ee_data:   %d\n", e->ee_data);

    // "Node that caused the error"
    // "Node that generated the error"
    icmp_addr = (struct sockaddr *)SO_EE_OFFENDER(e);
    icmp_sin = (struct sockaddr_in *)icmp_addr;

    if (icmp_addr->sa_family != AF_INET) {
        LOGD("ICMP's address family is %d, not AF_INET?\n", icmp_addr->sa_family);
        continue;
    }

    if (icmp_sin->sin_port != 0) {
        LOGD("ICMP's 'port' is not 0?\n");
        continue;
    }

    LOGD("msg_flags: 0x%x", msg.msg_flags);

    // if (msg.msg_flags & MSG_TRUNC)
    //     fprintf(stderr, " MSG_TRUNC");
    // if (msg.msg_flags & MSG_CTRUNC)
    //     fprintf(stderr, " MSG_CTRUNC");
    // if (msg.msg_flags & MSG_EOR)
    //     fprintf(stderr, " MSG_EOR");
    // if (msg.msg_flags & MSG_OOB)
    //     fprintf(stderr, " MSG_OOB");
    // if (msg.msg_flags & MSG_ERRQUEUE)
    //     fprintf(stderr, " MSG_ERRQUEUE");
    // fprintf(stderr, "\n");

    if (e->ee_type == 3 && e->ee_code == 4) { // utp猜测的MTU过大
        LOGD("ICMP: type 3, code 4: Fragmentation error, discovered MTU %d\n", e->ee_info);
        utp_process_icmp_fragmentation(m_utpContex, vec_buf, len, (struct sockaddr *)&remote, sizeof(remote), e->ee_info);
    } else {
        LOGD("ICMP: type %d, code %d\n", e->ee_type, e->ee_code);
        utp_process_icmp_error(m_utpContex, vec_buf, len, (struct sockaddr *)&remote, sizeof(remote));
    }
}
  • 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
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

在这里插入图片描述
在这里插入图片描述
详看ICMP报文协议可至此

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/819185
推荐阅读
相关标签
  

闽ICP备14008679号