/src/pdns/pdns/ednssubnet.cc
Line | Count | Source (jump to first uncovered line) |
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 | | #ifdef HAVE_CONFIG_H |
23 | | #include "config.h" |
24 | | #endif |
25 | | #include "ednssubnet.hh" |
26 | | #include "dns.hh" |
27 | | |
28 | | namespace { |
29 | | struct EDNSSubnetOptsWire |
30 | | { |
31 | | uint16_t family; |
32 | | uint8_t sourceMask; |
33 | | uint8_t scopeMask; |
34 | | } GCCPACKATTRIBUTE; // BRRRRR |
35 | | |
36 | | } |
37 | | |
38 | | bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso) |
39 | 0 | { |
40 | | //cerr<<"options.size:"<<options.size()<<endl; |
41 | 0 | return getEDNSSubnetOptsFromString(options.c_str(), options.length(), eso); |
42 | 0 | } |
43 | | bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubnetOpts* eso) |
44 | 248 | { |
45 | 248 | EDNSSubnetOptsWire esow; |
46 | 248 | static_assert (sizeof(esow) == 4, "sizeof(EDNSSubnetOptsWire) must be 4 bytes"); |
47 | 248 | if(len < sizeof(esow)) |
48 | 14 | return false; |
49 | 234 | memcpy(&esow, options, sizeof(esow)); |
50 | 234 | esow.family = ntohs(esow.family); |
51 | | //cerr<<"Family when parsing from string: "<<esow.family<<endl; |
52 | 234 | ComboAddress address; |
53 | 234 | unsigned int octetsin = esow.sourceMask > 0 ? (((esow.sourceMask - 1)>> 3)+1) : 0; |
54 | | //cerr<<"octetsin:"<<octetsin<<endl; |
55 | 234 | if(esow.family == 1) { |
56 | 80 | if(len != sizeof(esow)+octetsin) |
57 | 42 | return false; |
58 | 38 | if(octetsin > sizeof(address.sin4.sin_addr.s_addr)) |
59 | 5 | return false; |
60 | 33 | address.reset(); |
61 | 33 | address.sin4.sin_family = AF_INET; |
62 | 33 | if(octetsin > 0) |
63 | 12 | memcpy(&address.sin4.sin_addr.s_addr, options+sizeof(esow), octetsin); |
64 | 154 | } else if(esow.family == 2) { |
65 | 87 | if(len != sizeof(esow)+octetsin) |
66 | 33 | return false; |
67 | 54 | if(octetsin > sizeof(address.sin6.sin6_addr.s6_addr)) |
68 | 1 | return false; |
69 | | |
70 | 53 | address.reset(); |
71 | 53 | address.sin4.sin_family = AF_INET6; |
72 | 53 | if(octetsin > 0) |
73 | 33 | memcpy(&address.sin6.sin6_addr.s6_addr, options+sizeof(esow), octetsin); |
74 | 53 | } |
75 | 67 | else |
76 | 67 | return false; |
77 | | //cerr<<"Source address: "<<address.toString()<<", mask: "<<(int)esow.sourceMask<<endl; |
78 | 86 | eso->source = Netmask(address, esow.sourceMask); |
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 | 86 | address.truncate(esow.scopeMask); // truncate will not throw for odd scopeMasks |
83 | 86 | eso->scope = Netmask(address, esow.scopeMask); |
84 | | |
85 | 86 | return true; |
86 | 234 | } |
87 | | |
88 | | string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso) |
89 | 0 | { |
90 | 0 | string ret; |
91 | 0 | EDNSSubnetOptsWire esow; |
92 | 0 | uint16_t family = htons(eso.source.getNetwork().sin4.sin_family == AF_INET ? 1 : 2); |
93 | 0 | esow.family = family; |
94 | 0 | esow.sourceMask = eso.source.getBits(); |
95 | 0 | esow.scopeMask = eso.scope.getBits(); |
96 | 0 | ret.assign((const char*)&esow, sizeof(esow)); |
97 | 0 | int octetsout = ((esow.sourceMask - 1)>> 3)+1; |
98 | |
|
99 | 0 | ComboAddress src=eso.source.getNetwork(); |
100 | 0 | src.truncate(esow.sourceMask); |
101 | |
|
102 | 0 | if(family == htons(1)) |
103 | 0 | ret.append((const char*) &src.sin4.sin_addr.s_addr, octetsout); |
104 | 0 | else |
105 | 0 | ret.append((const char*) &src.sin6.sin6_addr.s6_addr, octetsout); |
106 | 0 | return ret; |
107 | 0 | } |
108 | | |