Merge commit '86cc97e55fe346502462284d2e636a2b3708163e' as 'Sources/OpenVPN3'

This commit is contained in:
Sergey Abramchuk
2020-02-24 14:43:11 +03:00
655 changed files with 146468 additions and 0 deletions
+171
View File
@@ -0,0 +1,171 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2018 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// IP checksum based on Linux kernel implementation
#pragma once
#include <cstdint>
#include <openvpn/common/endian.hpp>
#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 OPENVPN_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 OPENVPN_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));
}
}
}
+90
View File
@@ -0,0 +1,90 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef OPENVPN_IP_DHCP_H
#define OPENVPN_IP_DHCP_H
#include <openvpn/ip/eth.hpp>
#include <openvpn/ip/ip4.hpp>
#include <openvpn/ip/udp.hpp>
#pragma pack(push)
#pragma pack(1)
namespace openvpn {
struct DHCP {
enum {
/* DHCP Option types */
DHCP_PAD = 0,
DHCP_NETMASK = 1,
DHCP_ROUTER = 3,
DHCP_DNS = 6,
DHCP_MSG_TYPE = 53 /* message type (u8) */,
DHCP_END = 255,
/* DHCP Messages types */
DHCPDISCOVER = 1,
DHCPOFFER = 2,
DHCPREQUEST = 3,
DHCPDECLINE = 4,
DHCPACK = 5,
DHCPNAK = 6,
DHCPRELEASE = 7,
DHCPINFORM = 8,
/* DHCP UDP port numbers */
BOOTPS_PORT = 67,
BOOTPC_PORT = 68,
/* DHCP message op */
BOOTREQUEST = 1,
BOOTREPLY = 2,
};
std::uint8_t op; /* message op */
std::uint8_t htype; /* hardware address type (e.g. '1' = 10Mb Ethernet) */
std::uint8_t hlen; /* hardware address length (e.g. '6' for 10Mb Ethernet) */
std::uint8_t hops; /* client sets to 0, may be used by relay agents */
std::uint32_t xid; /* transaction ID, chosen by client */
std::uint16_t secs; /* seconds since request process began, set by client */
std::uint16_t flags;
std::uint32_t ciaddr; /* client IP address, client sets if known */
std::uint32_t yiaddr; /* 'your' IP address -- server's response to client */
std::uint32_t siaddr; /* server IP address */
std::uint32_t giaddr; /* relay agent IP address */
std::uint8_t chaddr[16]; /* client hardware address */
std::uint8_t sname[64]; /* optional server host name */
std::uint8_t file[128]; /* boot file name */
std::uint32_t magic; /* must be 0x63825363 (network order) */
};
struct DHCPPacket {
EthHeader eth;
IPv4Header ip;
UDPHeader udp;
DHCP dhcp;
std::uint8_t options[];
};
}
#pragma pack(pop)
#endif
+42
View File
@@ -0,0 +1,42 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Define the Ethernet header
#ifndef OPENVPN_IP_ETH_H
#define OPENVPN_IP_ETH_H
#include <cstdint> // for std::uint32_t, uint16_t, uint8_t
#pragma pack(push)
#pragma pack(1)
namespace openvpn {
struct EthHeader {
std::uint8_t dest_mac[6];
std::uint8_t src_mac[6];
std::uint16_t ethertype;
};
}
#pragma pack(pop)
#endif
+67
View File
@@ -0,0 +1,67 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Define the ICMPv4 header
#pragma once
#include <cstdint> // for std::uint32_t, uint16_t, uint8_t
#include <openvpn/ip/ip4.hpp>
#pragma pack(push)
#pragma pack(1)
namespace openvpn {
struct ICMPv4 {
enum {
ECHO_REQUEST = 8,
ECHO_REPLY = 0,
DEST_UNREACH = 3,
FRAG_NEEDED = 4,
MIN_DATA_SIZE = 8
};
struct IPv4Header head;
union {
struct {
std::uint8_t type;
std::uint8_t code;
};
std::uint16_t type_code;
};
std::uint16_t checksum;
union {
struct {
std::uint16_t id;
std::uint16_t seq_num;
};
struct {
std::uint16_t unused;
std::uint16_t nexthop_mtu;
};
};
};
}
#pragma pack(pop)
+64
View File
@@ -0,0 +1,64 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Define the ICMPv6 header
#pragma once
#include <cstdint> // for std::uint32_t, uint16_t, uint8_t
#include <openvpn/ip/ip6.hpp>
#pragma pack(push)
#pragma pack(1)
namespace openvpn {
struct ICMPv6 {
enum {
ECHO_REQUEST = 128,
ECHO_REPLY = 129,
DEST_UNREACH = 1,
PACKET_TOO_BIG = 2
};
struct IPv6Header head;
union {
struct {
std::uint8_t type;
std::uint8_t code;
};
std::uint16_t type_code;
};
std::uint16_t checksum;
union {
struct {
std::uint16_t id;
std::uint16_t seq_num;
};
std::uint32_t mtu;
};
};
}
#pragma pack(pop)
+68
View File
@@ -0,0 +1,68 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// IPv4 header
#pragma once
#include <cstdint> // for std::uint32_t, uint16_t, uint8_t
#pragma pack(push)
#pragma pack(1)
namespace openvpn {
struct IPv4Header
{
static unsigned int length(const std::uint8_t version_len)
{
return (version_len & 0x0F) << 2;
}
static std::uint8_t ver_len(const unsigned int version,
const unsigned int len)
{
return ((len >> 2) & 0x0F) | (version & 0x0F) << 4;
}
std::uint8_t version_len;
std::uint8_t tos;
std::uint16_t tot_len;
std::uint16_t id;
enum {
OFFMASK=0x1fff,
};
std::uint16_t frag_off;
std::uint8_t ttl;
std::uint8_t protocol;
std::uint16_t check;
std::uint32_t saddr;
std::uint32_t daddr;
/* The options start here. */
};
}
#pragma pack(pop)
+50
View File
@@ -0,0 +1,50 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// IPv6 header
#pragma once
#include <cstdint> // for std::uint32_t, uint16_t, uint8_t
#include <openvpn/common/socktypes.hpp>
#pragma pack(push)
#pragma pack(1)
namespace openvpn {
struct IPv6Header
{
std::uint8_t version_prio;
std::uint8_t flow_lbl[3];
std::uint16_t payload_len;
std::uint8_t nexthdr;
std::uint8_t hop_limit;
struct in6_addr saddr;
struct in6_addr daddr;
};
}
#pragma pack(pop)
+50
View File
@@ -0,0 +1,50 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Common declarations for IPv4 and IPv6
#pragma once
#include <cstdint> // for std::uint32_t, uint16_t, uint8_t
namespace openvpn {
namespace IPCommon {
enum {
ICMPv4 = 1, /* ICMPv4 protocol */
ICMPv6 = 58, /* ICMPv6 protocol */
IGMP = 2, /* IGMP protocol */
TCP = 6, /* TCP protocol */
UDP = 17, /* UDP protocol */
};
enum {
IPv4 = 4,
IPv6 = 6
};
inline unsigned int version(const std::uint8_t version_len_prio)
{
return (version_len_prio >> 4) & 0x0F;
}
}
}
+113
View File
@@ -0,0 +1,113 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2018 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#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();
}
}
}
+171
View File
@@ -0,0 +1,171 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2018 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#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 static const std::uint16_t* get_addr16(const struct in6_addr *addr)
{
#if defined(_WIN32)
return addr->u.Word;
#elif defined(__APPLE__)
return addr->__u6_addr.__u6_addr16;
#else
return addr->s6_addr16;
#endif
}
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 = 0;
std::uint32_t val = 0;
const std::uint16_t* addr = get_addr16(saddr);
for (int i = 0; i < 4; ++i)
{
val = (std::uint32_t)(addr[i * 2] << 16) + addr[i * 2 + 1];
sum += val;
carry = (sum < val);
sum += carry;
}
addr = get_addr16(daddr);
for (int i = 0; i < 4; ++i)
{
val = (std::uint32_t)(addr[i * 2] << 16) + addr[i * 2 + 1];
sum += val;
carry = (sum < val);
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();
}
}
}
+136
View File
@@ -0,0 +1,136 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Generates ICMP "packet too big" response
#pragma once
#include <openvpn/common/socktypes.hpp>
#include <openvpn/ip/csum.hpp>
#include <openvpn/ip/ip4.hpp>
#include <openvpn/ip/ip6.hpp>
#include <openvpn/ip/icmp4.hpp>
#include <openvpn/ip/icmp6.hpp>
#include <openvpn/ip/ping6.hpp>
#include <openvpn/ip/ipcommon.hpp>
#include <openvpn/buffer/buffer.hpp>
namespace openvpn {
class Ptb {
public:
static void generate_icmp_ptb(BufferAllocated& buf, std::uint16_t nexthop_mtu)
{
if (buf.empty())
return;
switch (IPCommon::version(buf[0]))
{
case IPCommon::IPv4:
if (buf.length() <= sizeof(struct IPv4Header))
break;
generate_icmp4_ptb(buf, nexthop_mtu);
break;
case IPCommon::IPv6:
if (buf.length() <= sizeof(struct IPv6Header))
break;
generate_icmp6_ptb(buf, nexthop_mtu);
break;
}
}
private:
static void generate_icmp6_ptb(BufferAllocated& buf, std::uint16_t nexthop_mtu)
{
// ICMPv6 data includes original IPv6 header and as many bytes of payload as possible
int data_size = std::min(buf.length(), (size_t)(nexthop_mtu - sizeof(ICMPv6)));
// sanity check
// we use headroom for adding IPv6 + ICMPv6 headers
if ((buf.offset() < sizeof(ICMPv6)) || (buf.capacity() < (sizeof(ICMPv6) + data_size)))
return;
IPv6Header* ipv6 = (IPv6Header*)buf.c_data();
uint8_t *b = buf.prepend_alloc(sizeof(ICMPv6));
ICMPv6 *icmp = (ICMPv6 *)b;
// IPv6 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 = ipv6->daddr;
icmp->head.daddr = ipv6->saddr;
// ICMP header
icmp->type = ICMPv6::PACKET_TOO_BIG;
icmp->code = 0;
icmp->mtu = htonl(nexthop_mtu);
icmp->checksum = 0;
icmp->checksum = Ping6::csum_icmp(icmp, sizeof(ICMPv6) + data_size);
buf.set_size(sizeof(ICMPv6) + data_size);
}
static void generate_icmp4_ptb(BufferAllocated& buf, std::uint16_t nexthop_mtu)
{
// ICMP data includes original IP header and first 8 bytes of payload
int data_size = sizeof(IPv4Header) + ICMPv4::MIN_DATA_SIZE;
// sanity check
// we use headroom for adding IPv4 + ICMPv4 headers
if ((buf.offset() < sizeof(ICMPv4)) || (buf.capacity() < (sizeof(ICMPv4) + data_size)))
return;
IPv4Header* ipv4 = (IPv4Header*)buf.c_data();
uint8_t *b = buf.prepend_alloc(sizeof(ICMPv4));
ICMPv4 *icmp = (ICMPv4 *)b;
icmp->head.saddr = ipv4->daddr;
icmp->head.daddr = ipv4->saddr;
icmp->head.version_len = IPv4Header::ver_len(IPCommon::IPv4, 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.check = IPChecksum::checksum(b, sizeof(IPv4Header));
icmp->type = ICMPv4::DEST_UNREACH;
icmp->code = ICMPv4::FRAG_NEEDED;
icmp->unused = 0;
icmp->nexthop_mtu = htons(nexthop_mtu);
icmp->checksum = 0;
icmp->checksum = IPChecksum::checksum(b + sizeof(IPv4Header), sizeof(ICMPv4) - sizeof(IPv4Header) + data_size);
buf.set_size(sizeof(ICMPv4) + data_size);
}
};
}
+90
View File
@@ -0,0 +1,90 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <openvpn/common/endian.hpp>
#include <openvpn/ip/ipcommon.hpp>
namespace openvpn {
#pragma pack(push)
#pragma pack(1)
struct TCPHeader {
static unsigned int length(const std::uint8_t doff_res)
{
return ((doff_res) & 0xF0) >> 2;
}
std::uint16_t source;
std::uint16_t dest;
std::uint32_t seq;
std::uint32_t ack_seq;
std::uint8_t doff_res;
std::uint8_t flags;
std::uint16_t window;
std::uint16_t check;
std::uint16_t urgent_p;
// helper enum to parse options in TCP header
enum {
OPT_EOL = 0,
OPT_NOP = 1,
OPT_MAXSEG = 2,
OPTLEN_MAXSEG = 4
};
enum {
FLAG_SYN = 1 << 1
};
};
#pragma pack(pop)
/*
* The following routine is used to update an
* internet checksum. "acc" is a 32-bit
* accumulation of all the changes to the
* checksum (adding in old 16-bit words and
* subtracting out new words), and "cksum"
* is the checksum value to be updated.
*/
inline void tcp_adjust_checksum(int acc, std::uint16_t& cksum)
{
int _acc = acc;
_acc += cksum;
if (_acc < 0)
{
_acc = -_acc;
_acc = (_acc >> 16) + (_acc & 0xffff);
_acc += _acc >> 16;
cksum = (uint16_t)~_acc;
}
else
{
_acc = (_acc >> 16) + (_acc & 0xffff);
_acc += _acc >> 16;
cksum = (uint16_t)_acc;
}
}
}
+83
View File
@@ -0,0 +1,83 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2017 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
// Define the UDP header
#ifndef OPENVPN_IP_UDP_H
#define OPENVPN_IP_UDP_H
#include <openvpn/ip/ipcommon.hpp>
namespace openvpn {
#pragma pack(push)
#pragma pack(1)
struct UDPHeader {
std::uint16_t source;
std::uint16_t dest;
std::uint16_t len;
std::uint16_t check;
};
#pragma pack(pop)
inline std::uint16_t udp_checksum (const std::uint8_t *buf,
const unsigned int len_udp,
const std::uint8_t *src_addr,
const std::uint8_t *dest_addr)
{
std::uint32_t sum = 0;
/* make 16 bit words out of every two adjacent 8 bit words and */
/* calculate the sum of all 16 bit words */
for (unsigned int i = 0; i < len_udp; i += 2)
{
std::uint16_t word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0);
sum += word16;
}
/* add the UDP pseudo header which contains the IP source and destination addresses */
for (unsigned int i = 0; i < 4; i += 2)
{
std::uint16_t word16 =((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF);
sum += word16;
}
for (unsigned int i = 0; i < 4; i += 2)
{
std::uint16_t word16 =((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF);
sum += word16;
}
/* the protocol number and the length of the UDP packet */
sum += (std::uint16_t)IPCommon::UDP + (std::uint16_t)len_udp;
/* keep only the last 16 bits of the 32 bit calculated sum and add the carries */
while (sum >> 16)
sum = (sum & 0xFFFF) + (sum >> 16);
/* take the one's complement of sum */
return std::uint16_t(~sum);
}
}
#endif