~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/lib/network.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 1999-2012 Dovecot authors, see the included COPYING file */
2
 
 
3
 
#define _GNU_SOURCE /* For Linux's struct ucred */
4
 
#include "lib.h"
5
 
#include "close-keep-errno.h"
6
 
#include "fd-set-nonblock.h"
7
 
#include "time-util.h"
8
 
#include "network.h"
9
 
 
10
 
#include <stdlib.h>
11
 
#include <unistd.h>
12
 
#include <fcntl.h>
13
 
#include <ctype.h>
14
 
#include <sys/un.h>
15
 
#include <netinet/tcp.h>
16
 
#ifdef HAVE_UCRED_H
17
 
#  include <ucred.h> /* for getpeerucred() */
18
 
#endif
19
 
 
20
 
union sockaddr_union {
21
 
        struct sockaddr sa;
22
 
        struct sockaddr_in sin;
23
 
#ifdef HAVE_IPV6
24
 
        struct sockaddr_in6 sin6;
25
 
#endif
26
 
};
27
 
 
28
 
union sockaddr_union_unix {
29
 
        struct sockaddr sa;
30
 
        struct sockaddr_un un;
31
 
};
32
 
 
33
 
#ifdef HAVE_IPV6
34
 
#  define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \
35
 
        sizeof(so.sin6) : sizeof(so.sin))
36
 
#else
37
 
#  define SIZEOF_SOCKADDR(so) (sizeof(so.sin))
38
 
#endif
39
 
 
40
 
bool net_ip_compare(const struct ip_addr *ip1, const struct ip_addr *ip2)
41
 
{
42
 
        return net_ip_cmp(ip1, ip2) == 0;
43
 
}
44
 
 
45
 
int net_ip_cmp(const struct ip_addr *ip1, const struct ip_addr *ip2)
46
 
{
47
 
        if (ip1->family != ip2->family)
48
 
                return ip1->family - ip2->family;
49
 
 
50
 
#ifdef HAVE_IPV6
51
 
        if (ip1->family == AF_INET6)
52
 
                return memcmp(&ip1->u.ip6, &ip2->u.ip6, sizeof(ip1->u.ip6));
53
 
#endif
54
 
 
55
 
        return memcmp(&ip1->u.ip4, &ip2->u.ip4, sizeof(ip1->u.ip4));
56
 
}
57
 
 
58
 
unsigned int net_ip_hash(const struct ip_addr *ip)
59
 
{
60
 
        const unsigned char *p;
61
 
        unsigned int len, g, h = 0;
62
 
 
63
 
#ifdef HAVE_IPV6
64
 
        if (ip->family == AF_INET6) {
65
 
                p = ip->u.ip6.s6_addr;
66
 
                len = sizeof(ip->u.ip6);
67
 
        } else
68
 
#endif
69
 
        {
70
 
                return ip->u.ip4.s_addr;
71
 
        }
72
 
 
73
 
        for (; len > 0; len--, p++) {
74
 
                h = (h << 4) + *p;
75
 
                if ((g = h & 0xf0000000UL)) {
76
 
                        h = h ^ (g >> 24);
77
 
                        h = h ^ g;
78
 
                }
79
 
        }
80
 
 
81
 
        return h;
82
 
}
83
 
 
84
 
/* copy IP to sockaddr */
85
 
static inline void
86
 
sin_set_ip(union sockaddr_union *so, const struct ip_addr *ip)
87
 
{
88
 
        if (ip == NULL) {
89
 
#ifdef HAVE_IPV6
90
 
                so->sin6.sin6_family = AF_INET6;
91
 
                so->sin6.sin6_addr = in6addr_any;
92
 
#else
93
 
                so->sin.sin_family = AF_INET;
94
 
                so->sin.sin_addr.s_addr = INADDR_ANY;
95
 
#endif
96
 
                return;
97
 
        }
98
 
 
99
 
        so->sin.sin_family = ip->family;
100
 
#ifdef HAVE_IPV6
101
 
        if (ip->family == AF_INET6)
102
 
                memcpy(&so->sin6.sin6_addr, &ip->u.ip6, sizeof(ip->u.ip6));
103
 
        else
104
 
#endif
105
 
                memcpy(&so->sin.sin_addr, &ip->u.ip4, sizeof(ip->u.ip4));
106
 
}
107
 
 
108
 
static inline void
109
 
sin_get_ip(const union sockaddr_union *so, struct ip_addr *ip)
110
 
