~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to lib/util/util_net.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 2001-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
    
 
11
   This program is free software; you can redistribute it and/or modify
 
12
   it under the terms of the GNU General Public License as published by
 
13
   the Free Software Foundation; either version 3 of the License, or
 
14
   (at your option) any later version.
 
15
   
 
16
   This program is distributed in the hope that it will be useful,
 
17
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
18
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
19
   GNU General Public License for more details.
 
20
   
 
21
   You should have received a copy of the GNU General Public License
 
22
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
23
*/
 
24
 
 
25
#include "includes.h"
 
26
#include "system/network.h"
 
27
#include "system/locale.h"
 
28
#include "system/filesys.h"
 
29
#undef strcasecmp
 
30
 
 
31
/**
 
32
 * Wrap getaddrinfo...
 
33
 */
 
34
bool interpret_string_addr_internal(struct addrinfo **ppres,
 
35
                                        const char *str, int flags)
 
36
{
 
37
        int ret;
 
38
        struct addrinfo hints;
 
39
 
 
40
        memset(&hints, '\0', sizeof(hints));
 
41
        /* By default make sure it supports TCP. */
 
42
        hints.ai_socktype = SOCK_STREAM;
 
43
        hints.ai_flags = flags;
 
44
 
 
45
        /* Linux man page on getaddinfo() says port will be
 
46
           uninitialized when service string in NULL */
 
47
 
 
48
        ret = getaddrinfo(str, NULL,
 
49
                        &hints,
 
50
                        ppres);
 
51
 
 
52
        if (ret) {
 
53
                DEBUG(3,("interpret_string_addr_internal: getaddrinfo failed "
 
54
                        "for name %s [%s]\n",
 
55
                        str,
 
56
                        gai_strerror(ret) ));
 
57
                return false;
 
58
        }
 
59
        return true;
 
60
}
 
61
 
 
62
/**
 
63
 * Interpret an internet address or name into an IP address in 4 byte form.
 
64
 * RETURNS IN NETWORK BYTE ORDER (big endian).
 
65
 */
 
66
 
 
67
uint32_t interpret_addr(const char *str)
 
68
{
 
69
        uint32_t ret;
 
70
 
 
71
        /* If it's in the form of an IP address then
 
72
         * get the lib to interpret it */
 
73
        if (is_ipaddress_v4(str)) {
 
74
                struct in_addr dest;
 
75
 
 
76
                if (inet_pton(AF_INET, str, &dest) <= 0) {
 
77
                        /* Error - this shouldn't happen ! */
 
78
                        DEBUG(0,("interpret_addr: inet_pton failed "
 
79
                                "host %s\n",
 
80
                                str));
 
81
                        return 0;
 
82
                }
 
83
                ret = dest.s_addr; /* NETWORK BYTE ORDER ! */
 
84
        } else {
 
85
                /* Otherwise assume it's a network name of some sort and use
 
86
                        getadddrinfo. */
 
87
                struct addrinfo *res = NULL;
 
88
                struct addrinfo *res_list = NULL;
 
89
                if (!interpret_string_addr_internal(&res_list,
 
90
                                        str,
 
91
                                        AI_ADDRCONFIG)) {
 
92
                        DEBUG(3,("interpret_addr: Unknown host. %s\n",str));
 
93
                        return 0;
 
94
                }
 
95
 
 
96
                /* Find the first IPv4 address. */
 
97
                for (res = res_list; res; res = res->ai_next) {
 
98
                        if (res->ai_family != AF_INET) {
 
99
                                continue;
 
100
                        }
 
101
                        if (res->ai_addr == NULL) {
 
102
                                continue;
 
103
                        }
 
104
                        break;
 
105
                }
 
106
                if(res == NULL) {
 
107
                        DEBUG(3,("interpret_addr: host address is "
 
108
                                "invalid for host %s\n",str));
 
109
                        if (res_list) {
 
110
                                freeaddrinfo(res_list);
 
111
                        }
 
112
                        return 0;
 
113
                }
 
114
                memcpy((char *)&ret,
 
115
                        &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr,
 
116
                        sizeof(ret));
 
117
                if (res_list) {
 
118
                        freeaddrinfo(res_list);
 
119
                }
 
120
        }
 
121
 
 
122
        /* This is so bogus - all callers need fixing... JRA. */
 
123
        if (ret == (uint32_t)-1) {
 
124
                return 0;
 
125
        }
 
126
 
 
127
        return ret;
 
128
}
 
