1dba34e3b1c736f9bc53d2c69abb17226a5a99b4
[public/netxms.git] / src / libnetxms / inetaddr.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Utility Library
4 ** Copyright (C) 2003-2014 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published
8 ** by the Free Software Foundation; either version 3 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: inetaddr.cpp
21 **
22 **/
23
24 #include "libnetxms.h"
25
26 /**
27 * Create IPv4 address object
28 */
29 InetAddress::InetAddress(UINT32 addr)
30 {
31 m_family = AF_INET;
32 m_addr.v4 = addr;
33 m_maskBits = 32;
34 }
35
36 /**
37 * Create IPv6 address object
38 */
39 InetAddress::InetAddress(BYTE *addr)
40 {
41 m_family = AF_INET6;
42 memcpy(m_addr.v6, addr, 16);
43 m_maskBits = 128;
44 }
45
46 /**
47 * Create invalid address object
48 */
49 InetAddress::InetAddress()
50 {
51 m_family = AF_UNSPEC;
52 m_maskBits = 0;
53 }
54
55 /**
56 * Returns true if address is a wildcard address
57 */
58 bool InetAddress::isAnyLocal() const
59 {
60 return (m_family == AF_INET) ? (m_addr.v4 == 0) : !memcmp(m_addr.v6, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
61 }
62
63 /**
64 * Returns true if address is a loopback address
65 */
66 bool InetAddress::isLoopback() const
67 {
68 return (m_family == AF_INET) ? ((m_addr.v4 & 0xFF000000) == 0x7F000000) : !memcmp(m_addr.v6, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16);
69 }
70
71 /**
72 * Returns true if address is a multicast address
73 */
74 bool InetAddress::isMulticast() const
75 {
76 return (m_family == AF_INET) ? ((m_addr.v4 >= 0xE0000000) && (m_addr.v4 != 0xFFFFFFFF)) : (m_addr.v6[0] == 0xFF);
77 }
78
79 /**
80 * Returns true if address is a broadcast address
81 */
82 bool InetAddress::isBroadcast() const
83 {
84 return (m_family == AF_INET) ? (m_addr.v4 == 0xFFFFFFFF) : false;
85 }
86
87 /**
88 * Convert to string
89 */
90 String InetAddress::toString() const
91 {
92 TCHAR buffer[64];
93 String s = (m_family == AF_INET) ? IpToStr(m_addr.v4, buffer) : Ip6ToStr(m_addr.v6, buffer);
94 return s;
95 }
96
97 /**
98 * Convert to string
99 */
100 TCHAR *InetAddress::toString(TCHAR *buffer) const
101 {
102 return (m_family == AF_INET) ? IpToStr(m_addr.v4, buffer) : Ip6ToStr(m_addr.v6, buffer);
103 }
104
105 /**
106 * Build hash key. Supplied array must be at least 18 bytes long.
107 */
108 BYTE *InetAddress::buildHashKey(BYTE *key) const
109 {
110 if (m_family == AF_INET)
111 {
112 key[0] = 6;
113 key[1] = AF_INET;
114 memcpy(&key[2], &m_addr.v4, 4);
115 memset(&key[6], 0, 12);
116 }
117 else
118 {
119 key[0] = 18;
120 key[1] = AF_INET6;
121 memcpy(&key[2], &m_addr.v6, 16);
122 }
123 return key;
124 }
125
126 /**
127 * Get corresponding subnet address for this InetAddress
128 */
129 InetAddress InetAddress::getSubnetAddress()
130 {
131 InetAddress addr(*this);
132 if ((m_family == AF_INET) && (m_maskBits < 32))
133 {
134 addr.m_addr.v4 = m_addr.v4 & (0xFFFFFFFF << (32 - m_maskBits));
135 }
136 else if ((m_family == AF_INET6) && (m_maskBits < 128))
137 {
138 int b = m_maskBits / 8;
139 int shift = m_maskBits % 8;
140 BYTE mask = (shift > 0) ? (BYTE)((1 << (8 - shift)) & 0xFF) : 0;
141 addr.m_addr.v6[b] &= mask;
142 for(int i = b + 1; i < 16; i++)
143 addr.m_addr.v6[i] = 0;
144 }
145 return addr;
146 }
147
148 /**
149 * Check if this InetAddress contain given InetAddress using current network mask
150 */
151 bool InetAddress::contain(const InetAddress &a) const
152 {
153 if (a.m_family != m_family)
154 return false;
155
156 if (m_family == AF_INET)
157 {
158 UINT32 mask = (m_maskBits > 0) ? (0xFFFFFFFF << (32 - m_maskBits)) : 0;
159 return (a.m_addr.v4 & mask) == m_addr.v4;
160 }
161 else
162 {
163 BYTE addr[16];
164 memcpy(addr, a.m_addr.v6, 16);
165 if (m_maskBits < 128)
166 {
167 int b = m_maskBits / 8;
168 int shift = m_maskBits % 8;
169 BYTE mask = (shift > 0) ? (BYTE)((1 << (8 - shift)) & 0xFF) : 0;
170 addr[b] &= mask;
171 for(int i = b + 1; i < 16; i++)
172 addr[i] = 0;
173 }
174 return !memcmp(addr, m_addr.v6, 16);
175 }
176 }
177
178 /**
179 * Check if this InetAddress are in same subnet with given InetAddress
180 */
181 bool InetAddress::sameSubnet(const InetAddress &a) const
182 {
183 if (a.m_family != m_family)
184 return false;
185
186 if (m_family == AF_INET)
187 {
188 UINT32 mask = (m_maskBits > 0) ? (0xFFFFFFFF << (32 - m_maskBits)) : 0;
189 return (a.m_addr.v4 & mask) == (m_addr.v4 & mask);
190 }
191 else
192 {
193 BYTE addr1[16], addr2[16];
194 memcpy(addr1, a.m_addr.v6, 16);
195 memcpy(addr2, m_addr.v6, 16);
196 if (m_maskBits < 128)
197 {
198 int b = m_maskBits / 8;
199 int shift = m_maskBits % 8;
200 BYTE mask = (shift > 0) ? (BYTE)((1 << (8 - shift)) & 0xFF) : 0;
201 addr1[b] &= mask;
202 addr2[b] &= mask;
203 for(int i = b + 1; i < 16; i++)
204 {
205 addr1[i] = 0;
206 addr2[i] = 0;
207 }
208 }
209 return !memcmp(addr1, addr2, 16);
210 }
211 }
212
213 /**
214 * Check if two inet addresses are equals
215 */
216 bool InetAddress::equals(const InetAddress &a) const
217 {
218 if (a.m_family != m_family)
219 return false;
220 return ((m_family == AF_INET) ? (a.m_addr.v4 == m_addr.v4) : !memcmp(a.m_addr.v6, m_addr.v6, 16)) && (a.m_maskBits == m_maskBits);
221 }
222
223 /**
224 * Compare two inet addresses
225 */
226 int InetAddress::compareTo(const InetAddress &a) const
227 {
228 int r = a.m_family - m_family;
229 if (r != 0)
230 return r;
231
232 if (m_family == AF_INET)
233 {
234 return (m_addr.v4 == a.m_addr.v4) ? (m_maskBits - a.m_maskBits) : ((m_addr.v4 < a.m_addr.v4) ? -1 : 1);
235 }
236 else
237 {
238 r = memcmp(a.m_addr.v6, m_addr.v6, 16);
239 return (r == 0) ? (m_maskBits - a.m_maskBits) : r;
240 }
241 }
242
243 /**
244 * Fill sockaddr structure
245 */
246 struct sockaddr *InetAddress::fillSockAddr(SockAddrBuffer *buffer, UINT16 port) const
247 {
248 if (!isValid())
249 return NULL;
250
251 memset(buffer, 0, sizeof(SockAddrBuffer));
252 ((struct sockaddr *)buffer)->sa_family = m_family;
253 if (m_family == AF_INET)
254 {
255 buffer->sa4.sin_addr.s_addr = htonl(m_addr.v4);
256 buffer->sa4.sin_port = htons(port);
257 }
258 else
259 {
260 #ifdef WITH_IPV6
261 memcpy(buffer->sa6.sin6_addr.s6_addr, m_addr.v6, 16);
262 buffer->sa6.sin6_port = htons(port);
263 #else
264 return NULL;
265 #endif
266 }
267 return (struct sockaddr *)buffer;
268 }
269
270 /**
271 * Get host name by IP address
272 *
273 * @param buffer buffer to place host name to
274 * @param buflen buffer length in characters
275 * @return buffer on success, NULL on failure
276 */
277 TCHAR *InetAddress::getHostByAddr(TCHAR *buffer, size_t buflen) const
278 {
279 if (!isValid())
280 return NULL;
281
282 struct hostent *hs = NULL;
283 if (m_family == AF_INET)
284 {
285 UINT32 addr = htonl(m_addr.v4);
286 hs = gethostbyaddr((const char *)&addr, 4, AF_INET);
287 }
288 else
289 {
290 hs = gethostbyaddr((const char *)m_addr.v6, 16, AF_INET6);
291 }
292
293 if (hs == NULL)
294 return NULL;
295
296 #ifdef UNICODE
297 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, hs->h_name, -1, buffer, (int)buflen);
298 buffer[buflen - 1] = 0;
299 #else
300 nx_strncpy(buffer, hs->h_name, buflen);
301 #endif
302
303 return buffer;
304 }
305
306 /**
307 * Resolve hostname
308 */
309 InetAddress InetAddress::resolveHostName(const WCHAR *hostname, int af)
310 {
311 char mbName[256];
312 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, hostname, -1, mbName, 256, NULL, NULL);
313 return resolveHostName(mbName, af);
314 }
315
316 /**
317 * Resolve hostname
318 */
319 InetAddress InetAddress::resolveHostName(const char *hostname, int af)
320 {
321 InetAddress addr = parse(hostname);
322 if (addr.isValid())
323 return addr;
324
325 // Not a valid IP address, resolve hostname
326 #if HAVE_GETHOSTBYNAME2_R
327 struct hostent h, *hs = NULL;
328 char buffer[1024];
329 int err;
330 gethostbyname2_r(hostname, af, &h, buffer, 1024, &hs, &err);
331 #else
332 struct hostent *hs = gethostbyname(hostname);
333 #endif
334 if (hs != NULL)
335 {
336 if (hs->h_addrtype == AF_INET)
337 {
338 return InetAddress(ntohl(*((UINT32 *)hs->h_addr)));
339 }
340 else if (hs->h_addrtype == AF_INET6)
341 {
342 return InetAddress((BYTE *)hs->h_addr);
343 }
344 }
345 return InetAddress();
346 }
347
348 /**
349 * Parse string as IP address
350 */
351 InetAddress InetAddress::parse(const WCHAR *str)
352 {
353 char mb[256];
354 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, str, -1, mb, 256, NULL, NULL);
355 return parse(mb);
356 }
357
358 /**
359 * Parse string as IP address
360 */
361 InetAddress InetAddress::parse(const char *str)
362 {
363 // Check for IPv4 address
364 #ifdef _WIN32
365 char strCopy[256];
366 strncpy(strCopy, str, 255);
367
368 struct sockaddr_in addr4;
369 addr4.sin_family = AF_INET;
370 INT addrLen = sizeof(addr4);
371 if (WSAStringToAddressA(strCopy, AF_INET, NULL, (struct sockaddr *)&addr4, &addrLen) == 0)
372 {
373 return InetAddress(ntohl(addr4.sin_addr.s_addr));
374 }
375 #else
376 struct in_addr addr4;
377 if (inet_aton(str, &addr4))
378 {
379 return InetAddress(ntohl(addr4.s_addr));
380 }
381 #endif
382
383 // Check for IPv6 address
384 #if defined(_WIN32)
385 struct sockaddr_in6 addr6;
386 addr6.sin6_family = AF_INET6;
387 addrLen = sizeof(addr6);
388 if (WSAStringToAddressA(strCopy, AF_INET6, NULL, (struct sockaddr *)&addr6, &addrLen) == 0)
389 {
390 return InetAddress(addr6.sin6_addr.u.Byte);
391 }
392 #elif defined(WITH_IPV6)
393 struct in6_addr addr6;
394 if (inet_pton(AF_INET6, str, &addr6))
395 {
396 return InetAddress(addr6.s6_addr);
397 }
398 #endif
399 return InetAddress();
400 }
401
402 /**
403 * Create IndetAddress from struct sockaddr
404 */
405 InetAddress InetAddress::createFromSockaddr(struct sockaddr *s)
406 {
407 if (s->sa_family == AF_INET)
408 return InetAddress(ntohl(((struct sockaddr_in *)s)->sin_addr.s_addr));
409 #ifdef WITH_IPV6
410 if (s->sa_family == AF_INET6)
411 return InetAddress(((struct sockaddr_in6 *)s)->sin6_addr.s6_addr);
412 #endif
413 return InetAddress();
414 }