]>
Commit | Line | Data |
---|---|---|
801085ac | 1 | /* |
12471842 PL |
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 | */ | |
870a0fe4 AT |
22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" | |
24 | #endif | |
801085ac BH |
25 | #include "ednssubnet.hh" |
26 | #include "dns.hh" | |
27 | ||
c0ebe1da PD |
28 | namespace |
29 | { | |
30 | struct EDNSSubnetOptsWire | |
31 | { | |
32 | uint16_t family; | |
33 | uint8_t sourceMask; | |
34 | uint8_t scopeMask; | |
35 | } GCCPACKATTRIBUTE; // BRRRRR | |
801085ac BH |
36 | |
37 | } | |
38 | ||
801085ac | 39 | bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso) |
dc5748ed | 40 | { |
c0ebe1da | 41 | // cerr<<"options.size:"<<options.size()<<endl; |
dc5748ed | 42 | return getEDNSSubnetOptsFromString(options.c_str(), options.length(), eso); |
43 | } | |
44 | bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubnetOpts* eso) | |
801085ac | 45 | { |
b7349b96 | 46 | EDNSSubnetOptsWire esow{}; |
c0ebe1da | 47 | static_assert(sizeof(esow) == 4, "sizeof(EDNSSubnetOptsWire) must be 4 bytes"); |
b7349b96 | 48 | if (len < sizeof(esow)) { |
a683e8bd | 49 | return false; |
b7349b96 | 50 | } |
dc5748ed | 51 | memcpy(&esow, options, sizeof(esow)); |
801085ac | 52 | esow.family = ntohs(esow.family); |
c0ebe1da | 53 | // cerr<<"Family when parsing from string: "<<esow.family<<endl; |
801085ac | 54 | ComboAddress address; |
c0ebe1da PD |
55 | unsigned int octetsin = esow.sourceMask > 0 ? (((esow.sourceMask - 1) >> 3) + 1) : 0; |
56 | // cerr<<"octetsin:"<<octetsin<<endl; | |
57 | if (esow.family == 1) { | |
b7349b96 | 58 | if (len != sizeof(esow) + octetsin) { |
801085ac | 59 | return false; |
b7349b96 PD |
60 | } |
61 | if (octetsin > sizeof(address.sin4.sin_addr.s_addr)) { | |
f6c101f2 | 62 | return false; |
b7349b96 | 63 | } |
d38e2ba9 | 64 | address.reset(); |
801085ac | 65 | address.sin4.sin_family = AF_INET; |
b7349b96 PD |
66 | if (octetsin > 0) { |
67 | memcpy(&address.sin4.sin_addr.s_addr, options + sizeof(esow), octetsin); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) | |
68 | } | |
c0ebe1da PD |
69 | } |
70 | else if (esow.family == 2) { | |
b7349b96 | 71 | if (len != sizeof(esow) + octetsin) { |
f6c101f2 | 72 | return false; |
b7349b96 PD |
73 | } |
74 | if (octetsin > sizeof(address.sin6.sin6_addr.s6_addr)) { | |
af7d3ea6 | 75 | return false; |
b7349b96 | 76 | } |
d38e2ba9 RG |
77 | |
78 | address.reset(); | |
af7d3ea6 | 79 | address.sin4.sin_family = AF_INET6; |
b7349b96 PD |
80 | if (octetsin > 0) { |
81 | memcpy(&address.sin6.sin6_addr.s6_addr, options + sizeof(esow), octetsin); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) | |
82 | } | |
801085ac | 83 | } |
b7349b96 | 84 | else { |
af7d3ea6 | 85 | return false; |
b7349b96 | 86 | } |
af7d3ea6 | 87 | eso->source = Netmask(address, esow.sourceMask); |
b85f49a0 | 88 | /* 'address' has more bits set (potentially) than scopeMask. This leads to odd looking netmasks that promise |
89 | more precision than they have. For this reason we truncate the address to scopeMask bits */ | |
c0ebe1da | 90 | |
b85f49a0 | 91 | address.truncate(esow.scopeMask); // truncate will not throw for odd scopeMasks |
af7d3ea6 | 92 | eso->scope = Netmask(address, esow.scopeMask); |
b85f49a0 | 93 | |
af7d3ea6 | 94 | return true; |
801085ac BH |
95 | } |
96 | ||
97 | string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso) | |
98 | { | |
99 | string ret; | |
b7349b96 | 100 | EDNSSubnetOptsWire esow{}; |
801085ac | 101 | uint16_t family = htons(eso.source.getNetwork().sin4.sin_family == AF_INET ? 1 : 2); |
a683e8bd | 102 | esow.family = family; |
801085ac BH |
103 | esow.sourceMask = eso.source.getBits(); |
104 | esow.scopeMask = eso.scope.getBits(); | |
b7349b96 | 105 | ret.assign((const char*)&esow, sizeof(esow)); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast) |
c0ebe1da | 106 | int octetsout = ((esow.sourceMask - 1) >> 3) + 1; |
f6c101f2 | 107 | |
c0ebe1da | 108 | ComboAddress src = eso.source.getNetwork(); |
d7da15c5 | 109 | src.truncate(esow.sourceMask); |
bd14f087 | 110 | |
b7349b96 PD |
111 | if (family == htons(1)) { |
112 | ret.append((const char*)&src.sin4.sin_addr.s_addr, octetsout); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast) | |
113 | } | |
114 | else { | |
115 | ret.append((const char*)&src.sin6.sin6_addr.s6_addr, octetsout); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast) | |
116 | } | |
801085ac BH |
117 | return ret; |
118 | } |