类型 | 说明 | 代码 |
---|---|---|
1 | 目的不可达消息 | 0 没有路由到达目的地 1 与目的地的通信由于管理被禁止,如防火墙禁止 2 超过了源地址的范围 3 地址不可达 4 端口不可达 5 源地址的入口/出口策略失败 6 拒绝到目的地的路由 |
2 | 数据包太大 | 0 |
3 | 超时消息 | 0 传输超时,即 hop-limit 为 0(tracetoute 原理) 1 分片重组超时,重组定时器超时了,还有分片没到达 |
4 | 参数问题消息 | 0 参数错误 1 错误的首部字段 2 不可识别的Next Header类型 3 不可识别的IPv6选项 |
100 | 私有实验用 | x |
101 | 私有实验用 | x |
127 | 扩展保留 | x |
类型 | 说明 | 代码 |
---|---|---|
128 | 回显请求 | 0 |
129 | 回显应答 | 0 |
200 | 私有实验用 | x |
201 | 私有实验用 | x |
255 | 扩展保留 | x |
#ifndef __icmpv6_h_
#define __icmpv6_h_
#define ICMPV6_DEST_UNREACH 1
#define ICMPV6_PKT_TOOBIG 2
#define ICMPV6_TIME_EXCEED 3
#define ICMPV6_PARAMPROB 4
#define ICMPV6_ECHO_REQUEST 128
#define ICMPV6_ECHO_REPLY 129
struct icmp6hdr {
uint8_t type;
uint8_t code;
uint16_t cksum;
union {
uint32_t un_data32[1];
uint16_t un_data16[2];
uint8_t un_data8[4];
struct icmpv6_echo {
uint16_t identifier;
uint16_t sequence;
} u_echo;
struct icmpv6_nd_advt {
uint32_t reserved:5;
uint32_t override:1;
uint32_t solicited:1;
uint32_t router:1;
uint32_t reserved2:24;
} u_nd_advt;
struct icmpv6_nd_ra {
uint8_t hop_limit;
uint8_t reserved:3;
uint8_t router_pref:2;
uint8_t home_agent:1;
uint8_t other:1;
uint8_t managed:1;
uint16_t rt_lifetime;
} u_nd_ra;
} icmp6_dataun;
uint8_t data[0];
#define icmp6_identifier icmp6_dataun.u_echo.identifier
#define icmp6_sequence icmp6_dataun.u_echo.sequence
#define icmp6_pointer icmp6_dataun.un_data32[0]
#define icmp6_mtu icmp6_dataun.un_data32[0]
#define icmp6_unused icmp6_dataun.un_data32[0]
#define icmp6_maxdelay icmp6_dataun.un_data16[0]
#define icmp6_router icmp6_dataun.u_nd_advt.router
#define icmp6_solicited icmp6_dataun.u_nd_advt.solicited
#define icmp6_override icmp6_dataun.u_nd_advt.override
#define icmp6_ndiscreserved icmp6_dataun.u_nd_advt.reserved
#define icmp6_hop_limit icmp6_dataun.u_nd_ra.hop_limit
#define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
#define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref
};
struct icmp6hdr* icmp6_alloc_echo_datagram(unsigned short id, unsigned seq);
struct icmp6hdr* icmp6_alloc_dest_unreach_datagram(
unsigned short code, const void *data, size_t size);
void icmp6_free_datagram(struct icmp6hdr **icmp6);
void icmp6_print_echo(const struct icmp6hdr *icmp6);
int icmp6_socket();
ssize_t icmp6_send(int sockfd, const void *data, size_t size,
const char *daddr, int flags);
ssize_t icmp6_recv(int sockfd, void *buf, size_t size,
const char *daddr, int flags);
void icmp6_close(int sockfd);
#endif /* __icmp6v6_h_ */
#include
#include
#include
#include
#include
#include
#include "icmp6.h"
#include "common.h"
struct icmp6hdr* icmp6_alloc_echo_datagram(unsigned short id, unsigned seq)
{
struct icmp6hdr *icmp6;
icmp6 = (struct icmp6hdr *) calloc(1, sizeof(struct icmp6hdr));
icmp6->type = ICMPV6_ECHO_REQUEST;
icmp6->code = 0;
icmp6->icmp6_identifier = htons(id);
icmp6->icmp6_sequence = htons(seq);
return icmp6;
}
struct icmp6hdr* icmp6_alloc_dest_unreach_datagram(unsigned short code,
const void *data, size_t size)
{
struct icmp6hdr *icmp6;
icmp6 = (struct icmp6hdr *) calloc(1, sizeof(struct icmp6hdr) + size);
icmp6->type = ICMPV6_DEST_UNREACH;
icmp6->code = code;
memcpy(icmp6->data, data, size);
return icmp6;
}
void icmp6_free_datagram(struct icmp6hdr **icmp6)
{
if (NULL != icmp6 && NULL != *icmp6) {
free(*icmp6);
*icmp6 = NULL;
}
}
void icmp6_print_echo(const struct icmp6hdr *icmp6)
{
printf("%02x\n", icmp6->type);
printf("%02x\n", icmp6->code);
printf("%04x\n", htons(icmp6->cksum));
printf("%04x\n", ntohs(icmp6->icmp6_identifier));
printf("%04x\n", ntohs(icmp6->icmp6_sequence));
}
int icmp6_socket()
{
int sockfd, size;
if ((sockfd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1)
handle_error("socket");
// 增大接收缓冲区, 防止 ping 组播地址时溢出
size = 128 * 1024;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)))
handle_error("setsockopt : SO_RCVBUF");
return sockfd;
}
ssize_t icmp6_send(int sockfd, const void *data, size_t size, const char *daddr, int flags)
{
ssize_t count;
struct sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
inet_pton(addr.sin6_family, daddr, &addr.sin6_addr);
if ((count = sendto(sockfd, data, size, flags, (struct sockaddr *)&addr, sizeof(addr))) == -1)
handle_error("sendto");
return count;
}
ssize_t icmp6_recv(int sockfd, void *buf, size_t size,
const char *daddr, int flags)
{
ssize_t count;
struct sockaddr_in6 addr;
socklen_t socklen = sizeof(addr);
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
inet_pton(addr.sin6_family, daddr, &addr.sin6_addr);
if ((count = recvfrom(sockfd, buf, size, flags, (struct sockaddr *)&addr, &socklen)) == -1)
handle_error("recvfrom");
return count;
}
void icmp6_close(int sockfd)
{
if (close(sockfd) == -1)
handle_error("close");
}
#include
#include
#include
#include
#include
#include "ipv6.h"
#include "icmp6.h"
#define BUFFER_SIZE 1500
static void icmp6_ping(const char *saddr, const char *daddr)
{
int sockfd;
struct icmp6hdr *icmp6;
char buffer[BUFFER_SIZE];
sockfd = icmp6_socket();
// 发送消息
icmp6 = icmp6_alloc_echo_datagram(0x0001, 0x0009);
icmp6->cksum = ipv6_cksum(saddr, daddr, IPPROTO_ICMPV6, icmp6, sizeof(struct icmp6hdr));
icmp6_send(sockfd, icmp6, sizeof(struct icmp6hdr), daddr, 0);
icmp6_free_datagram(&icmp6);
// 接收消息
memset(buffer, 0, BUFFER_SIZE);
icmp6_recv(sockfd, buffer, BUFFER_SIZE, daddr, 0);
// 解析消息
icmp6 = (struct icmp6hdr *) buffer;
icmp6_print_echo(icmp6);
icmp6_close(sockfd);
}
int main(int argc, char *argv[])
{
icmp6_ping("fe80::e0c:cff:fe0c:c0c", "fe80::20d:dff:fe0d:d0d");
return 0;
}
192.168.2.100> watch make run
192.168.2.200> sudo tcpdump -nt -XX icmp6
IP6 fe80::e0c:cff:fe0c:c0c > fe80::20d:dff:fe0d:d0d: ICMP6, echo request,seq 9, len 8
0x0000: 000d 0d0d 0d0d 0c0c 0c0c 0c0c 86dd 600a ..............`.
0x0010: 1b04 0008 3a40 fe80 0000 0000 0000 0e0c ....:@..........
0x0020: 0cff fe0c 0c0c fe80 0000 0000 0000 020d ................
0x0030: 0dff fe0d 0d0d 8000 4266 0001 0009 ........Bf....
IP6 fe80::20d:dff:fe0d:d0d > fe80::e0c:cff:fe0c:c0c: ICMP6, echo reply, seq 9, len 8
0x0000: 0c0c 0c0c 0c0c 000d 0d0d 0d0d 86dd 6009 ..............`.
0x0010: 1647 0008 3a40 fe80 0000 0000 0000 020d .G..:@..........
0x0020: 0dff fe0d 0d0d fe80 0000 0000 0000 0e0c ................
0x0030: 0cff fe0c 0c0c 8100 4166 0001 0009 ........Af....
https://tools.ietf.org/html/rfc4443
https://tools.ietf.org/html/rfc2463
https://tools.ietf.org/html/rfc2460