Coverage Report

Created: 2026-09-14 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib/net.c
Line
Count
Source
1
/* Copyright (c) Dovecot authors, see top-level 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
0
{
55
0
  if (gai_errno == 0)
56
0
    return 0;
57
0
  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
0
  case EAI_NONAME:
67
0
    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
0
  }
81
0
  return gai_errno;
82
0
}
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
0
{
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
0
  i_zero(ip);
153
154
0
  ip->family = so->sin.sin_family;
155
156
0
  if (ip->family == AF_INET6) {
157
0
    memcpy(&ip->u.ip6, &so->sin6.sin6_addr, sizeof(ip->u.ip6));
158
0
    ip->scope_id = so->sin6.sin6_scope_id;
159
0
  } else if (ip->family == AF_INET)
160
0
    memcpy(&ip->u.ip4, &so->sin.sin_addr, sizeof(ip->u.ip4));
161
0
  else
162
0
    i_zero(&ip->u);
163
0
}
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
#if defined(__FreeBSD__) || defined(__OpenBSD__)
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
0
{
380
0
  fd_set_nonblock(fd, nonblock);
381
0
}
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
0
{
397
0
  int val = nodelay;
398
399
0
  return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
400
0
}
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
    return -1;
633
0
  if (so.sin.sin_family == AF_UNIX) {
634
0
    if (addr_r != NULL)
635
0
      i_zero(addr_r);
636
0
    if (port_r != NULL) *port_r = 0;
637
0
  } else {
638
0
    if (addr_r != NULL) sin_get_ip(&so, addr_r);
639
0
    if (port_r != NULL) *port_r = sin_get_port(&so);
640
0
  }
641
0
  return ret;
642
0
}
643
644
ssize_t net_receive(int fd, void *buf, size_t len)
645
0
{
646
0
  ssize_t ret;
647
648
0
  i_assert(fd >= 0);
649
0
  i_assert(len <= SSIZE_T_MAX);
650
651
0
  ret = read(fd, buf, len);
652
0
  if (ret == 0) {
653
    /* disconnected */
654
0
    errno = 0;
655
0
    return -2;
656
0
  }
657
658
0
  if (unlikely(ret < 0)) {
659
0
    if (errno == EINTR || errno == EAGAIN)
660
0
      return 0;
661
662
0
    if (errno == ECONNRESET || errno == ETIMEDOUT) {
663
      /* treat as disconnection */
664
0
      return -2;
665
0
    }
666
0
  }
667
668
0
  return ret;
669
0
}
670
671
int net_gethostbyname(const char *addr, struct ip_addr **ips,
672
          unsigned int *ips_count)
