This commit is contained in:
Arti Zirk 2022-10-02 20:02:58 +03:00
commit d55ff5a0fb
4 changed files with 175 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea
cmake-*

6
CMakeLists.txt Normal file
View File

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.24)
project(icmpv6_echo C)
set(CMAKE_C_STANDARD 23)
add_executable(icmpv6_echo main.c)

27
README.md Normal file
View File

@ -0,0 +1,27 @@
# Build IPv6 ICMP ECHO packet with Ethernet headers
* https://en.wikipedia.org/wiki/Ethernet_frame
* https://en.wikipedia.org/wiki/IPv6_packet
* https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol_for_IPv6
* https://www.pdbuchan.com/rawsock/icmp6_cooked.c
* https://stackoverflow.com/a/14937171
* https://github.com/secdev/scapy/blob/a1f999fb1721a64415af75d575cabde19625a6f5/scapy/utils.py#L493-L501
* https://github.com/secdev/scapy/blob/master/scapy/layers/inet6.py#L608-L624
## Scapy code samples
Writen in `scapy` shell
```python
# import hex as packet
e = Ether(bytes.fromhex('fc de ad be ef 05 fc de ad be ef 56 86 dd 60 00 00 00 00 08 3a 02 fe 80 00 00 00 00 00 00 00 00 00 00 00 00 00 01 fe 80 00 00 00 00 00 00 50 5d 18 fb 5e 52 ec c0 81 00 4e cd 00 00 00 00 ef be ad de'))
e.show()
# Write packet as pcap to open in Wireshark
wrpcap("test.pcap", e)
# Calculate icmpv6 checksum
i = e[IPv6][ICMPv6EchoReply]
i.cksum = 0
r = raw(i)
print(hex(in6_chksum(socket.IPPROTO_ICMPV6, e[IPv6], r)))
```

140
main.c Normal file
View File

@ -0,0 +1,140 @@
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <netinet/in.h>
struct ethernet_header {
uint8_t dest[6];
uint8_t src[6];
uint16_t ethertype;
} __attribute__((packed));
struct ipv6_header {
uint32_t vtf;
/*uint32_t version :4;
uint32_t traffic_class :8;
uint32_t flow_label :20;*/
uint16_t len;
uint8_t next_header;
uint8_t hop_limit;
uint8_t src[16];
uint8_t dest[16];
} __attribute__((packed));
struct icmpv6_header {
uint8_t type;
uint8_t code;
uint16_t checksum;
} __attribute__((packed));
struct ipv6_pseudo {
uint8_t src[16];
uint8_t dest[16];
uint32_t len;
uint32_t zeros :24;
uint32_t next_header :8;
} __attribute__((packed));
struct icmpv6_echo {
uint16_t identifier;
uint16_t sequence;
} __attribute__((packed));
struct packet {
struct ethernet_header eth;
struct ipv6_header ip6;
struct icmpv6_header icmp;
struct icmpv6_echo echo;
uint32_t ethernet_frame_check;
} __attribute__((packed));
uint16_t checksum (uint16_t *addr, size_t bytes) {
unsigned int i;
uint16_t *p = addr;
uint32_t sum = 0;
/* Sum */
for (i=bytes; i > 1; i -= 2)
sum += *p++;
/* If uneven length */
if (i > 0)
sum += (uint16_t) *((unsigned char *) (p));
/* Carry */
while ((sum & 0xFFFF0000) != 0)
sum = (sum >> 16) + (sum & 0xFFFF);
return ~((uint16_t) sum);
}
uint16_t calc_icmpv6_checksum(struct ipv6_header *ip6_header, void *data, size_t len) {
uint8_t buf[1500] = {};
struct ipv6_pseudo pseudo = {};
memcpy(pseudo.src, ip6_header->src, sizeof(ip6_header->src));
memcpy(pseudo.dest, ip6_header->dest, sizeof(ip6_header->dest));
pseudo.next_header = ip6_header->next_header;
pseudo.len = htonl(len);
memcpy(buf, &pseudo, sizeof(pseudo));
memcpy(buf + sizeof(pseudo), data, len);
return checksum(&buf, sizeof(pseudo) + len);
}
int main() {
struct packet pkt;
uint8_t eth_dest[] = {0xfc, 0xde, 0xad, 0xbe, 0xef, 0x05};
uint8_t eth_src[] = {0xfc, 0xde, 0xad, 0xbe, 0xef, 0x56};
memcpy(pkt.eth.dest, eth_dest, sizeof(pkt.eth.dest));
memcpy(pkt.eth.src, eth_src, sizeof(pkt.eth.src));
pkt.eth.ethertype = 0xdd86; // ipv6
pkt.ip6.vtf = htonl ((6 << 28) | (0 << 20) | 0);
/*pkt.ip6.version = 6;
pkt.ip6.traffic_class = 0;
pkt.ip6.flow_label = 0;*/
pkt.ip6.len = htons(sizeof(struct icmpv6_header) + sizeof(struct icmpv6_echo));
pkt.ip6.next_header = 0x3a; // ipv6-icmp
pkt.ip6.hop_limit = 2;
uint8_t ipv6_src[] = {
0xfe, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01
};
uint8_t ipv6_dest[] = {
0xfe, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x50, 0x5d, 0x18, 0xfb,
0x5e, 0x52, 0xec, 0xc0,
};
memcpy(pkt.ip6.src, ipv6_src, sizeof(pkt.ip6.src));
memcpy(pkt.ip6.dest, ipv6_dest, sizeof(pkt.ip6.dest));
pkt.icmp.type = 129; // icmp reply
pkt.icmp.checksum = 0;
pkt.echo.identifier = 0;
pkt.echo.sequence = 0;
pkt.icmp.checksum = calc_icmpv6_checksum(&pkt.ip6, &pkt.icmp, sizeof(struct icmpv6_header) + sizeof(struct icmpv6_echo));
pkt.ethernet_frame_check = 0xdeadbeef;
printf("sizeof(pkt) = %lu, pointer %p\n", sizeof(pkt), &pkt);
printf("checksum %#x\n", pkt.icmp.checksum);
int i;
for (i=0; i < sizeof(pkt); i++) {
printf("%02x ", *(((uint8_t *)&pkt) + i));
}
printf("\n%d", i);
return 0;
}