Coverage Report

Created: 2023-11-19 07:06

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