Coverage Report

Created: 2026-05-16 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib/net.c
Line
Count
Source
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
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(HAVE_GETPEEREID)
836
  /* OSX 10.4+, FreeBSD 4.6+, OpenBSD 3.0+, NetBSD 5.0+ */
837
  if (getpeereid(fd, &cred_r->uid, &cred_r->gid) < 0) {
838
    i_error("getpeereid() failed: %m");
839
    return -1;
840
  }
841
  cred_r->pid = (pid_t)-1;
842
  return 0;
843
#elif defined(LOCAL_PEERCRED)
844
  /* Older FreeBSD */
845
  struct xucred ucred;
846
  socklen_t len = sizeof(ucred);
847
848
  if (getsockopt(fd, 0, LOCAL_PEERCRED, &ucred, &len) < 0) {
849
    i_error("getsockopt(LOCAL_PEERCRED) failed: %m");
850
    return -1;
851
  }
852
853
  if (ucred.cr_version != XUCRED_VERSION) {
854
    errno = EINVAL;
855
    return -1;
856
  }
857
858
  cred_r->uid = ucred.cr_uid;
859
  cred_r->gid = ucred.cr_gid;
860
  cred_r->pid = (pid_t)-1;
861
  return 0;
862
#elif defined(HAVE_GETPEERUCRED)
863
  /* Solaris */
864
  ucred_t *ucred = NULL;
865
866
  if (getpeerucred(fd, &ucred) < 0) {
867
    i_error("getpeerucred() failed: %m");
868
    return -1;
869
  }
870
  cred_r->uid = ucred_geteuid(ucred);
871
  cred_r->gid = ucred_getrgid(ucred);
872
  cred_r->pid = ucred_getpid(ucred);
873
  ucred_free(ucred);
874
875
  if (cred_r->uid == (uid_t)-1 ||
876
      cred_r->gid == (gid_t)-1) {
877
    errno = EINVAL;
878
    return -1;
879
  }
880
  return 0;
881
#elif defined(NEEDS_LOCAL_CREDS)
882
  /* NetBSD < 5 */
883
  int i, n, on;
884
  struct iovec iov;
885
  struct msghdr msg;
886
  struct {
887
    struct cmsghdr ch;
888
    char buf[110];
889
  } cdata;
890
  struct sockcred *sc;
891
892
  iov.iov_base = (char *)&on;
893
  iov.iov_len = 1;
894
895
  sc = (struct sockcred *)cdata.buf;
896
  sc->sc_uid = sc->sc_euid = sc->sc_gid = sc->sc_egid = -1;
897
  i_zero(&cdata.ch);
898
899
  i_zero(&msg);
900
901
  msg.msg_iov = &iov;
902
  msg.msg_iovlen = 1;
903
  msg.msg_control = &cdata;
904
  msg.msg_controllen = sizeof(cdata.ch) + sizeof(cdata.buf);
905
906
  for (i = 0; i < 10; i++) {
907
    n = recvmsg(fd, &msg, MSG_WAITALL | MSG_PEEK);
908
    if (n >= 0 || errno != EAGAIN)
909
      break;
910
    usleep(100);
911
  }
912
  if (n < 0) {
913
    i_error("recvmsg() failed: %m");
914
    return -1;
915
  }
916
  cred_r->uid = sc->sc_euid;
917
  cred_r->gid = sc->sc_egid;
918
  cred_r->pid = (pid_t)-1;
919
  return 0;
920
#else
921
  errno = EINVAL;
922
  return -1;
