2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 - 2011 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<string, string, 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 socklen_t getSocklen() const
100 if(sin4.sin_family == AF_INET)
108 sin4.sin_family=AF_INET;
109 sin4.sin_addr.s_addr=0;
113 // 'port' sets a default value in case 'str' does not set a port
114 explicit ComboAddress(const string& str, uint16_t port=0)
116 memset(&sin6, 0, sizeof(sin6));
117 sin4.sin_family = AF_INET;
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 +"'");
125 if(!sin4.sin_port) // 'str' overrides port!
126 sin4.sin_port=htons(port);
129 bool isMappedIPv4() const
131 if(sin4.sin_family!=AF_INET6)
135 const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
136 for(n=0; n < 10; ++n)
147 ComboAddress mapToIPv4() const
150 throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
152 ret.sin4.sin_family=AF_INET;
153 ret.sin4.sin_port=sin4.sin_port;
155 const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
157 memcpy(&ret.sin4.sin_addr.s_addr, ptr, 4);
161 string toString() const
164 getnameinfo((struct sockaddr*) this, getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST);
169 string toStringWithPort() const
171 if(sin4.sin_family==AF_INET)
172 return toString() + ":" + boost::lexical_cast<string>(ntohs(sin4.sin_port));
174 return "["+toString() + "]:" + boost::lexical_cast<string>(ntohs(sin4.sin_port));
178 /** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
179 class NetmaskException: public PDNSException
182 NetmaskException(const string &a) : PDNSException(a) {}
185 inline ComboAddress makeComboAddress(const string& str)
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");
197 /** This class represents a netmask and can be queried to see if a certain
198 IP address is matched by this mask */
204 d_network.sin4.sin_family=0; // disable this doing anything useful
207 Netmask(const ComboAddress& network, uint8_t bits=0xff)
212 bits = (network.sin4.sin_family == AF_INET) ? 32 : 128;
216 d_mask=~(0xFFFFFFFF>>d_bits);
218 d_mask=0xFFFFFFFF; // not actually used for IPv6
221 //! Constructor supplies the mask, which cannot be changed
222 Netmask(const string &mask)
224 pair<string,string> split=splitField(mask,'/');
225 d_network=makeComboAddress(split.first);
227 if(!split.second.empty()) {
228 d_bits = lexical_cast<unsigned int>(split.second);
230 d_mask=~(0xFFFFFFFF>>d_bits);
234 else if(d_network.sin4.sin_family==AF_INET) {
240 d_mask=0; // silence silly warning - d_mask is unused for IPv6
244 bool match(const ComboAddress& ip) const
249 //! If this IP address in socket address matches
250 bool match(const ComboAddress *ip) const
252 if(d_network.sin4.sin_family != ip->sin4.sin_family) {
255 if(d_network.sin4.sin_family == AF_INET) {
256 return match4(htonl((unsigned int)ip->sin4.sin_addr.s_addr));
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;
263 for(n=0; n < bytes; ++n) {
268 // still here, now match remaining bits
269 uint8_t bits= d_bits % 8;
270 uint8_t mask= ~(0xFF>>bits);
272 return((us[n] & mask) == (them[n] & mask));
277 //! If this ASCII IP address matches
278 bool match(const string &ip) const
280 ComboAddress address=makeComboAddress(ip);
281 return match(&address);
284 //! If this IP address in native format matches
285 bool match4(uint32_t ip) const
287 return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
290 string toString() const
292 return d_network.toString()+"/"+boost::lexical_cast<string>((unsigned int)d_bits);
295 string toStringNoMask() const
297 return d_network.toString();
299 const ComboAddress& getNetwork() const
308 ComboAddress d_network;
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.
319 //! If this IP address is matched by any of the classes within
321 bool match(const ComboAddress *ip)
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()) ))
330 bool match(const ComboAddress& ip)
335 //! Add this Netmask to the list of possible matches
336 void addMask(const string &ip)
338 d_masks.push_back(Netmask(ip));
343 return d_masks.empty();
348 return (unsigned int)d_masks.size();
351 string toString() const
354 for(container_t::const_iterator iter = d_masks.begin(); iter != d_masks.end(); ++iter) {
355 if(iter != d_masks.begin())
357 str<<iter->toString();
363 typedef vector<Netmask> container_t;
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);