]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/iputils.hh
add OpenSSL exception to PowerDNS, Netherlabs, van Dijk and Hubert copyrights
[thirdparty/pdns.git] / pdns / iputils.hh
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 - 2011 PowerDNS.COM BV
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
8
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22 #ifndef PDNS_IPUTILSHH
23 #define PDNS_IPUTILSHH
24
25 #include <string>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <iostream>
30 #include <stdio.h>
31 #include <functional>
32 #include "pdnsexception.hh"
33 #include "misc.hh"
34 #include <sys/socket.h>
35 #include <netdb.h>
36
37 #include <boost/tuple/tuple.hpp>
38 #include <boost/tuple/tuple_comparison.hpp>
39 #include <boost/lexical_cast.hpp>
40
41 #include "namespaces.hh"
42
43 union ComboAddress {
44 struct sockaddr_in sin4;
45 struct sockaddr_in6 sin6;
46
47 bool operator==(const ComboAddress& rhs) const
48 {
49 if(boost::tie(sin4.sin_family, sin4.sin_port) != boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
50 return false;
51 if(sin4.sin_family == AF_INET)
52 return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
53 else
54 return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16)==0;
55 }
56
57 bool operator<(const ComboAddress& rhs) const
58 {
59 if(boost::tie(sin4.sin_family, sin4.sin_port) < boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
60 return true;
61 if(boost::tie(sin4.sin_family, sin4.sin_port) > boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
62 return false;
63
64 if(sin4.sin_family == AF_INET)
65 return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
66 else
67 return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16) < 0;
68 }
69
70 bool operator>(const ComboAddress& rhs) const
71 {
72 if(boost::tie(sin4.sin_family, sin4.sin_port) > boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
73 return true;
74 if(boost::tie(sin4.sin_family, sin4.sin_port) < boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
75 return false;
76
77 if(sin4.sin_family == AF_INET)
78 return sin4.sin_addr.s_addr > rhs.sin4.sin_addr.s_addr;
79 else
80 return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16) > 0;
81 }
82
83 struct addressOnlyLessThan: public std::binary_function<string, string, bool>
84 {
85 bool operator()(const ComboAddress& a, const ComboAddress& b) const
86 {
87 if(a.sin4.sin_family < b.sin4.sin_family)
88 return true;
89 if(a.sin4.sin_family > b.sin4.sin_family)
90 return false;
91 if(a.sin4.sin_family == AF_INET)
92 return a.sin4.sin_addr.s_addr < b.sin4.sin_addr.s_addr;
93 else
94 return memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, 16) < 0;
95 }
96 };
97
98 socklen_t getSocklen() const
99 {
100 if(sin4.sin_family == AF_INET)
101 return sizeof(sin4);
102 else
103 return sizeof(sin6);
104 }
105
106 ComboAddress()
107 {
108 sin4.sin_family=AF_INET;
109 sin4.sin_addr.s_addr=0;
110 sin4.sin_port=0;
111 }
112
113 // 'port' sets a default value in case 'str' does not set a port
114 explicit ComboAddress(const string& str, uint16_t port=0)
115 {
116 memset(&sin6, 0, sizeof(sin6));
117 sin4.sin_family = AF_INET;
118 sin4.sin_port = 0;
119 if(makeIPv4sockaddr(str, &sin4)) {
120 sin6.sin6_family = AF_INET6;
121 if(makeIPv6sockaddr(str, &sin6) < 0)
122 throw PDNSException("Unable to convert presentation address '"+ str +"'");
123
124 }
125 if(!sin4.sin_port) // 'str' overrides port!
126 sin4.sin_port=htons(port);
127 }
128
129 bool isMappedIPv4() const
130 {
131 if(sin4.sin_family!=AF_INET6)
132 return false;
133
134 int n=0;
135 const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
136 for(n=0; n < 10; ++n)
137 if(ptr[n])
138 return false;
139
140 for(; n < 12; ++n)
141 if(ptr[n]!=0xff)
142 return false;
143
144 return true;
145 }
146
147 ComboAddress mapToIPv4() const
148 {
149 if(!isMappedIPv4())
150 throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
151 ComboAddress ret;
152 ret.sin4.sin_family=AF_INET;
153 ret.sin4.sin_port=sin4.sin_port;
154
155 const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
156 ptr+=12;
157 memcpy(&ret.sin4.sin_addr.s_addr, ptr, 4);
158 return ret;
159 }
160
161 string toString() const
162 {
163 char host[1024];
164 getnameinfo((struct sockaddr*) this, getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST);
165
166 return host;
167 }
168
169 string toStringWithPort() const
170 {
171 if(sin4.sin_family==AF_INET)
172 return toString() + ":" + boost::lexical_cast<string>(ntohs(sin4.sin_port));
173 else
174 return "["+toString() + "]:" + boost::lexical_cast<string>(ntohs(sin4.sin_port));
175 }
176 };
177
178 /** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
179 class NetmaskException: public PDNSException
180 {
181 public:
182 NetmaskException(const string &a) : PDNSException(a) {}
183 };
184
185 inline ComboAddress makeComboAddress(const string& str)
186 {
187 ComboAddress address;
188 address.sin4.sin_family=AF_INET;
189 if(Utility::inet_pton(AF_INET, str.c_str(), &address.sin4.sin_addr) <= 0) {
190 address.sin4.sin_family=AF_INET6;
191 if(makeIPv6sockaddr(str, &address.sin6) < 0)
192 throw NetmaskException("Unable to convert '"+str+"' to a netmask");
193 }
194 return address;
195 }
196
197 /** This class represents a netmask and can be queried to see if a certain
198 IP address is matched by this mask */
199 class Netmask
200 {
201 public:
202 Netmask()
203 {
204 d_network.sin4.sin_family=0; // disable this doing anything useful
205 }
206
207 Netmask(const ComboAddress& network, uint8_t bits=0xff)
208 {
209 d_network = network;
210
211 if(bits == 0xff)
212 bits = (network.sin4.sin_family == AF_INET) ? 32 : 128;
213
214 d_bits = bits;
215 if(d_bits<32)
216 d_mask=~(0xFFFFFFFF>>d_bits);
217 else
218 d_mask=0xFFFFFFFF; // not actually used for IPv6
219 }
220
221 //! Constructor supplies the mask, which cannot be changed
222 Netmask(const string &mask)
223 {
224 pair<string,string> split=splitField(mask,'/');
225 d_network=makeComboAddress(split.first);
226
227 if(!split.second.empty()) {
228 d_bits = lexical_cast<unsigned int>(split.second);
229 if(d_bits<32)
230 d_mask=~(0xFFFFFFFF>>d_bits);
231 else
232 d_mask=0xFFFFFFFF;
233 }
234 else if(d_network.sin4.sin_family==AF_INET) {
235 d_bits = 32;
236 d_mask = 0xFFFFFFFF;
237 }
238 else {
239 d_bits=128;
240 d_mask=0; // silence silly warning - d_mask is unused for IPv6
241 }
242 }
243
244 bool match(const ComboAddress& ip) const
245 {
246 return match(&ip);
247 }
248
249 //! If this IP address in socket address matches
250 bool match(const ComboAddress *ip) const
251 {
252 if(d_network.sin4.sin_family != ip->sin4.sin_family) {
253 return false;
254 }
255 if(d_network.sin4.sin_family == AF_INET) {
256 return match4(htonl((unsigned int)ip->sin4.sin_addr.s_addr));
257 }
258 if(d_network.sin6.sin6_family == AF_INET6) {
259 uint8_t bytes=d_bits/8, n;
260 const uint8_t *us=(const uint8_t*) &d_network.sin6.sin6_addr.s6_addr;
261 const uint8_t *them=(const uint8_t*) &ip->sin6.sin6_addr.s6_addr;
262
263 for(n=0; n < bytes; ++n) {
264 if(us[n]!=them[n]) {
265 return false;
266 }
267 }
268 // still here, now match remaining bits
269 uint8_t bits= d_bits % 8;
270 uint8_t mask= ~(0xFF>>bits);
271
272 return((us[n] & mask) == (them[n] & mask));
273 }
274 return false;
275 }
276
277 //! If this ASCII IP address matches
278 bool match(const string &ip) const
279 {
280 ComboAddress address=makeComboAddress(ip);
281 return match(&address);
282 }
283
284 //! If this IP address in native format matches
285 bool match4(uint32_t ip) const
286 {
287 return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
288 }
289
290 string toString() const
291 {
292 return d_network.toString()+"/"+boost::lexical_cast<string>((unsigned int)d_bits);
293 }
294
295 string toStringNoMask() const
296 {
297 return d_network.toString();
298 }
299 const ComboAddress& getNetwork() const
300 {
301 return d_network;
302 }
303 int getBits() const
304 {
305 return d_bits;
306 }
307 private:
308 ComboAddress d_network;
309 uint32_t d_mask;
310 uint8_t d_bits;
311 };
312
313 /** This class represents a group of supplemental Netmask classes. An IP address matchs
314 if it is matched by zero or more of the Netmask classes within.
315 */
316 class NetmaskGroup
317 {
318 public:
319 //! If this IP address is matched by any of the classes within
320
321 bool match(const ComboAddress *ip)
322 {
323 for(container_t::const_iterator i=d_masks.begin();i!=d_masks.end();++i)
324 if(i->match(ip) || (ip->isMappedIPv4() && i->match(ip->mapToIPv4()) ))
325 return true;
326
327 return false;
328 }
329
330 bool match(const ComboAddress& ip)
331 {
332 return match(&ip);
333 }
334
335 //! Add this Netmask to the list of possible matches
336 void addMask(const string &ip)
337 {
338 d_masks.push_back(Netmask(ip));
339 }
340
341 bool empty()
342 {
343 return d_masks.empty();
344 }
345
346 unsigned int size()
347 {
348 return (unsigned int)d_masks.size();
349 }
350
351 string toString() const
352 {
353 ostringstream str;
354 for(container_t::const_iterator iter = d_masks.begin(); iter != d_masks.end(); ++iter) {
355 if(iter != d_masks.begin())
356 str <<", ";
357 str<<iter->toString();
358 }
359 return str.str();
360 }
361
362 private:
363 typedef vector<Netmask> container_t;
364 container_t d_masks;
365 };
366
367
368 int SSocket(int family, int type, int flags);
369 int SConnect(int sockfd, const ComboAddress& remote);
370 int SBind(int sockfd, const ComboAddress& local);
371 int SAccept(int sockfd, ComboAddress& remote);
372 int SListen(int sockfd, int limit);
373 int SSetsockopt(int sockfd, int level, int opname, int value);
374
375 #endif