673
0
{
674
  /* @UNSAFE */
675
0
  const union sockaddr_union *so;
676
0
  struct addrinfo hints, *ai, *origai;
677
0
  struct ip_addr ip;
678
0
  int host_error;
679
0
  int count;
680
681
0
  *ips = NULL;
682
0
  *ips_count = 0;
683
684
  /* support [ipv6] style addresses here so they work globally */
685
0
  if (addr[0] == '[' && net_addr2ip(addr, &ip) == 0) {
686
0
    *ips_count = 1;
687
0
    *ips = t_new(struct ip_addr, 1);
688
0
    **ips = ip;
689
0
    return 0;
690
0
  }
691
692
0
  i_zero(&hints);
693
0
  hints.ai_socktype = SOCK_STREAM;
694
695
0
  ai = NULL;
696
  /* save error to host_error for later use */
697
0
  host_error = getaddrinfo(addr, NULL, &hints, &ai);
698
0
  if (net_handle_gai_error("getaddrinfo", host_error, FALSE) != 0) {
699
0
    i_assert(ai == NULL);
700
0
    return host_error;
701
0
  }
702
703
  /* get number of IPs */
704
0
  origai = ai;
705
0
  for (count = 0; ai != NULL; ai = ai->ai_next)
706
0
    count++;
707
0
  i_assert(count > 0);
708
709
0
  *ips_count = count;
710
0
  *ips = t_new(struct ip_addr, count);
711
712
0
  count = 0;
713
0
  for (ai = origai; ai != NULL; ai = ai->ai_next, count++) {
714
0
    so = (union sockaddr_union *) ai->ai_addr;
715
716
0
    sin_get_ip(so, &(*ips)[count]);
717
0
  }
718
0
  freeaddrinfo(origai);
719
720
0
  return 0;
721
0
}
722
723
int net_gethostbyaddr(const struct ip_addr *ip, const char **name_r)
724
0
{
725
0
  union sockaddr_union so;
726
0
  socklen_t addrlen = sizeof(so);
727
0
  char hbuf[NI_MAXHOST];
728
0
  int ret;
729
730
0
  i_zero(&so);
731
0
  sin_set_ip(&so, ip);
732
0
  ret = getnameinfo(&so.sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
733
0
        NI_NAMEREQD);
734
0
  if (net_handle_gai_error("getnameinfo", ret, FALSE) != 0)
735
0
    return ret;
736
737
0
  *name_r = t_strdup(hbuf);
738
0
  return 0;
739
0
}
740
741
int net_getsockname(int fd, struct ip_addr *addr, in_port_t *port)
742
0
{
743
0
  union sockaddr_union so;
744
0
  socklen_t addrlen;
745
746
0
  i_assert(fd >= 0);
747
748
0
  i_zero(&so);
749
0
  addrlen = sizeof(so);
750
0
  if (getsockname(fd, &so.sa, &addrlen) == -1)
751
0
    return -1;
752
0
  if (so.sin.sin_family == AF_UNIX) {
753
0
    if (addr != NULL)
754
0
      i_zero(addr);
755
0
    if (port != NULL) *port = 0;
756
0
  } else {
757
0
    if (addr != NULL) sin_get_ip(&so, addr);
758
0
    if (port != NULL) *port = sin_get_port(&so);
759
0
  }
760
0
  return 0;
761
0
}
762
763
int net_getpeername(int fd, struct ip_addr *addr, in_port_t *port)
764
0
{
765
0
  union sockaddr_union so;
766
0
  socklen_t addrlen;
767
768
0
  i_assert(fd >= 0);
769
770
0
  i_zero(&so);
771
0
  addrlen = sizeof(so);
772
0
  if (getpeername(fd, &so.sa, &addrlen) == -1)
773
0
    return -1;
774
0
  if (so.sin.sin_family == AF_UNIX) {
775
0
    if (addr != NULL)
776
0
      i_zero(addr);
777
0
    if (port != NULL) *port = 0;
778
0
  } else {
779
0
    if (addr != NULL) sin_get_ip(&so, addr);
780
0
    if (port != NULL) *port = sin_get_port(&so);
781
0
  }
782
0
  return 0;
783
0
}
784
785
int net_getunixname(int fd, const char **name_r)
786
0
{
787
0
  union sockaddr_union_unix so;
788
0
  socklen_t addrlen = sizeof(so);
789
790
0
  i_zero(&so);
791
0
  if (getsockname(fd, &so.sa, &addrlen) < 0)
792
0
    return -1;
793
0
  if (so.un.sun_family != AF_UNIX) {
794
0
    errno = ENOTSOCK;
795
0
    return -1;
796
0
  }
797
0
  *name_r = t_strdup(so.un.sun_path);
798
0
  return 0;
799
0
}
800
801
int net_getunixcred(int fd, struct net_unix_cred *cred_r)
802
0
{
803
0
#if defined(SO_PEERCRED)
804
# if defined(HAVE_STRUCT_SOCKPEERCRED)
805
  /* OpenBSD (may also provide getpeereid, but we also want pid) */
806
  struct sockpeercred ucred;
807
# else
808
  /* Linux */
809
0
  struct ucred ucred;
810
0
# endif
811
0
  socklen_t len = sizeof(ucred);
812
813
0
  if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
814
0
    i_error("getsockopt(SO_PEERCRED) failed: %m");
815
0
    return -1;
816
0
  }
817
0
  cred_r->uid = ucred.uid;
818
0
  cred_r->gid = ucred.gid;
819
0
  cred_r->pid = ucred.pid;
820
0
  return 0;
821
#elif defined(LOCAL_PEEREID)
822
  /* NetBSD (may also provide getpeereid, but we also want pid) */
823
  struct unpcbid ucred;
824
  socklen_t len = sizeof(ucred);
825
826
  if (getsockopt(fd, 0, LOCAL_PEEREID, &ucred, &len) < 0) {
827
    i_error("getsockopt(LOCAL_PEEREID) failed: %m");
828
    return -1;
829
  }
830
831
  cred_r->uid = ucred.unp_euid;
832
  cred_r->gid = ucred.unp_egid;
833
  cred_r->pid = ucred.unp_pid;
834
  return 0;