129
 
 
130
/**
 
131
 A convenient addition to interpret_addr().
 
132
**/
 
133
_PUBLIC_ struct in_addr interpret_addr2(const char *str)
 
134
{
 
135
        struct in_addr ret;
 
136
        uint32_t a = interpret_addr(str);
 
137
        ret.s_addr = a;
 
138
        return ret;
 
139
}
 
140
 
 
141
/**
 
142
 Check if an IP is the 0.0.0.0.
 
143
**/
 
144
 
 
145
_PUBLIC_ bool is_zero_ip_v4(struct in_addr ip)
 
146
{
 
147
        return ip.s_addr == 0;
 
148
}
 
149
 
 
150
/**
 
151
 Are two IPs on the same subnet?
 
152
**/
 
153
 
 
154
_PUBLIC_ bool same_net_v4(struct in_addr ip1, struct in_addr ip2, struct in_addr mask)
 
155
{
 
156
        uint32_t net1,net2,nmask;
 
157
 
 
158
        nmask = ntohl(mask.s_addr);
 
159
        net1  = ntohl(ip1.s_addr);
 
160
        net2  = ntohl(ip2.s_addr);
 
161
            
 
162
        return((net1 & nmask) == (net2 & nmask));
 
163
}
 
164
 
 
165
/**
 
166
 * Return true if a string could be an IPv4 address.
 
167
 */
 
168
 
 
169
bool is_ipaddress_v4(const char *str)
 
170
{
 
171
        int ret = -1;
 
172
        struct in_addr dest;
 
173
 
 
174
        ret = inet_pton(AF_INET, str, &dest);
 
175
        if (ret > 0) {
 
176
                return true;
 
177
        }
 
178
        return false;
 
179
}
 
180
 
 
181
/**
 
182
 * Return true if a string could be an IPv4 or IPv6 address.
 
183
 */
 
184
 
 
185
bool is_ipaddress(const char *str)
 
186
{
 
187
#if defined(HAVE_IPV6)
 
188
        int ret = -1;
 
189
 
 
190
        if (strchr_m(str, ':')) {
 
191
                char addr[INET6_ADDRSTRLEN];
 
192
                struct in6_addr dest6;
 
193
                const char *sp = str;
 
194
                char *p = strchr_m(str, '%');
 
195
 
 
196
                /*
 
197
                 * Cope with link-local.
 
198
                 * This is IP:v6:addr%ifname.
 
199
                 */
 
200
 
 
201
                if (p && (p > str) && (if_nametoindex(p+1) != 0)) {
 
202
                        strlcpy(addr, str,
 
203
                                MIN(PTR_DIFF(p,str)+1,
 
204
                                        sizeof(addr)));
 
205
                        sp = addr;
 
206
                }
 
207
                ret = inet_pton(AF_INET6, sp, &dest6);
 
208
                if (ret > 0) {
 
209
                        return true;
 
210
                }
 
211
        }
 
212
#endif
 
213
        return is_ipaddress_v4(str);
 
214
}
 
215
 
 
216
/**
 
217
 * Is a sockaddr a broadcast address ?
 
218
 */
 
219
 
 
220
bool is_broadcast_addr(const struct sockaddr *pss)
 
221
{
 
222
#if defined(HAVE_IPV6)
 
223
        if (pss->sa_family == AF_INET6) {
 
224
                const struct in6_addr *sin6 =
 
225
                        &((const struct sockaddr_in6 *)pss)->sin6_addr;
 
226
                return IN6_IS_ADDR_MULTICAST(sin6);
 
227
        }
 
228
#endif
 
229
        if (pss->sa_family == AF_INET) {
 
230
                uint32_t addr =
 
231
                ntohl(((const struct sockaddr_in *)pss)->sin_addr.s_addr);
 
232
                return addr == INADDR_BROADCAST;
 
233
        }
 
234
        return false;
 
235
}
 
