From d55ff5a0fb21bf2bc5f2bbb4270466e169fded19 Mon Sep 17 00:00:00 2001 From: Arti Zirk Date: Sun, 2 Oct 2022 20:02:58 +0300 Subject: [PATCH] init --- .gitignore | 2 + CMakeLists.txt | 6 +++ README.md | 27 ++++++++++ main.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2220e1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +cmake-* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..540ce4b --- /dev/null +++ b/CMakeLists.txt @@ -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) diff --git a/README.md b/README.md new file mode 100644 index 0000000..5057d94 --- /dev/null +++ b/README.md @@ -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))) +``` diff --git a/main.c b/main.c new file mode 100644 index 0000000..6ca4b5d --- /dev/null +++ b/main.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include + +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; +}