923
#endif
924
0
}
925
926
const char *net_ip2addr(const struct ip_addr *ip)
927
0
{
928
0
  union sockaddr_union u;
929
0
  socklen_t so_len;
930
931
0
  if (ip->family == AF_INET) {
932
0
    u.sin.sin_addr = ip->u.ip4;
933
0
    u.sin.sin_family = ip->family;
934
0
    so_len = sizeof(u.sin);
935
0
  } else if (ip->family == AF_INET6) {
936
0
    u.sin6.sin6_addr = ip->u.ip6;
937
0
    u.sin6.sin6_family = ip->family;
938
0
    u.sin6.sin6_scope_id = ip->scope_id;
939
0
    so_len = sizeof(u.sin6);
940
0
  } else /* not an IP */
941
0
    return "";
942
943
0
  char *addr = t_malloc_no0(MAX_IP_LEN+1);
944
0
  int ret;
945
0
  if ((ret = getnameinfo(&u.sa, so_len, addr, MAX_IP_LEN+1, NULL, 0,
946
0
             NI_NUMERICHOST)) < 0) {
947
0
    (void)net_handle_gai_error("getnameinfo", ret, TRUE);
948
0
    return "";
949
0
  }
950
0
  return addr;
951
0
}
952
953
static bool net_addr2ip_inet4_fast(const char *addr, struct ip_addr *ip)
954
0
{
955
0
  uint8_t *saddr = (void *)&ip->u.ip4.s_addr;
956
0
  unsigned int i, num;
957
958
0
  if (str_parse_uint(addr, &num, &addr) < 0)
959
0
    return FALSE;
960
961
  /* try to parse as a.b.c.d */
962
0
  i = 0;
963
0
  for (;;) {
964
0
    if (num >= 256)
965
0
      return FALSE;
966
0
    saddr[i] = num;
967
0
    if (i == 3)
968
0
      break;
969
0
    i++;
970
0
    if (*addr != '.')
971
0
      return FALSE;
972
0
    addr++;
973
0
    if (str_parse_uint(addr, &num, &addr) < 0)
974
0
      return FALSE;
975
0
  }
976
0
  if (*addr != '\0')
977
0
    return FALSE;
978
0
  ip->family = AF_INET;
979
0
  return TRUE;
980
0
}
981
982
int net_addr2ip(const char *addr, struct ip_addr *ip_r)
983
0
{
984
0
  int ret;
985
986
0
  if (net_addr2ip_inet4_fast(addr, ip_r))
987
0
    return 0;
988
989
0
  T_BEGIN {
990
0
    if (strchr(addr, ':') != NULL) {
991
0
      if (addr[0] == '[') {
992
        /* allow [ipv6 addr] */
993
0
        size_t len = strlen(addr);
994
0
        if (addr[len-1] == ']')
995
0
          addr = t_strndup(addr+1, len-2);
996
0
      }
997
0
    }
998
999
0
    struct addrinfo *res = NULL;
1000
0
    const struct addrinfo hints = {
1001
0
      .ai_flags = AI_NUMERICHOST,
1002
0
    };
1003
0
    if ((ret = getaddrinfo(addr, NULL, &hints, &res)) == 0) {
1004
0
      i_assert(res != NULL);
1005
0
      const union sockaddr_union *so =
1006
0
        (union sockaddr_union *)res->ai_addr;
1007
0
      sin_get_ip(so, ip_r);
1008
0
    }
1009
0
    if (res != NULL)
1010
0
      freeaddrinfo(res);
1011
0
    ret = net_handle_gai_error("getaddrinfo", ret, TRUE);
1012
0
  } T_END;
1013
0
  return ret != 0 ? -1 : 0;
1014
0
}
1015
1016
int net_str2port(const char *str, in_port_t *port_r)
1017
0
{
1018
0
  uintmax_t l;
1019
1020
0
  if (str_to_uintmax(str, &l) < 0)
1021
0
    return -1;
1022
1023
0
  if (l == 0 || l > (in_port_t)-1)
1024
0
    return -1;
1025
0
  *port_r = (in_port_t)l;
1026
0
  return 0;
1027
0
}
1028
1029
int net_str2port_zero(const char *str, in_port_t *port_r)
1030
0
{
1031
0
  uintmax_t l;
1032
1033
0
  if (str_to_uintmax(str, &l) < 0)
1034
0
    return -1;
1035
1036
0
  if (l > (in_port_t)-1)
1037
0
    return -1;
1038
0
  *port_r = (in_port_t)l;
1039
0
  return 0;
1040
0
}
1041
1042
int net_str2hostport(const char *str, in_port_t default_port,
1043
         const char **host_r, in_port_t *port_r)