{
111
 
        /* IP structs may be sent across processes. Clear the whole struct
112
 
           first to make sure it won't leak any data across processes. */
113
 
        memset(ip, 0, sizeof(*ip));
114
 
 
115
 
        ip->family = so->sin.sin_family;
116
 
 
117
 
#ifdef HAVE_IPV6
118
 
        if (ip->family == AF_INET6)
119
 
                memcpy(&ip->u.ip6, &so->sin6.sin6_addr, sizeof(ip->u.ip6));
120
 
        else
121
 
#endif
122
 
        if (ip->family == AF_INET)
123
 
                memcpy(&ip->u.ip4, &so->sin.sin_addr, sizeof(ip->u.ip4));
124
 
        else
125
 
                memset(&ip->u, 0, sizeof(ip->u));
126
 
}
127
 
 
128
 
static inline void sin_set_port(union sockaddr_union *so, unsigned int port)
129
 
{
130
 
#ifdef HAVE_IPV6
131
 
        if (so->sin.sin_family == AF_INET6)
132
 
                so->sin6.sin6_port = htons((unsigned short) port);
133
 
        else
134
 
#endif
135
 
                so->sin.sin_port = htons((unsigned short) port);
136
 
}
137
 
 
138
 
static inline unsigned int sin_get_port(union sockaddr_union *so)
139
 
{
140
 
#ifdef HAVE_IPV6
141
 
        if (so->sin.sin_family == AF_INET6)
142
 
                return ntohs(so->sin6.sin6_port);
143
 
#endif
144
 
        if (so->sin.sin_family == AF_INET)
145
 
                return ntohs(so->sin.sin_port);
146
 
 
147
 
        return 0;
148
 
}
149
 
 
150
 
#ifdef __FreeBSD__
151
 
static int
152
 
net_connect_ip_full_freebsd(const struct ip_addr *ip, unsigned int port,
153
 
                            const struct ip_addr *my_ip, bool blocking);
154
 
 
155
 
static int net_connect_ip_full(const struct ip_addr *ip, unsigned int port,
156
 
                               const struct ip_addr *my_ip, bool blocking)
157
 
{
158
 
        int fd, try;
159
 
 
160
 
        for (try = 0;;) {
161
 
                fd = net_connect_ip_full_freebsd(ip, port, my_ip, blocking);
162
 
                if (fd != -1 || ++try == 5 ||
163
 
                    (errno != EADDRINUSE && errno != EACCES))
164
 
                        break;
165
 
                /*
166
 
                   This may be just a temporary problem:
167
 
 
168
 
                   EADDRINUSE: busy
169
 
                   EACCES: pf may cause this if another connection used
170
 
                           the same port recently
171
 
                */
172
 
        }
173
 
        return fd;
174
 
}
175
 
/* then some kludging: */
176
 
#define net_connect_ip_full net_connect_ip_full_freebsd
177
 
#endif
178
 
 
179
 
static int net_connect_ip_full(const struct ip_addr *ip, unsigned int port,
180
 
                               const struct ip_addr *my_ip, bool blocking)
181
 
{
182
 
        union sockaddr_union so;
183
 
        int fd, ret, opt = 1;
184
 
 
185
 
        if (my_ip != NULL && ip->family != my_ip->family) {
186
 
                i_warning("net_connect_ip(): ip->family != my_ip->family");
187
 
                my_ip = NULL;
188
 
        }
189
 
 
190
 
        /* create the socket */
191
 
        memset(&so, 0, sizeof(so));
192
 
        so.sin.sin_family = ip->family;
193
 
        fd = socket(ip->family, SOCK_STREAM, 0);
194
 
 
195
 
        if (fd == -1) {
196
 
                i_error("socket() failed: %m");
197
 
                return -1;
198
 
        }
199
 
 
200
 
        /* set socket options */
201
 
        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
202
 
        setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
203
 
        if (!blocking)
204
 
                net_set_nonblock(fd, TRUE);
205
 
 
206
 
        /* set our own address */
207
 
        if (my_ip != NULL) {
208
 
                sin_set_ip(&so, my_ip);
209
 
                if (bind(fd, &so.sa, SIZEOF_SOCKADDR(so)) == -1) {
210
 
                        i_error("bind(%s) failed: %m", net_ip2addr(my_ip));
211
 
                        close_keep_errno(fd);
212
 
                        return -1;
213
 
                }
214
 
        }
215
 
 
216
 
        /* connect */
217
 
        sin_set_ip(&so, ip);
218
 
        sin_set_port(&so, port);
219
 
        ret = connect(fd, &so.sa, SIZEOF_SOCKADDR(so));
220
 
 
221
 
#ifndef WIN32
222
 
        if (ret < 0 && errno != EINPROGRESS)
223
 
#else
224
 
        if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
225
 
#endif
226
 
        {
227
 
                close_keep_errno(fd);
228
 
                return -1;
229
 
        }
230
 
 
231
 
        return fd;
232
 
}
233
 
#ifdef __FreeBSD__
234
 
#  undef net_connect_ip_full
235
 
#endif
236
 
 
237
 
int net_connect_ip(const struct ip_addr *ip, unsigned int port,
238
 
                   const struct ip_addr *my_ip)
