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

« back to all changes in this revision

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