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