239
 
{
240
 
        return net_connect_ip_full(ip, port, my_ip, FALSE);
241
 
}
242
 
 
243
 
int net_connect_ip_blocking(const struct ip_addr *ip, unsigned int port,
244
 
                            const struct ip_addr *my_ip)
245
 
{
246
 
        return net_connect_ip_full(ip, port, my_ip, TRUE);
247
 
}
248
 
 
249
 
int net_try_bind(const struct ip_addr *ip)
250
 
{
251
 
        union sockaddr_union so;
252
 
        int fd;
253
 
 
254
 
        /* create the socket */
255
 
        memset(&so, 0, sizeof(so));
256
 
        so.sin.sin_family = ip->family;
257
 
        fd = socket(ip->family, SOCK_STREAM, 0);
258
 
        if (fd == -1) {
259
 
                i_error("socket() failed: %m");
260
 
                return -1;
261
 
        }
262
 
 
263
 
        sin_set_ip(&so, ip);
264
 
        if (bind(fd, &so.sa, SIZEOF_SOCKADDR(so)) == -1) {
265
 
                close_keep_errno(fd);
266
 
                return -1;
267
 
        }
268
 
        (void)close(fd);
269
 
        return 0;
270
 
}
271
 
 
272
 
int net_connect_unix(const char *path)
273
 
{
274
 
        union sockaddr_union_unix sa;
275
 
        int fd, ret;
276
 
 
277
 
        memset(&sa, 0, sizeof(sa));
278
 
        sa.un.sun_family = AF_UNIX;
279
 
        if (i_strocpy(sa.un.sun_path, path, sizeof(sa.un.sun_path)) < 0) {
280
 
                /* too long path */
281
 
                errno = EINVAL;
282
 
                return -1;
283
 
        }
284
 
 
285
 
        /* create the socket */
286
 
        fd = socket(PF_UNIX, SOCK_STREAM, 0);
287
 
        if (fd == -1) {
288
 
                i_error("socket(%s) failed: %m", path);
289
 
                return -1;
290
 
        }
291
 
 
292
 
        net_set_nonblock(fd, TRUE);
293
 
 
294
 
        /* connect */
295
 
        ret = connect(fd, &sa.sa, sizeof(sa));
296
 
        if (ret < 0 && errno != EINPROGRESS) {
297
 
                close_keep_errno(fd);
298
 
                return -1;
299
 
        }
300
 
 
301
 
        return fd;
302
 
}
303
 
 
304
 
int net_connect_unix_with_retries(const char *path, unsigned int msecs)
305
 
{
306
 
        struct timeval start, now;
307
 
        int fd;
308
 
 
309
 
        if (gettimeofday(&start, NULL) < 0)
310
 
                i_panic("gettimeofday() failed: %m");
311
 
 
312
 
        do {
313
 
                fd = net_connect_unix(path);
314
 
                if (fd != -1 || (errno != EAGAIN && errno != ECONNREFUSED))
315
 
                        break;
316
 
 
317
 
                /* busy. wait for a while. */
318
 
                usleep(((rand() % 10) + 1) * 10000);
319
 
                if (gettimeofday(&now, NULL) < 0)
320
 
                        i_panic("gettimeofday() failed: %m");
321
 
        } while (timeval_diff_msecs(&now, &start) < (int)msecs);
322
 
        return fd;
323
 
}
324
 
 
325
 
void net_disconnect(int fd)
326
 
{
327
 
        /* FreeBSD's close() fails with ECONNRESET if socket still has unsent
328
 
           data in transmit buffer. We don't care. */
329
 
        if (close(fd) < 0 && errno != ECONNRESET)
330
 
                i_error("net_disconnect() failed: %m");
331
 
}
332
 
 
333
 
void net_set_nonblock(int fd, bool nonblock)
334
 
{
335
 
        if (fd_set_nonblock(fd, nonblock) < 0)
336
 
                i_fatal("fd_set_nonblock(%d) failed: %m", fd);
337
 
}
338
 
 
339
 
int net_set_cork(int fd ATTR_UNUSED, bool cork ATTR_UNUSED)
340
 
{
341
 
#ifdef TCP_CORK
342
 
        int val = cork;
343
 
 
344
 
        return setsockopt(fd, IPPROTO_TCP, TCP_CORK, &val, sizeof(val));
345
 
#else
346
 
        errno = ENOPROTOOPT;
347
 
        return -1;
348
 
#endif
349
 
}
350
 
 
351
 
void net_get_ip_any4(struct ip_addr *ip)
352
 
{
353
 
        ip->family = AF_INET;
354
 
        ip->u.ip4.s_addr = INADDR_ANY;
355
 
}
356
 
 
357
 
void net_get_ip_any6(struct ip_addr *ip)
358
 
