]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/iputils.hh
Merge branch 'master' into ednssubnet
[thirdparty/pdns.git] / pdns / iputils.hh
CommitLineData
12c86877
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
2c78bd57 3 Copyright (C) 2002 - 2014 PowerDNS.COM BV
12c86877
BH
4
5 This program is free software; you can redistribute it and/or modify
22dc646a
BH
6 it under the terms of the GNU General Public License version 2
7 as published by the Free Software Foundation
f782fe38
MH
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.
12c86877
BH
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
06bd9ccf 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877
BH
21*/
22#ifndef PDNS_IPUTILSHH
23#define PDNS_IPUTILSHH
24
25#include <string>
092f210a
BH
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
12c86877
BH
29#include <iostream>
30#include <stdio.h>
31#include <functional>
5c409fa2 32#include "pdnsexception.hh"
809fe23f 33#include "misc.hh"
506a9050
BH
34#include <sys/socket.h>
35#include <netdb.h>
36
fd4ed0ab
BH
37#include <boost/tuple/tuple.hpp>
38#include <boost/tuple/tuple_comparison.hpp>
b8c3ea84 39#include <boost/lexical_cast.hpp>
fd4ed0ab 40
10f4eea8 41#include "namespaces.hh"
12c86877 42
37d3f960
BH
43union ComboAddress {
44 struct sockaddr_in sin4;
45 struct sockaddr_in6 sin6;
46
fd4ed0ab
BH
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
37d3f960
BH
57 bool operator<(const ComboAddress& rhs) const
58 {
fd4ed0ab 59 if(boost::tie(sin4.sin_family, sin4.sin_port) < boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
37d3f960 60 return true;
fd4ed0ab 61 if(boost::tie(sin4.sin_family, sin4.sin_port) > boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
37d3f960
BH
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
9bdaa2e1 67 return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16) < 0;
37d3f960
BH
68 }
69
fd4ed0ab
BH
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
662d5441 83 struct addressOnlyLessThan: public std::binary_function<ComboAddress, ComboAddress, bool>
11a7242f
BH
84 {
85 bool operator()(const ComboAddress& a, const ComboAddress& b) const
86 {
87 if(a.sin4.sin_family < b.sin4.sin_family)
4957a608 88 return true;
11a7242f 89 if(a.sin4.sin_family > b.sin4.sin_family)
4957a608 90 return false;
11a7242f 91 if(a.sin4.sin_family == AF_INET)
4957a608 92 return a.sin4.sin_addr.s_addr < b.sin4.sin_addr.s_addr;
11a7242f 93 else
4957a608 94 return memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, 16) < 0;
11a7242f
BH
95 }
96 };
fd4ed0ab 97
0940e4eb 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
fd4ed0ab 112 socklen_t getSocklen() const
a9af3782
BH
113 {
114 if(sin4.sin_family == AF_INET)
115 return sizeof(sin4);
116 else
117 return sizeof(sin6);
118 }
fd4ed0ab
BH
119
120 ComboAddress()
121 {
122 sin4.sin_family=AF_INET;
123 sin4.sin_addr.s_addr=0;
124 sin4.sin_port=0;
125 }
126
a7360cd9
AT
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
85db02c5 144 // 'port' sets a default value in case 'str' does not set a port
fd4ed0ab
BH
145 explicit ComboAddress(const string& str, uint16_t port=0)
146 {
147 memset(&sin6, 0, sizeof(sin6));
148 sin4.sin_family = AF_INET;
85db02c5
BH
149 sin4.sin_port = 0;
150 if(makeIPv4sockaddr(str, &sin4)) {
fd4ed0ab 151 sin6.sin6_family = AF_INET6;
f71bc087 152 if(makeIPv6sockaddr(str, &sin6) < 0)
3f81d239 153 throw PDNSException("Unable to convert presentation address '"+ str +"'");
b03c5a46 154
fd4ed0ab 155 }
85db02c5
BH
156 if(!sin4.sin_port) // 'str' overrides port!
157 sin4.sin_port=htons(port);
fd4ed0ab 158 }
a9af3782 159
eb5bae86 160 bool isMappedIPv4() const
2914b022
BH
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])
4957a608 169 return false;
2914b022
BH
170
171 for(; n < 12; ++n)
172 if(ptr[n]!=0xff)
4957a608 173 return false;
2914b022
BH
174
175 return true;
176 }
177
eb5bae86 178 ComboAddress mapToIPv4() const
2914b022
BH
179 {
180 if(!isMappedIPv4())
3f81d239 181 throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
2914b022
BH
182 ComboAddress ret;
183 ret.sin4.sin_family=AF_INET;
11a7242f 184 ret.sin4.sin_port=sin4.sin_port;
2914b022
BH
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
37d3f960
BH
192 string toString() const
193 {
506a9050
BH
194 char host[1024];
195 getnameinfo((struct sockaddr*) this, getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST);
37d3f960 196
506a9050 197 return host;
37d3f960 198 }
b8c3ea84
BH
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 }
22779196 207
208 void truncate(unsigned int bits);
37d3f960
BH
209};
210
12c86877 211/** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
3f81d239 212class NetmaskException: public PDNSException
12c86877
BH
213{
214public:
3f81d239 215 NetmaskException(const string &a) : PDNSException(a) {}
12c86877
BH
216};
217
37d3f960
BH
218inline ComboAddress makeComboAddress(const string& str)
219{
220 ComboAddress address;
221 address.sin4.sin_family=AF_INET;
1e77c17c 222 if(inet_pton(AF_INET, str.c_str(), &address.sin4.sin_addr) <= 0) {
37d3f960 223 address.sin4.sin_family=AF_INET6;
f71bc087 224 if(makeIPv6sockaddr(str, &address.sin6) < 0)
4957a608 225 throw NetmaskException("Unable to convert '"+str+"' to a netmask");
37d3f960
BH
226 }
227 return address;
228}
229
12c86877
BH
230/** This class represents a netmask and can be queried to see if a certain
231 IP address is matched by this mask */
12c86877
BH
232class Netmask
233{
234public:
6f97329b
BH
235 Netmask()
236 {
237 d_network.sin4.sin_family=0; // disable this doing anything useful
2fd2d93c
AT
238 d_mask=0;
239 d_bits=0;
6f97329b
BH
240 }
241
a4c8835f 242 Netmask(const ComboAddress& network, uint8_t bits=0xff)
6f97329b
BH
243 {
244 d_network = network;
a4c8835f
BH
245
246 if(bits == 0xff)
247 bits = (network.sin4.sin_family == AF_INET) ? 32 : 128;
248
6f97329b
BH
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
12c86877
BH
256 //! Constructor supplies the mask, which cannot be changed
257 Netmask(const string &mask)
258 {
37d3f960
BH
259 pair<string,string> split=splitField(mask,'/');
260 d_network=makeComboAddress(split.first);
261
262 if(!split.second.empty()) {
8ac6bd6d 263 d_bits = lexical_cast<unsigned int>(split.second);
37d3f960 264 if(d_bits<32)
4957a608 265 d_mask=~(0xFFFFFFFF>>d_bits);
8519b8a2 266 else
4957a608 267 d_mask=0xFFFFFFFF;
37d3f960
BH
268 }
269 else if(d_network.sin4.sin_family==AF_INET) {
270 d_bits = 32;
271 d_mask = 0xFFFFFFFF;
272 }
5c1def57 273 else {
37d3f960 274 d_bits=128;
5c1def57
BH
275 d_mask=0; // silence silly warning - d_mask is unused for IPv6
276 }
12c86877
BH
277 }
278
2914b022
BH
279 bool match(const ComboAddress& ip) const
280 {
281 return match(&ip);
282 }
283
12c86877 284 //! If this IP address in socket address matches
37d3f960 285 bool match(const ComboAddress *ip) const
12c86877 286 {
37d3f960
BH
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) {
4957a608
BH
299 if(us[n]!=them[n]) {
300 return false;
301 }
37d3f960
BH
302 }
303 // still here, now match remaining bits
f0739fb6 304 uint8_t bits= d_bits % 8;
37d3f960 305 uint8_t mask= ~(0xFF>>bits);
f0739fb6 306
37d3f960
BH
307 return((us[n] & mask) == (them[n] & mask));
308 }
309 return false;
12c86877
BH
310 }
311
312 //! If this ASCII IP address matches
313 bool match(const string &ip) const
314 {
37d3f960
BH
315 ComboAddress address=makeComboAddress(ip);
316 return match(&address);
12c86877
BH
317 }
318
319 //! If this IP address in native format matches
37d3f960 320 bool match4(uint32_t ip) const
12c86877 321 {
37d3f960 322 return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
12c86877
BH
323 }
324
2c95fc65
BH
325 string toString() const
326 {
6f97329b 327 return d_network.toString()+"/"+boost::lexical_cast<string>((unsigned int)d_bits);
2c95fc65
BH
328 }
329
a4c8835f
BH
330 string toStringNoMask() const
331 {
332 return d_network.toString();
333 }
9f84a557 334 const ComboAddress& getNetwork() const
a4c8835f
BH
335 {
336 return d_network;
337 }
338 int getBits() const
339 {
340 return d_bits;
341 }
709ca59f
AT
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 }
644dd1da 350
351 bool operator<(const Netmask& rhs) const
352 {
353 return tie(d_network, d_bits) < tie(rhs.d_network, rhs.d_bits);
354 }
39ec5d29 355
356 bool operator==(const Netmask& rhs) const
357 {
358 return tie(d_network, d_bits) == tie(rhs.d_network, rhs.d_bits);
359 }
360
12c86877 361private:
37d3f960 362 ComboAddress d_network;
092f210a 363 uint32_t d_mask;
37d3f960 364 uint8_t d_bits;
12c86877
BH
365};
366
367/** This class represents a group of supplemental Netmask classes. An IP address matchs
368 if it is matched by zero or more of the Netmask classes within.
369*/
370class NetmaskGroup
371{
372public:
373 //! If this IP address is matched by any of the classes within
60af67b8 374
1e77c17c 375 bool match(const ComboAddress *ip) const
12c86877
BH
376 {
377 for(container_t::const_iterator i=d_masks.begin();i!=d_masks.end();++i)
2914b022 378 if(i->match(ip) || (ip->isMappedIPv4() && i->match(ip->mapToIPv4()) ))
4957a608 379 return true;
12c86877
BH
380
381 return false;
382 }
60af67b8 383
1e77c17c 384 bool match(const ComboAddress& ip) const
60af67b8 385 {
386 return match(&ip);
387 }
388
12c86877
BH
389 //! Add this Netmask to the list of possible matches
390 void addMask(const string &ip)
391 {
392 d_masks.push_back(Netmask(ip));
393 }
68b011bd
KM
394
395 void clear()
396 {
397 d_masks.clear();
398 }
399
12c86877
BH
400 bool empty()
401 {
402 return d_masks.empty();
403 }
404
2c95fc65
BH
405 unsigned int size()
406 {
407 return (unsigned int)d_masks.size();
408 }
409
410 string toString() const
411 {
412 ostringstream str;
413 for(container_t::const_iterator iter = d_masks.begin(); iter != d_masks.end(); ++iter) {
414 if(iter != d_masks.begin())
4957a608 415 str <<", ";
2c95fc65
BH
416 str<<iter->toString();
417 }
418 return str.str();
419 }
420
41942bb3
CH
421 void toStringVector(vector<string>* vec) const
422 {
423 for(container_t::const_iterator iter = d_masks.begin(); iter != d_masks.end(); ++iter) {
424 vec->push_back(iter->toString());
425 }
426 }
427
68b011bd
KM
428 void toMasks(const string &ips)
429 {
430 vector<string> parts;
431 stringtok(parts, ips, ", \t");
432
433 for (vector<string>::const_iterator iter = parts.begin(); iter != parts.end(); ++iter)
434 addMask(*iter);
435 }
436
12c86877
BH
437private:
438 typedef vector<Netmask> container_t;
68b011bd 439 container_t d_masks;
12c86877
BH
440};
441
002c970a 442
60c8afa8 443struct SComboAddress
444{
445 SComboAddress(const ComboAddress& orig) : ca(orig) {}
446 ComboAddress ca;
447 bool operator<(const SComboAddress& rhs) const
448 {
449 return ComboAddress::addressOnlyLessThan()(ca, rhs.ca);
450 }
451 operator const ComboAddress&()
452 {
453 return ca;
454 }
455};
456
457
002c970a 458int SSocket(int family, int type, int flags);
459int SConnect(int sockfd, const ComboAddress& remote);
460int SBind(int sockfd, const ComboAddress& local);
461int SAccept(int sockfd, ComboAddress& remote);
462int SListen(int sockfd, int limit);
463int SSetsockopt(int sockfd, int level, int opname, int value);
464
3e3f0358 465#if defined(IP_PKTINFO)
466 #define GEN_IP_PKTINFO IP_PKTINFO
467#elif defined(IP_RECVDSTADDR)
468 #define GEN_IP_PKTINFO IP_RECVDSTADDR
469#endif
470bool IsAnyAddress(const ComboAddress& addr);
471bool HarvestDestinationAddress(struct msghdr* msgh, ComboAddress* destination);
472bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv);
b71b60ee 473void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
549d63c9 474int sendfromto(int sock, const char* data, int len, int flags, const ComboAddress& from, const ComboAddress& to);
12c86877 475#endif