Use ZERO_STRUCTP
[nivanova/samba-autobuild/.git] / lib / util / util_net.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
5    Copyright (C) Andrew Tridgell 1992-1998
6    Copyright (C) Jeremy Allison  1992-2007
7    Copyright (C) Simo Sorce 2001
8    Copyright (C) Jim McDonough (jmcd@us.ibm.com)  2003.
9    Copyright (C) James J Myers 2003
10    Copyright (C) Tim Potter      2000-2001
11     
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16    
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21    
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "system/network.h"
28 #include "system/locale.h"
29 #include "system/filesys.h"
30 #undef strcasecmp
31
32 /*******************************************************************
33  Set an address to INADDR_ANY.
34 ******************************************************************/
35
36 void zero_sockaddr(struct sockaddr_storage *pss)
37 {
38         ZERO_STRUCTP(pss);
39         /* Ensure we're at least a valid sockaddr-storage. */
40         pss->ss_family = AF_INET;
41 }
42
43 /**
44  * Wrap getaddrinfo...
45  */
46 bool interpret_string_addr_internal(struct addrinfo **ppres,
47                                         const char *str, int flags)
48 {
49         int ret;
50         struct addrinfo hints;
51
52         memset(&hints, '\0', sizeof(hints));
53         /* By default make sure it supports TCP. */
54         hints.ai_socktype = SOCK_STREAM;
55         hints.ai_flags = flags;
56
57         /* Linux man page on getaddrinfo() says port will be
58            uninitialized when service string in NULL */
59
60         ret = getaddrinfo(str, NULL,
61                         &hints,
62                         ppres);
63
64         if (ret) {
65                 DEBUG(3,("interpret_string_addr_internal: getaddrinfo failed "
66                         "for name %s [%s]\n",
67                         str,
68                         gai_strerror(ret) ));
69                 return false;
70         }
71         return true;
72 }
73
74 /*******************************************************************
75  Map a text hostname or IP address (IPv4 or IPv6) into a
76  struct sockaddr_storage. Takes a flag which allows it to
77  prefer an IPv4 address (needed for DC's).
78 ******************************************************************/
79
80 static bool interpret_string_addr_pref(struct sockaddr_storage *pss,
81                 const char *str,
82                 int flags,
83                 bool prefer_ipv4)
84 {
85         struct addrinfo *res = NULL;
86 #if defined(HAVE_IPV6)
87         char addr[INET6_ADDRSTRLEN];
88         unsigned int scope_id = 0;
89
90         if (strchr_m(str, ':')) {
91                 char *p = strchr_m(str, '%');
92
93                 /*
94                  * Cope with link-local.
95                  * This is IP:v6:addr%ifname.
96                  */
97
98                 if (p && (p > str) && ((scope_id = if_nametoindex(p+1)) != 0)) {
99                         strlcpy(addr, str,
100                                 MIN(PTR_DIFF(p,str)+1,
101                                         sizeof(addr)));
102                         str = addr;
103                 }
104         }
105 #endif
106
107         zero_sockaddr(pss);
108
109         if (!interpret_string_addr_internal(&res, str, flags|AI_ADDRCONFIG)) {
110                 return false;
111         }
112         if (!res) {
113                 return false;
114         }
115
116         if (prefer_ipv4) {
117                 struct addrinfo *p;
118
119                 for (p = res; p; p = p->ai_next) {
120                         if (p->ai_family == AF_INET) {
121                                 memcpy(pss, p->ai_addr, p->ai_addrlen);
122                                 break;
123                         }
124                 }
125                 if (p == NULL) {
126                         /* Copy the first sockaddr. */
127                         memcpy(pss, res->ai_addr, res->ai_addrlen);
128                 }
129         } else {
130                 /* Copy the first sockaddr. */
131                 memcpy(pss, res->ai_addr, res->ai_addrlen);
132         }
133
134 #if defined(HAVE_IPV6)
135         if (pss->ss_family == AF_INET6 && scope_id) {
136                 struct sockaddr_in6 *ps6 = (struct sockaddr_in6 *)pss;
137                 if (IN6_IS_ADDR_LINKLOCAL(&ps6->sin6_addr) &&
138                                 ps6->sin6_scope_id == 0) {
139                         ps6->sin6_scope_id = scope_id;
140                 }
141         }
142 #endif
143
144         freeaddrinfo(res);
145         return true;
146 }
147
148 /*******************************************************************
149  Map a text hostname or IP address (IPv4 or IPv6) into a
150  struct sockaddr_storage. Address agnostic version.
151 ******************************************************************/
152
153 bool interpret_string_addr(struct sockaddr_storage *pss,
154                 const char *str,
155                 int flags)
156 {
157         return interpret_string_addr_pref(pss,
158                                         str,
159                                         flags,
160                                         false);
161 }
162
163 /*******************************************************************
164  Map a text hostname or IP address (IPv4 or IPv6) into a
165  struct sockaddr_storage. Version that prefers IPv4.
166 ******************************************************************/
167
168 bool interpret_string_addr_prefer_ipv4(struct sockaddr_storage *pss,
169                 const char *str,
170                 int flags)
171 {
172         return interpret_string_addr_pref(pss,
173                                         str,
174                                         flags,
175                                         true);
176 }
177
178 /**
179  * Interpret an internet address or name into an IP address in 4 byte form.
180  * RETURNS IN NETWORK BYTE ORDER (big endian).
181  */
182
183 uint32_t interpret_addr(const char *str)
184 {
185         uint32_t ret;
186
187         /* If it's in the form of an IP address then
188          * get the lib to interpret it */
189         if (is_ipaddress_v4(str)) {
190                 struct in_addr dest;
191
192                 if (inet_pton(AF_INET, str, &dest) <= 0) {
193                         /* Error - this shouldn't happen ! */
194                         DEBUG(0,("interpret_addr: inet_pton failed "
195                                 "host %s\n",
196                                 str));
197                         return 0;
198                 }
199                 ret = dest.s_addr; /* NETWORK BYTE ORDER ! */
200         } else {
201                 /* Otherwise assume it's a network name of some sort and use
202                         getadddrinfo. */
203                 struct addrinfo *res = NULL;
204                 struct addrinfo *res_list = NULL;
205                 if (!interpret_string_addr_internal(&res_list,
206                                         str,
207                                         AI_ADDRCONFIG)) {
208                         DEBUG(3,("interpret_addr: Unknown host. %s\n",str));
209                         return 0;
210                 }
211
212                 /* Find the first IPv4 address. */
213                 for (res = res_list; res; res = res->ai_next) {
214                         if (res->ai_family != AF_INET) {
215                                 continue;
216                         }
217                         if (res->ai_addr == NULL) {
218                                 continue;
219                         }
220                         break;
221                 }
222                 if(res == NULL) {
223                         DEBUG(3,("interpret_addr: host address is "
224                                 "invalid for host %s\n",str));
225                         if (res_list) {
226                                 freeaddrinfo(res_list);
227                         }
228                         return 0;
229                 }
230                 memcpy((char *)&ret,
231                         &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr,
232                         sizeof(ret));
233                 if (res_list) {
234                         freeaddrinfo(res_list);
235                 }
236         }
237
238         /* This is so bogus - all callers need fixing... JRA. */
239         if (ret == (uint32_t)-1) {
240                 return 0;
241         }
242
243         return ret;
244 }
245
246 /**
247  A convenient addition to interpret_addr().
248 **/
249 _PUBLIC_ struct in_addr interpret_addr2(const char *str)
250 {
251         struct in_addr ret;
252         uint32_t a = interpret_addr(str);
253         ret.s_addr = a;
254         return ret;
255 }
256
257 /**
258  Check if an IP is the 0.0.0.0.
259 **/
260
261 _PUBLIC_ bool is_zero_ip_v4(struct in_addr ip)
262 {
263         return ip.s_addr == 0;
264 }
265
266 /**
267  Are two IPs on the same subnet?
268 **/
269
270 _PUBLIC_ bool same_net_v4(struct in_addr ip1, struct in_addr ip2, struct in_addr mask)
271 {
272         uint32_t net1,net2,nmask;
273
274         nmask = ntohl(mask.s_addr);
275         net1  = ntohl(ip1.s_addr);
276         net2  = ntohl(ip2.s_addr);
277             
278         return((net1 & nmask) == (net2 & nmask));
279 }
280
281 /**
282  * Return true if a string could be an IPv4 address.
283  */
284
285 bool is_ipaddress_v4(const char *str)
286 {
287         int ret = -1;
288         struct in_addr dest;
289
290         ret = inet_pton(AF_INET, str, &dest);
291         if (ret > 0) {
292                 return true;
293         }
294         return false;
295 }
296
297 /**
298  * Return true if a string could be an IPv4 or IPv6 address.
299  */
300
301 bool is_ipaddress(const char *str)
302 {
303 #if defined(HAVE_IPV6)
304         int ret = -1;
305
306         if (strchr_m(str, ':')) {
307                 char addr[INET6_ADDRSTRLEN];
308                 struct in6_addr dest6;
309                 const char *sp = str;
310                 char *p = strchr_m(str, '%');
311
312                 /*
313                  * Cope with link-local.
314                  * This is IP:v6:addr%ifname.
315                  */
316
317                 if (p && (p > str) && (if_nametoindex(p+1) != 0)) {
318                         strlcpy(addr, str,
319                                 MIN(PTR_DIFF(p,str)+1,
320                                         sizeof(addr)));
321                         sp = addr;
322                 }
323                 ret = inet_pton(AF_INET6, sp, &dest6);
324                 if (ret > 0) {
325                         return true;
326                 }
327         }
328 #endif
329         return is_ipaddress_v4(str);
330 }
331
332 /**
333  * Is a sockaddr a broadcast address ?
334  */
335
336 bool is_broadcast_addr(const struct sockaddr *pss)
337 {
338 #if defined(HAVE_IPV6)
339         if (pss->sa_family == AF_INET6) {
340                 const struct in6_addr *sin6 =
341                         &((const struct sockaddr_in6 *)pss)->sin6_addr;
342                 return IN6_IS_ADDR_MULTICAST(sin6);
343         }
344 #endif
345         if (pss->sa_family == AF_INET) {
346                 uint32_t addr =
347                 ntohl(((const struct sockaddr_in *)pss)->sin_addr.s_addr);
348                 return addr == INADDR_BROADCAST;
349         }
350         return false;
351 }
352
353 /**
354  * Check if an IPv7 is 127.0.0.1
355  */
356 bool is_loopback_ip_v4(struct in_addr ip)
357 {
358         struct in_addr a;
359         a.s_addr = htonl(INADDR_LOOPBACK);
360         return(ip.s_addr == a.s_addr);
361 }
362
363 /**
364  * Check if a struct sockaddr is the loopback address.
365  */
366 bool is_loopback_addr(const struct sockaddr *pss)
367 {
368 #if defined(HAVE_IPV6)
369         if (pss->sa_family == AF_INET6) {
370                 const struct in6_addr *pin6 =
371                         &((const struct sockaddr_in6 *)pss)->sin6_addr;
372                 return IN6_IS_ADDR_LOOPBACK(pin6);
373         }
374 #endif
375         if (pss->sa_family == AF_INET) {
376                 const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
377                 return is_loopback_ip_v4(*pin);
378         }
379         return false;
380 }
381
382 /**
383  * Check if a struct sockaddr has an unspecified address.
384  */
385 bool is_zero_addr(const struct sockaddr *pss)
386 {
387 #if defined(HAVE_IPV6)
388         if (pss->sa_family == AF_INET6) {
389                 const struct in6_addr *pin6 =
390                         &((const struct sockaddr_in6 *)pss)->sin6_addr;
391                 return IN6_IS_ADDR_UNSPECIFIED(pin6);
392         }
393 #endif
394         if (pss->sa_family == AF_INET) {
395                 const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
396                 return is_zero_ip_v4(*pin);
397         }
398         return false;
399 }
400
401 /**
402  * Set an IP to 0.0.0.0.
403  */
404 void zero_ip_v4(struct in_addr *ip)
405 {
406         memset(ip, '\0', sizeof(struct in_addr));
407 }
408
409 /**
410  * Convert an IPv4 struct in_addr to a struct sockaddr_storage.
411  */
412 void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
413                 struct in_addr ip)
414 {
415         struct sockaddr_in *sa = (struct sockaddr_in *)ss;
416         memset(ss, '\0', sizeof(*ss));
417         sa->sin_family = AF_INET;
418         sa->sin_addr = ip;
419 }
420
421 #if defined(HAVE_IPV6)
422 /**
423  * Convert an IPv6 struct in_addr to a struct sockaddr_storage.
424  */
425 void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
426                 struct in6_addr ip)
427 {
428         struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ss;
429         memset(ss, '\0', sizeof(*ss));
430         sa->sin6_family = AF_INET6;
431         sa->sin6_addr = ip;
432 }
433 #endif
434
435 /**
436  * Are two IPs on the same subnet?
437  */
438 bool same_net(const struct sockaddr *ip1,
439                 const struct sockaddr *ip2,
440                 const struct sockaddr *mask)
441 {
442         if (ip1->sa_family != ip2->sa_family) {
443                 /* Never on the same net. */
444                 return false;
445         }
446
447 #if defined(HAVE_IPV6)
448         if (ip1->sa_family == AF_INET6) {
449                 struct sockaddr_in6 ip1_6 = *(const struct sockaddr_in6 *)ip1;
450                 struct sockaddr_in6 ip2_6 = *(const struct sockaddr_in6 *)ip2;
451                 struct sockaddr_in6 mask_6 = *(const struct sockaddr_in6 *)mask;
452                 char *p1 = (char *)&ip1_6.sin6_addr;
453                 char *p2 = (char *)&ip2_6.sin6_addr;
454                 char *m = (char *)&mask_6.sin6_addr;
455                 int i;
456
457                 for (i = 0; i < sizeof(struct in6_addr); i++) {
458                         *p1++ &= *m;
459                         *p2++ &= *m;
460                         m++;
461                 }
462                 return (memcmp(&ip1_6.sin6_addr,
463                                 &ip2_6.sin6_addr,
464                                 sizeof(struct in6_addr)) == 0);
465         }
466 #endif
467         if (ip1->sa_family == AF_INET) {
468                 return same_net_v4(((const struct sockaddr_in *)ip1)->sin_addr,
469                                 ((const struct sockaddr_in *)ip2)->sin_addr,
470                                 ((const struct sockaddr_in *)mask)->sin_addr);
471         }
472         return false;
473 }
474
475 /**
476  * Are two sockaddr 's the same family and address ? Ignore port etc.
477  */
478
479 bool sockaddr_equal(const struct sockaddr *ip1,
480                 const struct sockaddr *ip2)
481 {
482         if (ip1->sa_family != ip2->sa_family) {
483                 /* Never the same. */
484                 return false;
485         }
486
487 #if defined(HAVE_IPV6)
488         if (ip1->sa_family == AF_INET6) {
489                 return (memcmp(&((const struct sockaddr_in6 *)ip1)->sin6_addr,
490                                 &((const struct sockaddr_in6 *)ip2)->sin6_addr,
491                                 sizeof(struct in6_addr)) == 0);
492         }
493 #endif
494         if (ip1->sa_family == AF_INET) {
495                 return (memcmp(&((const struct sockaddr_in *)ip1)->sin_addr,
496                                 &((const struct sockaddr_in *)ip2)->sin_addr,
497                                 sizeof(struct in_addr)) == 0);
498         }
499         return false;
500 }
501
502 /**
503  * Is an IP address the INADDR_ANY or in6addr_any value ?
504  */
505 bool is_address_any(const struct sockaddr *psa)
506 {
507 #if defined(HAVE_IPV6)
508         if (psa->sa_family == AF_INET6) {
509                 const struct sockaddr_in6 *si6 = (const struct sockaddr_in6 *)psa;
510                 if (memcmp(&in6addr_any,
511                                 &si6->sin6_addr,
512                                 sizeof(in6addr_any)) == 0) {
513                         return true;
514                 }
515                 return false;
516         }
517 #endif
518         if (psa->sa_family == AF_INET) {
519                 const struct sockaddr_in *si = (const struct sockaddr_in *)psa;
520                 if (si->sin_addr.s_addr == INADDR_ANY) {
521                         return true;
522                 }
523                 return false;
524         }
525         return false;
526 }
527
528 void set_sockaddr_port(struct sockaddr *psa, uint16_t port)
529 {
530 #if defined(HAVE_IPV6)
531         if (psa->sa_family == AF_INET6) {
532                 ((struct sockaddr_in6 *)psa)->sin6_port = htons(port);
533         }
534 #endif
535         if (psa->sa_family == AF_INET) {
536                 ((struct sockaddr_in *)psa)->sin_port = htons(port);
537         }
538 }
539
540