{
359
 
#ifdef HAVE_IPV6
360
 
        ip->family = AF_INET6;
361
 
        ip->u.ip6 = in6addr_any;
362
 
#else
363
 
        memset(ip, 0, sizeof(struct ip_addr));
364
 
#endif
365
 
}
366
 
 
367
 
int net_listen(const struct ip_addr *my_ip, unsigned int *port, int backlog)
368
 
{
369
 
        union sockaddr_union so;
370
 
        int ret, fd, opt = 1;
371
 
        socklen_t len;
372
 
 
373
 
        memset(&so, 0, sizeof(so));
374
 
        sin_set_port(&so, *port);
375
 
        sin_set_ip(&so, my_ip);
376
 
 
377
 
        /* create the socket */
378
 
        fd = socket(so.sin.sin_family, SOCK_STREAM, 0);
379
 
#ifdef HAVE_IPV6
380
 
        if (fd == -1 && my_ip == NULL &&
381
 
            (errno == EINVAL || errno == EAFNOSUPPORT)) {
382
 
                /* IPv6 is not supported by OS */
383
 
                so.sin.sin_family = AF_INET;
384
 
                so.sin.sin_addr.s_addr = INADDR_ANY;
385
 
 
386
 
                fd = socket(AF_INET, SOCK_STREAM, 0);
387
 
        }
388
 
#endif
389
 
        if (fd == -1) {
390
 
                i_error("socket() failed: %m");
391
 
                return -1;
392
 
        }
393
 
 
394
 
        /* set socket options */
395
 
        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
396
 
        setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
397
 
 
398
 
        /* If using IPv6, bind only to IPv6 if possible. This avoids
399
 
           ambiguities with IPv4-mapped IPv6 addresses. */
400
 
#ifdef IPV6_V6ONLY
401
 
        if (so.sin.sin_family == AF_INET6) {
402
 
                opt = 1;
403
 
                setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
404
 
        }
405
 
#endif
406
 
        /* specify the address/port we want to listen in */
407
 
        ret = bind(fd, &so.sa, SIZEOF_SOCKADDR(so));
408
 
        if (ret < 0) {
409
 
                if (errno != EADDRINUSE) {
410
 
                        i_error("bind(%s, %u) failed: %m",
411
 
                                my_ip == NULL ? "" : net_ip2addr(my_ip), *port);
412
 
                }
413
 
        } else {
414
 
                /* get the actual port we started listen */
415
 
                len = SIZEOF_SOCKADDR(so);
416
 
                ret = getsockname(fd, &so.sa, &len);
417
 
                if (ret >= 0) {
418
 
                        *port = sin_get_port(&so);
419
 
 
420
 
                        /* start listening */
421
 
                        if (listen(fd, backlog) >= 0)
422
 
                                return fd;
423
 
 
424
 
                        if (errno != EADDRINUSE)
425
 
                                i_error("listen() failed: %m");
426
 
                }
427
 
        }
428
 
 
429
 
        /* error */
430
 
        close_keep_errno(fd);
431
 
        return -1;
432
 
}
433
 
 
434
 
int net_listen_unix(const char *path, int backlog)
435
 
{
436
 
        union {
437
 
                struct sockaddr sa;
438
 
                struct sockaddr_un un;
439
 
        } sa;
440
 
        int fd;
441
 
 
442
 
        memset(&sa, 0, sizeof(sa));
443
 
        sa.un.sun_family = AF_UNIX;
444
 
        if (i_strocpy(sa.un.sun_path, path, sizeof(sa.un.sun_path)) < 0) {
445
 
                /* too long path */
446
 
                errno = EINVAL;
447
 
                return -1;
448
 
        }
449
 
 
450
 
        /* create the socket */
451
 
        fd = socket(PF_UNIX, SOCK_STREAM, 0);
452
 
        if (fd == -1) {
453
 
                i_error("socket() failed: %m");
454
 
                return -1;
455
 
        }
456
 
 
457
 
        /* bind */
458
 
        if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
459
 
                if (errno != EADDRINUSE)
460
 
                        i_error("bind(%s) failed: %m", path);
461
 
        } else {
462
 
                /* start listening */
463
 
                if (listen(fd, backlog) == 0)
464
 
                        return fd;
465
 
 
466
 
                if (errno != EADDRINUSE)
467
 
                        i_error("listen() failed: %m");
468
 
        }
469
 
 
470
 
        close_keep_errno(fd);
471
 
        return -1;
472
 
}
473
 
 
474
 
int net_listen_unix_unlink_stale(const char *path, int backlog)
475
 