236
 
 
237
/**
 
238
 * Check if an IPv7 is 127.0.0.1
 
239
 */
 
240
bool is_loopback_ip_v4(struct in_addr ip)
 
241
{
 
242
        struct in_addr a;
 
243
        a.s_addr = htonl(INADDR_LOOPBACK);
 
244
        return(ip.s_addr == a.s_addr);
 
245
}
 
246
 
 
247
/**
 
248
 * Check if a struct sockaddr is the loopback address.
 
249
 */
 
250
bool is_loopback_addr(const struct sockaddr *pss)
 
251
{
 
252
#if defined(HAVE_IPV6)
 
253
        if (pss->sa_family == AF_INET6) {
 
254
                const struct in6_addr *pin6 =
 
255
                        &((const struct sockaddr_in6 *)pss)->sin6_addr;
 
256
                return IN6_IS_ADDR_LOOPBACK(pin6);
 
257
        }
 
258
#endif
 
259
        if (pss->sa_family == AF_INET) {
 
260
                const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
 
261
                return is_loopback_ip_v4(*pin);
 
262
        }
 
263
        return false;
 
264
}
 
265
 
 
266
/**
 
267
 * Check if a struct sockaddr has an unspecified address.
 
268
 */
 
269
bool is_zero_addr(const struct sockaddr *pss)
 
270
{
 
271
#if defined(HAVE_IPV6)
 
272
        if (pss->sa_family == AF_INET6) {
 
273
                const struct in6_addr *pin6 =
 
274
                        &((const struct sockaddr_in6 *)pss)->sin6_addr;
 
275
                return IN6_IS_ADDR_UNSPECIFIED(pin6);
 
276
        }
 
277
#endif
 
278
        if (pss->sa_family == AF_INET) {
 
279
                const struct in_addr *pin = &((const struct sockaddr_in *)pss)->sin_addr;
 
280
                return is_zero_ip_v4(*pin);
 
281
        }
 
282
        return false;
 
283
}
 
284
 
 
285
/**
 
286
 * Set an IP to 0.0.0.0.
 
287
 */
 
288
void zero_ip_v4(struct in_addr *ip)
 
289
{
 
290
        memset(ip, '\0', sizeof(struct in_addr));
 
291
}
 
292
 
 
293
/**
 
294
 * Convert an IPv4 struct in_addr to a struct sockaddr_storage.
 
295
 */
 
296
void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
 
297
                struct in_addr ip)
 
298
{
 
299
        struct sockaddr_in *sa = (struct sockaddr_in *)ss;
 
300
        memset(ss, '\0', sizeof(*ss));
 
301
        sa->sin_family = AF_INET;
 
302
        sa->sin_addr = ip;
 
303
}
 
304
 
 
305
#if defined(HAVE_IPV6)
 
306
/**
 
307
 * Convert an IPv6 struct in_addr to a struct sockaddr_storage.
 
308
 */
 
309
void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
 
310
                struct in6_addr ip)
 
311
{
 
312
        struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ss;
 
313
        memset(ss, '\0', sizeof(*ss));
 
314
        sa->sin6_family = AF_INET6;
 
315
        sa->sin6_addr = ip;
 
316
}
 
317
#endif
 
318
 
 
319
/**
 
320
 * Are two IPs on the same subnet?
 
321
 */
 
322
bool same_net(const struct sockaddr *ip1,
 
323
                const struct sockaddr *ip2,
 
324
                const struct sockaddr *mask)
 