1044
0
{
1045
0
  const char *p, *host;
1046
0
  in_port_t port;
1047
1048
0
  if (str[0] == '[') {
1049
    /* [IPv6] address, possibly followed by :port */
1050
0
    p = strchr(str, ']');
1051
0
    if (p == NULL)
1052
0
      return -1;
1053
0
    host = t_strdup_until(str+1, p++);
1054
0
  } else {
1055
0
    p = strchr(str, ':');
1056
0
    if (p == NULL || strchr(p+1, ':') != NULL) {
1057
      /* host or IPv6 address */
1058
0
      *host_r = str;
1059
0
      *port_r = default_port;
1060
0
      return 0;
1061
0
    }
1062
0
    host = t_strdup_until(str, p);
1063
0
  }
1064
0
  if (p[0] == '\0') {
1065
0
    *host_r = host;
1066
0
    *port_r = default_port;
1067
0
    return 0;
1068
0
  }
1069
0
  if (p[0] != ':')
1070
0
    return -1;
1071
0
  if (net_str2port(p+1, &port) < 0)
1072
0
    return -1;
1073
0
  *host_r = host;
1074
0
  *port_r = port;
1075
0
  return 0;
1076
0
}
1077
1078
const char *net_ipport2str(const struct ip_addr *ip, in_port_t port)
1079
0
{
1080
0
  i_assert(IPADDR_IS_V4(ip) || IPADDR_IS_V6(ip));
1081
1082
0
  return t_strdup_printf("%s%s%s:%u",
1083
0
             (IPADDR_IS_V6(ip) ? "[" : ""), net_ip2addr(ip),
1084
0
             (IPADDR_IS_V6(ip) ? "]" : ""), port);
1085
0
}
1086
1087
int net_ipv6_mapped_ipv4_convert(const struct ip_addr *src,
1088
         struct ip_addr *dest)
1089
0
{
1090
0
  static const uint8_t v4_prefix[] =
1091
0
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
1092
1093
0
  if (!IPADDR_IS_V6(src))
1094
0
    return -1;
1095
0
  if (memcmp(src->u.ip6.s6_addr, v4_prefix, sizeof(v4_prefix)) != 0)
1096
0
    return -1;
1097
1098
0
  i_zero(dest);
1099
0
  dest->family = AF_INET;
1100
0
  memcpy(&dest->u.ip6, &src->u.ip6.s6_addr[3*4], 4);
1101
0
  return 0;
1102
0
}
1103
1104
int net_geterror(int fd)
1105
0
{
1106
0
  int data;
1107
0
  socklen_t len = sizeof(data);
1108
1109
0
  if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &data, &len) == -1) {
1110
    /* we're now really returning the getsockopt()'s error code
1111
       instead of the socket's, but normally we should never get
1112
       here anyway. */
1113
0
    return errno;
1114
0
  }
1115
1116
0
  return data;