{
476
 
        unsigned int i = 0;
477
 
        int fd;
478
 
 
479
 
        while ((fd = net_listen_unix(path, backlog)) == -1) {
480
 
                if (errno != EADDRINUSE || ++i == 2)
481
 
                        return -1;
482
 
 
483
 
                /* see if it really exists */
484
 
                fd = net_connect_unix(path);
485
 
                if (fd != -1 || errno != ECONNREFUSED) {
486
 
                        if (fd != -1) (void)close(fd);
487
 
                        errno = EADDRINUSE;
488
 
                        return -1;
489
 
                }
490
 
 
491
 
                /* delete and try again */
492
 
                if (unlink(path) < 0 && errno != ENOENT) {
493
 
                        i_error("unlink(%s) failed: %m", path);
494
 
                        errno = EADDRINUSE;
495
 
                        return -1;
496
 
                }
497
 
        }
498
 
        return fd;
499
 
}
500
 
 
501
 
int net_accept(int fd, struct ip_addr *addr, unsigned int *port)
502
 
{
503
 
        union sockaddr_union so;
504
 
        int ret;
505
 
        socklen_t addrlen;
506
 
 
507
 
        i_assert(fd >= 0);
508
 
 
509
 
        addrlen = sizeof(so);
510
 
        ret = accept(fd, &so.sa, &addrlen);
511
 
 
512
 
        if (ret < 0) {
513
 
                if (errno == EAGAIN || errno == ECONNABORTED)
514
 
                        return -1;
515
 
                else
516
 
                        return -2;
517
 
        }
518
 
        if (so.sin.sin_family == AF_UNIX) {
519
 
                if (addr != NULL)
520
 
                        memset(addr, 0, sizeof(*addr));
521
 
                if (port != NULL) *port = 0;
522
 
        } else {
523
 
                if (addr != NULL) sin_get_ip(&so, addr);
524
 
                if (port != NULL) *port = sin_get_port(&so);
525
 
        }
526
 
        return ret;
527
 
}
528
 
 
529
 
ssize_t net_receive(int fd, void *buf, size_t len)
530
 
{
531
 
        ssize_t ret;
532
 
 
533
 
        i_assert(fd >= 0);
534
 
        i_assert(len <= SSIZE_T_MAX);
535
 
 
536
 
        ret = read(fd, buf, len);
537
 
        if (ret == 0) {
538
 
                /* disconnected */
539
 
                errno = 0;
540
 
                return -2;
541
 
        }
542
 
 
543
 
        if (unlikely(ret < 0)) {
544
 
                if (errno == EINTR || errno == EAGAIN)
545
 
                        return 0;
546
 
 
547
 
                if (errno == ECONNRESET || errno == ETIMEDOUT) {
548
 
                        /* treat as disconnection */
549
 
                        return -2;
550
 
                }
551
 
        }
552
 
 
553
 
        return ret;
554
 
}
555
 
 
556
 
ssize_t net_transmit(int fd, const void *data, size_t len)
557
 
{
558
 
        ssize_t ret;
559
 
 
560
 
        i_assert(fd >= 0);
561
 
        i_assert(len <= SSIZE_T_MAX);
562
 
 
563
 
        ret = send(fd, data, len, 0);
564
 
        if (unlikely(ret == -1 && (errno == EINTR || errno == EAGAIN)))
565
 
                return 0;
566
 
 
567
 
        if (unlikely(errno == EPIPE))
568
 
                return -2;
569
 
 
570
 
        return ret;
571
 
}
572
 
 
573
 
int net_gethostbyname(const char *addr, struct ip_addr **ips,
574
 
                      unsigned int *ips_count)
575
 
{
576
 
        /* @UNSAFE */
577
 
#ifdef HAVE_IPV6
578
 
        union sockaddr_union *so;
579
 
        struct addrinfo hints, *ai, *origai;
580
 
        int host_error;
581
 
#else
582
 
        struct hostent *hp;
583
 
#endif
584
 
        int count;
585
 
 
586
 
        *ips = NULL;
587
 
        *ips_count = 0;
588
 
 
589
 
#ifdef HAVE_IPV6
590
 
        memset(&hints, 0, sizeof(struct addrinfo));
591
 
        hints.ai_socktype = SOCK_STREAM;
592
 
 
593
 
        /* save error to host_error for later use */
594
 
        host_error = getaddrinfo(addr, NULL, &hints, &ai);
595
 
        if (host_error != 0)
596
 
                return host_error;
597
 
 
598
 
        /* get number of IPs */
599
 
        origai = ai;
600
 
        for (count = 0; ai != NULL; ai = ai->ai_next)
601
 
                count++;
602
 
 
603
 
        *ips_count = count;
604
 
        *ips = t_malloc(sizeof(struct ip_addr) * count);
605
 
 
606
 
        count = 0;
607
 
        for (ai = origai; ai != NULL; ai = ai->ai_next, count++) {
608
 
                so = (union sockaddr_union *) ai->ai_addr;
609
 
 
610
 
                sin_get_ip(so, &(*ips)[count]);
611
 
        }
612
 
        freeaddrinfo(origai);
613
 
#else
614
 
        hp = gethostbyname(addr);
615
 
        if (hp == NULL)
616
 
                return h_errno;
617
 
 
618
 
        /* get number of IPs */
619
 
        count = 0;
620
 
        while (hp->h_addr_list[count] != NULL)
621
 
                count++;
622
 
 
623
 
        *ips_count = count;
624
 
        *ips = t_malloc(sizeof(struct ip_addr) * count);
625
 
 
626
 
        while (count > 0) {
627
 
                count--;
628
 
 
629
 
                (*ips)[count].family = AF_INET;
630
 
                memcpy(&(*ips)[count].u.ip4, hp->h_addr_list[count],
631
 
                       sizeof((*ips)[count].u.ip4));
632
 
        }
633
 
#endif
634
 
 
635
 
        return 0;
636
 
}
637
 
 
638
 
