Coverage Report

Created: 2024-02-11 06:22

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