1
/* Copyright (c) 1999-2013 Dovecot authors, see the included COPYING file */
3
#define _GNU_SOURCE /* For Linux's struct ucred */
5
#include "fd-set-nonblock.h"
14
#include <netinet/tcp.h>
15
#if defined(HAVE_UCRED_H)
16
# include <ucred.h> /* for getpeerucred() */
17
#elif defined(HAVE_SYS_UCRED_H)
18
# include <sys/ucred.h> /* for FreeBSD struct xucred */
21
union sockaddr_union {
23
struct sockaddr_in sin;
25
struct sockaddr_in6 sin6;
29
union sockaddr_union_unix {
31
struct sockaddr_un un;
35
# define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \
36
sizeof(so.sin6) : sizeof(so.sin))
38
# define SIZEOF_SOCKADDR(so) (sizeof(so.sin))
41
#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_GETPEERUCRED) && defined(MSG_WAITALL) && defined(LOCAL_CREDS)
42
# define NEEDS_LOCAL_CREDS 1
45
bool net_ip_compare(const struct ip_addr *ip1, const struct ip_addr *ip2)
47
return net_ip_cmp(ip1, ip2) == 0;
50
int net_ip_cmp(const struct ip_addr *ip1, const struct ip_addr *ip2)
52
if (ip1->family != ip2->family)
53
return ip1->family - ip2->family;
56
if (ip1->family == AF_INET6)
57
return memcmp(&ip1->u.ip6, &ip2->u.ip6, sizeof(ip1->u.ip6));
60
return memcmp(&ip1->u.ip4, &ip2->u.ip4, sizeof(ip1->u.ip4));
63
unsigned int net_ip_hash(const struct ip_addr *ip)
65
const unsigned char *p;
66
unsigned int len, g, h = 0;
69
if (ip->family == AF_INET6) {
70
p = ip->u.ip6.s6_addr;
71
len = sizeof(ip->u.ip6);
75
return ip->u.ip4.s_addr;
78
for (; len > 0; len--, p++) {
80
if ((g = h & 0xf0000000UL)) {
89
/* copy IP to sockaddr */
91
sin_set_ip(union sockaddr_union *so, const struct ip_addr *ip)
95
so->sin6.sin6_family = AF_INET6;
96
so->sin6.sin6_addr = in6addr_any;
98
so->sin.sin_family = AF_INET;
99
so->sin.sin_addr.s_addr = INADDR_ANY;
104
so->sin.sin_family = ip->family;
106
if (ip->family == AF_INET6)
107
memcpy(&so->sin6.sin6_addr, &ip->u.ip6, sizeof(ip->u.ip6));
110
memcpy(&so->sin.sin_addr, &ip->u.ip4, sizeof(ip->u.ip4));
114
sin_get_ip(const union sockaddr_union *so, struct ip_addr *ip)
116
/* IP structs may be sent across processes. Clear the whole struct
117
first to make sure it won't leak any data across processes. */
118
memset(ip, 0, sizeof(*ip));
120
ip->family = so->sin.sin_family;
123
if (ip->family == AF_INET6)
124
memcpy(&ip->u.ip6, &so->sin6.sin6_addr, sizeof(ip->u.ip6));
127
if (ip->family == AF_INET)
128
memcpy(&ip->u.ip4, &so->sin.sin_addr, sizeof(ip->u.ip4));
130
memset(&ip->u, 0, sizeof(ip->u));
133
static inline void sin_set_port(union sockaddr_union *so, unsigned int port)
136
if (so->sin.sin_family == AF_INET6)
137
so->sin6.sin6_port = htons((unsigned short) port);
140
so->sin.sin_port = htons((unsigned short) port);
143
static inline unsigned int sin_get_port(union sockaddr_union *so)
146
if (so->sin.sin_family == AF_INET6)
147
return ntohs(so->sin6.sin6_port);
149
if (so->sin.sin_family == AF_INET)
150
return ntohs(so->sin.sin_port);
157
net_connect_ip_full_freebsd(const struct ip_addr *ip, unsigned int port,
158
const struct ip_addr *my_ip, bool blocking);
160
static int net_connect_ip_full(const struct ip_addr *ip, unsigned int port,
161
const struct ip_addr *my_ip, bool blocking)
166
fd = net_connect_ip_full_freebsd(ip, port, my_ip, blocking);
167
if (fd != -1 || ++try == 5 ||
168
(errno != EADDRINUSE && errno != EACCES))
171
This may be just a temporary problem:
174
EACCES: pf may cause this if another connection used
175
the same port recently
180
/* then some kludging: */
181
#define net_connect_ip_full net_connect_ip_full_freebsd
184
static int net_connect_ip_full(const struct ip_addr *ip, unsigned int port,
185
const struct ip_addr *my_ip, bool blocking)
187
union sockaddr_union so;
188
int fd, ret, opt = 1;
190
if (my_ip != NULL && ip->family != my_ip->family) {
191
i_warning("net_connect_ip(): ip->family != my_ip->family");
195
/* create the socket */
196
memset(&so, 0, sizeof(so));
197
so.sin.sin_family = ip->family;
198
fd = socket(ip->family, SOCK_STREAM, 0);
201
i_error("socket() failed: %m");
205
/* set socket options */
206
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
207
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
209
net_set_nonblock(fd, TRUE);
211
/* set our own address */
213
sin_set_ip(&so, my_ip);
214
if (bind(fd, &so.sa, SIZEOF_SOCKADDR(so)) == -1) {
215
i_error("bind(%s) failed: %m", net_ip2addr(my_ip));
223
sin_set_port(&so, port);
224
ret = connect(fd, &so.sa, SIZEOF_SOCKADDR(so));
227
if (ret < 0 && errno != EINPROGRESS)
229
if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
239
# undef net_connect_ip_full
242
int net_connect_ip(const struct ip_addr *ip, unsigned int port,
243
const struct ip_addr *my_ip)
245
return net_connect_ip_full(ip, port, my_ip, FALSE);
248
int net_connect_ip_blocking(const struct ip_addr *ip, unsigned int port,
249
const struct ip_addr *my_ip)
251
return net_connect_ip_full(ip, port, my_ip, TRUE);
254
int net_try_bind(const struct ip_addr *ip)
256
union sockaddr_union so;
259
/* create the socket */
260
memset(&so, 0, sizeof(so));
261
so.sin.sin_family = ip->family;
262
fd = socket(ip->family, SOCK_STREAM, 0);
264
i_error("socket() failed: %m");
269
if (bind(fd, &so.sa, SIZEOF_SOCKADDR(so)) == -1) {
277
int net_connect_unix(const char *path)
279
union sockaddr_union_unix sa;
282
memset(&sa, 0, sizeof(sa));
283
sa.un.sun_family = AF_UNIX;
284
if (i_strocpy(sa.un.sun_path, path, sizeof(sa.un.sun_path)) < 0) {
287
errno = ENAMETOOLONG;
294
/* create the socket */
295
fd = socket(PF_UNIX, SOCK_STREAM, 0);
297
i_error("socket(%s) failed: %m", path);
301
net_set_nonblock(fd, TRUE);
304
ret = connect(fd, &sa.sa, sizeof(sa));
305
if (ret < 0 && errno != EINPROGRESS) {
310
#ifdef NEEDS_LOCAL_CREDS
313
if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof on)) {
314
i_error("setsockopt(LOCAL_CREDS) failed: %m");
323
int net_connect_unix_with_retries(const char *path, unsigned int msecs)
325
struct timeval start, now;
328
if (gettimeofday(&start, NULL) < 0)
329
i_panic("gettimeofday() failed: %m");
332
fd = net_connect_unix(path);
333
if (fd != -1 || (errno != EAGAIN && errno != ECONNREFUSED))
336
/* busy. wait for a while. */
337
usleep(((rand() % 10) + 1) * 10000);
338
if (gettimeofday(&now, NULL) < 0)
339
i_panic("gettimeofday() failed: %m");
340
} while (timeval_diff_msecs(&now, &start) < (int)msecs);
344
void net_disconnect(int fd)
346
/* FreeBSD's close() fails with ECONNRESET if socket still has unsent
347
data in transmit buffer. We don't care. */
348
if (close(fd) < 0 && errno != ECONNRESET)
349
i_error("net_disconnect() failed: %m");
352
void net_set_nonblock(int fd, bool nonblock)
354
fd_set_nonblock(fd, nonblock);
357
int net_set_cork(int fd ATTR_UNUSED, bool cork ATTR_UNUSED)
362
return setsockopt(fd, IPPROTO_TCP, TCP_CORK, &val, sizeof(val));
369
void net_get_ip_any4(struct ip_addr *ip)
371
ip->family = AF_INET;
372
ip->u.ip4.s_addr = INADDR_ANY;
375
void net_get_ip_any6(struct ip_addr *ip)
378
ip->family = AF_INET6;
379
ip->u.ip6 = in6addr_any;
381
memset(ip, 0, sizeof(struct ip_addr));
385
int net_listen(const struct ip_addr *my_ip, unsigned int *port, int backlog)
387
enum net_listen_flags flags = 0;
389
return net_listen_full(my_ip, port, &flags, backlog);
392
int net_listen_full(const struct ip_addr *my_ip, unsigned int *port,
393
enum net_listen_flags *flags, int backlog)
395
union sockaddr_union so;
396
int ret, fd, opt = 1;
399
memset(&so, 0, sizeof(so));
400
sin_set_port(&so, *port);
401
sin_set_ip(&so, my_ip);
403
/* create the socket */
404
fd = socket(so.sin.sin_family, SOCK_STREAM, 0);
406
if (fd == -1 && my_ip == NULL &&
407
(errno == EINVAL || errno == EAFNOSUPPORT)) {
408
/* IPv6 is not supported by OS */
409
so.sin.sin_family = AF_INET;
410
so.sin.sin_addr.s_addr = INADDR_ANY;
412
fd = socket(AF_INET, SOCK_STREAM, 0);
416
i_error("socket() failed: %m");
420
/* set socket options */
421
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
422
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
424
if ((*flags & NET_LISTEN_FLAG_REUSEPORT) != 0) {
426
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT,
427
&opt, sizeof(opt)) < 0)
429
*flags &= ~NET_LISTEN_FLAG_REUSEPORT;
432
/* If using IPv6, bind only to IPv6 if possible. This avoids
433
ambiguities with IPv4-mapped IPv6 addresses. */
435
if (so.sin.sin_family == AF_INET6) {
437
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
440
/* specify the address/port we want to listen in */
441
ret = bind(fd, &so.sa, SIZEOF_SOCKADDR(so));
443
if (errno != EADDRINUSE) {
444
i_error("bind(%s, %u) failed: %m",
445
my_ip == NULL ? "" : net_ip2addr(my_ip), *port);
448
/* get the actual port we started listen */
449
len = SIZEOF_SOCKADDR(so);
450
ret = getsockname(fd, &so.sa, &len);
452
*port = sin_get_port(&so);
454
/* start listening */
455
if (listen(fd, backlog) >= 0)
458
if (errno != EADDRINUSE)
459
i_error("listen() failed: %m");
468
int net_listen_unix(const char *path, int backlog)
472
struct sockaddr_un un;
476
memset(&sa, 0, sizeof(sa));
477
sa.un.sun_family = AF_UNIX;
478
if (i_strocpy(sa.un.sun_path, path, sizeof(sa.un.sun_path)) < 0) {
484
/* create the socket */
485
fd = socket(PF_UNIX, SOCK_STREAM, 0);
487
i_error("socket() failed: %m");
491
#ifdef NEEDS_LOCAL_CREDS
494
if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof on)) {
495
i_error("setsockopt(LOCAL_CREDS) failed: %m");
502
if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
503
if (errno != EADDRINUSE)
504
i_error("bind(%s) failed: %m", path);
506
/* start listening */
507
if (listen(fd, backlog) == 0)
510
if (errno != EADDRINUSE)
511
i_error("listen() failed: %m");
518
int net_listen_unix_unlink_stale(const char *path, int backlog)
523
while ((fd = net_listen_unix(path, backlog)) == -1) {
524
if (errno != EADDRINUSE || ++i == 2)
527
/* see if it really exists */
528
fd = net_connect_unix(path);
529
if (fd != -1 || errno != ECONNREFUSED) {
530
if (fd != -1) i_close_fd(&fd);
535
/* delete and try again */
536
if (unlink(path) < 0 && errno != ENOENT) {
537
i_error("unlink(%s) failed: %m", path);
545
int net_accept(int fd, struct ip_addr *addr_r, unsigned int *port_r)
547
union sockaddr_union so;
553
addrlen = sizeof(so);
554
ret = accept(fd, &so.sa, &addrlen);
557
if (errno == EAGAIN || errno == ECONNABORTED)
562
if (so.sin.sin_family == AF_UNIX) {
564
memset(addr_r, 0, sizeof(*addr_r));
565
if (port_r != NULL) *port_r = 0;
567
if (addr_r != NULL) sin_get_ip(&so, addr_r);
568
if (port_r != NULL) *port_r = sin_get_port(&so);
573
ssize_t net_receive(int fd, void *buf, size_t len)
578
i_assert(len <= SSIZE_T_MAX);
580
ret = read(fd, buf, len);
587
if (unlikely(ret < 0)) {
588
if (errno == EINTR || errno == EAGAIN)
591
if (errno == ECONNRESET || errno == ETIMEDOUT) {
592
/* treat as disconnection */
600
ssize_t net_transmit(int fd, const void *data, size_t len)
605
i_assert(len <= SSIZE_T_MAX);
607
ret = send(fd, data, len, 0);
608
if (unlikely(ret == -1 && (errno == EINTR || errno == EAGAIN)))
611
if (unlikely(errno == EPIPE))
617
int net_gethostbyname(const char *addr, struct ip_addr **ips,
618
unsigned int *ips_count)
622
union sockaddr_union *so;
623
struct addrinfo hints, *ai, *origai;
634
memset(&hints, 0, sizeof(struct addrinfo));
635
hints.ai_socktype = SOCK_STREAM;
637
/* save error to host_error for later use */
638
host_error = getaddrinfo(addr, NULL, &hints, &ai);
642
/* get number of IPs */
644
for (count = 0; ai != NULL; ai = ai->ai_next)
648
*ips = t_malloc(sizeof(struct ip_addr) * count);
651
for (ai = origai; ai != NULL; ai = ai->ai_next, count++) {
652
so = (union sockaddr_union *) ai->ai_addr;
654
sin_get_ip(so, &(*ips)[count]);
656
freeaddrinfo(origai);
658
hp = gethostbyname(addr);
662
/* get number of IPs */
664
while (hp->h_addr_list[count] != NULL)
668
*ips = t_malloc(sizeof(struct ip_addr) * count);
673
(*ips)[count].family = AF_INET;
674
memcpy(&(*ips)[count].u.ip4, hp->h_addr_list[count],
675
sizeof((*ips)[count].u.ip4));
682
int net_gethostbyaddr(const struct ip_addr *ip, const char **name_r)
684
union sockaddr_union so;
685
socklen_t addrlen = sizeof(so);
686
char hbuf[NI_MAXHOST];
689
memset(&so, 0, sizeof(so));
691
ret = getnameinfo(&so.sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
696
*name_r = t_strdup(hbuf);
700
int net_getsockname(int fd, struct ip_addr *addr, unsigned int *port)
702
union sockaddr_union so;
707
addrlen = sizeof(so);
708
if (getsockname(fd, &so.sa, &addrlen) == -1)
710
if (so.sin.sin_family == AF_UNIX) {
712
memset(addr, 0, sizeof(*addr));
713
if (port != NULL) *port = 0;
715
if (addr != NULL) sin_get_ip(&so, addr);
716
if (port != NULL) *port = sin_get_port(&so);
721
int net_getpeername(int fd, struct ip_addr *addr, unsigned int *port)
723
union sockaddr_union so;
728
addrlen = sizeof(so);
729
if (getpeername(fd, &so.sa, &addrlen) == -1)
731
if (so.sin.sin_family == AF_UNIX) {
733
memset(addr, 0, sizeof(*addr));
734
if (port != NULL) *port = 0;
736
if (addr != NULL) sin_get_ip(&so, addr);
737
if (port != NULL) *port = sin_get_port(&so);
742
int net_getunixname(int fd, const char **name_r)
744
union sockaddr_union_unix so;
745
socklen_t addrlen = sizeof(so);
747
if (getsockname(fd, &so.sa, &addrlen) < 0)
749
if (so.un.sun_family != AF_UNIX) {
753
*name_r = t_strdup(so.un.sun_path);
757
int net_getunixcred(int fd, struct net_unix_cred *cred_r)
759
#if defined(SO_PEERCRED)
760
# if defined(HAVE_STRUCT_SOCKPEERCRED)
761
/* OpenBSD (may also provide getpeereid, but we also want pid) */
762
struct sockpeercred ucred;
767
socklen_t len = sizeof(ucred);
769
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
770
i_error("getsockopt(SO_PEERCRED) failed: %m");
773
cred_r->uid = ucred.uid;
774
cred_r->gid = ucred.gid;
775
cred_r->pid = ucred.pid;
777
#elif defined(LOCAL_PEEREID)
778
/* NetBSD (may also provide getpeereid, but we also want pid) */
779
struct unpcbid ucred;
780
socklen_t len = sizeof(ucred);
782
if (getsockopt(fd, 0, LOCAL_PEEREID, &ucred, &len) < 0) {
783
i_error("getsockopt(LOCAL_PEEREID) failed: %m");
787
cred_r->uid = ucred.unp_euid;
788
cred_r->gid = ucred.unp_egid;
789
cred_r->pid = ucred.unp_pid;
791
#elif defined(HAVE_GETPEEREID)
792
/* OSX 10.4+, FreeBSD 4.6+, OpenBSD 3.0+, NetBSD 5.0+ */
793
if (getpeereid(fd, &cred_r->uid, &cred_r->gid) < 0) {
794
i_error("getpeereid() failed: %m");
797
cred_r->pid = (pid_t)-1;
799
#elif defined(LOCAL_PEERCRED)
802
socklen_t len = sizeof(ucred);
804
if (getsockopt(fd, 0, LOCAL_PEERCRED, &ucred, &len) < 0) {
805
i_error("getsockopt(LOCAL_PEERCRED) failed: %m");
809
if (ucred.cr_version != XUCRED_VERSION) {
814
cred_r->uid = ucred.cr_uid;
815
cred_r->gid = ucred.cr_gid;
816
cred_r->pid = (pid_t)-1;
818
#elif defined(HAVE_GETPEERUCRED)
820
ucred_t *ucred = NULL;
822
if (getpeerucred(fd, &ucred) < 0) {
823
i_error("getpeerucred() failed: %m");
826
cred_r->uid = ucred_geteuid(ucred);
827
cred_r->gid = ucred_getrgid(ucred);
828
cred_r->pid = ucred_getpid(ucred);
831
if (cred_r->uid == (uid_t)-1 ||
832
cred_r->gid == (gid_t)-1) {
837
#elif NEEDS_LOCAL_CREDS
848
iov.iov_base = (char *)&on;
851
sc = (struct sockcred *)cdata.buf;
852
sc->sc_uid = sc->sc_euid = sc->sc_gid = sc->sc_egid = -1;
853
memset(&cdata.ch, 0, sizeof cdata.ch);
855
memset(&msg, 0, sizeof msg);
859
msg.msg_control = &cdata;
860
msg.msg_controllen = sizeof(cdata.ch) + sizeof(cdata.buf);
862
for (i = 0; i < 10; i++) {
863
n = recvmsg(fd, &msg, MSG_WAITALL | MSG_PEEK);
864
if (n >= 0 || errno != EAGAIN)
869
i_error("recvmsg() failed: %m");
872
cred_r->uid = sc->sc_euid;
873
cred_r->gid = sc->sc_egid;
874
cred_r->pid = (pid_t)-1;
882
const char *net_ip2addr(const struct ip_addr *ip)
885
char addr[MAX_IP_LEN+1];
887
addr[MAX_IP_LEN] = '\0';
888
if (inet_ntop(ip->family, &ip->u.ip6, addr, MAX_IP_LEN) == NULL)
891
return t_strdup(addr);
895
if (ip->family != AF_INET)
898
ip4 = ntohl(ip->u.ip4.s_addr);
899
return t_strdup_printf("%lu.%lu.%lu.%lu",
900
(ip4 & 0xff000000UL) >> 24,
901
(ip4 & 0x00ff0000) >> 16,
902
(ip4 & 0x0000ff00) >> 8,
907
int net_addr2ip(const char *addr, struct ip_addr *ip)
911
if (strchr(addr, ':') != NULL) {
913
ip->family = AF_INET6;
916
if (addr[0] == '[') {
917
/* allow [ipv6 addr] */
918
unsigned int len = strlen(addr);
919
if (addr[len-1] == ']')
920
addr = t_strndup(addr+1, len-2);
922
ret = inet_pton(AF_INET6, addr, &ip->u.ip6);
927
ip->u.ip4.s_addr = 0;
931
ip->family = AF_INET;
932
if (inet_aton(addr, &ip->u.ip4) == 0)
939
int net_ipv6_mapped_ipv4_convert(const struct ip_addr *src,
940
struct ip_addr *dest)
943
static uint8_t v4_prefix[] =
944
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
946
if (!IPADDR_IS_V6(src))
948
if (memcmp(src->u.ip6.s6_addr, v4_prefix, sizeof(v4_prefix)) != 0)
951
dest->family = AF_INET;
952
memcpy(&dest->u.ip6, &src->u.ip6.s6_addr[3*4], 4);
959
int net_geterror(int fd)
962
socklen_t len = sizeof(data);
964
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &data, &len) == -1)
970
const char *net_gethosterror(int error)
973
i_assert(error != 0);
975
return gai_strerror(error);
979
return "Host not found";
981
return "No IP address found for name";
983
return "A non-recoverable name server error occurred";
985
return "A temporary error on an authoritative name server";
987
return t_strdup_printf("Unknown error %d", error);
992
int net_hosterror_notfound(int error)
995
#ifdef EAI_NODATA /* NODATA is depricated */
996
return error != 1 && (error == EAI_NONAME || error == EAI_NODATA);
998
return error != 1 && (error == EAI_NONAME);
1001
return error == HOST_NOT_FOUND || error == NO_ADDRESS;
1005
const char *net_getservbyport(unsigned short port)
1007
struct servent *entry;
1009
entry = getservbyport(htons(port), "tcp");
1010
return entry == NULL ? NULL : entry->s_name;
1013
bool is_ipv4_address(const char *addr)
1015
while (*addr != '\0') {
1016
if (*addr != '.' && !i_isdigit(*addr))
1024
bool is_ipv6_address(const char *addr)
1026
bool have_prefix = FALSE;
1032
while (*addr != '\0') {
1033
if (*addr != ':' && !i_isxdigit(*addr)) {
1034
if (have_prefix && *addr == ']' && addr[1] == '\0')
1044
int net_parse_range(const char *network, struct ip_addr *ip_r,
1045
unsigned int *bits_r)
1048
unsigned int bits, max_bits;
1050
p = strchr(network, '/');
1052
network = t_strdup_until(network, p++);
1054
if (net_addr2ip(network, ip_r) < 0)
1057
max_bits = IPADDR_BITS(ip_r);
1059
/* full IP address must match */
1062
/* get the network mask */
1063
if (str_to_uint(p, &bits) < 0 || bits > max_bits)
1070
bool net_is_in_network(const struct ip_addr *ip,
1071
const struct ip_addr *net_ip, unsigned int bits)
1073
struct ip_addr tmp_ip;
1074
const uint32_t *ip1, *ip2;
1075
uint32_t mask, i1, i2;
1076
unsigned int pos, i;
1078
if (net_ipv6_mapped_ipv4_convert(ip, &tmp_ip) == 0) {
1079
/* IPv4 address mapped disguised as IPv6 address */
1083
if (ip->family == 0) {
1084
/* non-IPv4/IPv6 address (e.g. UNIX socket) never matches
1088
if (IPADDR_IS_V4(ip) != IPADDR_IS_V4(net_ip)) {
1089
/* one is IPv6 and one is IPv4 */
1092
i_assert(IPADDR_IS_V6(ip) == IPADDR_IS_V6(net_ip));
1094
if (IPADDR_IS_V4(ip)) {
1095
ip1 = &ip->u.ip4.s_addr;
1096
ip2 = &net_ip->u.ip4.s_addr;
1099
ip1 = (const void *)&ip->u.ip6;
1100
ip2 = (const void *)&net_ip->u.ip6;
1102
/* shouldn't get here */
1107
/* check first the full 32bit ints */
1108
for (pos = 0, i = 0; pos + 32 <= bits; pos += 32, i++) {
1109
if (ip1[i] != ip2[i])
1115
/* check the last full bytes */
1116
for (mask = 0xff000000; pos + 8 <= bits; pos += 8, mask >>= 8) {
1117
if ((i1 & mask) != (i2 & mask))
1121
/* check the last bits, they're reversed in bytes */
1123
for (mask = 0x80000000 >> (pos % 32); bits > 0; bits--, mask >>= 1) {
1124
if ((i1 & mask) != (i2 & mask))