int net_getsockname(int fd, struct ip_addr *addr, unsigned int *port)
639
 
{
640
 
        union sockaddr_union so;
641
 
        socklen_t addrlen;
642
 
 
643
 
        i_assert(fd >= 0);
644
 
 
645
 
        addrlen = sizeof(so);
646
 
        if (getsockname(fd, &so.sa, &addrlen) == -1)
647
 
                return -1;
648
 
        if (so.sin.sin_family == AF_UNIX) {
649
 
                if (addr != NULL)
650
 
                        memset(addr, 0, sizeof(*addr));
651
 
                if (port != NULL) *port = 0;
652
 
        } else {
653
 
                if (addr != NULL) sin_get_ip(&so, addr);
654
 
                if (port != NULL) *port = sin_get_port(&so);
655
 
        }
656
 
        return 0;
657
 
}
658
 
 
659
 
int net_getpeername(int fd, struct ip_addr *addr, unsigned int *port)
660
 
{
661
 
        union sockaddr_union so;
662
 
        socklen_t addrlen;
663
 
 
664
 
        i_assert(fd >= 0);
665
 
 
666
 
        addrlen = sizeof(so);
667
 
        if (getpeername(fd, &so.sa, &addrlen) == -1)
668
 
                return -1;
669
 
        if (so.sin.sin_family == AF_UNIX) {
670
 
                if (addr != NULL)
671
 
                        memset(addr, 0, sizeof(*addr));
672
 
                if (port != NULL) *port = 0;
673
 
        } else {
674
 
                if (addr != NULL) sin_get_ip(&so, addr);
675
 
                if (port != NULL) *port = sin_get_port(&so);
676
 
        }
677
 
        return 0;
678
 
}
679
 
 
680
 
int net_getunixname(int fd, const char **name_r)
681
 
{
682
 
        union sockaddr_union_unix so;
683
 
        socklen_t addrlen = sizeof(so);
684
 
 
685
 
        if (getsockname(fd, &so.sa, &addrlen) < 0)
686
 
                return -1;
687
 
        if (so.un.sun_family != AF_UNIX) {
688
 
                errno = ENOTSOCK;
689
 
                return -1;
690
 
        }
691
 
        *name_r = t_strdup(so.un.sun_path);
692
 
        return 0;
693
 
}
694
 
 
695
 
int net_getunixcred(int fd, struct net_unix_cred *cred_r)
696
 
{
697
 
#if defined(HAVE_GETPEEREID)
698
 
        /* OSX 10.4+, FreeBSD 4.6+, OpenBSD 3.0+, NetBSD 5.0+ */
699
 
        if (getpeereid(fd, &cred_r->uid, &cred_r->gid) < 0) {
700
 
                i_error("getpeereid() failed: %m");
701
 
                return -1;
702
 
        }
703
 
        return 0;
704
 
#elif defined(SO_PEERCRED)
705
 
        /* Linux */
706
 
        struct ucred ucred;
707
 
        socklen_t len = sizeof(ucred);
708
 
 
709
 
        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
710
 
                i_error("getsockopt(SO_PEERCRED) failed: %m");
711
 
                return -1;
712
 
        }
713
 
        cred_r->uid = ucred.uid;
714
 
        cred_r->gid = ucred.gid;
715
 
        return 0;
716
 
#elif defined(HAVE_GETPEERUCRED)
717
 
        /* Solaris */
718
 
        ucred_t *ucred = NULL;
719
 
 
720
 
        if (getpeerucred(fd, &ucred) < 0) {
721
 
                i_error("getpeerucred() failed: %m");
722
 
                return -1;
723
 
        }
724
 
        cred_r->uid = ucred_geteuid(ucred);
725
 
        cred_r->gid = ucred_getrgid(ucred);
726
 
        ucred_free(ucred);
727
 
 
728
 
        if (cred_r->uid == (uid_t)-1 ||
729
 
            cred_r->gid == (gid_t)-1) {
730
 
                errno = EINVAL;
731
 
                return -1;
732
 
        }
