mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-04-24 00:00:05 +08:00
Merge commit '86cc97e55fe346502462284d2e636a2b3708163e' as 'Sources/OpenVPN3'
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user