]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/ednssubnet.cc
Merge pull request #14021 from Habbie/auth-lua-join-whitespace
[thirdparty/pdns.git] / pdns / ednssubnet.cc
CommitLineData
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
28namespace
29{
30struct EDNSSubnetOptsWire
31{
32 uint16_t family;
33 uint8_t sourceMask;
34 uint8_t scopeMask;
35} GCCPACKATTRIBUTE; // BRRRRR
801085ac
BH
36
37}
38
801085ac 39bool 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}
44bool 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
97string 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}