733
 
        return 0;
734
 
#else
735
 
        errno = EINVAL;
736
 
        return -1;
737
 
#endif
738
 
}
739
 
 
740
 
const char *net_ip2addr(const struct ip_addr *ip)
741
 
{
742
 
#ifdef HAVE_IPV6
743
 
        char addr[MAX_IP_LEN+1];
744
 
 
745
 
        addr[MAX_IP_LEN] = '\0';
746
 
        if (inet_ntop(ip->family, &ip->u.ip6, addr, MAX_IP_LEN) == NULL)
747
 
                return NULL;
748
 
 
749
 
        return t_strdup(addr);
750
 
#else
751
 
        unsigned long ip4;
752
 
 
753
 
        if (ip->family != AF_INET)
754
 
                return NULL;
755
 
 
756
 
        ip4 = ntohl(ip->u.ip4.s_addr);
757
 
        return t_strdup_printf("%lu.%lu.%lu.%lu",
758
 
                               (ip4 & 0xff000000UL) >> 24,
759
 
                               (ip4 & 0x00ff0000) >> 16,
760
 
                               (ip4 & 0x0000ff00) >> 8,
761
 
                               (ip4 & 0x000000ff));
762
 
#endif
763
 
}
764
 
 
765
 
int net_addr2ip(const char *addr, struct ip_addr *ip)
766
 
{
767
 
        int ret;
768
 
 
769
 
        if (strchr(addr, ':') != NULL) {
770
 
                /* IPv6 */
771
 
                ip->family = AF_INET6;
772
 
#ifdef HAVE_IPV6
773
 
                T_BEGIN {
774
 
                        if (addr[0] == '[') {
775
 
                                /* allow [ipv6 addr] */
776
 
                                unsigned int len = strlen(addr);
777
 
                                if (addr[len-1] == ']')
778
 
                                        addr = t_strndup(addr+1, len-2);
779
 
                        }
780
 
                        ret = inet_pton(AF_INET6, addr, &ip->u.ip6);
781
 
                } T_END;
782
 
                if (ret == 0)
783
 
                        return -1;
784
 
#else
785
 
                ip->u.ip4.s_addr = 0;
786
 
#endif
787
 
        } else {
788
 
                /* IPv4 */
789
 
                ip->family = AF_INET;
790
 
                if (inet_aton(addr, &ip->u.ip4) == 0)
791
 
                        return -1;
792
 
        }
793
 
 
794
 
        return 0;
795
 
}
796
 
 
797
 
int net_ipv6_mapped_ipv4_convert(const struct ip_addr *src,
798
 
                                 struct ip_addr *dest)
799
 
{
800
 
#ifdef HAVE_IPV6
801
 
        static uint8_t v4_prefix[] =
802
 
                { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
803
 
 
804
 
        if (!IPADDR_IS_V6(src))
805
 
                return -1;
806
 
        if (memcmp(src->u.ip6.s6_addr, v4_prefix, sizeof(v4_prefix)) != 0)
807
 
                return -1;
808
 
 
809
 
        dest->family = AF_INET;
810
 
        memcpy(&dest->u.ip6, &src->u.ip6.s6_addr[3*4], 4);
811
 
        return 0;
812
 
#else
813
 
        return -1;
814
 
#endif
815
 
}
816
 
 
817
 
int net_geterror(int fd)
818
 
{
819
 
        int data;
820
 
        socklen_t len = sizeof(data);
821
 
 
822
 
        if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &data, &len) == -1)
823
 
                return -1;
824
 
 
825
 
        return data;
826
 
}
827
 
 
828
 
const char *net_gethosterror(int error)
829
 
{
830
 
#ifdef HAVE_IPV6
831
 
        i_assert(error != 0);
832
 
 
833
 
        return gai_strerror(error);
834
 
#else
835
 
        switch (error) {
836
 
        case HOST_NOT_FOUND:
837
 
                return "Host not found";
838
 
        case NO_ADDRESS:
839
 
                return "No IP address found for name";
840
 
        case NO_RECOVERY:
841
 
                return "A non-recoverable name server error occurred";
842
 
        case TRY_AGAIN:
843
 
                return "A temporary error on an authoritative name server";
844
 
        }
845
 
 
846
 
        /* unknown error */
847
 
        return NULL;
848
 
#endif
849
 
}
850
 
 
851
 
int net_hosterror_notfound(int error)
852
 
{
853
 
#ifdef HAVE_IPV6
854
 
#ifdef EAI_NODATA /* NODATA is depricated */
855
 
        return error != 1 && (error == EAI_NONAME || error == EAI_NODATA);
856
 
#else
857
 
        return error != 1 && (error == EAI_NONAME);
858
 
#endif
859
 
#else
860
 
        return error == HOST_NOT_FOUND || error == NO_ADDRESS;
861
 
#endif
862
 
}
863
 
 
864
 
