0
0
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:
James Yonan 2018-04-05 18:22:57 -06:00 committed by Lev Stipakov
parent 04de9c4259
commit c93af60a77
3 changed files with 403 additions and 0 deletions

149
openvpn/ip/csum.hpp Normal file
View 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
View 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
View 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();
}
}
}