]>
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 | ||
28 | namespace { | |
232f0877 CH |
29 | struct EDNSSubnetOptsWire |
30 | { | |
31 | uint16_t family; | |
32 | uint8_t sourceMask; | |
33 | uint8_t scopeMask; | |
795215f2 | 34 | } GCCPACKATTRIBUTE; // BRRRRR |
801085ac BH |
35 | |
36 | } | |
37 | ||
801085ac | 38 | bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso) |
dc5748ed | 39 | { |
53221eaf | 40 | //cerr<<"options.size:"<<options.size()<<endl; |
dc5748ed | 41 | return getEDNSSubnetOptsFromString(options.c_str(), options.length(), eso); |
42 | } | |
43 | bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubnetOpts* eso) | |
801085ac | 44 | { |
801085ac | 45 | EDNSSubnetOptsWire esow; |
a683e8bd | 46 | static_assert (sizeof(esow) == 4, "sizeof(EDNSSubnetOptsWire) must be 4 bytes"); |
53221eaf | 47 | if(len < sizeof(esow)) |
a683e8bd | 48 | return false; |
dc5748ed | 49 | memcpy(&esow, options, sizeof(esow)); |
801085ac | 50 | esow.family = ntohs(esow.family); |
af7d3ea6 | 51 | //cerr<<"Family when parsing from string: "<<esow.family<<endl; |
801085ac | 52 | ComboAddress address; |
53221eaf | 53 | unsigned int octetsin = esow.sourceMask > 0 ? (((esow.sourceMask - 1)>> 3)+1) : 0; |
f6c101f2 | 54 | //cerr<<"octetsin:"<<octetsin<<endl; |
801085ac | 55 | if(esow.family == 1) { |
a683e8bd | 56 | if(len != sizeof(esow)+octetsin) |
801085ac | 57 | return false; |
a683e8bd | 58 | if(octetsin > sizeof(address.sin4.sin_addr.s_addr)) |
f6c101f2 | 59 | return false; |
1caa9c83 | 60 | address.reset(); |
801085ac | 61 | address.sin4.sin_family = AF_INET; |
53221eaf RG |
62 | if(octetsin > 0) |
63 | memcpy(&address.sin4.sin_addr.s_addr, options+sizeof(esow), octetsin); | |
af7d3ea6 | 64 | } else if(esow.family == 2) { |
a683e8bd | 65 | if(len != sizeof(esow)+octetsin) |
f6c101f2 | 66 | return false; |
a683e8bd | 67 | if(octetsin > sizeof(address.sin6.sin6_addr.s6_addr)) |
af7d3ea6 | 68 | return false; |
1caa9c83 RG |
69 | |
70 | address.reset(); | |
af7d3ea6 | 71 | address.sin4.sin_family = AF_INET6; |
53221eaf RG |
72 | if(octetsin > 0) |
73 | memcpy(&address.sin6.sin6_addr.s6_addr, options+sizeof(esow), octetsin); | |
801085ac | 74 | } |
af7d3ea6 BH |
75 | else |
76 | return false; | |
53221eaf | 77 | //cerr<<"Source address: "<<address.toString()<<", mask: "<<(int)esow.sourceMask<<endl; |
af7d3ea6 | 78 | eso->source = Netmask(address, esow.sourceMask); |
b85f49a0 | 79 | /* 'address' has more bits set (potentially) than scopeMask. This leads to odd looking netmasks that promise |
80 | more precision than they have. For this reason we truncate the address to scopeMask bits */ | |
81 | ||
82 | address.truncate(esow.scopeMask); // truncate will not throw for odd scopeMasks | |
af7d3ea6 | 83 | eso->scope = Netmask(address, esow.scopeMask); |
b85f49a0 | 84 | |
af7d3ea6 | 85 | return true; |
801085ac BH |
86 | } |
87 | ||
88 | string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso) | |
89 | { | |
90 | string ret; | |
91 | EDNSSubnetOptsWire esow; | |
92 | uint16_t family = htons(eso.source.getNetwork().sin4.sin_family == AF_INET ? 1 : 2); | |
a683e8bd | 93 | esow.family = family; |
801085ac BH |
94 | esow.sourceMask = eso.source.getBits(); |
95 | esow.scopeMask = eso.scope.getBits(); | |
96 | ret.assign((const char*)&esow, sizeof(esow)); | |
f6c101f2 PD |
97 | int octetsout = ((esow.sourceMask - 1)>> 3)+1; |
98 | ||
d7da15c5 | 99 | ComboAddress src=eso.source.getNetwork(); |
100 | src.truncate(esow.sourceMask); | |
101 | ||
801085ac | 102 | if(family == htons(1)) |
d7da15c5 | 103 | ret.append((const char*) &src.sin4.sin_addr.s_addr, octetsout); |
801085ac | 104 | else |
d7da15c5 | 105 | ret.append((const char*) &src.sin6.sin6_addr.s6_addr, octetsout); |
801085ac BH |
106 | return ret; |
107 | } | |
108 |