mirror of
https://github.com/OpenVPN/openvpn3.git
synced 2024-09-20 12:12:15 +02:00
Move files from ovpn3-common to openvpn3 repo
Signed-off-by: James Yonan <james@openvpn.net> Signed-off-by: Lev Stipakov <lev@openvpn.net>
This commit is contained in:
parent
04de9c4259
commit
c93af60a77
149
openvpn/ip/csum.hpp
Normal file
149
openvpn/ip/csum.hpp
Normal file
@ -0,0 +1,149 @@
|
||||
// IP checksum based on Linux kernel implementation
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <openvpn/common/socktypes.hpp>
|
||||
#include <openvpn/common/size.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace IPChecksum {
|
||||
|
||||
inline std::uint16_t fold(std::uint32_t sum)
|
||||
{
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
sum += (sum >> 16);
|
||||
return sum;
|
||||
}
|
||||
|
||||
inline std::uint16_t cfold(const std::uint32_t sum)
|
||||
{
|
||||
return ~fold(sum);
|
||||
}
|
||||
|
||||
inline std::uint32_t unfold(const std::uint16_t sum)
|
||||
{
|
||||
return sum;
|
||||
}
|
||||
|
||||
inline std::uint32_t cunfold(const std::uint16_t sum)
|
||||
{
|
||||
return ~unfold(sum);
|
||||
}
|
||||
|
||||
inline std::uint32_t compute(const std::uint8_t *buf, size_t len)
|
||||
{
|
||||
std::uint32_t result = 0;
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
const bool odd = size_t(buf) & 1;
|
||||
if (odd)
|
||||
{
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
result += (*buf << 8);
|
||||
#else
|
||||
result = *buf;
|
||||
#endif
|
||||
len--;
|
||||
buf++;
|
||||
}
|
||||
|
||||
if (len >= 2)
|
||||
{
|
||||
if (size_t(buf) & 2)
|
||||
{
|
||||
result += *(std::uint16_t *)buf;
|
||||
len -= 2;
|
||||
buf += 2;
|
||||
}
|
||||
if (len >= 4)
|
||||
{
|
||||
const uint8_t *end = buf + (len & ~3);
|
||||
std::uint32_t carry = 0;
|
||||
do {
|
||||
std::uint32_t w = *(std::uint32_t *)buf;
|
||||
buf += 4;
|
||||
result += carry;
|
||||
result += w;
|
||||
carry = (w > result);
|
||||
} while (buf < end);
|
||||
result += carry;
|
||||
result = (result & 0xffff) + (result >> 16);
|
||||
}
|
||||
if (len & 2)
|
||||
{
|
||||
result += *(std::uint16_t *)buf;
|
||||
buf += 2;
|
||||
}
|
||||
}
|
||||
if (len & 1)
|
||||
{
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
result += *buf;
|
||||
#else
|
||||
result += (*buf << 8);
|
||||
#endif
|
||||
}
|
||||
result = fold(result);
|
||||
if (odd)
|
||||
result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::uint32_t compute(const void *buf, const size_t len)
|
||||
{
|
||||
return compute((const std::uint8_t *)buf, len);
|
||||
}
|
||||
|
||||
inline std::uint32_t partial(const void *buf, const size_t len, const std::uint32_t sum)
|
||||
{
|
||||
std::uint32_t result = compute(buf, len);
|
||||
|
||||
/* add in old sum, and carry.. */
|
||||
result += sum;
|
||||
if (sum > result)
|
||||
result += 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::uint32_t diff16(const std::uint32_t *old,
|
||||
const std::uint32_t *new_,
|
||||
const std::uint32_t oldsum)
|
||||
{
|
||||
std::uint32_t diff[8] = { ~old[0], ~old[1], ~old[2], ~old[3],
|
||||
new_[0], new_[1], new_[2], new_[3] };
|
||||
return partial(diff, sizeof(diff), oldsum);
|
||||
}
|
||||
|
||||
inline std::uint32_t diff16(const std::uint8_t *old,
|
||||
const std::uint8_t *new_,
|
||||
const std::uint32_t oldsum)
|
||||
{
|
||||
return diff16((const std::uint32_t *)old, (const std::uint32_t *)new_, oldsum);
|
||||
}
|
||||
|
||||
inline std::uint32_t diff4(const std::uint32_t old,
|
||||
const std::uint32_t new_,
|
||||
const std::uint32_t oldsum)
|
||||
{
|
||||
std::uint32_t diff[2] = { ~old, new_ };
|
||||
return partial(diff, sizeof(diff), oldsum);
|
||||
}
|
||||
|
||||
inline std::uint32_t diff2(const std::uint16_t old,
|
||||
const std::uint16_t new_,
|
||||
const std::uint32_t oldsum)
|
||||
{
|
||||
std::uint16_t diff[2] = { std::uint16_t(~old), new_ };
|
||||
return partial(diff, sizeof(diff), oldsum);
|
||||
}
|
||||
|
||||
inline std::uint16_t checksum(const void *data, const size_t size)
|
||||
{
|
||||
return cfold(compute(data, size));
|
||||
}
|
||||
}
|
||||
}
|
97
openvpn/ip/ping4.hpp
Normal file
97
openvpn/ip/ping4.hpp
Normal file
@ -0,0 +1,97 @@
|
||||
// OpenVPN
|
||||
//
|
||||
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||
// All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include <openvpn/common/size.hpp>
|
||||
#include <openvpn/common/socktypes.hpp>
|
||||
#include <openvpn/buffer/buffer.hpp>
|
||||
#include <openvpn/addr/ipv4.hpp>
|
||||
#include <openvpn/ip/ipcommon.hpp>
|
||||
#include <openvpn/ip/icmp4.hpp>
|
||||
#include <openvpn/ip/csum.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace Ping4 {
|
||||
|
||||
inline void generate_echo_request(Buffer& buf,
|
||||
const IPv4::Addr& src,
|
||||
const IPv4::Addr& dest,
|
||||
const void *extra_data,
|
||||
const size_t extra_data_size,
|
||||
const unsigned int id,
|
||||
const unsigned int seq_num,
|
||||
const size_t total_size,
|
||||
std::string* log_info)
|
||||
{
|
||||
const unsigned int data_size = std::max(int(extra_data_size), int(total_size) - int(sizeof(ICMPv4)));
|
||||
|
||||
if (log_info)
|
||||
*log_info = "PING4 " + 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);
|
||||
|
||||
std::uint8_t *b = buf.write_alloc(sizeof(ICMPv4) + data_size);
|
||||
ICMPv4 *icmp = (ICMPv4 *)b;
|
||||
|
||||
// IP Header
|
||||
icmp->head.version_len = IPv4Header::ver_len(4, sizeof(IPv4Header));
|
||||
icmp->head.tos = 0;
|
||||
icmp->head.tot_len = htons(sizeof(ICMPv4) + data_size);
|
||||
icmp->head.id = 0;
|
||||
icmp->head.frag_off = 0;
|
||||
icmp->head.ttl = 64;
|
||||
icmp->head.protocol = IPCommon::ICMPv4;
|
||||
icmp->head.check = 0;
|
||||
icmp->head.saddr = src.to_uint32_net();
|
||||
icmp->head.daddr = dest.to_uint32_net();
|
||||
icmp->head.check = IPChecksum::checksum(b, sizeof(IPv4Header));
|
||||
|
||||
// ICMP header
|
||||
icmp->type = ICMPv4::ECHO_REQUEST;
|
||||
icmp->code = 0;
|
||||
icmp->checksum = 0;
|
||||
icmp->id = ntohs(id);
|
||||
icmp->seq_num = ntohs(seq_num);
|
||||
|
||||
// Data
|
||||
std::uint8_t *data = b + sizeof(ICMPv4);
|
||||
for (size_t i = 0; i < data_size; ++i)
|
||||
data[i] = (std::uint8_t)i;
|
||||
|
||||
// Extra data
|
||||
std::memcpy(data, extra_data, extra_data_size);
|
||||
|
||||
// ICMP checksum
|
||||
icmp->checksum = IPChecksum::checksum(b + sizeof(IPv4Header),
|
||||
sizeof(ICMPv4) - sizeof(IPv4Header) + data_size);
|
||||
|
||||
//std::cout << dump_hex(buf);
|
||||
}
|
||||
|
||||
// assumes that buf is a validated ECHO_REQUEST
|
||||
inline void generate_echo_reply(Buffer& buf,
|
||||
std::string* log_info)
|
||||
{
|
||||
if (buf.size() < sizeof(ICMPv4))
|
||||
{
|
||||
if (log_info)
|
||||
*log_info = "Invalid ECHO4_REQUEST";
|
||||
return;
|
||||
}
|
||||
|
||||
ICMPv4* icmp = (ICMPv4*) buf.c_data();
|
||||
std::swap(icmp->head.saddr, icmp->head.daddr);
|
||||
const std::uint16_t old_type_code = icmp->type_code;
|
||||
icmp->type = ICMPv4::ECHO_REPLY;
|
||||
icmp->checksum = IPChecksum::cfold(IPChecksum::diff2(old_type_code, icmp->type_code, IPChecksum::cunfold(icmp->checksum)));
|
||||
|
||||
if (log_info)
|
||||
*log_info = "ECHO4_REPLY size=" + std::to_string(buf.size()) + ' ' + IPv4::Addr::from_uint32_net(icmp->head.saddr).to_string() + " -> " + IPv4::Addr::from_uint32_net(icmp->head.daddr).to_string();
|
||||
}
|
||||
}
|
||||
}
|
157
openvpn/ip/ping6.hpp
Normal file
157
openvpn/ip/ping6.hpp
Normal file
@ -0,0 +1,157 @@
|
||||
// OpenVPN
|
||||
//
|
||||
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||
// All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include <openvpn/common/size.hpp>
|
||||
#include <openvpn/common/socktypes.hpp>
|
||||
#include <openvpn/buffer/buffer.hpp>
|
||||
#include <openvpn/addr/ipv6.hpp>
|
||||
#include <openvpn/ip/ipcommon.hpp>
|
||||
#include <openvpn/ip/icmp6.hpp>
|
||||
#include <openvpn/ip/csum.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace Ping6 {
|
||||
|
||||
inline 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)
|
||||
{
|
||||
int carry;
|
||||
|
||||
sum += (std::uint32_t)saddr->s6_addr32[0];
|
||||
carry = (sum < (std::uint32_t)saddr->s6_addr32[0]);
|
||||
sum += carry;
|
||||
|
||||
sum += (std::uint32_t)saddr->s6_addr32[1];
|
||||
carry = (sum < (std::uint32_t)saddr->s6_addr32[1]);
|
||||
sum += carry;
|
||||
|
||||
sum += (std::uint32_t)saddr->s6_addr32[2];
|
||||
carry = (sum < (std::uint32_t)saddr->s6_addr32[2]);
|
||||
sum += carry;
|
||||
|
||||
sum += (std::uint32_t)saddr->s6_addr32[3];
|
||||
carry = (sum < (std::uint32_t)saddr->s6_addr32[3]);
|
||||
sum += carry;
|
||||
|
||||
sum += (std::uint32_t)daddr->s6_addr32[0];
|
||||
carry = (sum < (std::uint32_t)daddr->s6_addr32[0]);
|
||||
sum += carry;
|
||||
|
||||
sum += (std::uint32_t)daddr->s6_addr32[1];
|
||||
carry = (sum < (std::uint32_t)daddr->s6_addr32[1]);
|
||||
sum += carry;
|
||||
|
||||
sum += (std::uint32_t)daddr->s6_addr32[2];
|
||||
carry = (sum < (std::uint32_t)daddr->s6_addr32[2]);
|
||||
sum += carry;
|
||||
|
||||
sum += (std::uint32_t)daddr->s6_addr32[3];
|
||||
carry = (sum < (std::uint32_t)daddr->s6_addr32[3]);
|
||||
sum += carry;
|
||||
|
||||
const std::uint32_t ulen = (std::uint32_t)htonl((std::uint32_t) len);
|
||||
sum += ulen;
|
||||
carry = (sum < ulen);
|
||||
sum += carry;
|
||||
|
||||
const std::uint32_t uproto = (std::uint32_t)htonl(proto);
|
||||
sum += uproto;
|
||||
carry = (sum < uproto);
|
||||
sum += carry;
|
||||
|
||||
return IPChecksum::cfold(sum);
|
||||
}
|
||||
|
||||
// len must be >= sizeof(ICMPv6)
|
||||
inline std::uint16_t csum_icmp(const ICMPv6 *icmp, const size_t len)
|
||||
{
|
||||
return csum_ipv6_pseudo(&icmp->head.saddr,
|
||||
&icmp->head.daddr,
|
||||
len - sizeof(IPv6Header),
|
||||
IPCommon::ICMPv6,
|
||||
IPChecksum::compute((std::uint8_t *)icmp + sizeof(IPv6Header), len - sizeof(IPv6Header)));
|
||||
}
|
||||
|
||||
inline 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 unsigned int id,
|
||||
const unsigned int seq_num,
|
||||
const size_t total_size,
|
||||
std::string* log_info)
|
||||
{
|
||||
const unsigned int data_size = std::max(int(extra_data_size), int(total_size) - int(sizeof(ICMPv6)));
|
||||
|
||||
if (log_info)
|
||||
*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);
|
||||
|
||||
std::uint8_t *b = buf.write_alloc(sizeof(ICMPv6) + data_size);
|
||||
ICMPv6 *icmp = (ICMPv6 *)b;
|
||||
|
||||
// IP Header
|
||||
icmp->head.version_prio = (6 << 4);
|
||||
icmp->head.flow_lbl[0] = 0;
|
||||
icmp->head.flow_lbl[1] = 0;
|
||||
icmp->head.flow_lbl[2] = 0;
|
||||
icmp->head.payload_len = htons(sizeof(ICMPv6) - sizeof(IPv6Header) + data_size);
|
||||
icmp->head.nexthdr = IPCommon::ICMPv6;
|
||||
icmp->head.hop_limit = 64;
|
||||
icmp->head.saddr = src.to_in6_addr();
|
||||
icmp->head.daddr = dest.to_in6_addr();
|
||||
|
||||
// ICMP header
|
||||
icmp->type = ICMPv6::ECHO_REQUEST;
|
||||
icmp->code = 0;
|
||||
icmp->checksum = 0;
|
||||
icmp->id = ntohs(id);
|
||||
icmp->seq_num = ntohs(seq_num);
|
||||
|
||||
// Data
|
||||
std::uint8_t *data = b + sizeof(ICMPv6);
|
||||
for (size_t i = 0; i < data_size; ++i)
|
||||
data[i] = (std::uint8_t)i;
|
||||
|
||||
// Extra data
|
||||
std::memcpy(data, extra_data, extra_data_size);
|
||||
|
||||
// ICMP checksum
|
||||
icmp->checksum = csum_icmp(icmp, sizeof(ICMPv6) + data_size);
|
||||
|
||||
//std::cout << dump_hex(buf);
|
||||
}
|
||||
|
||||
// assumes that buf is a validated ECHO_REQUEST
|
||||
inline void generate_echo_reply(Buffer& buf,
|
||||
std::string* log_info)
|
||||
{
|
||||
if (buf.size() < sizeof(ICMPv6))
|
||||
{
|
||||
if (log_info)
|
||||
*log_info = "Invalid ECHO6_REQUEST";
|
||||
return;
|
||||
}
|
||||
|
||||
ICMPv6* icmp = (ICMPv6*) buf.c_data();
|
||||
std::swap(icmp->head.saddr, icmp->head.daddr);
|
||||
const std::uint16_t old_type_code = icmp->type_code;
|
||||
icmp->type = ICMPv6::ECHO_REPLY;
|
||||
icmp->checksum = IPChecksum::cfold(IPChecksum::diff2(old_type_code, icmp->type_code, IPChecksum::cunfold(icmp->checksum)));
|
||||
|
||||
if (log_info)
|
||||
*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();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user