2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 - 2014 PowerDNS.COM BV
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
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.
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.
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
22 #ifndef PDNS_IPUTILSHH
23 #define PDNS_IPUTILSHH
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
32 #include "pdnsexception.hh"
34 #include <sys/socket.h>
37 #include <boost/tuple/tuple.hpp>
38 #include <boost/tuple/tuple_comparison.hpp>
39 #include <boost/lexical_cast.hpp>
41 #include "namespaces.hh"
44 struct sockaddr_in sin4;
45 struct sockaddr_in6 sin6;
47 bool operator==(const ComboAddress& rhs) const
49 if(boost::tie(sin4.sin_family, sin4.sin_port) != boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
51 if(sin4.sin_family == AF_INET)
52 return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
54 return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16)==0;
57 bool operator<(const ComboAddress& rhs) const
59 if(boost::tie(sin4.sin_family, sin4.sin_port) < boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
61 if(boost::tie(sin4.sin_family, sin4.sin_port) > boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
64 if(sin4.sin_family == AF_INET)
65 return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
67 return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16) < 0;
70 bool operator>(const ComboAddress& rhs) const
72 if(boost::tie(sin4.sin_family, sin4.sin_port) > boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
74 if(boost::tie(sin4.sin_family, sin4.sin_port) < boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
77 if(sin4.sin_family == AF_INET)
78 return sin4.sin_addr.s_addr > rhs.sin4.sin_addr.s_addr;
80 return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16) > 0;
83 struct addressOnlyLessThan: public std::binary_function<ComboAddress, ComboAddress, bool>
85 bool operator()(const ComboAddress& a, const ComboAddress& b) const
87 if(a.sin4.sin_family < b.sin4.sin_family)
89 if(a.sin4.sin_family > b.sin4.sin_family)
91 if(a.sin4.sin_family == AF_INET)
92 return a.sin4.sin_addr.s_addr < b.sin4.sin_addr.s_addr;
94 return memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, 16) < 0;
98 struct addressOnlyEqual: public std::binary_function<ComboAddress, ComboAddress, bool>
100 bool operator()(const ComboAddress& a, const ComboAddress& b) const
102 if(a.sin4.sin_family != b.sin4.sin_family)
104 if(a.sin4.sin_family == AF_INET)
105 return a.sin4.sin_addr.s_addr == b.sin4.sin_addr.s_addr;
107 return !memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, 16);
112 socklen_t getSocklen() const
114 if(sin4.sin_family == AF_INET)
122 sin4.sin_family=AF_INET;
123 sin4.sin_addr.s_addr=0;
127 ComboAddress(const struct sockaddr *sa, socklen_t salen) {
128 setSockaddr(sa, salen);
131 ComboAddress(const struct sockaddr_in6 *sa) {
132 setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in6));
135 ComboAddress(const struct sockaddr_in *sa) {
136 setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in));
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);
144 // 'port' sets a default value in case 'str' does not set a port
145 explicit ComboAddress(const string& str, uint16_t port=0)
147 memset(&sin6, 0, sizeof(sin6));
148 sin4.sin_family = AF_INET;
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 +"'");
156 if(!sin4.sin_port) // 'str' overrides port!
157 sin4.sin_port=htons(port);
160 bool isMappedIPv4() const
162 if(sin4.sin_family!=AF_INET6)
166 const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
167 for(n=0; n < 10; ++n)
178 ComboAddress mapToIPv4() const
181 throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
183 ret.sin4.sin_family=AF_INET;
184 ret.sin4.sin_port=sin4.sin_port;
186 const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
188 memcpy(&ret.sin4.sin_addr.s_addr, ptr, 4);
192 string toString() const
195 getnameinfo((struct sockaddr*) this, getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST);
200 string toStringWithPort() const
202 if(sin4.sin_family==AF_INET)
203 return toString() + ":" + boost::lexical_cast<string>(ntohs(sin4.sin_port));
205 return "["+toString() + "]:" + boost::lexical_cast<string>(ntohs(sin4.sin_port));
208 void truncate(unsigned int bits);
211 /** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
212 class NetmaskException: public PDNSException
215 NetmaskException(const string &a) : PDNSException(a) {}
218 inline ComboAddress makeComboAddress(const string& str)
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");
230 /** This class represents a netmask and can be queried to see if a certain
231 IP address is matched by this mask */
237 d_network.sin4.sin_family=0; // disable this doing anything useful
242 Netmask(const ComboAddress& network, uint8_t bits=0xff)
247 bits = (network.sin4.sin_family == AF_INET) ? 32 : 128;
251 d_mask=~(0xFFFFFFFF>>d_bits);
253 d_mask=0xFFFFFFFF; // not actually used for IPv6
256 //! Constructor supplies the mask, which cannot be changed
257 Netmask(const string &mask)
259 pair<string,string> split=splitField(mask,'/');
260 d_network=makeComboAddress(split.first);
262 if(!split.second.empty()) {
263 d_bits = lexical_cast<unsigned int>(split.second);
265 d_mask=~(0xFFFFFFFF>>d_bits);
269 else if(d_network.sin4.sin_family==AF_INET) {
275 d_mask=0; // silence silly warning - d_mask is unused for IPv6
279 bool match(const ComboAddress& ip) const
284 //! If this IP address in socket address matches
285 bool match(const ComboAddress *ip) const
287 if(d_network.sin4.sin_family != ip->sin4.sin_family) {
290 if(d_network.sin4.sin_family == AF_INET) {
291 return match4(htonl((unsigned int)ip->sin4.sin_addr.s_addr));
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;
298 for(n=0; n < bytes; ++n) {
303 // still here, now match remaining bits
304 uint8_t bits= d_bits % 8;
305 uint8_t mask= ~(0xFF>>bits);
307 return((us[n] & mask) == (them[n] & mask));
312 //! If this ASCII IP address matches
313 bool match(const string &ip) const
315 ComboAddress address=makeComboAddress(ip);
316 return match(&address);
319 //! If this IP address in native format matches
320 bool match4(uint32_t ip) const
322 return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
325 string toString() const
327 return d_network.toString()+"/"+boost::lexical_cast<string>((unsigned int)d_bits);
330 string toStringNoMask() const
332 return d_network.toString();
334 const ComboAddress& getNetwork() const
344 return d_network.sin6.sin6_family == AF_INET6;
348 return d_network.sin4.sin_family == AF_INET;
351 bool operator<(const Netmask& rhs) const
353 return tie(d_network, d_bits) < tie(rhs.d_network, rhs.d_bits);
356 ComboAddress d_network;
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.
367 //! If this IP address is matched by any of the classes within
369 bool match(const ComboAddress *ip) const
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()) ))
378 bool match(const ComboAddress& ip) const
383 //! Add this Netmask to the list of possible matches
384 void addMask(const string &ip)
386 d_masks.push_back(Netmask(ip));
396 return d_masks.empty();
401 return (unsigned int)d_masks.size();
404 string toString() const
407 for(container_t::const_iterator iter = d_masks.begin(); iter != d_masks.end(); ++iter) {
408 if(iter != d_masks.begin())
410 str<<iter->toString();
415 void toStringVector(vector<string>* vec) const
417 for(container_t::const_iterator iter = d_masks.begin(); iter != d_masks.end(); ++iter) {
418 vec->push_back(iter->toString());
422 void toMasks(const string &ips)
424 vector<string> parts;
425 stringtok(parts, ips, ", \t");
427 for (vector<string>::const_iterator iter = parts.begin(); iter != parts.end(); ++iter)
432 typedef vector<Netmask> container_t;
439 SComboAddress(const ComboAddress& orig) : ca(orig) {}
441 bool operator<(const SComboAddress& rhs) const
443 return ComboAddress::addressOnlyLessThan()(ca, rhs.ca);
445 operator const ComboAddress&()
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);
459 #if defined(IP_PKTINFO)
460 #define GEN_IP_PKTINFO IP_PKTINFO
461 #elif defined(IP_RECVDSTADDR)
462 #define GEN_IP_PKTINFO IP_RECVDSTADDR
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);