+2006-03-02 Michael Poole <mdpoole@troilus.org>
+
+ * include/ircd_osdep.h (os_socket): New parameter.
+
+ * include/res.h (irc_in_addr_unspec): New macro.
+
+ * ircd/ircd_res.c (restart_resolver): Set family appropriately.
+
+ * ircd/listener.c (inetport): Let os_ library pick socket family.
+
+ * ircd/os_generic.c: Do not #define _XOPEN_SOURCE on FreeBSD 5+.
+ (sockaddr_from_irc): New parameter.
+ (os_sendto_nonb): Use new parameter to sockaddr_from_irc().
+ (os_socket): New parameter. Try to turn off IPV6_V6ONLY on
+ sockets that listen on unspecified addresses.
+ (os_connect_nonb): Use new parameter to sockaddr_from_irc().
+
+ * ircd/s_auth.c (start_auth_query): Let os_ library pick socket
+ family.
+
+ * ircd/s_bsd.c (connect_inet): If we pick the IPv4 vhost, specify
+ family for os_socket() as AF_INET.
+
+ * ircd/uping.c (uping_init): Set socket family appropriately.
+ (uping_server): Likewise.
+ (uping_end): Fix format strings (the ms_* fields are int, not
+ long, and this causes bad results on LP64 machines).
+
2006-02-22 Michael Poole <mdpoole@troilus.org>
* ircd/m_silence.c (apply_silence): Refuse to apply silences for
extern int os_get_sockerr(int fd);
extern int os_get_sockname(int fd, struct irc_sockaddr* sin_out);
extern int os_get_peername(int fd, struct irc_sockaddr* sin_out);
-extern int os_socket(const struct irc_sockaddr* local, int type, const char* port_name);
+extern int os_socket(const struct irc_sockaddr* local, int type, const char* port_name, int family);
extern int os_accept(int fd, struct irc_sockaddr* peer);
extern IOResult os_sendto_nonb(int fd, const char* buf, unsigned int length,
unsigned int* length_out, unsigned int flags,
extern void gethost_byname(const char *name, dns_callback_f callback, void *ctx);
extern void gethost_byaddr(const struct irc_in_addr *addr, dns_callback_f callback, void *ctx);
+/** Evaluate to non-zero if \a ADDR is an unspecified (all zeros) address. */
+#define irc_in_addr_unspec(ADDR) (((ADDR)->in6_16[0] == 0) \
+ && ((ADDR)->in6_16[1] == 0) \
+ && ((ADDR)->in6_16[2] == 0) \
+ && ((ADDR)->in6_16[3] == 0) \
+ && ((ADDR)->in6_16[4] == 0) \
+ && ((ADDR)->in6_16[6] == 0) \
+ && ((ADDR)->in6_16[7] == 0) \
+ && ((ADDR)->in6_16[5] == 0 \
+ || (ADDR)->in6_16[5] == 65535))
/** Evaluate to non-zero if \a ADDR is a valid address (not all 0s and not all 1s). */
#define irc_in_addr_valid(ADDR) (((ADDR)->in6_16[0] && ~(ADDR)->in6_16[0]) \
|| (ADDR)->in6_16[1] != (ADDR)->in6_16[0] \
if (!s_active(&res_socket_v4))
{
- int fd = os_socket(&VirtualHost_v4, SOCK_DGRAM, "Resolver UDPv4 socket");
+ int fd = os_socket(&VirtualHost_v4, SOCK_DGRAM, "Resolver UDPv4 socket", AF_INET);
if (fd >= 0)
socket_add(&res_socket_v4, res_readreply, NULL,
SS_DATAGRAM, SOCK_EVENT_READABLE, fd);
}
+#ifdef AF_INET6
if (!s_active(&res_socket_v6))
{
- int fd = os_socket(&VirtualHost_v6, SOCK_DGRAM, "Resolver UDPv6 socket");
+ int fd = os_socket(&VirtualHost_v6, SOCK_DGRAM, "Resolver UDPv6 socket", AF_INET6);
if (fd >= 0)
socket_add(&res_socket_v6, res_readreply, NULL,
SS_DATAGRAM, SOCK_EVENT_READABLE, fd);
}
+#endif
if (s_active(&res_socket_v4) || s_active(&res_socket_v6))
timer_init(&res_timeout);
/*
* At first, open a new socket
*/
- fd = os_socket(&listener->addr, SOCK_STREAM, get_listener_name(listener));
+ fd = os_socket(&listener->addr, SOCK_STREAM, get_listener_name(listener), 0);
if (fd < 0)
return 0;
/*
*/
#define _XOPEN_SOURCE 500
#define __EXTENSIONS__ 1
-#else
-/* FreeBSD 6.0 requires SUSv3 to support IPv6. Apparently some other
- * OS requires SUSv3 to define IOV_MAX, but its identity is lost for
- * the time being.
+#elif defined(__FreeBSD__) && __FreeBSD__ >= 5
+/* FreeBSD 6.0 requires SUSv3 to support IPv6 -- but if you ask for
+ * that specifically (by defining _XOPEN_SOURCE to anything at all),
+ * they cleverly hide IPPROTO_IPV6. If you don't ask for anything,
+ * they give you everything.
*/
+#else
#define _XOPEN_SOURCE 600
#endif
#include <unistd.h>
#endif
+#if defined(IPV6_BINDV6ONLY) &&!defined(IPV6_V6ONLY)
+# define IPV6_V6ONLY IPV6_BINDV6ONLY
+#endif
+
#ifndef IOV_MAX
#define IOV_MAX 16 /**< minimum required length of an iovec array */
#endif
* @param[in] compat_fd If non-negative, an FD specifying address family.
* @return Length of address written to \a v6.
*/
-int sockaddr_from_irc(struct sockaddr_in6 *v6, const struct irc_sockaddr *irc, int compat_fd)
+int sockaddr_from_irc(struct sockaddr_in6 *v6, const struct irc_sockaddr *irc, int compat_fd, int family)
{
struct sockaddr_in6 sin6;
socklen_t slen;
- int family;
assert(irc != 0);
slen = sizeof(sin6);
- if ((0 <= compat_fd)
+ if (family) {
+ /* accept whatever user specified */
+ } else if ((0 <= compat_fd)
&& (0 == getsockname(compat_fd, (struct sockaddr*)&sin6, &slen)))
family = sin6.sin6_family;
else if ((irc == &VirtualHost_v4) || irc_in_addr_is_ipv4(&irc->addr))
#define sn_family sin_family
#define sockaddr_to_irc sockaddr_in_to_irc
-int sockaddr_from_irc(struct sockaddr_in *v4, const struct irc_sockaddr *irc, int compat_fd)
+int sockaddr_from_irc(struct sockaddr_in *v4, const struct irc_sockaddr *irc, int compat_fd, int family)
{
assert(irc != 0);
v4->sin_family = AF_INET;
} else{
memset(&v4, 0, sizeof(v4));
}
- (void)compat_fd;
+ (void)compat_fd; (void)family;
return sizeof(*v4);
}
int res, size;
assert(0 != buf);
- size = sockaddr_from_irc(&addr, peer, fd);
+ size = sockaddr_from_irc(&addr, peer, fd, 0);
assert((addr.sn_family == AF_INET) == irc_in_addr_is_ipv4(&peer->addr));
if (-1 < (res = sendto(fd, buf, length, flags, (struct sockaddr*)&addr, size))) {
if (count_out)
* @param[in] local Local address to bind to.
* @param[in] type SOCK_STREAM or SOCK_DGRAM.
* @param[in] port_name Port name (used in error diagnostics).
+ * @param[in] family A specific address family to use, or 0 for automatic.
* @return Bound descriptor, or -1 on error.
*/
-int os_socket(const struct irc_sockaddr* local, int type, const char* port_name)
+int os_socket(const struct irc_sockaddr* local, int type, const char* port_name, int family)
{
struct sockaddr_native addr;
int size, fd;
assert(local != 0);
- size = sockaddr_from_irc(&addr, local, -1);
+ size = sockaddr_from_irc(&addr, local, -1, family);
fd = socket(addr.sn_family, type, 0);
if (fd < 0) {
report_error(SOCKET_ERROR_MSG, port_name, errno);
return -1;
}
if (local) {
+#if defined(IPV6_V6ONLY)
+ int on = 0;
+ if (family == 0 && irc_in_addr_unspec(&local->addr))
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
+#endif
if (bind(fd, (struct sockaddr*)&addr, size)) {
report_error(BIND_ERROR_MSG, port_name, errno);
close(fd);
struct sockaddr_native addr;
int size;
- size = sockaddr_from_irc(&addr, sin, fd);
+ size = sockaddr_from_irc(&addr, sin, fd, 0);
if (0 == connect(fd, (struct sockaddr*) &addr, size))
return IO_SUCCESS;
else if (errno == EINPROGRESS)
local_addr.port = 0;
memcpy(&remote_addr.addr, &cli_ip(auth->client), sizeof(remote_addr.addr));
remote_addr.port = 113;
- fd = os_socket(&local_addr, SOCK_STREAM, "auth query");
+ fd = os_socket(&local_addr, SOCK_STREAM, "auth query", 0);
if (fd < 0) {
++ServerStats->is_abad;
if (IsUserPort(auth->client))
{
const struct irc_sockaddr *local;
IOResult result;
+ int family = 0;
+
assert(0 != aconf);
assert(0 != cptr);
/*
*/
if (irc_in_addr_valid(&aconf->origin.addr))
local = &aconf->origin;
- else if (irc_in_addr_is_ipv4(&aconf->address.addr))
+ else if (irc_in_addr_is_ipv4(&aconf->address.addr)) {
local = &VirtualHost_v4;
- else
+ family = AF_INET;
+ } else
local = &VirtualHost_v6;
- cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr));
+ cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr), family);
if (cli_fd(cptr) < 0)
return 0;
memcpy(&from, &VirtualHost_v4, sizeof(from));
from.port = atoi(UDP_PORT);
- fd = os_socket(&from, SOCK_DGRAM, "IPv4 uping listener");
+ fd = os_socket(&from, SOCK_DGRAM, "IPv4 uping listener", AF_INET);
if (fd < 0)
return -1;
if (!socket_add(&upingSock_v4, uping_echo_callback, 0, SS_DATAGRAM,
return -1;
}
+#ifdef AF_INET6
memcpy(&from, &VirtualHost_v6, sizeof(from));
from.port = atoi(UDP_PORT);
- fd = os_socket(&from, SOCK_DGRAM, "IPv6 uping listener");
+ fd = os_socket(&from, SOCK_DGRAM, "IPv6 uping listener", AF_INET6);
if (fd < 0)
return -1;
if (!socket_add(&upingSock_v6, uping_echo_callback, 0, SS_DATAGRAM,
close(fd);
return -1;
}
+#endif
return 0;
}
int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int count)
{
int fd;
+ int family = 0;
struct UPing* pptr;
struct irc_sockaddr *local;
if (IsUPing(sptr))
uping_cancel(sptr, sptr); /* Cancel previous ping request */
- local = irc_in_addr_is_ipv4(&aconf->address.addr) ? &VirtualHost_v4 : &VirtualHost_v6;
- fd = os_socket(local, SOCK_DGRAM, "Outbound uping socket");
+ if (irc_in_addr_is_ipv4(&aconf->address.addr)) {
+ local = &VirtualHost_v4;
+ family = AF_INET;
+ } else {
+ local = &VirtualHost_v6;
+ }
+ fd = os_socket(local, SOCK_DGRAM, "Outbound uping socket", family);
if (fd < 0)
return 0;
sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING %s%s",
pptr->client, pptr->name, pptr->buf);
sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING Stats: "
- "sent %d recvd %d ; min/avg/max = %1lu/%1lu/%1lu ms",
+ "sent %d recvd %d ; min/avg/max = %u/%u/%u ms",
pptr->client, pptr->sent, pptr->received, pptr->ms_min,
(2 * pptr->ms_ave) / (2 * pptr->received), pptr->ms_max);
} else
}
ClearUPing(sptr);
}
-
-