const char *net_getservbyport(unsigned short port)
865
 
{
866
 
        struct servent *entry;
867
 
 
868
 
        entry = getservbyport(htons(port), "tcp");
869
 
        return entry == NULL ? NULL : entry->s_name;
870
 
}
871
 
 
872
 
bool is_ipv4_address(const char *addr)
873
 
{
874
 
        while (*addr != '\0') {
875
 
                if (*addr != '.' && !i_isdigit(*addr))
876
 
                        return FALSE;
877
 
                addr++;
878
 
        }
879
 
 
880
 
        return TRUE;
881
 
}
882
 
 
883
 
bool is_ipv6_address(const char *addr)
884
 
{
885
 
        bool have_prefix = FALSE;
886
 
 
887
 
        if (*addr == '[') {
888
 
                have_prefix = TRUE;
889
 
                addr++;
890
 
        }
891
 
        while (*addr != '\0') {
892
 
                if (*addr != ':' && !i_isxdigit(*addr)) {
893
 
                        if (have_prefix && *addr == ']' && addr[1] == '\0')
894
 
                                break;
895
 
                        return FALSE;
896
 
                }
897
 
                addr++;
898
 
        }
899
 
 
900
 
        return TRUE;
901
 
}
902
 
 
903
 
int net_parse_range(const char *network, struct ip_addr *ip_r,
904
 
                    unsigned int *bits_r)
905
 
{
906
 
        const char *p;
907
 
        unsigned int bits, max_bits;
908
 
 
909
 
        p = strchr(network, '/');
910
 
        if (p != NULL)
911
 
                network = t_strdup_until(network, p++);
912
 
 
913
 
        if (net_addr2ip(network, ip_r) < 0)
914
 
                return -1;
915
 
 
916
 
        max_bits = IPADDR_BITS(ip_r);
917
 
        if (p == NULL) {
918
 
                /* full IP address must match */
919
 
                bits = max_bits;
920
 
        } else {
921
 
                /* get the network mask */
922
 
                if (str_to_uint(p, &bits) < 0 || bits > max_bits)
923
 
                        return -1;
924
 
        }
925
 
        *bits_r = bits;
926
 
        return 0;
927
 
}
928
 
 
929
 
bool net_is_in_network(const struct ip_addr *ip,
930
 
                       const struct ip_addr *net_ip, unsigned int bits)
931
 
{
932
 
        struct ip_addr tmp_ip;
933
 
        const uint32_t *ip1, *ip2;
934
 
        uint32_t mask, i1, i2;
935
 
        unsigned int pos, i;
936
 
 
937
 
        if (net_ipv6_mapped_ipv4_convert(ip, &tmp_ip) == 0) {
938
 
                /* IPv4 address mapped disguised as IPv6 address */
939
 
                ip = &tmp_ip;
940
 
        }
941
 
 
942
 
        if (IPADDR_IS_V4(ip) != IPADDR_IS_V4(net_ip)) {
943
 
                /* one is IPv6 and one is IPv4 */
944
 
                return FALSE;
945
 
        }
946
 
        i_assert(IPADDR_IS_V6(ip) == IPADDR_IS_V6(net_ip));
947
 
 
948
 
        if (IPADDR_IS_V4(ip)) {
949
 
                ip1 = &ip->u.ip4.s_addr;
950
 
                ip2 = &net_ip->u.ip4.s_addr;
951
 
        } else {
952
 
#ifdef HAVE_IPV6
953
 
                ip1 = (const void *)&ip->u.ip6;
954
 
                ip2 = (const void *)&net_ip->u.ip6;
955
 
#else
956
 
                /* shouldn't get here */
957
 
                return FALSE;
958
 
#endif
959
 
        }
960
 
 
961
 
        /* check first the full 32bit ints */
962
 
        for (pos = 0, i = 0; pos + 32 <= bits; pos += 32, i++) {
963
 
                if (ip1[i] != ip2[i])
964
 
                        return FALSE;
965
 
        }
966
 
        i1 = htonl(ip1[i]);
967
 
        i2 = htonl(ip2[i]);
968
 
 
969
 
        /* check the last full bytes */
970
 
        for (mask = 0xff000000; pos + 8 <= bits; pos += 8, mask >>= 8) {
971
 
                if ((i1 & mask) != (i2 & mask))
972
 
                        return FALSE;
973
 
        }
974
 
 
975
 
        /* check the last bits, they're reversed in bytes */
976
 
        bits -= pos;
977
 
        for (mask = 0x80000000 >> (pos % 32); bits > 0; bits--, mask >>= 1) {
978
 
                if ((i1 & mask) != (i2 & mask))
979
 
                        return FALSE;
980
 
        }
981
 
        return TRUE;
982
 
}