835
#elif defined(LOCAL_PEERCRED) && \
836
  (defined(HAVE_STRUCT_XUCRED_CR_PID) || !defined(HAVE_GETPEEREID))
837
  /* FreeBSD, macOS. getpeereid() usually exists as well, but it can't
838
     return the pid. Prefer it only if struct xucred has no pid either
839
     (FreeBSD <13, macOS). */
840
  struct xucred ucred;
841
  socklen_t len = sizeof(ucred);
842
843
  if (getsockopt(fd, 0, LOCAL_PEERCRED, &ucred, &len) < 0) {
844
    i_error("getsockopt(LOCAL_PEERCRED) failed: %m");
845
    return -1;
846
  }
847
848
  if (ucred.cr_version != XUCRED_VERSION) {
849
    errno = EINVAL;
850
    return -1;
851
  }
852
853
  cred_r->uid = ucred.cr_uid;
854
  cred_r->gid = ucred.cr_gid;
855
# ifdef HAVE_STRUCT_XUCRED_CR_PID
856
  cred_r->pid = ucred.cr_pid;
857
# else
858
  cred_r->pid = (pid_t)-1;
859
# endif
860
  return 0;
861
#elif defined(HAVE_GETPEEREID)
862
  /* OSX 10.4+, FreeBSD 4.6+, OpenBSD 3.0+, NetBSD 5.0+ */
863
  if (getpeereid(fd, &cred_r->uid, &cred_r->gid) < 0) {
864
    i_error("getpeereid() failed: %m");
865
    return -1;
866
  }
867
  cred_r->pid = (pid_t)-1;
868
  return 0;
869
#elif defined(HAVE_GETPEERUCRED)
870
  /* Solaris */
871
  ucred_t *ucred = NULL;
872
873
  if (getpeerucred(fd, &ucred) < 0) {
874
    i_error("getpeerucred() failed: %m");
875
    return -1;
876
  }
877
  cred_r->uid = ucred_geteuid(ucred);
878
  cred_r->gid = ucred_getrgid(ucred);
879
  cred_r->pid = ucred_getpid(ucred);
880
  ucred_free(ucred);
881
882
  if (cred_r->uid == (uid_t)-1 ||
883
      cred_r->gid == (gid_t)-1) {
884
    errno = EINVAL;
885
    return -1;
886
  }
887
  return 0;
888
#elif defined(NEEDS_LOCAL_CREDS)
889
  /* NetBSD < 5 */
890
  int i, n, on;
891
  struct iovec iov;
892
  struct msghdr msg;
893
  struct {
894
    struct cmsghdr ch;
895
    char buf[110];
896
  } cdata;
897
  struct sockcred *sc;
898
899
  iov.iov_base = (char *)&on;
900
  iov.iov_len = 1;
901
902
  sc = (struct sockcred *)cdata.buf;
903
  sc->sc_uid = sc->sc_euid = sc->sc_gid = sc->sc_egid = -1;
904
  i_zero(&cdata.ch);
905
906
  i_zero(&msg);
907
908
  msg.msg_iov = &iov;
909
  msg.msg_iovlen = 1;
910
  msg.msg_control = &cdata;
911
  msg.msg_controllen = sizeof(cdata.ch) + sizeof(cdata.buf);
912
913
  for (i = 0; i < 10; i++) {
914
    n = recvmsg(fd, &msg, MSG_WAITALL | MSG_PEEK);
915
    if (n >= 0 || errno != EAGAIN)
916
      break;
917
    usleep(100);
918
  }
919
  if (n < 0) {
920
    i_error("recvmsg() failed: %m");
921
    return -1;
922
  }
923
  cred_r->uid = sc->sc_euid;
924
  cred_r->gid = sc->sc_egid;
925
  cred_r->pid = (pid_t)-1;
926
  return 0;
927
#else
928
  errno = EINVAL;
929
  return -1;
