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