1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
/*
* This file is part of PowerDNS or dnsdist.
* Copyright -- PowerDNS.COM B.V. and its contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* In addition, for the avoidance of any doubt, permission is granted to
* link this program with OpenSSL and to (re)distribute the binaries
* produced as the result of such linking.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "xpf.hh"
std::string generateXPFPayload(bool tcp, const ComboAddress& source, const ComboAddress& destination)
{
if (source.sin4.sin_family != destination.sin4.sin_family) {
throw std::runtime_error("The XPF destination and source addresses must be of the same family");
}
std::string ret;
const uint8_t version = source.isIPv4() ? 4 : 6;
const uint8_t protocol = tcp ? 6 : 17;
const size_t addrSize = source.isIPv4() ? sizeof(source.sin4.sin_addr.s_addr) : sizeof(source.sin6.sin6_addr.s6_addr);
const uint16_t sourcePort = source.sin4.sin_port;
const uint16_t destinationPort = destination.sin4.sin_port;
ret.reserve(sizeof(version) + sizeof(protocol) + (addrSize * 2) + sizeof(sourcePort) + sizeof(destinationPort));
ret.append(reinterpret_cast<const char*>(&version), sizeof(version));
ret.append(reinterpret_cast<const char*>(&protocol), sizeof(protocol));
// We already established source and destination sin_family equivalence
if (source.isIPv4()) {
assert(addrSize == sizeof(source.sin4.sin_addr.s_addr));
ret.append(reinterpret_cast<const char*>(&source.sin4.sin_addr.s_addr), addrSize);
assert(addrSize == sizeof(destination.sin4.sin_addr.s_addr));
ret.append(reinterpret_cast<const char*>(&destination.sin4.sin_addr.s_addr), addrSize);
}
else {
assert(addrSize == sizeof(source.sin6.sin6_addr.s6_addr));
ret.append(reinterpret_cast<const char*>(&source.sin6.sin6_addr.s6_addr), addrSize);
assert(addrSize == sizeof(destination.sin6.sin6_addr.s6_addr));
ret.append(reinterpret_cast<const char*>(&destination.sin6.sin6_addr.s6_addr), addrSize);
}
ret.append(reinterpret_cast<const char*>(&sourcePort), sizeof(sourcePort));
ret.append(reinterpret_cast<const char*>(&destinationPort), sizeof(destinationPort));
return ret;
}
bool parseXPFPayload(const char* payload, size_t len, ComboAddress& source, ComboAddress* destination)
{
static const size_t addr4Size = sizeof(source.sin4.sin_addr.s_addr);
static const size_t addr6Size = sizeof(source.sin6.sin6_addr.s6_addr);
uint8_t version;
uint8_t protocol;
uint16_t sourcePort;
uint16_t destinationPort;
if (len != (sizeof(version) + sizeof(protocol) + (addr4Size * 2) + sizeof(sourcePort) + sizeof(destinationPort)) &&
len != (sizeof(version) + sizeof(protocol) + (addr6Size * 2) + sizeof(sourcePort) + sizeof(destinationPort))) {
return false;
}
size_t pos = 0;
memcpy(&version, payload + pos, sizeof(version));
pos += sizeof(version);
if (version != 4 && version != 6) {
return false;
}
memcpy(&protocol, payload + pos, sizeof(protocol));
pos += sizeof(protocol);
if (protocol != 6 && protocol != 17) {
return false;
}
const size_t addrSize = version == 4 ? sizeof(source.sin4.sin_addr.s_addr) : sizeof(source.sin6.sin6_addr.s6_addr);
if (len - pos != ((addrSize * 2) + sizeof(sourcePort) + sizeof(destinationPort))) {
return false;
}
source = makeComboAddressFromRaw(version, payload + pos, addrSize);
pos += addrSize;
if (destination != nullptr) {
*destination = makeComboAddressFromRaw(version, payload + pos, addrSize);
}
pos += addrSize;
memcpy(&sourcePort, payload + pos, sizeof(sourcePort));
pos += sizeof(sourcePort);
source.sin4.sin_port = sourcePort;
memcpy(&destinationPort, payload + pos, sizeof(destinationPort));
pos += sizeof(destinationPort);
(void) pos;
if (destination != nullptr) {
destination->sin4.sin_port = destinationPort;
}
return true;
}
|