930
#endif
931
0
}
932
933
const char *net_ip2addr(const struct ip_addr *ip)
934
0
{
935
0
  union sockaddr_union u;
936
0
  socklen_t so_len;
937
938
0
  if (ip->family == AF_INET) {
939
0
    u.sin.sin_addr = ip->u.ip4;
940
0
    u.sin.sin_family = ip->family;
941
0
    so_len = sizeof(u.sin);
942
0
  } else if (ip->family == AF_INET6) {
943
0
    u.sin6.sin6_addr = ip->u.ip6;
944
0
    u.sin6.sin6_family = ip->family;
945
0
    u.sin6.sin6_scope_id = ip->scope_id;
946
0
    so_len = sizeof(u.sin6);
947
0
  } else /* not an IP */
948
0
    return "";
949
950
0
  char *addr = t_malloc_no0(MAX_IP_LEN+1);
951
0
  int ret;
952
0
  if ((ret = getnameinfo(&u.sa, so_len, addr, MAX_IP_LEN+1, NULL, 0,
953
0
             NI_NUMERICHOST)) < 0) {
954
0
    (void)net_handle_gai_error("getnameinfo", ret, TRUE);
955
0
    return "";
956
0
  }
957
0
  return addr;
958
0
}
959
960
static bool net_addr2ip_inet4_fast(const char *addr, struct ip_addr *ip)
961
0
{
962
0
  uint8_t *saddr = (void *)&ip->u.ip4.s_addr;
963
0
  unsigned int i, num;
964
965
0
  if (str_parse_uint(addr, &num, &addr) < 0)
966
0
    return FALSE;
967
968
  /* try to parse as a.b.c.d */
969
0
  i = 0;
970
0
  for (;;) {
971
0
    if (num >= 256)
972
0
      return FALSE;
973
0
    saddr[i] = num;
974
0
    if (i == 3)
975
0
      break;
976
0
    i++;
977
0
    if (*addr != '.')
978
0
      return FALSE;
979
0
    addr++;
980
0
    if (str_parse_uint(addr, &num, &addr) < 0)
981
0
      return FALSE;
982
0
  }
983
0
  if (*addr != '\0')
984
0
    return FALSE;
985
0
  ip->family = AF_INET;
986
0
  return TRUE;
987
0
}
988
989
int net_addr2ip(const char *addr, struct ip_addr *ip_r)
990
0
{
991
0
  int ret;
992
993
0
  if (net_addr2ip_inet4_fast(addr, ip_r))
994
0
    return 0;
995
996
0
  T_BEGIN {
997
0
    if (strchr(addr, ':') != NULL) {
998
0
      if (addr[0] == '[') {
999
        /* allow [ipv6 addr] */
1000
0
        size_t len = strlen(addr);
1001
0
        if (addr[len-1] == ']')
1002
0
          addr = t_strndup(addr+1, len-2);
1003
0
      }
1004
0
    }
1005
1006
0
    struct addrinfo *res = NULL;
1007
0
    const struct addrinfo hints = {
1008
0
      .ai_flags = AI_NUMERICHOST,
1009
0
    };
1010
0
    if ((ret = getaddrinfo(addr, NULL, &hints, &res)) == 0) {
1011
0
      i_assert(res != NULL);
1012
0
      const union sockaddr_union *so =
1013
0
        (union sockaddr_union *)res->ai_addr;
1014
0
      sin_get_ip(so, ip_r);
1015
0
    }
1016
0
    if (res != NULL)
1017
0
      freeaddrinfo(res);
1018
0
    ret = net_handle_gai_error("getaddrinfo", ret, TRUE);
1019
0
  } T_END;
1020
0
  return ret != 0 ? -1 : 0;
1021
0
}
1022
1023
int net_str2port(const char *str, in_port_t *port_r)
1024
0
{
1025
0
  uintmax_t l;
1026
1027
0
  if (str_to_uintmax(str, &l) < 0)
1028
0
    return -1;
1029
1030
0
  if (l == 0 || l > (in_port_t)-1)
1031
0
    return -1;
1032
0
  *port_r = (in_port_t)l;
1033
0
  return 0;
1034
0
}
1035
1036
int net_str2port_zero(const char *str, in_port_t *port_r)
1037
0
{
1038
0
  uintmax_t l;
1039
1040
0
  if (str_to_uintmax(str, &l) < 0)
1041
0
    return -1;
1042
1043
0
  if (l > (in_port_t)-1)
1044
0
    return -1;
1045
0
  *port_r = (in_port_t)l;
1046
0
  return 0;
1047
0
}
1048
1049
int net_str2hostport(const char *str, in_port_t default_port,
1050
         const char **host_r, in_port_t *port_r)