325
{
 
326
        if (ip1->sa_family != ip2->sa_family) {
 
327
                /* Never on the same net. */
 
328
                return false;
 
329
        }
 
330
 
 
331
#if defined(HAVE_IPV6)
 
332
        if (ip1->sa_family == AF_INET6) {
 
333
                struct sockaddr_in6 ip1_6 = *(const struct sockaddr_in6 *)ip1;
 
334
                struct sockaddr_in6 ip2_6 = *(const struct sockaddr_in6 *)ip2;
 
335
                struct sockaddr_in6 mask_6 = *(const struct sockaddr_in6 *)mask;
 
336
                char *p1 = (char *)&ip1_6.sin6_addr;
 
337
                char *p2 = (char *)&ip2_6.sin6_addr;
 
338
                char *m = (char *)&mask_6.sin6_addr;
 
339
                int i;
 
340
 
 
341
                for (i = 0; i < sizeof(struct in6_addr); i++) {
 
342
                        *p1++ &= *m;
 
343
                        *p2++ &= *m;
 
344
                        m++;
 
345
                }
 
346
                return (memcmp(&ip1_6.sin6_addr,
 
347
                                &ip2_6.sin6_addr,
 
348
                                sizeof(struct in6_addr)) == 0);
 
349
        }
 
350
#endif
 
351
        if (ip1->sa_family == AF_INET) {
 
352
                return same_net_v4(((const struct sockaddr_in *)ip1)->sin_addr,
 
353
                                ((const struct sockaddr_in *)ip2)->sin_addr,
 
354
                                ((const struct sockaddr_in *)mask)->sin_addr);
 
355
        }
 
356
        return false;
 
357
}
 
358
 
 
359
/**
 
360
 * Are two sockaddr 's the same family and address ? Ignore port etc.
 
361
 */
 
362
 
 
363
bool sockaddr_equal(const struct sockaddr *ip1,
 
364
                const struct sockaddr *ip2)
 
365
{
 
366
        if (ip1->sa_family != ip2->sa_family) {
 
367
                /* Never the same. */
 
368
                return false;
 
369
        }
 
370
 
 
371
#if defined(HAVE_IPV6)
 
372
        if (ip1->sa_family == AF_INET6) {
 
373
                return (memcmp(&((const struct sockaddr_in6 *)ip1)->sin6_addr,
 
374
                                &((const struct sockaddr_in6 *)ip2)->sin6_addr,
 
375
                                sizeof(struct in6_addr)) == 0);
 
376
        }
 
377
#endif
 
378
        if (ip1->sa_family == AF_INET) {
 
379
                return (memcmp(&((const struct sockaddr_in *)ip1)->sin_addr,
 
380
                                &((const struct sockaddr_in *)ip2)->sin_addr,
 
381
                                sizeof(struct in_addr)) == 0);
 
382
        }
 
383
        return false;
 
384
}
 
385
 
 
386
/**
 
387
 * Is an IP address the INADDR_ANY or in6addr_any value ?
 
388
 */
 
389
bool is_address_any(const struct sockaddr *psa)
 
390
{
 
391
#if defined(HAVE_IPV6)
 
392
        if (psa->sa_family == AF_INET6) {
 
393
                const struct sockaddr_in6 *si6 = (const struct sockaddr_in6 *)psa;
 
394
                if (memcmp(&in6addr_any,
 
395
                                &si6->sin6_addr,
 
396
                                sizeof(in6addr_any)) == 0) {
 
397
                        return true;
 
398
                }
 
399
                return false;
 
400
        }
 
401
#endif
 
402
        if (psa->sa_family == AF_INET) {
 
403
                const struct sockaddr_in *si = (const struct sockaddr_in *)psa;
 
404
                if (si->sin_addr.s_addr == INADDR_ANY) {
 
405
                        return true;
 
406
                }
 
407
                return false;
 
408
        }
 
409
        return false;
 
410
}
 
411
 
 
412
void set_sockaddr_port(struct sockaddr *psa, uint16_t port)
 
413
{
 
414
#if defined(HAVE_IPV6)
 
415
        if (psa->sa_family == AF_INET6) {
 
416
                ((struct sockaddr_in6 *)psa)->sin6_port = htons(port);
 
417
        }
 
418
#endif
 
419
        if (psa->sa_family == AF_INET) {
 
420
                ((struct sockaddr_in *)psa)->sin_port = htons(port);
 
421
        }
 
422
}
 
423
 
 
424