net.c revision efbeceffc8cb1602d698151b0246f29e13b980fa
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 1999-2014 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define _GNU_SOURCE /* For Linux's struct ucred */
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "fd-set-nonblock.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "time-util.h"
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen#include "net.h"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen#include <stdlib.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen#include <fcntl.h>
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#include <ctype.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <sys/un.h>
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen#include <netinet/tcp.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#if defined(HAVE_UCRED_H)
66ae183b6e895216037bd921367670f4b0665911Timo Sirainen# include <ucred.h> /* for getpeerucred() */
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen#elif defined(HAVE_SYS_UCRED_H)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen# include <sys/ucred.h> /* for FreeBSD struct xucred */
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen#endif
9e0b187933b52db68c1aefb913970eeba47b986eAki Tuomi
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainenunion sockaddr_union {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sockaddr sa;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sockaddr_in sin;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef HAVE_IPV6
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct sockaddr_in6 sin6;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#endif
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen};
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenunion sockaddr_union_unix {
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen struct sockaddr sa;
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen struct sockaddr_un un;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef HAVE_IPV6
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen# define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(so.sin6) : sizeof(so.sin))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen# define SIZEOF_SOCKADDR(so) (sizeof(so.sin))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_GETPEERUCRED) && defined(MSG_WAITALL) && defined(LOCAL_CREDS)
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen# define NEEDS_LOCAL_CREDS 1
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen#endif
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainenbool net_ip_compare(const struct ip_addr *ip1, const struct ip_addr *ip2)
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen{
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen return net_ip_cmp(ip1, ip2) == 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainenint net_ip_cmp(const struct ip_addr *ip1, const struct ip_addr *ip2)
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (ip1->family != ip2->family)
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen return ip1->family - ip2->family;
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen#ifdef HAVE_IPV6
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen if (ip1->family == AF_INET6)
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen return memcmp(&ip1->u.ip6, &ip2->u.ip6, sizeof(ip1->u.ip6));
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen#endif
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen return memcmp(&ip1->u.ip4, &ip2->u.ip4, sizeof(ip1->u.ip4));
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainenunsigned int net_ip_hash(const struct ip_addr *ip)
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen{
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen const unsigned char *p;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen unsigned int len, g, h = 0;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen#ifdef HAVE_IPV6
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ip->family == AF_INET6) {
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen p = ip->u.ip6.s6_addr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen len = sizeof(ip->u.ip6);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ip->u.ip4.s_addr;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen for (; len > 0; len--, p++) {
9f32b9444d2a6db8f556d2c49ffceab1a59791ffTimo Sirainen h = (h << 4) + *p;
9f32b9444d2a6db8f556d2c49ffceab1a59791ffTimo Sirainen if ((g = h & 0xf0000000UL)) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen h = h ^ (g >> 24);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen h = h ^ g;
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen }
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen }
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen return h;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen/* copy IP to sockaddr */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenstatic inline void
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainensin_set_ip(union sockaddr_union *so, const struct ip_addr *ip)
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ip == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef HAVE_IPV6
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen so->sin6.sin6_family = AF_INET6;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen so->sin6.sin6_addr = in6addr_any;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen so->sin.sin_family = AF_INET;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen so->sin.sin_addr.s_addr = INADDR_ANY;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen#endif
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen return;
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen }
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen so->sin.sin_family = ip->family;
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen#ifdef HAVE_IPV6
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen if (ip->family == AF_INET6)
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen memcpy(&so->sin6.sin6_addr, &ip->u.ip6, sizeof(ip->u.ip6));
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen else
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen#endif
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen memcpy(&so->sin.sin_addr, &ip->u.ip4, sizeof(ip->u.ip4));
e704b4ab2c204e538f87b2a90aca68c0deac6296Timo Sirainen}
e704b4ab2c204e538f87b2a90aca68c0deac6296Timo Sirainen
e704b4ab2c204e538f87b2a90aca68c0deac6296Timo Sirainenstatic inline void
96595bf98ed9264b2b35700a640daf53debc3082Timo Sirainensin_get_ip(const union sockaddr_union *so, struct ip_addr *ip)
96595bf98ed9264b2b35700a640daf53debc3082Timo Sirainen{
96595bf98ed9264b2b35700a640daf53debc3082Timo Sirainen /* IP structs may be sent across processes. Clear the whole struct
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen first to make sure it won't leak any data across processes. */
96595bf98ed9264b2b35700a640daf53debc3082Timo Sirainen memset(ip, 0, sizeof(*ip));
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen ip->family = so->sin.sin_family;
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen#ifdef HAVE_IPV6
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen if (ip->family == AF_INET6)
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen memcpy(&ip->u.ip6, &so->sin6.sin6_addr, sizeof(ip->u.ip6));
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen else
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen#endif
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen if (ip->family == AF_INET)
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen memcpy(&ip->u.ip4, &so->sin.sin_addr, sizeof(ip->u.ip4));
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen else
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen memset(&ip->u, 0, sizeof(ip->u));
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen}
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainenstatic inline void sin_set_port(union sockaddr_union *so, unsigned int port)
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen{
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen#ifdef HAVE_IPV6
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen if (so->sin.sin_family == AF_INET6)
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen so->sin6.sin6_port = htons((unsigned short) port);
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen else
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen#endif
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen so->sin.sin_port = htons((unsigned short) port);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen}
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainenstatic inline unsigned int sin_get_port(union sockaddr_union *so)
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen{
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen#ifdef HAVE_IPV6
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen if (so->sin.sin_family == AF_INET6)
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen return ntohs(so->sin6.sin6_port);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen#endif
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen if (so->sin.sin_family == AF_INET)
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen return ntohs(so->sin.sin_port);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen return 0;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen}
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen#ifdef __FreeBSD__
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainenstatic int
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainennet_connect_ip_full_freebsd(const struct ip_addr *ip, unsigned int port,
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen const struct ip_addr *my_ip, bool blocking);
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainenstatic int net_connect_ip_full(const struct ip_addr *ip, unsigned int port,
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen const struct ip_addr *my_ip, bool blocking)
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen{
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen int fd, try;
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen for (try = 0;;) {
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen fd = net_connect_ip_full_freebsd(ip, port, my_ip, blocking);
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen if (fd != -1 || ++try == 5 ||
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen (errno != EADDRINUSE && errno != EACCES))
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen break;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen /*
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen This may be just a temporary problem:
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen EADDRINUSE: busy
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen EACCES: pf may cause this if another connection used
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen the same port recently
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen */
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen }
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen return fd;
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen}
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen/* then some kludging: */
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen#define net_connect_ip_full net_connect_ip_full_freebsd
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen#endif
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainenstatic int net_connect_ip_full(const struct ip_addr *ip, unsigned int port,
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen const struct ip_addr *my_ip, int sock_type, bool blocking)
47e0598840ecffa364ebed523e06939e22738f06Timo Sirainen{
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen union sockaddr_union so;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen int fd, ret, opt = 1;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (my_ip != NULL && ip->family != my_ip->family) {
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen i_warning("net_connect_ip(): ip->family != my_ip->family");
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen my_ip = NULL;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen /* create the socket */
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen memset(&so, 0, sizeof(so));
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen so.sin.sin_family = ip->family;
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainen fd = socket(ip->family, sock_type, 0);
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainen if (fd == -1) {
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen i_error("socket() failed: %m");
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen return -1;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen /* set socket options */
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch (void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (sock_type == SOCK_STREAM)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen (void)setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (!blocking)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen net_set_nonblock(fd, TRUE);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* set our own address */
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (my_ip != NULL) {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen sin_set_ip(&so, my_ip);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (bind(fd, &so.sa, SIZEOF_SOCKADDR(so)) == -1) {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen i_error("bind(%s) failed: %m", net_ip2addr(my_ip));
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen i_close_fd(&fd);
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen return -1;
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen }
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen }
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen /* connect */
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen sin_set_ip(&so, ip);
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen sin_set_port(&so, port);
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen ret = connect(fd, &so.sa, SIZEOF_SOCKADDR(so));
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen#ifndef WIN32
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen if (ret < 0 && errno != EINPROGRESS)
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen#else
ea91861234475257f436dc07925f80cf4ac32b71Timo Sirainen if (ret < 0 && WSAGetLastError() != WSAEWOULDBLOCK)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen#endif
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen i_close_fd(&fd);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return -1;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return fd;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen}
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen#ifdef __FreeBSD__
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen# undef net_connect_ip_full
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen#endif
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainenint net_connect_ip(const struct ip_addr *ip, unsigned int port,
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen const struct ip_addr *my_ip)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen{
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return net_connect_ip_full(ip, port, my_ip, SOCK_STREAM, FALSE);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenint net_connect_ip_blocking(const struct ip_addr *ip, unsigned int port,
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen const struct ip_addr *my_ip)
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen{
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen return net_connect_ip_full(ip, port, my_ip, SOCK_STREAM, TRUE);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenint net_connect_udp(const struct ip_addr *ip, unsigned int port,
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen const struct ip_addr *my_ip)
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen{
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return net_connect_ip_full(ip, port, my_ip, SOCK_DGRAM, FALSE);
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen}
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainenint net_try_bind(const struct ip_addr *ip)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen union sockaddr_union so;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen int fd;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen /* create the socket */
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen memset(&so, 0, sizeof(so));
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen so.sin.sin_family = ip->family;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen fd = socket(ip->family, SOCK_STREAM, 0);
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen if (fd == -1) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen i_error("socket() failed: %m");
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen return -1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen sin_set_ip(&so, ip);
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen if (bind(fd, &so.sa, SIZEOF_SOCKADDR(so)) == -1) {
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen i_close_fd(&fd);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return -1;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen }
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen i_close_fd(&fd);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen return 0;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenint net_connect_unix(const char *path)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen{
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen union sockaddr_union_unix sa;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen int fd, ret;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen memset(&sa, 0, sizeof(sa));
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen sa.un.sun_family = AF_UNIX;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (i_strocpy(sa.un.sun_path, path, sizeof(sa.un.sun_path)) < 0) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen /* too long path */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen#ifdef ENAMETOOLONG
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen errno = ENAMETOOLONG;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen#else
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen errno = EINVAL;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen#endif
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen /* create the socket */
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen fd = socket(PF_UNIX, SOCK_STREAM, 0);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen if (fd == -1) {
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen i_error("socket(%s) failed: %m", path);
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen net_set_nonblock(fd, TRUE);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen /* connect */
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen ret = connect(fd, &sa.sa, sizeof(sa));
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (ret < 0 && errno != EINPROGRESS) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen i_close_fd(&fd);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return -1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen#ifdef NEEDS_LOCAL_CREDS
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen int on = 1;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof on)) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen i_error("setsockopt(LOCAL_CREDS) failed: %m");
6825360d446542046757b06064282301c4c6b27cTimo Sirainen return -1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen }
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen#endif
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen return fd;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen}
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainenint net_connect_unix_with_retries(const char *path, unsigned int msecs)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct timeval start, now;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen int fd;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (gettimeofday(&start, NULL) < 0)
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen i_panic("gettimeofday() failed: %m");
6825360d446542046757b06064282301c4c6b27cTimo Sirainen
6825360d446542046757b06064282301c4c6b27cTimo Sirainen do {
6825360d446542046757b06064282301c4c6b27cTimo Sirainen fd = net_connect_unix(path);
6825360d446542046757b06064282301c4c6b27cTimo Sirainen if (fd != -1 || (errno != EAGAIN && errno != ECONNREFUSED))
6825360d446542046757b06064282301c4c6b27cTimo Sirainen break;
6825360d446542046757b06064282301c4c6b27cTimo Sirainen
6825360d446542046757b06064282301c4c6b27cTimo Sirainen /* busy. wait for a while. */
6825360d446542046757b06064282301c4c6b27cTimo Sirainen usleep(((rand() % 10) + 1) * 10000);
6825360d446542046757b06064282301c4c6b27cTimo Sirainen if (gettimeofday(&now, NULL) < 0)
c8d093d149253fe8faec267c5057f45fe626f84cTimo Sirainen i_panic("gettimeofday() failed: %m");
c8d093d149253fe8faec267c5057f45fe626f84cTimo Sirainen } while (timeval_diff_msecs(&now, &start) < (int)msecs);
6825360d446542046757b06064282301c4c6b27cTimo Sirainen return fd;
6825360d446542046757b06064282301c4c6b27cTimo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenvoid net_disconnect(int fd)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* FreeBSD's close() fails with ECONNRESET if socket still has unsent
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen data in transmit buffer. We don't care. */
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen if (close(fd) < 0 && errno != ECONNRESET)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_error("net_disconnect() failed: %m");
f5c53272acbe1517440aa9c277133babc887ee84Timo Sirainen}
f5c53272acbe1517440aa9c277133babc887ee84Timo Sirainen
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainenvoid net_set_nonblock(int fd, bool nonblock)
f5c53272acbe1517440aa9c277133babc887ee84Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen fd_set_nonblock(fd, nonblock);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenint net_set_cork(int fd ATTR_UNUSED, bool cork ATTR_UNUSED)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#ifdef TCP_CORK
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen int val = cork;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen return setsockopt(fd, IPPROTO_TCP, TCP_CORK, &val, sizeof(val));
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen#else
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen errno = ENOPROTOOPT;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen return -1;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen#endif
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen}
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainenvoid net_get_ip_any4(struct ip_addr *ip)
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen{
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen ip->family = AF_INET;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen ip->u.ip4.s_addr = INADDR_ANY;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen}
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainenvoid net_get_ip_any6(struct ip_addr *ip)
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen{
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen#ifdef HAVE_IPV6
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen ip->family = AF_INET6;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen ip->u.ip6 = in6addr_any;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen#else
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen memset(ip, 0, sizeof(struct ip_addr));
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen#endif
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen}
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainenint net_listen(const struct ip_addr *my_ip, unsigned int *port, int backlog)
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen{
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen enum net_listen_flags flags = 0;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen return net_listen_full(my_ip, port, &flags, backlog);
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen}
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainenint net_listen_full(const struct ip_addr *my_ip, unsigned int *port,
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen enum net_listen_flags *flags, int backlog)
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen{
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen union sockaddr_union so;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen int ret, fd, opt = 1;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen socklen_t len;
4a09c57f1c66b4a8880bcc12b567bb42c3549f52Timo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen memset(&so, 0, sizeof(so));
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen sin_set_port(&so, *port);
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen sin_set_ip(&so, my_ip);
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen /* create the socket */
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen fd = socket(so.sin.sin_family, SOCK_STREAM, 0);
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen#ifdef HAVE_IPV6
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen if (fd == -1 && my_ip == NULL &&
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen (errno == EINVAL || errno == EAFNOSUPPORT)) {
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen /* IPv6 is not supported by OS */
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen so.sin.sin_family = AF_INET;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen so.sin.sin_addr.s_addr = INADDR_ANY;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen fd = socket(AF_INET, SOCK_STREAM, 0);
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen }
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen#endif
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen if (fd == -1) {
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen i_error("socket() failed: %m");
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen return -1;
e7d0bea63a08b08c47c4b5c187d2cb7127859657Timo Sirainen }
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen /* set socket options */
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen (void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen (void)setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof(opt));
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen if ((*flags & NET_LISTEN_FLAG_REUSEPORT) != 0) {
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen#ifdef SO_REUSEPORT
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT,
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen &opt, sizeof(opt)) < 0)
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen#endif
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen *flags &= ~NET_LISTEN_FLAG_REUSEPORT;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen }
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen /* If using IPv6, bind only to IPv6 if possible. This avoids
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen ambiguities with IPv4-mapped IPv6 addresses. */
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen#ifdef IPV6_V6ONLY
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen if (so.sin.sin_family == AF_INET6) {
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen opt = 1;
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen (void)setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen }
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen#endif
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen /* specify the address/port we want to listen in */
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen ret = bind(fd, &so.sa, SIZEOF_SOCKADDR(so));
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen if (ret < 0) {
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen if (errno != EADDRINUSE) {
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen i_error("bind(%s, %u) failed: %m",
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen my_ip == NULL ? "" : net_ip2addr(my_ip), *port);
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen }
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen } else {
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen /* get the actual port we started listen */
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen len = SIZEOF_SOCKADDR(so);
3f2ad7b8c3a243dabcba469c8a331423d036f3fcTimo Sirainen ret = getsockname(fd, &so.sa, &len);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (ret >= 0) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen *port = sin_get_port(&so);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen /* start listening */
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (listen(fd, backlog) >= 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return fd;
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen if (errno != EADDRINUSE)
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen i_error("listen() failed: %m");
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen }
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen }
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* error */
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen i_close_fd(&fd);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen return -1;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainenint net_listen_unix(const char *path, int backlog)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen union {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen struct sockaddr sa;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen struct sockaddr_un un;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen } sa;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen int fd;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen memset(&sa, 0, sizeof(sa));
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen sa.un.sun_family = AF_UNIX;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (i_strocpy(sa.un.sun_path, path, sizeof(sa.un.sun_path)) < 0) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* too long path */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen errno = EOVERFLOW;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* create the socket */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen fd = socket(PF_UNIX, SOCK_STREAM, 0);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen if (fd == -1) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen i_error("socket() failed: %m");
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen return -1;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen }
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen#ifdef NEEDS_LOCAL_CREDS
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen int on = 1;
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen if (setsockopt(fd, 0, LOCAL_CREDS, &on, sizeof on)) {
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen i_error("setsockopt(LOCAL_CREDS) failed: %m");
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen return -1;
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen }
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen#endif
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* bind */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
06fc580f6baf83fe5bb94c64be8149d527b01a42Timo Sirainen if (errno != EADDRINUSE)
06fc580f6baf83fe5bb94c64be8149d527b01a42Timo Sirainen i_error("bind(%s) failed: %m", path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen /* start listening */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (listen(fd, backlog) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (errno != EADDRINUSE)
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen i_error("listen() failed: %m");
06fc580f6baf83fe5bb94c64be8149d527b01a42Timo Sirainen }
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen i_close_fd(&fd);
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen return -1;
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen}
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainenint net_listen_unix_unlink_stale(const char *path, int backlog)
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen{
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen unsigned int i = 0;
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen int fd;
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen while ((fd = net_listen_unix(path, backlog)) == -1) {
14b8bbb81e0b546436d4d5d5f38e45027c146b9bTimo Sirainen if (errno != EADDRINUSE || ++i == 2)
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen return -1;
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen /* see if it really exists */
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen fd = net_connect_unix(path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fd != -1 || errno != ECONNREFUSED) {
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen if (fd != -1) i_close_fd(&fd);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen errno = EADDRINUSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* delete and try again */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (unlink(path) < 0 && errno != ENOENT) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("unlink(%s) failed: %m", path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen errno = EADDRINUSE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen return fd;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen}
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainenint net_accept(int fd, struct ip_addr *addr_r, unsigned int *port_r)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen{
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen union sockaddr_union so;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen int ret;
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen socklen_t addrlen;
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen i_assert(fd >= 0);
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen addrlen = sizeof(so);
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen ret = accept(fd, &so.sa, &addrlen);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (ret < 0) {
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen if (errno == EAGAIN || errno == ECONNABORTED)
2bda0d095e029ec72ec683b4186e04f322b4978eTimo Sirainen return -1;
2bda0d095e029ec72ec683b4186e04f322b4978eTimo Sirainen else
2bda0d095e029ec72ec683b4186e04f322b4978eTimo Sirainen return -2;
2bda0d095e029ec72ec683b4186e04f322b4978eTimo Sirainen }
2bda0d095e029ec72ec683b4186e04f322b4978eTimo Sirainen if (so.sin.sin_family == AF_UNIX) {
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen if (addr_r != NULL)
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen memset(addr_r, 0, sizeof(*addr_r));
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (port_r != NULL) *port_r = 0;
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen } else {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (addr_r != NULL) sin_get_ip(&so, addr_r);
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen if (port_r != NULL) *port_r = sin_get_port(&so);
0b49cfeae91a4020a404714b11c99e8e955fb631Timo Sirainen }
94aa90d2d17a7aebcda5a4193a62e80ddbb169b7Timo Sirainen return ret;
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen}
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainenssize_t net_receive(int fd, void *buf, size_t len)
0b49cfeae91a4020a404714b11c99e8e955fb631Timo Sirainen{
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen ssize_t ret;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen i_assert(fd >= 0);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(len <= SSIZE_T_MAX);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = read(fd, buf, len);
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen if (ret == 0) {
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen /* disconnected */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen errno = 0;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen return -2;
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen }
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
e4b242684975b4d3702ca79bfd56452fe139a2bfTimo Sirainen if (unlikely(ret < 0)) {
e4b242684975b4d3702ca79bfd56452fe139a2bfTimo Sirainen if (errno == EINTR || errno == EAGAIN)
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen return 0;
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen if (errno == ECONNRESET || errno == ETIMEDOUT) {
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen /* treat as disconnection */
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen return -2;
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen }
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen }
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen return ret;
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen}
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainenssize_t net_transmit(int fd, const void *data, size_t len)
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen{
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen ssize_t ret;
7be1a5530fcb414588fbe90eaed65eff83e84737Timo Sirainen
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen i_assert(fd >= 0);
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen i_assert(len <= SSIZE_T_MAX);
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen ret = send(fd, data, len, 0);
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen if (ret == -1) {
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen if (errno == EINTR || errno == EAGAIN)
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen return 0;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen if (errno == EPIPE)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint net_gethostbyname(const char *addr, struct ip_addr **ips,
9f32b9444d2a6db8f556d2c49ffceab1a59791ffTimo Sirainen unsigned int *ips_count)
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen{
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen /* @UNSAFE */
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen#ifdef HAVE_IPV6
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen union sockaddr_union *so;
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen struct addrinfo hints, *ai, *origai;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int host_error;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen#else
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen struct hostent *hp;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen#endif
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen int count;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen *ips = NULL;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen *ips_count = 0;
07e80e04c8876b6bf3f95266f48b41e1a681e445Timo Sirainen
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen#ifdef HAVE_IPV6
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen memset(&hints, 0, sizeof(struct addrinfo));
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen hints.ai_socktype = SOCK_STREAM;
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen /* save error to host_error for later use */
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen host_error = getaddrinfo(addr, NULL, &hints, &ai);
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen if (host_error != 0)
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen return host_error;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* get number of IPs */
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen origai = ai;
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen for (count = 0; ai != NULL; ai = ai->ai_next)
f01d1332d49dbd34baef4601ac7b3cc557021084Timo Sirainen count++;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen *ips_count = count;
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen *ips = t_malloc(sizeof(struct ip_addr) * count);
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen count = 0;
9e0b187933b52db68c1aefb913970eeba47b986eAki Tuomi for (ai = origai; ai != NULL; ai = ai->ai_next, count++) {
3c72b9bc9fd67b4492d6e949f54a3964dcb26344Timo Sirainen so = (union sockaddr_union *) ai->ai_addr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
9e0b187933b52db68c1aefb913970eeba47b986eAki Tuomi sin_get_ip(so, &(*ips)[count]);
9e0b187933b52db68c1aefb913970eeba47b986eAki Tuomi }
9e0b187933b52db68c1aefb913970eeba47b986eAki Tuomi freeaddrinfo(origai);
9e0b187933b52db68c1aefb913970eeba47b986eAki Tuomi#else
9e0b187933b52db68c1aefb913970eeba47b986eAki Tuomi hp = gethostbyname(addr);
9e0b187933b52db68c1aefb913970eeba47b986eAki Tuomi if (hp == NULL)
9e0b187933b52db68c1aefb913970eeba47b986eAki Tuomi return h_errno;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen /* get number of IPs */
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen count = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (hp->h_addr_list[count] != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen count++;
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen *ips_count = count;
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen *ips = t_malloc(sizeof(struct ip_addr) * count);
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen while (count > 0) {
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen count--;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen (*ips)[count].family = AF_INET;
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen memcpy(&(*ips)[count].u.ip4, hp->h_addr_list[count],
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen sizeof((*ips)[count].u.ip4));
41e6eb07b411ea58352ba9d2cc8cf340325d49f3Timo Sirainen }
c2feb7d13482d0f60691cd71d06d42a80df99397Timo Sirainen#endif
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint net_gethostbyaddr(const struct ip_addr *ip, const char **name_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen union sockaddr_union so;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen socklen_t addrlen = sizeof(so);
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen char hbuf[NI_MAXHOST];
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int ret;
1727610dbc69920b7f0d0622b4e5d7127c59093dTimo Sirainen
5ea06115cb60413b62ffb58ffdd62786fec6a316Timo Sirainen memset(&so, 0, sizeof(so));
5ea06115cb60413b62ffb58ffdd62786fec6a316Timo Sirainen sin_set_ip(&so, ip);
5ea06115cb60413b62ffb58ffdd62786fec6a316Timo Sirainen ret = getnameinfo(&so.sa, addrlen, hbuf, sizeof(hbuf), NULL, 0,
5ea06115cb60413b62ffb58ffdd62786fec6a316Timo Sirainen NI_NAMEREQD);
5ea06115cb60413b62ffb58ffdd62786fec6a316Timo Sirainen if (ret != 0)
5ea06115cb60413b62ffb58ffdd62786fec6a316Timo Sirainen return ret;
ef4d0eafab4d26bba047551db1e23ceff8aa9404Timo Sirainen
1727610dbc69920b7f0d0622b4e5d7127c59093dTimo Sirainen *name_r = t_strdup(hbuf);
90c5979b3c530707744beab6413f9d1e446335d1Timo Sirainen return 0;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen}
90c5979b3c530707744beab6413f9d1e446335d1Timo Sirainen
90c5979b3c530707744beab6413f9d1e446335d1Timo Sirainenint net_getsockname(int fd, struct ip_addr *addr, unsigned int *port)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen union sockaddr_union so;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen socklen_t addrlen;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(fd >= 0);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen addrlen = sizeof(so);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (getsockname(fd, &so.sa, &addrlen) == -1)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return -1;
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen if (so.sin.sin_family == AF_UNIX) {
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen if (addr != NULL)
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen memset(addr, 0, sizeof(*addr));
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen if (port != NULL) *port = 0;
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen } else {
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen if (addr != NULL) sin_get_ip(&so, addr);
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen if (port != NULL) *port = sin_get_port(&so);
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen }
0bd15afe9cadd09b01e68b493b30c9d7e92b4095Timo Sirainen return 0;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen}
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainenint net_getpeername(int fd, struct ip_addr *addr, unsigned int *port)
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen{
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen union sockaddr_union so;
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen socklen_t addrlen;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen i_assert(fd >= 0);
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen addrlen = sizeof(so);
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen if (getpeername(fd, &so.sa, &addrlen) == -1)
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen return -1;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen if (so.sin.sin_family == AF_UNIX) {
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen if (addr != NULL)
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen memset(addr, 0, sizeof(*addr));
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen if (port != NULL) *port = 0;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen } else {
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen if (addr != NULL) sin_get_ip(&so, addr);
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen if (port != NULL) *port = sin_get_port(&so);
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen }
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen return 0;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen}
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainenint net_getunixname(int fd, const char **name_r)
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen{
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen union sockaddr_union_unix so;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen socklen_t addrlen = sizeof(so);
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen if (getsockname(fd, &so.sa, &addrlen) < 0)
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen return -1;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen if (so.un.sun_family != AF_UNIX) {
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen errno = ENOTSOCK;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen return -1;
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen }
4d4d585520538a752e9f0a4a1c019a2918f52e56Timo Sirainen *name_r = t_strdup(so.un.sun_path);
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen return 0;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenint net_getunixcred(int fd, struct net_unix_cred *cred_r)
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen#if defined(SO_PEERCRED)
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen# if defined(HAVE_STRUCT_SOCKPEERCRED)
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen /* OpenBSD (may also provide getpeereid, but we also want pid) */
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen struct sockpeercred ucred;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen# else
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen /* Linux */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct ucred ucred;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen# endif
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen socklen_t len = sizeof(ucred);
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
6143fece58262865ce89b5012b73ef08f2ad6abcTimo Sirainen i_error("getsockopt(SO_PEERCRED) failed: %m");
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen return -1;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen cred_r->uid = ucred.uid;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen cred_r->gid = ucred.gid;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen cred_r->pid = ucred.pid;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return 0;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen#elif defined(LOCAL_PEEREID)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen /* NetBSD (may also provide getpeereid, but we also want pid) */
dec85d9856c33f427a06dda01e0e50de0bc8fa7dTimo Sirainen struct unpcbid ucred;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen socklen_t len = sizeof(ucred);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (getsockopt(fd, 0, LOCAL_PEEREID, &ucred, &len) < 0) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen i_error("getsockopt(LOCAL_PEEREID) failed: %m");
dec85d9856c33f427a06dda01e0e50de0bc8fa7dTimo Sirainen return -1;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen }
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen cred_r->uid = ucred.unp_euid;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen cred_r->gid = ucred.unp_egid;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen cred_r->pid = ucred.unp_pid;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return 0;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen#elif defined(HAVE_GETPEEREID)
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen /* OSX 10.4+, FreeBSD 4.6+, OpenBSD 3.0+, NetBSD 5.0+ */
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen if (getpeereid(fd, &cred_r->uid, &cred_r->gid) < 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_error("getpeereid() failed: %m");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen cred_r->pid = (pid_t)-1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen#elif defined(LOCAL_PEERCRED)
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen /* Older FreeBSD */
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen struct xucred ucred;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen socklen_t len = sizeof(ucred);
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen if (getsockopt(fd, 0, LOCAL_PEERCRED, &ucred, &len) < 0) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen i_error("getsockopt(LOCAL_PEERCRED) failed: %m");
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return -1;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen }
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen if (ucred.cr_version != XUCRED_VERSION) {
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen errno = EINVAL;
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen return -1;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen }
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen cred_r->uid = ucred.cr_uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cred_r->gid = ucred.cr_gid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cred_r->pid = (pid_t)-1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#elif defined(HAVE_GETPEERUCRED)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Solaris */
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen ucred_t *ucred = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (getpeerucred(fd, &ucred) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("getpeerucred() failed: %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cred_r->uid = ucred_geteuid(ucred);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cred_r->gid = ucred_getrgid(ucred);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cred_r->pid = ucred_getpid(ucred);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ucred_free(ucred);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (cred_r->uid == (uid_t)-1 ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cred_r->gid == (gid_t)-1) {
95e4021e3e2a733d27f48fe97912fc96df52005fTimo Sirainen errno = EINVAL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen#elif NEEDS_LOCAL_CREDS
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen /* NetBSD < 5 */
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen int i, n, on;
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen struct iovec iov;
15cc66ca72982a43e3bfa58f307adc57e9caa52dTimo Sirainen struct msghdr msg;
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen struct {
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen struct cmsghdr ch;
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen char buf[110];
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen } cdata;
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen struct sockcred *sc;
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen iov.iov_base = (char *)&on;
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen iov.iov_len = 1;
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen sc = (struct sockcred *)cdata.buf;
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen sc->sc_uid = sc->sc_euid = sc->sc_gid = sc->sc_egid = -1;
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen memset(&cdata.ch, 0, sizeof cdata.ch);
c61d52810496376a2ea60b8f4e27bbcaa8754f3fTimo Sirainen
2469ed8e17534f6cb5f41493df8c7e6f3b2c9b61Timo Sirainen memset(&msg, 0, sizeof msg);
c61d52810496376a2ea60b8f4e27bbcaa8754f3fTimo Sirainen
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen msg.msg_iov = &iov;
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen msg.msg_iovlen = 1;
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen msg.msg_control = &cdata;
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen msg.msg_controllen = sizeof(cdata.ch) + sizeof(cdata.buf);
27db4ce5fe399c981e09dcf9e885a1546afd34f4Timo Sirainen
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen for (i = 0; i < 10; i++) {
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen n = recvmsg(fd, &msg, MSG_WAITALL | MSG_PEEK);
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen if (n >= 0 || errno != EAGAIN)
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen break;
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen usleep(100);
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen }
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen if (n < 0) {
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen i_error("recvmsg() failed: %m");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen }
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen cred_r->uid = sc->sc_euid;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen cred_r->gid = sc->sc_egid;
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen cred_r->pid = (pid_t)-1;
ae14dfd895881f9d1c6899b0c09f1a8b51447d61Timo Sirainen return 0;
ae14dfd895881f9d1c6899b0c09f1a8b51447d61Timo Sirainen#else
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen errno = EINVAL;
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen return -1;
ae14dfd895881f9d1c6899b0c09f1a8b51447d61Timo Sirainen#endif
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen}
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainenconst char *net_ip2addr(const struct ip_addr *ip)
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen{
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen#ifdef HAVE_IPV6
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen char addr[MAX_IP_LEN+1];
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen addr[MAX_IP_LEN] = '\0';
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen if (inet_ntop(ip->family, &ip->u.ip6, addr, MAX_IP_LEN) == NULL)
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen return "";
87712707722ef7d73acb065546e61afa4455cd9eTimo Sirainen
5ec0ca7ff13595daf0d096c17100afb352e6294aTimo Sirainen return t_strdup(addr);
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen#else
87712707722ef7d73acb065546e61afa4455cd9eTimo Sirainen unsigned long ip4;
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen if (ip->family != AF_INET)
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen return "";
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen ip4 = ntohl(ip->u.ip4.s_addr);
1be964ec6d835f95b4fdebf02add9265d58ad290Timo Sirainen return t_strdup_printf("%lu.%lu.%lu.%lu",
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen (ip4 & 0xff000000UL) >> 24,
5ec0ca7ff13595daf0d096c17100afb352e6294aTimo Sirainen (ip4 & 0x00ff0000) >> 16,
5ec0ca7ff13595daf0d096c17100afb352e6294aTimo Sirainen (ip4 & 0x0000ff00) >> 8,
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen (ip4 & 0x000000ff));
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen#endif
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen}
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainenint net_addr2ip(const char *addr, struct ip_addr *ip)
6c2ddb9f586e6392552ddfb82ab55e57fcfc4110Timo Sirainen{
6c2ddb9f586e6392552ddfb82ab55e57fcfc4110Timo Sirainen int ret;
6c2ddb9f586e6392552ddfb82ab55e57fcfc4110Timo Sirainen
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen if (strchr(addr, ':') != NULL) {
6c2ddb9f586e6392552ddfb82ab55e57fcfc4110Timo Sirainen /* IPv6 */
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen ip->family = AF_INET6;
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen#ifdef HAVE_IPV6
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen T_BEGIN {
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen if (addr[0] == '[') {
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen /* allow [ipv6 addr] */
6c2ddb9f586e6392552ddfb82ab55e57fcfc4110Timo Sirainen unsigned int len = strlen(addr);
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen if (addr[len-1] == ']')
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen addr = t_strndup(addr+1, len-2);
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen }
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen ret = inet_pton(AF_INET6, addr, &ip->u.ip6);
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen } T_END;
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen if (ret == 0)
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen return -1;
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen#else
6c2ddb9f586e6392552ddfb82ab55e57fcfc4110Timo Sirainen ip->u.ip4.s_addr = 0;
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen#endif
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen } else {
6c2ddb9f586e6392552ddfb82ab55e57fcfc4110Timo Sirainen /* IPv4 */
bb444f746dc6c15a8d0af67ef81bfa48c28471d0Timo Sirainen ip->family = AF_INET;
6c2ddb9f586e6392552ddfb82ab55e57fcfc4110Timo Sirainen if (inet_aton(addr, &ip->u.ip4) == 0)
6c2ddb9f586e6392552ddfb82ab55e57fcfc4110Timo Sirainen return -1;
6c2ddb9f586e6392552ddfb82ab55e57fcfc4110Timo Sirainen }
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen return 0;
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen}
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainenint net_ipv6_mapped_ipv4_convert(const struct ip_addr *src,
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen struct ip_addr *dest)
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen{
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen#ifdef HAVE_IPV6
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen static uint8_t v4_prefix[] =
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen if (!IPADDR_IS_V6(src))
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen return -1;
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen if (memcmp(src->u.ip6.s6_addr, v4_prefix, sizeof(v4_prefix)) != 0)
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen return -1;
fe5c1094aec29b5d29356ad5f06c970eb4ce7a78Timo Sirainen
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen dest->family = AF_INET;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen memcpy(&dest->u.ip6, &src->u.ip6.s6_addr[3*4], 4);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen return 0;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen#else
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen return -1;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen#endif
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen}
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainenint net_geterror(int fd)
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen{
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen int data;
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen socklen_t len = sizeof(data);
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &data, &len) == -1) {
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen /* we're now really returning the getsockopt()'s error code
1f80b32fc28f7a723ff07c1694230a090808b506Timo Sirainen instead of the socket's, but normally we should never get
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen here anyway. */
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return errno;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenconst char *net_gethosterror(int error)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef HAVE_IPV6
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen i_assert(error != 0);
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return gai_strerror(error);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (error) {
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi case HOST_NOT_FOUND:
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi return "Host not found";
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi case NO_ADDRESS:
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi return "No IP address found for name";
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi case NO_RECOVERY:
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi return "A non-recoverable name server error occurred";
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi case TRY_AGAIN:
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi return "A temporary error on an authoritative name server";
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi default:
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi return t_strdup_printf("Unknown error %d", error);
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi }
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi#endif
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi}
eba201921d0e5ddc2319e94359576fbcba78eb41Aki Tuomi
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint net_hosterror_notfound(int error)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen#ifdef HAVE_IPV6
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen#ifdef EAI_NODATA /* NODATA is depricated */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return error != 1 && (error == EAI_NONAME || error == EAI_NODATA);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#else
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen return error != 1 && (error == EAI_NONAME);
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen#endif
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen#else
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen return error == HOST_NOT_FOUND || error == NO_ADDRESS;
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen#endif
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen}
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenconst char *net_getservbyport(unsigned short port)
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen{
6bb8c6900ad4f1223f388a6814bed0fb80ae27d2Timo Sirainen struct servent *entry;
6bb8c6900ad4f1223f388a6814bed0fb80ae27d2Timo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen entry = getservbyport(htons(port), "tcp");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return entry == NULL ? NULL : entry->s_name;
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenbool is_ipv4_address(const char *addr)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (*addr != '\0') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*addr != '.' && !i_isdigit(*addr))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen addr++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenbool is_ipv6_address(const char *addr)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool have_prefix = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*addr == '[') {
have_prefix = TRUE;
addr++;
}
while (*addr != '\0') {
if (*addr != ':' && !i_isxdigit(*addr)) {
if (have_prefix && *addr == ']' && addr[1] == '\0')
break;
return FALSE;
}
addr++;
}
return TRUE;
}
int net_parse_range(const char *network, struct ip_addr *ip_r,
unsigned int *bits_r)
{
const char *p;
unsigned int bits, max_bits;
p = strchr(network, '/');
if (p != NULL)
network = t_strdup_until(network, p++);
if (net_addr2ip(network, ip_r) < 0)
return -1;
max_bits = IPADDR_BITS(ip_r);
if (p == NULL) {
/* full IP address must match */
bits = max_bits;
} else {
/* get the network mask */
if (str_to_uint(p, &bits) < 0 || bits > max_bits)
return -1;
}
*bits_r = bits;
return 0;
}
bool net_is_in_network(const struct ip_addr *ip,
const struct ip_addr *net_ip, unsigned int bits)
{
struct ip_addr tmp_ip;
const uint32_t *ip1, *ip2;
uint32_t mask, i1, i2;
unsigned int pos, i;
if (net_ipv6_mapped_ipv4_convert(ip, &tmp_ip) == 0) {
/* IPv4 address mapped disguised as IPv6 address */
ip = &tmp_ip;
}
if (ip->family == 0) {
/* non-IPv4/IPv6 address (e.g. UNIX socket) never matches
anything */
return FALSE;
}
if (IPADDR_IS_V4(ip) != IPADDR_IS_V4(net_ip)) {
/* one is IPv6 and one is IPv4 */
return FALSE;
}
i_assert(IPADDR_IS_V6(ip) == IPADDR_IS_V6(net_ip));
if (IPADDR_IS_V4(ip)) {
ip1 = &ip->u.ip4.s_addr;
ip2 = &net_ip->u.ip4.s_addr;
} else {
#ifdef HAVE_IPV6
ip1 = (const void *)&ip->u.ip6;
ip2 = (const void *)&net_ip->u.ip6;
#else
/* shouldn't get here */
return FALSE;
#endif
}
/* check first the full 32bit ints */
for (pos = 0, i = 0; pos + 32 <= bits; pos += 32, i++) {
if (ip1[i] != ip2[i])
return FALSE;
}
i1 = htonl(ip1[i]);
i2 = htonl(ip2[i]);
/* check the last full bytes */
for (mask = 0xff000000; pos + 8 <= bits; pos += 8, mask >>= 8) {
if ((i1 & mask) != (i2 & mask))
return FALSE;
}
/* check the last bits, they're reversed in bytes */
bits -= pos;
for (mask = 0x80000000 >> (pos % 32); bits > 0; bits--, mask >>= 1) {
if ((i1 & mask) != (i2 & mask))
return FALSE;
}
return TRUE;
}