OpenVPN 3 Core Library
Loading...
Searching...
No Matches
ping6.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#pragma once
13
14#include <string>
15#include <cstring>
16#include <utility>
17
22#include <openvpn/addr/ipv6.hpp>
24#include <openvpn/ip/icmp6.hpp>
25#include <openvpn/ip/csum.hpp>
26
27using namespace openvpn::numeric_util;
28
29namespace openvpn::Ping6 {
30
31inline static const std::uint16_t *get_addr16(const struct in6_addr *addr)
32{
33#if defined(_WIN32)
34 return addr->u.Word;
35#elif defined(__APPLE__) || defined(__FreeBSD__)
36 return addr->__u6_addr.__u6_addr16;
37#else
38 return addr->s6_addr16;
39#endif
40}
41
42inline std::uint16_t csum_ipv6_pseudo(const struct in6_addr *saddr,
43 const struct in6_addr *daddr,
44 const std::uint32_t len,
45 const std::uint16_t proto,
46 std::uint32_t sum)
47{
48 int carry = 0;
49 std::uint32_t val = 0;
50
51 const std::uint16_t *addr = get_addr16(saddr);
52 for (int i = 0; i < 4; ++i)
53 {
54 val = (std::uint32_t)(addr[i * 2] << 16) + addr[i * 2 + 1];
55 sum += val;
56 carry = (sum < val);
57 sum += carry;
58 }
59
60 addr = get_addr16(daddr);
61 for (int i = 0; i < 4; ++i)
62 {
63 val = (std::uint32_t)(addr[i * 2] << 16) + addr[i * 2 + 1];
64 sum += val;
65 carry = (sum < val);
66 sum += carry;
67 }
68
69 const std::uint32_t ulen = (std::uint32_t)htonl((std::uint32_t)len);
70 sum += ulen;
71 carry = (sum < ulen);
72 sum += carry;
73
74 const std::uint32_t uproto = (std::uint32_t)htonl(proto);
75 sum += uproto;
76 carry = (sum < uproto);
77 sum += carry;
78
79 return IPChecksum::cfold(sum);
80}
81
82// len must be >= sizeof(ICMPv6)
83inline std::uint16_t csum_icmp(const ICMPv6 *icmp, const size_t len)
84{
85 if (len < sizeof(IPv6Header))
86 throw std::range_error("Argument 'len' too small");
87
88 if (len > static_cast<size_t>(std::numeric_limits<uint32_t>::max()))
89 throw std::range_error("Argument 'len' too large");
90
91 auto lenArg = static_cast<uint32_t>(len - sizeof(IPv6Header));
92 return csum_ipv6_pseudo(&icmp->head.saddr,
93 &icmp->head.daddr,
94 lenArg,
96 IPChecksum::compute((std::uint8_t *)icmp + sizeof(IPv6Header), len - sizeof(IPv6Header)));
97}
98
100 const IPv6::Addr &src,
101 const IPv6::Addr &dest,
102 const void *extra_data,
103 const size_t extra_data_size,
104 const uint16_t id,
105 const uint16_t seq_num,
106 const size_t total_size,
107 std::string *log_info)
108{
109 const auto data_size = std::max(extra_data_size, total_size - sizeof(ICMPv6));
110
111 if (log_info)
112 *log_info = "PING6 " + src.to_string() + " -> " + dest.to_string() + " id=" + std::to_string(id) + " seq_num=" + std::to_string(seq_num) + " data_size=" + std::to_string(data_size);
113
114 std::uint8_t *b = buf.write_alloc(sizeof(ICMPv6) + data_size);
115 ICMPv6 *icmp = (ICMPv6 *)b;
116
117 auto payload_len = sizeof(ICMPv6) - sizeof(IPv6Header) + data_size;
118
119 // IP Header
120 icmp->head.version_prio = (6 << 4);
121 icmp->head.flow_lbl[0] = 0;
122 icmp->head.flow_lbl[1] = 0;
123 icmp->head.flow_lbl[2] = 0;
124 icmp->head.payload_len = htons(clamp_to_typerange<uint16_t>(payload_len));
126 icmp->head.hop_limit = 64;
127 icmp->head.saddr = src.to_in6_addr();
128 icmp->head.daddr = dest.to_in6_addr();
129
130 // ICMP header
132 icmp->code = 0;
133 icmp->checksum = 0;
134 icmp->id = ntohs(id);
135 icmp->seq_num = ntohs(seq_num);
136
137 // Data
138 std::uint8_t *data = b + sizeof(ICMPv6);
139 for (size_t i = 0; i < data_size; ++i)
140 data[i] = (std::uint8_t)i;
141
142 // Extra data
143 std::memcpy(data, extra_data, extra_data_size);
144
145 // ICMP checksum
146 icmp->checksum = csum_icmp(icmp, sizeof(ICMPv6) + data_size);
147
148 // std::cout << dump_hex(buf);
149}
150
151// assumes that buf is a validated ECHO_REQUEST
153 std::string *log_info)
154{
155 if (buf.size() < sizeof(ICMPv6))
156 {
157 if (log_info)
158 *log_info = "Invalid ECHO6_REQUEST";
159 return;
160 }
161
162 ICMPv6 *icmp = (ICMPv6 *)buf.c_data();
163 std::swap(icmp->head.saddr, icmp->head.daddr);
164 const std::uint16_t old_type_code = icmp->type_code;
165 icmp->type = ICMPv6::ECHO_REPLY;
167
168 if (log_info)
169 *log_info = "ECHO6_REPLY size=" + std::to_string(buf.size()) + ' ' + IPv6::Addr::from_in6_addr(&icmp->head.saddr).to_string() + " -> " + IPv6::Addr::from_in6_addr(&icmp->head.daddr).to_string();
170}
171} // namespace openvpn::Ping6
const T * c_data() const
Returns a const pointer to the start of the buffer.
Definition buffer.hpp:1194
T * write_alloc(const size_t size)
Allocate space for writing data to the buffer.
Definition buffer.hpp:1587
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1242
static Addr from_in6_addr(const in6_addr *in6)
Definition ipv6.hpp:63
in6_addr to_in6_addr() const
Definition ipv6.hpp:75
std::string to_string() const
Definition ipv6.hpp:131
std::uint32_t compute(const std::uint8_t *buf, size_t len)
Definition csum.hpp:46
std::uint32_t cunfold(const std::uint16_t sum)
Definition csum.hpp:41
std::uint16_t cfold(const std::uint32_t sum)
Definition csum.hpp:31
std::uint32_t diff2(const std::uint16_t old, const std::uint16_t new_, const std::uint32_t oldsum)
Definition csum.hpp:150
std::uint16_t csum_ipv6_pseudo(const struct in6_addr *saddr, const struct in6_addr *daddr, const std::uint32_t len, const std::uint16_t proto, std::uint32_t sum)
Definition ping6.hpp:42
static const std::uint16_t * get_addr16(const struct in6_addr *addr)
Definition ping6.hpp:31
void generate_echo_reply(Buffer &buf, std::string *log_info)
Definition ping6.hpp:152
std::uint16_t csum_icmp(const ICMPv6 *icmp, const size_t len)
Definition ping6.hpp:83
void generate_echo_request(Buffer &buf, const IPv6::Addr &src, const IPv6::Addr &dest, const void *extra_data, const size_t extra_data_size, const uint16_t id, const uint16_t seq_num, const size_t total_size, std::string *log_info)
Definition ping6.hpp:99
std::uint8_t code
Definition icmp6.hpp:41
std::uint16_t checksum
Definition icmp6.hpp:45
std::uint16_t seq_num
Definition icmp6.hpp:51
std::uint8_t type
Definition icmp6.hpp:40
std::uint16_t type_code
Definition icmp6.hpp:43
struct IPv6Header head
Definition icmp6.hpp:35
std::uint16_t id
Definition icmp6.hpp:50
struct in6_addr saddr
Definition ip6.hpp:35
std::uint8_t hop_limit
Definition ip6.hpp:33
std::uint16_t payload_len
Definition ip6.hpp:31
std::uint8_t flow_lbl[3]
Definition ip6.hpp:29
struct in6_addr daddr
Definition ip6.hpp:36
std::uint8_t version_prio
Definition ip6.hpp:27
std::uint8_t nexthdr
Definition ip6.hpp:32