1117
0
}
1118
1119
const char *net_gethosterror(int error)
1120
0
{
1121
0
  i_assert(error != 0);
1122
1123
0
  return gai_strerror(error);
1124
0
}
1125
1126
enum net_hosterror_type net_get_hosterror_type(int error)
1127
0
{
1128
0
  const struct {
1129
0
    int error;
1130
0
    enum net_hosterror_type type;
1131
0
  } error_map[] = {
1132
0
#ifdef EAI_ADDRFAMILY /* Obsoleted by RFC 2553bis-02 */
1133
0
    { EAI_ADDRFAMILY, NET_HOSTERROR_TYPE_NOT_FOUND },
1134
0
#endif
1135
0
    { EAI_AGAIN, NET_HOSTERROR_TYPE_NAMESERVER },
1136
0
    { EAI_BADFLAGS, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1137
0
    { EAI_FAIL, NET_HOSTERROR_TYPE_NAMESERVER },
1138
0
    { EAI_FAMILY, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1139
0
    { EAI_MEMORY, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1140
0
#ifdef EAI_NODATA /* Obsoleted by RFC 2553bis-02 */
1141
0
    { EAI_NODATA, NET_HOSTERROR_TYPE_NOT_FOUND },
1142
0
#endif
1143
0
    { EAI_NONAME, NET_HOSTERROR_TYPE_NOT_FOUND },
1144
0
    { EAI_SERVICE, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1145
0
    { EAI_SOCKTYPE, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1146
0
    { EAI_SYSTEM, NET_HOSTERROR_TYPE_INTERNAL_ERROR },
1147
0
  };
1148
0
  for (unsigned int i = 0; i < N_ELEMENTS(error_map); i++) {
1149
0
    if (error_map[i].error == error)
1150
0
      return error_map[i].type;
1151
0
  }
1152
1153
  /* shouldn't happen? assume internal error */
1154
0
  return NET_HOSTERROR_TYPE_INTERNAL_ERROR;
1155
0
}
1156
1157
int net_hosterror_notfound(int error)
1158
0
{
1159
0
#ifdef EAI_NODATA /* NODATA is deprecated */
1160
0
  return (error != 1 && (error == EAI_NONAME || error == EAI_NODATA)) ? 1 : 0;
1161
#else
1162
  return (error != 1 && (error == EAI_NONAME)) ? 1 : 0;
1163
#endif
1164
0
}
1165
1166
const char *net_getservbyport(in_port_t port)
1167
0
{
1168
0
  const struct servent *entry;
1169
1170
0
  entry = getservbyport(htons(port), "tcp");
1171
0
  return entry == NULL ? NULL : entry->s_name;
1172
0
}
1173
1174
int net_parse_range(const char *network, struct ip_addr *ip_r,
1175
        unsigned int *bits_r)
1176
0
{
1177
0
  const char *p;
1178
0
  unsigned int bits, max_bits;
1179
1180
0
  p = strchr(network, '/');
1181
0
  if (p != NULL)
1182
0
    network = t_strdup_until(network, p++);
1183
1184
0
  if (net_addr2ip(network, ip_r) < 0)
1185
0
    return -1;
1186
1187
0
  max_bits = IPADDR_BITS(ip_r);
1188
0
  if (p == NULL) {
1189
    /* full IP address must match */
1190
0
    bits = max_bits;
1191
0
  } else {
1192
    /* get the network mask */
1193
0
    if (str_to_uint(p, &bits) < 0 || bits > max_bits)
1194
0
      return -1;
1195
0
  }
1196
0
  *bits_r = bits;
1197
0
  return 0;
1198
0
}
1199
1200
bool net_is_in_network(const struct ip_addr *ip,
1201
           const struct ip_addr *net_ip, unsigned int bits)
1202
0
{
1203
0
  struct ip_addr tmp_ip;
1204
0
  const uint32_t *ip1, *ip2;
1205
0
  uint32_t mask, i1, i2;
1206
0
  unsigned int pos, i;
1207
1208
0
  if (net_ipv6_mapped_ipv4_convert(ip, &tmp_ip) == 0) {
1209
    /* IPv4 address mapped disguised as IPv6 address */
1210
0
    ip = &tmp_ip;
1211
0
  }
1212
1213
0
  if (ip->family == 0 || net_ip->family == 0) {
1214
    /* non-IPv4/IPv6 address (e.g. UNIX socket) never matches
1215
       anything */
1216
0
    return FALSE;
1217
0
  }
1218
0
  if (IPADDR_IS_V4(ip) != IPADDR_IS_V4(net_ip)) {
1219
    /* one is IPv6 and one is IPv4 */
1220
0
    return FALSE;
1221
0
  }
1222
0
  i_assert(IPADDR_IS_V6(ip) == IPADDR_IS_V6(net_ip));
1223
1224
0
  if (IPADDR_IS_V4(ip)) {
1225
0
    ip1 = &ip->u.ip4.s_addr;
1226
0
    ip2 = &net_ip->u.ip4.s_addr;
1227
0
  } else {
1228
0
    ip1 = (const void *)&ip->u.ip6;
1229
0
    ip2 = (const void *)&net_ip->u.ip6;
1230
0
    if (ip->scope_id != net_ip->scope_id &&
1231
0
        net_ip->scope_id != 0) {
1232
      /* %iface1 != %iface2 never matches, but allow
1233
         missing interface on the net_ip */
1234
0
      return FALSE;
1235
0
    }
1236
0
  }
1237
1238
  /* check first the full 32bit ints */
1239
0
  for (pos = 0, i = 0; pos + 32 <= bits; pos += 32, i++) {
1240
0
    if (ip1[i] != ip2[i])
1241
0
      return FALSE;
1242
0
  }
1243
0
  i1 = htonl(ip1[i]);
1244
0
  i2 = htonl(ip2[i]);
1245
1246
  /* check the last full bytes */
1247
0
  for (mask = 0xff000000; pos + 8 <= bits; pos += 8, mask >>= 8) {
1248
0
    if ((i1 & mask) != (i2 & mask))
1249
0
      return FALSE;
1250
0
  }
1251
1252
  /* check the last bits, they're reversed in bytes */
1253
0
  bits -= pos;
1254
0
  for (mask = 0x80000000 >> (pos % 32); bits > 0; bits--, mask >>= 1) {
1255
0
    if ((i1 & mask) != (i2 & mask))
1256
0
      return FALSE;
1257
0
  }
1258
0
  return TRUE;
1259
0
}