1051
0
{
1052
0
  const char *p, *host;
1053
0
  in_port_t port;
1054
1055
0
  if (str[0] == '[') {
1056
    /* [IPv6] address, possibly followed by :port */
1057
0
    p = strchr(str, ']');
1058
0
    if (p == NULL)
1059
0
      return -1;
1060
0
    host = t_strdup_until(str+1, p++);
1061
0
  } else {
1062
0
    p = strchr(str, ':');
1063
0
    if (p == NULL || strchr(p+1, ':') != NULL) {
1064
      /* host or IPv6 address */
1065
0
      *host_r = str;
1066
0
      *port_r = default_port;
1067
0
      return 0;
1068
0
    }
1069
0
    host = t_strdup_until(str, p);
1070
0
  }
1071
0
  if (p[0] == '\0') {
1072
0
    *host_r = host;
1073
0
    *port_r = default_port;
1074
0
    return 0;
1075
0
  }
1076
0
  if (p[0] != ':')
1077
0
    return -1;
1078
0
  if (net_str2port(p+1, &port) < 0)
1079
0
    return -1;
1080
0
  *host_r = host;
1081
0
  *port_r = port;
1082
0
  return 0;
1083
0
}
1084
1085
const char *net_ipport2str(const struct ip_addr *ip, in_port_t port)
1086
0
{
1087
0
  i_assert(IPADDR_IS_V4(ip) || IPADDR_IS_V6(ip));
1088
1089
0
  return t_strdup_printf("%s%s%s:%u",
1090
0
             (IPADDR_IS_V6(ip) ? "[" : ""), net_ip2addr(ip),
1091
0
             (IPADDR_IS_V6(ip) ? "]" : ""), port);
1092
0
}
1093
1094
int net_ipv6_mapped_ipv4_convert(const struct ip_addr *src,
1095
         struct ip_addr *dest)
1096
0
{
1097
0
  static const uint8_t v4_prefix[] =
1098
0
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
1099
1100
0
  if (!IPADDR_IS_V6(src))
1101
0
    return -1;
1102
0
  if (memcmp(src->u.ip6.s6_addr, v4_prefix, sizeof(v4_prefix)) != 0)
1103
0
    return -1;
1104
1105
0
  i_zero(dest);
1106
0
  dest->family = AF_INET;
1107
0
  memcpy(&dest->u.ip6, &src->u.ip6.s6_addr[3*4], 4);
1108
0
  return 0;
1109
0
}
1110
1111
int net_geterror(int fd)
1112
0
{
1113
0
  int data;
1114
0
  socklen_t len = sizeof(data);
1115
1116
0
  if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &data, &len) == -1) {
1117
    /* we're now really returning the getsockopt()'s error code
1118
       instead of the socket's, but normally we should never get
1119
       here anyway. */
1120
0
    return errno;
1121
0
  }
1122
1123
0
  return data;
