]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/iputils.hh
very first RPZ work. Can load RPZ from disk, most policies work. What doesn't: IPv6...
[thirdparty/pdns.git] / pdns / iputils.hh
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 - 2014 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<ComboAddress, ComboAddress, 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 struct addressOnlyEqual: public std::binary_function<ComboAddress, ComboAddress, bool>
99 {
100 bool operator()(const ComboAddress& a, const ComboAddress& b) const
101 {
102 if(a.sin4.sin_family != b.sin4.sin_family)
103 return false;
104 if(a.sin4.sin_family == AF_INET)
105 return a.sin4.sin_addr.s_addr == b.sin4.sin_addr.s_addr;
106 else
107 return !memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, 16);
108 }
109 };
110
111
112 socklen_t getSocklen() const
113 {
114 if(sin4.sin_family == AF_INET)
115 return sizeof(sin4);
116 else
117 return sizeof(sin6);
118 }
119
120 ComboAddress()
121 {
122 sin4.sin_family=AF_INET;
123 sin4.sin_addr.s_addr=0;
124 sin4.sin_port=0;
125 }
126
127 ComboAddress(const struct sockaddr *sa, socklen_t salen) {
128 setSockaddr(sa, salen);
129 };
130
131 ComboAddress(const struct sockaddr_in6 *sa) {
132 setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in6));
133 };
134
135 ComboAddress(const struct sockaddr_in *sa) {
136 setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in));
137 };
138
139 void setSockaddr(const struct sockaddr *sa, socklen_t salen) {
140 if (salen > sizeof(struct sockaddr_in6)) throw PDNSException("ComboAddress can't handle other than sockaddr_in or sockaddr_in6");
141 memcpy(this, sa, salen);
142 }
143
144 // 'port' sets a default value in case 'str' does not set a port
145 explicit ComboAddress(const string& str, uint16_t port=0)
146 {
147 memset(&sin6, 0, sizeof(sin6));
148 sin4.sin_family = AF_INET;
149 sin4.sin_port = 0;
150 if(makeIPv4sockaddr(str, &sin4)) {
151 sin6.sin6_family = AF_INET6;
152 if(makeIPv6sockaddr(str, &sin6) < 0)
153 throw PDNSException("Unable to convert presentation address '"+ str +"'");
154
155 }
156 if(!sin4.sin_port) // 'str' overrides port!
157 sin4.sin_port=htons(port);
158 }
159
160 bool isMappedIPv4() const
161 {
162 if(sin4.sin_family!=AF_INET6)
163 return false;
164
165 int n=0;
166 const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
167 for(n=0; n < 10; ++n)
168 if(ptr[n])
169 return false;
170
171 for(; n < 12; ++n)
172 if(ptr[n]!=0xff)
173 return false;
174
175 return true;
176 }
177
178 ComboAddress mapToIPv4() const
179 {
180 if(!isMappedIPv4())
181 throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
182 ComboAddress ret;
183 ret.sin4.sin_family=AF_INET;
184 ret.sin4.sin_port=sin4.sin_port;
185
186 const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
187 ptr+=12;
188 memcpy(&ret.sin4.sin_addr.s_addr, ptr, 4);
189 return ret;
190 }
191
192 string toString() const
193 {
194 char host[1024];
195 getnameinfo((struct sockaddr*) this, getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST);
196
197 return host;
198 }
199
200 string toStringWithPort() const
201 {
202 if(sin4.sin_family==AF_INET)
203 return toString() + ":" + boost::lexical_cast<string>(ntohs(sin4.sin_port));
204 else
205 return "["+toString() + "]:" + boost::lexical_cast<string>(ntohs(sin4.sin_port));
206 }
207
208 void truncate(unsigned int bits);
209 };
210
211 /** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
212 class NetmaskException: public PDNSException
213 {
214 public:
215 NetmaskException(const string &a) : PDNSException(a) {}
216 };
217
218 inline ComboAddress makeComboAddress(const string& str)
219 {
220 ComboAddress address;
221 address.sin4.sin_family=AF_INET;
222 if(inet_pton(AF_INET, str.c_str(), &address.sin4.sin_addr) <= 0) {
223 address.sin4.sin_family=AF_INET6;
224 if(makeIPv6sockaddr(str, &address.sin6) < 0)
225 throw NetmaskException("Unable to convert '"+str+"' to a netmask");
226 }
227 return address;
228 }
229
230 /** This class represents a netmask and can be queried to see if a certain
231 IP address is matched by this mask */
232 class Netmask
233 {
234 public:
235 Netmask()
236 {
237 d_network.sin4.sin_family=0; // disable this doing anything useful
238 d_mask=0;
239 d_bits=0;
240 }
241
242 Netmask(const ComboAddress& network, uint8_t bits=0xff)
243 {
244 d_network = network;
245
246 if(bits == 0xff)
247 bits = (network.sin4.sin_family == AF_INET) ? 32 : 128;
248
249 d_bits = bits;
250 if(d_bits<32)
251 d_mask=~(0xFFFFFFFF>>d_bits);
252 else
253 d_mask=0xFFFFFFFF; // not actually used for IPv6
254 }
255
256 //! Constructor supplies the mask, which cannot be changed
257 Netmask(const string &mask)
258 {
259 pair<string,string> split=splitField(mask,'/');
260 d_network=makeComboAddress(split.first);
261
262 if(!split.second.empty()) {
263 d_bits = lexical_cast<unsigned int>(split.second);
264 if(d_bits<32)
265 d_mask=~(0xFFFFFFFF>>d_bits);
266 else
267 d_mask=0xFFFFFFFF;
268 }
269 else if(d_network.sin4.sin_family==AF_INET) {
270 d_bits = 32;
271 d_mask = 0xFFFFFFFF;
272 }
273 else {
274 d_bits=128;
275 d_mask=0; // silence silly warning - d_mask is unused for IPv6
276 }
277 }
278
279 bool match(const ComboAddress& ip) const
280 {
281 return match(&ip);
282 }
283
284 //! If this IP address in socket address matches
285 bool match(const ComboAddress *ip) const
286 {
287 if(d_network.sin4.sin_family != ip->sin4.sin_family) {
288 return false;
289 }
290 if(d_network.sin4.sin_family == AF_INET) {
291 return match4(htonl((unsigned int)ip->sin4.sin_addr.s_addr));
292 }
293 if(d_network.sin6.sin6_family == AF_INET6) {
294 uint8_t bytes=d_bits/8, n;
295 const uint8_t *us=(const uint8_t*) &d_network.sin6.sin6_addr.s6_addr;
296 const uint8_t *them=(const uint8_t*) &ip->sin6.sin6_addr.s6_addr;
297
298 for(n=0; n < bytes; ++n) {
299 if(us[n]!=them[n]) {
300 return false;
301 }
302 }
303 // still here, now match remaining bits
304 uint8_t bits= d_bits % 8;
305 uint8_t mask= ~(0xFF>>bits);
306
307 return((us[n] & mask) == (them[n] & mask));
308 }
309 return false;
310 }
311
312 //! If this ASCII IP address matches
313 bool match(const string &ip) const
314 {
315 ComboAddress address=makeComboAddress(ip);
316 return match(&address);
317 }
318
319 //! If this IP address in native format matches
320 bool match4(uint32_t ip) const
321 {
322 return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
323 }
324
325 string toString() const
326 {
327 return d_network.toString()+"/"+boost::lexical_cast<string>((unsigned int)d_bits);
328 }
329
330 string toStringNoMask() const
331 {
332 return d_network.toString();
333 }
334 const ComboAddress& getNetwork() const
335 {
336 return d_network;
337 }
338 int getBits() const
339 {
340 return d_bits;
341 }
342 bool isIpv6() const
343 {
344 return d_network.sin6.sin6_family == AF_INET6;
345 }
346 bool isIpv4() const
347 {
348 return d_network.sin4.sin_family == AF_INET;
349 }
350
351 bool operator<(const Netmask& rhs) const
352 {
353 return tie(d_network, d_bits) < tie(rhs.d_network, rhs.d_bits);
354 }
355 private:
356 ComboAddress d_network;
357 uint32_t d_mask;
358 uint8_t d_bits;
359 };
360
361 /** This class represents a group of supplemental Netmask classes. An IP address matchs
362 if it is matched by zero or more of the Netmask classes within.
363 */
364 class NetmaskGroup
365 {
366 public:
367 //! If this IP address is matched by any of the classes within
368
369 bool match(const ComboAddress *ip) const
370 {
371 for(container_t::const_iterator i=d_masks.begin();i!=d_masks.end();++i)
372 if(i->match(ip) || (ip->isMappedIPv4() && i->match(ip->mapToIPv4()) ))
373 return true;
374
375 return false;
376 }
377
378 bool match(const ComboAddress& ip) const
379 {
380 return match(&ip);
381 }
382
383 //! Add this Netmask to the list of possible matches
384 void addMask(const string &ip)
385 {
386 d_masks.push_back(Netmask(ip));
387 }
388
389 void clear()
390 {
391 d_masks.clear();
392 }
393
394 bool empty()
395 {
396 return d_masks.empty();
397 }
398
399 unsigned int size()
400 {
401 return (unsigned int)d_masks.size();
402 }
403
404 string toString() const
405 {
406 ostringstream str;
407 for(container_t::const_iterator iter = d_masks.begin(); iter != d_masks.end(); ++iter) {
408 if(iter != d_masks.begin())
409 str <<", ";
410 str<<iter->toString();
411 }
412 return str.str();
413 }
414
415 void toStringVector(vector<string>* vec) const
416 {
417 for(container_t::const_iterator iter = d_masks.begin(); iter != d_masks.end(); ++iter) {
418 vec->push_back(iter->toString());
419 }
420 }
421
422 void toMasks(const string &ips)
423 {
424 vector<string> parts;
425 stringtok(parts, ips, ", \t");
426
427 for (vector<string>::const_iterator iter = parts.begin(); iter != parts.end(); ++iter)
428 addMask(*iter);
429 }
430
431 private:
432 typedef vector<Netmask> container_t;
433 container_t d_masks;
434 };
435
436
437 struct SComboAddress
438 {
439 SComboAddress(const ComboAddress& orig) : ca(orig) {}
440 ComboAddress ca;
441 bool operator<(const SComboAddress& rhs) const
442 {
443 return ComboAddress::addressOnlyLessThan()(ca, rhs.ca);
444 }
445 operator const ComboAddress&()
446 {
447 return ca;
448 }
449 };
450
451
452 int SSocket(int family, int type, int flags);
453 int SConnect(int sockfd, const ComboAddress& remote);
454 int SBind(int sockfd, const ComboAddress& local);
455 int SAccept(int sockfd, ComboAddress& remote);
456 int SListen(int sockfd, int limit);
457 int SSetsockopt(int sockfd, int level, int opname, int value);
458
459 #if defined(IP_PKTINFO)
460 #define GEN_IP_PKTINFO IP_PKTINFO
461 #elif defined(IP_RECVDSTADDR)
462 #define GEN_IP_PKTINFO IP_RECVDSTADDR
463 #endif
464 bool IsAnyAddress(const ComboAddress& addr);
465 bool HarvestDestinationAddress(struct msghdr* msgh, ComboAddress* destination);
466 bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv);
467 void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
468 int sendfromto(int sock, const char* data, int len, int flags, const ComboAddress& from, const ComboAddress& to);
469 #endif