root/trunk/pdns/pdns/iputils.hh @ 2009

Revision 2009, 8.8 KB (checked in by ahu, 2 years ago)

widen allow-axfr-ips to IPv6, plus add query-local-address6 for inbound AXFR & outbound notifications over IPv6

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
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
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18*/
19#ifndef PDNS_IPUTILSHH
20#define PDNS_IPUTILSHH
21
22#include <string>
23
24#ifndef WIN32
25#include <sys/socket.h>
26#include <netinet/in.h>
27#include <arpa/inet.h>
28#endif // WIN32
29
30#include <iostream>
31#include <stdio.h>
32#include <functional>
33#include "ahuexception.hh"
34#include "misc.hh"
35#include <boost/tuple/tuple.hpp>
36#include <boost/tuple/tuple_comparison.hpp>
37#include <boost/lexical_cast.hpp>
38
39#include "namespaces.hh"
40
41union ComboAddress {
42  struct sockaddr_in sin4;
43  struct sockaddr_in6 sin6;
44
45  bool operator==(const ComboAddress& rhs) const
46  {
47    if(boost::tie(sin4.sin_family, sin4.sin_port) != boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
48      return false;
49    if(sin4.sin_family == AF_INET)
50      return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
51    else
52      return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16)==0;
53  }
54
55  bool operator<(const ComboAddress& rhs) const
56  {
57    if(boost::tie(sin4.sin_family, sin4.sin_port) < boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
58      return true;
59    if(boost::tie(sin4.sin_family, sin4.sin_port) > boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
60      return false;
61   
62    if(sin4.sin_family == AF_INET)
63      return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
64    else
65      return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16) < 0;
66  }
67
68  bool operator>(const ComboAddress& rhs) const
69  {
70    if(boost::tie(sin4.sin_family, sin4.sin_port) > boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
71      return true;
72    if(boost::tie(sin4.sin_family, sin4.sin_port) < boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
73      return false;
74   
75    if(sin4.sin_family == AF_INET)
76      return sin4.sin_addr.s_addr > rhs.sin4.sin_addr.s_addr;
77    else
78      return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16) > 0;
79  }
80
81  struct addressOnlyLessThan: public std::binary_function<string, string, bool>
82  {
83    bool operator()(const ComboAddress& a, const ComboAddress& b) const
84    {
85      if(a.sin4.sin_family < b.sin4.sin_family)
86        return true;
87      if(a.sin4.sin_family > b.sin4.sin_family)
88        return false;
89      if(a.sin4.sin_family == AF_INET)
90        return a.sin4.sin_addr.s_addr < b.sin4.sin_addr.s_addr;
91      else
92        return memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, 16) < 0;
93    }
94  };
95
96  socklen_t getSocklen() const
97  {
98    if(sin4.sin_family == AF_INET)
99      return sizeof(sin4);
100    else
101      return sizeof(sin6);
102  }
103 
104  ComboAddress() 
105  {
106    sin4.sin_family=AF_INET;
107    sin4.sin_addr.s_addr=0;
108    sin4.sin_port=0;
109  }
110
111  explicit ComboAddress(const string& str, uint16_t port=0)
112  {
113    memset(&sin6, 0, sizeof(sin6));
114    sin4.sin_family = AF_INET;
115   
116    if(!IpToU32(str, (uint32_t*)&sin4.sin_addr.s_addr)) {
117      sin6.sin6_family = AF_INET6;
118      if(makeIPv6sockaddr(str, &sin6) < 0)
119        throw AhuException("Unable to convert presentation address '"+ str +"'"); 
120     
121    }
122    sin4.sin_port=htons(port);
123  }
124
125  bool isMappedIPv4()  const
126  {
127    if(sin4.sin_family!=AF_INET6)
128      return false;
129   
130    int n=0;
131    const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
132    for(n=0; n < 10; ++n)
133      if(ptr[n])
134        return false;
135   
136    for(; n < 12; ++n)
137      if(ptr[n]!=0xff)
138        return false;
139   
140    return true;
141  }
142 
143  ComboAddress mapToIPv4() const
144  {
145    if(!isMappedIPv4())
146      throw AhuException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
147    ComboAddress ret;
148    ret.sin4.sin_family=AF_INET;
149    ret.sin4.sin_port=sin4.sin_port;
150   
151    const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
152    ptr+=12;
153    memcpy(&ret.sin4.sin_addr.s_addr, ptr, 4);
154    return ret;
155  }
156
157  string toString() const
158  {
159    char tmp[128];
160    if(sin4.sin_family==AF_INET && !Utility::inet_ntop(AF_INET, ( const char * ) &sin4.sin_addr, tmp, sizeof(tmp)))
161      return tmp;
162
163    if(sin4.sin_family==AF_INET6 && !Utility::inet_ntop(AF_INET6, ( const char * ) &sin6.sin6_addr, tmp, sizeof(tmp)))
164      return tmp;
165     
166    return tmp;
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 */
179class NetmaskException: public AhuException
180{
181public:
182  NetmaskException(const string &a) : AhuException(a) {}
183};
184
185inline 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 */
199class Netmask
200{
201public:
202  //! Constructor supplies the mask, which cannot be changed
203  Netmask(const string &mask) 
204  {
205    pair<string,string> split=splitField(mask,'/');
206    d_network=makeComboAddress(split.first);
207   
208    if(!split.second.empty()) {
209      d_bits = (uint8_t) atoi(split.second.c_str());
210      if(d_bits<32)
211        d_mask=~(0xFFFFFFFF>>d_bits);
212      else
213        d_mask=0xFFFFFFFF;
214    }
215    else if(d_network.sin4.sin_family==AF_INET) {
216      d_bits = 32;
217      d_mask = 0xFFFFFFFF;
218    }
219    else {
220      d_bits=128;
221      d_mask=0;  // silence silly warning - d_mask is unused for IPv6
222    }
223  }
224
225  bool match(const ComboAddress& ip) const
226  {
227    return match(&ip);
228  }
229
230  //! If this IP address in socket address matches
231  bool match(const ComboAddress *ip) const
232  {
233    if(d_network.sin4.sin_family != ip->sin4.sin_family) {
234      return false;
235    }
236    if(d_network.sin4.sin_family == AF_INET) {
237      return match4(htonl((unsigned int)ip->sin4.sin_addr.s_addr));
238    }
239    if(d_network.sin6.sin6_family == AF_INET6) {
240      uint8_t bytes=d_bits/8, n;
241      const uint8_t *us=(const uint8_t*) &d_network.sin6.sin6_addr.s6_addr;
242      const uint8_t *them=(const uint8_t*) &ip->sin6.sin6_addr.s6_addr;
243     
244      for(n=0; n < bytes; ++n) {
245        if(us[n]!=them[n]) {
246          return false;
247        }
248      }
249      // still here, now match remaining bits
250      uint8_t bits= d_bits % 8;
251      uint8_t mask= ~(0xFF>>bits);
252
253      return((us[n] & mask) == (them[n] & mask));
254    }
255    return false;
256  }
257
258  //! If this ASCII IP address matches
259  bool match(const string &ip) const
260  {
261    ComboAddress address=makeComboAddress(ip);
262    return match(&address);
263  }
264
265  //! If this IP address in native format matches
266  bool match4(uint32_t ip) const
267  {
268    return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
269  }
270
271  string toString() const
272  {
273    return d_network.toString()+"/"+boost::lexical_cast<string>(d_bits);
274  }
275
276private:
277  ComboAddress d_network;
278  uint32_t d_mask;
279  uint8_t d_bits;
280};
281
282/** This class represents a group of supplemental Netmask classes. An IP address matchs
283    if it is matched by zero or more of the Netmask classes within.
284*/
285class NetmaskGroup
286{
287public:
288  //! If this IP address is matched by any of the classes within
289  bool match(const ComboAddress *ip)
290  {
291    for(container_t::const_iterator i=d_masks.begin();i!=d_masks.end();++i)
292      if(i->match(ip) || (ip->isMappedIPv4() && i->match(ip->mapToIPv4()) ))
293        return true;
294
295    return false;
296  }
297  //! Add this Netmask to the list of possible matches
298  void addMask(const string &ip)
299  {
300    d_masks.push_back(Netmask(ip));
301  }
302 
303  bool empty()
304  {
305    return d_masks.empty();
306  }
307
308  unsigned int size()
309  {
310    return (unsigned int)d_masks.size();
311  }
312
313  string toString() const
314  {
315    ostringstream str;
316    for(container_t::const_iterator iter = d_masks.begin(); iter != d_masks.end(); ++iter) {
317      if(iter != d_masks.begin())
318        str <<", ";
319      str<<iter->toString();
320    }
321    return str.str();
322  }
323
324
325private:
326  typedef vector<Netmask> container_t;
327  container_t d_masks;
328 
329};
330
331#endif
Note: See TracBrowser for help on using the browser.