1124
0
}
1125
1126
const char *net_gethosterror(int error)
1127
0
{
1128
0
  i_assert(error != 0);
1129
1130
0
  return gai_strerror(error);
1131
0
}
1132
1133
enum net_hosterror_type net_get_hosterror_type(int error)
1134
0
{
1135
0
  const struct {
1136
0
    int error;
1137
0
    enum net_hosterror_type type;
1138
0
  } error_map[] = {
1139
0
#ifdef EAI_ADDRFAMILY /* Obsoleted by RFC 2553bis-02 */
1140
0
    { EAI_ADDRFAMILY, NET_HOSTERROR_TYPE_NOT_FOUND },
1141
0
#endif
1142
0
    { EAI_AGAIN, NET_HOSTERROR_TYPE_NAMESERVER },
1143
0
    { EAI_BADFLAGS, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1144
0
    { EAI_FAIL, NET_HOSTERROR_TYPE_NAMESERVER },
1145
0
    { EAI_FAMILY, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1146
0
    { EAI_MEMORY, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1147
0
#ifdef EAI_NODATA /* Obsoleted by RFC 2553bis-02 */
1148
0
    { EAI_NODATA, NET_HOSTERROR_TYPE_NOT_FOUND },
1149
0
#endif
1150
0
    { EAI_NONAME, NET_HOSTERROR_TYPE_NOT_FOUND },
1151
0
    { EAI_SERVICE, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1152
0
    { EAI_SOCKTYPE, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1153
0
    { EAI_SYSTEM, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1154
0
  };
1155
0
  for (unsigned int i = 0; i < N_ELEMENTS(error_map); i++) {
1156
0
    if (error_map[i].error == error)
1157
0
      return error_map[i].type;
1158
0
  }
1159
1160
  /* shouldn't happen? assume internal error */
1161
0
  return NET_HOSTERROR_TYPE_INTERNAL_ERROR;
1162
0
}
1163
1164
int net_hosterror_notfound(int error)
1165
0
{
1166
0
#ifdef EAI_NODATA /* NODATA is deprecated */
1167
0
  return (error != 1 && (error == EAI_NONAME || error == EAI_NODATA)) ? 1 : 0;
1168
#else
1169
  return (error != 1 && (error == EAI_NONAME)) ? 1 : 0;
1170
#endif
1171
0
}
1172
1173
const char *net_getservbyport(in_port_t port)
1174
0
{
1175
0
  const struct servent *entry;
1176
1177
0
  entry = getservbyport(htons(port), "tcp");
1178
0
  return entry == NULL ? NULL : entry->s_name;
1179
0
}
1180
1181
int net_parse_range(const char *network, struct ip_addr *ip_r,
1182
        unsigned int *bits_r)
1183
0
{
1184
0
  const char *p;
1185
0
  unsigned int bits, max_bits;
1186
1187
0
  p = strchr(network, '/');
1188
0
  if (p != NULL)
1189
0
    network = t_strdup_until(network, p++);
1190
1191
0
  if (net_addr2ip(network, ip_r) < 0)
1192
0
    return -1;
1193
1194
0
  max_bits = IPADDR_BITS(ip_r);
1195
0
  if (p == NULL) {
1196
    /* full IP address must match */
1197
0
    bits = max_bits;
1198
0
  } else {
1199
    /* get the network mask */
1200
0
    if (str_to_uint(p, &bits) < 0 || bits > max_bits)
1201
0
      return -1;
1202
0
  }
1203
0
  *bits_r = bits;
1204
0
  return 0;
1205
0
}
1206
1207
bool net_is_in_network(const struct ip_addr *ip,
1208
           const struct ip_addr *net_ip, unsigned int bits)
1209
0
{
1210
0
  struct ip_addr tmp_ip;
1211
0
  const uint32_t *ip1, *ip2;
1212
0
  uint32_t mask, i1, i2;
1213
0
  unsigned int pos, i;
1214
1215
0
  if (net_ipv6_mapped_ipv4_convert(ip, &tmp_ip) == 0) {
1216
    /* IPv4 address mapped disguised as IPv6 address */
1217
0
    ip = &tmp_ip;
1218
0
  }
1219
1220
0
  if (ip->family == 0 || net_ip->family == 0) {
1221
    /* non-IPv4/IPv6 address (e.g. UNIX socket) never matches
1222
       anything */
1223
0
    return FALSE;
1224
0
  }
1225
0
  if (IPADDR_IS_V4(ip) != IPADDR_IS_V4(net_ip)) {
1226
    /* one is IPv6 and one is IPv4 */
1227
0
    return FALSE;
1228
0
  }
1229
0
  i_assert(IPADDR_IS_V6(ip) == IPADDR_IS_V6(net_ip));
1230
1231
0
  if (IPADDR_IS_V4(ip)) {
1232
0
    ip1 = &ip->u.ip4.s_addr;
1233
0
    ip2 = &net_ip->u.ip4.s_addr;
1234
0
  } else {
1235
0
    ip1 = (const void *)&ip->u.ip6;
1236
0
    ip2 = (const void *)&net_ip->u.ip6;
1237
0
    if (ip->scope_id != net_ip->scope_id &&
1238
0
        net_ip->scope_id != 0) {
1239
      /* %iface1 != %iface2 never matches, but allow
1240
         missing interface on the net_ip */
1241
0
      return FALSE;
1242
0
    }
1243
0
  }
1244
1245
  /* check first the full 32bit ints */
1246
0
  for (pos = 0, i = 0; pos + 32 <= bits; pos += 32, i++) {
1247
0
    if (ip1[i] != ip2[i])
1248
0
      return FALSE;
1249
0
  }
1250
0
  i1 = htonl(ip1[i]);
1251
0
  i2 = htonl(ip2[i]);
1252
1253
  /* check the last full bytes */
1254
0
  for (mask = 0xff000000; pos + 8 <= bits; pos += 8, mask >>= 8) {
1255
0
    if ((i1 & mask) != (i2 & mask))
1256
0
      return FALSE;
1257
0
  }
1258
1259
  /* check the last bits, they're reversed in bytes */
1260
0
  bits -= pos;
1261
0
  for (mask = 0x80000000 >> (pos % 32); bits > 0; bits--, mask >>= 1) {
1262
0
    if ((i1 & mask) != (i2 & mask))
1263
0
      return FALSE;
1264
0
  }
1265
0
  return TRUE;
1266
0
}