+2004-12-28 Michael Poole <mdpoole@troilus.org>
+
+ * include/s_bsd.h (VirtualHost): Replace with separate variables
+ for IPv4 and IPv6 virtual hosts.
+
+ * include/uping.h (uping_echo): Remove declaration.
+
+ * ircd/ircd_auth.c (iauth_reconnect): Select VirtualHost_v4 or
+ VirtualHost_v6 based on iauth server address family.
+
+ * ircd/ircd_lexer.l: Do not recognize RESOLVER token.
+
+ * ircd/ircd_parser.y (ResolverAddr): Remove declaration.
+ (RESOLVER): Remove definition.
+ (generalresolver): Remove.
+ (generalvhost): Assign address to either VirtualHost_v4 or
+ VirtualHost_v6, depending on format.
+
+ * ircd/ircd_res.c (res_socket): Replace with separate variables
+ for IPv4 and IPv6 resolver sockets.
+ (ResolverAddr): Remove definition.
+ (restart_resolver): Attempt to set up both IPv4 and IPv6 sockets.
+ (send_res_msg): Select outbound FD based on resolver address type.
+ (res_readreply): Recognize either inbound socket FD.
+
+ * ircd/os_generic.c (sockaddr_from_irc): Require irc != NULL.
+ (os_socket): Require local != NULL.
+
+ * ircd/s_bsd.c (VirtualHost): Replace with separate variables
+ for IPv4 and IPv6 virtual hosts.
+ (connect_inet): Select virtual host based on destination address.
+
+ * ircd/uping.c (UPingFIleDescriptor): Remove.
+ (upingSock): Split into separate IPv4 and IPv6 variables.
+ (uping_echo_callback): Incorporate uping_echo() body here, so the
+ proper socket FD can be used.
+ (uping_init): Attempt to set up both v4 and v6 UPING sockets.
+ (uping_server): Create uping socket with appropriate local address.
+
+ * doc/example.conf (General): Update example config file to
+ reflect removal of Resolver setting and support for separate IPv4
+ and IPv6 VHost settings.
+
2004-12-28 Michael Poole <mdpoole@troilus.org>
* ircd/sys.h (BITS_ZERO_ON_*, HAVE_RELIABLE_SIGNALS, DOCURSES,
# First some information about the server.
# General {
# name = "servername";
-# vhost = "virtualhost";
-# resolver = "ipaddress";
+# vhost = "ipv4vhost";
+# vhost = "ipv6vhost";
# description = "description";
# numeric = numericnumber;
# };
# override it. See Port{} for listener virtual hosting. If in doubt,
# leave it out.
#
-# You may need to specify the resolver address if your compile
-# defaults to using IPv6 but your resolvers are all IPv4 hosts.
+# You may specify both an IPv4 virtual host and an IPv6 virtual host,
+# to indicate which address should be used for outbound connections
+# of the respective type.
#
# Note that <server numeric> has to be unique on the network your server
# is running on, must be between 0 and 4095, and is not updated on a rehash.
extern int HighestFd;
extern struct Client* LocalClientArray[MAXCONNECTIONS];
-extern struct irc_sockaddr VirtualHost;
+extern struct irc_sockaddr VirtualHost_v4;
+extern struct irc_sockaddr VirtualHost_v6;
/*
* Proto types
extern void uping_read(struct UPing* pptr);
extern void uping_end(struct UPing* pptr);
extern void uping_cancel(struct Client *sptr, struct Client *acptr);
-extern void uping_echo(void);
extern struct UPing* uping_begin(void);
extern int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int count);
*/
static void iauth_reconnect(struct IAuth *iauth)
{
+ struct irc_sockaddr *local;
IOResult result;
int fd;
gethost_byname(i_host(iauth), &i_query(iauth));
return;
}
- fd = os_socket(&VirtualHost, SOCK_STREAM, "IAuth");
+ local = irc_in_addr_is_ipv4(&i_addr(iauth).addr) ? &VirtualHost_v4 : &VirtualHost_v6;
+ fd = os_socket(local, SOCK_STREAM, "IAuth");
if (fd < 0)
return;
if (!os_set_sockbufs(fd, SERVER_TCP_WINDOW, SERVER_TCP_WINDOW)) {
TOKEN(OPER),
TOKEN(LOCAL),
TOKEN(VHOST),
- TOKEN(RESOLVER),
TOKEN(MASK),
TOKEN(HIDDEN),
TOKEN(MOTD),
extern struct ServerConf* serverConfList;
extern struct s_map* GlobalServiceMapList;
extern struct qline* GlobalQuarantineList;
- extern struct irc_sockaddr ResolverAddr;
int yylex(void);
/* Now all the globals we need :/... */
%token NO
%token OPER
%token VHOST
-%token RESOLVER
%token HIDDEN
%token MOTD
%token JUPE
parse_error("Your General block must contain a numeric (between 1 and 4095).");
} ';' ;
generalitems: generalitem generalitems | generalitem;
-generalitem: generalnumeric | generalname | generalvhost | generalresolver | generaldesc | error;
+generalitem: generalnumeric | generalname | generalvhost | generaldesc | error;
generalnumeric: NUMERIC '=' NUMBER ';'
{
if (localConf.numeric == 0)
generalvhost: VHOST '=' QSTRING ';'
{
- ircd_aton(&VirtualHost.addr, $3);
-};
-
-generalresolver: RESOLVER '=' QSTRING ';'
-{
- ircd_aton(&ResolverAddr.addr, $3);
+ struct irc_in_addr addr;
+ if (!ircd_aton(&addr, $3))
+ parse_error("Invalid virtual host '%s'.", $3);
+ else if (irc_in_addr_is_ipv4(&addr))
+ memcpy(&VirtualHost_v4.addr, &addr, sizeof(addr));
+ else
+ memcpy(&VirtualHost_v6.addr, &addr, sizeof(addr));
};
adminblock: ADMIN '{' adminitems '}'
#error this code needs to be able to address individual octets
#endif
-/** Resolver UDP socket. */
-static struct Socket res_socket;
+/** IPv4 resolver UDP socket. */
+static struct Socket res_socket_v4;
+/** IPv6 resolver UDP socket. */
+static struct Socket res_socket_v6;
/** Next DNS lookup timeout. */
static struct Timer res_timeout;
/** Check for whether the resolver has been initialized yet. */
extern int irc_nscount;
extern char irc_domain[HOSTLEN];
-struct irc_sockaddr ResolverAddr;
-
/** Check whether \a inp is a nameserver we use.
* @param[in] inp Nameserver address.
* @return Non-zero if we trust \a inp; zero if not.
if (!request_list.next)
request_list.next = request_list.prev = &request_list;
- if (!s_active(&res_socket))
+ if (!s_active(&res_socket_v4))
{
- struct irc_sockaddr *local;
- int fd;
- local = irc_in_addr_valid(&ResolverAddr.addr) ? &ResolverAddr : &VirtualHost;
- fd = os_socket(local, SOCK_DGRAM, "Resolver UDP socket");
- if (fd < 0) return;
- if (!socket_add(&res_socket, res_readreply, NULL, SS_DATAGRAM,
- SOCK_EVENT_READABLE, fd)) return;
- timer_init(&res_timeout);
+ int fd = os_socket(&VirtualHost_v4, SOCK_DGRAM, "Resolver UDPv4 socket");
+ if (fd >= 0)
+ socket_add(&res_socket_v4, res_readreply, NULL,
+ SS_DATAGRAM, SOCK_EVENT_READABLE, fd);
+ }
+
+ if (!s_active(&res_socket_v6))
+ {
+ int fd = os_socket(&VirtualHost_v6, SOCK_DGRAM, "Resolver UDPv6 socket");
+ if (fd >= 0)
+ socket_add(&res_socket_v6, res_readreply, NULL,
+ SS_DATAGRAM, SOCK_EVENT_READABLE, fd);
}
+
+ if (s_active(&res_socket_v4) || s_active(&res_socket_v6))
+ timer_init(&res_timeout);
}
/** Append local domain to hostname if needed.
if (max_queries == 0)
max_queries = 1;
- for (i = 0; i < max_queries; i++)
- if (os_sendto_nonb(s_fd(&res_socket), msg, len, NULL, 0, &irc_nsaddr_list[i]) == IO_SUCCESS)
+ for (i = 0; i < max_queries; i++) {
+ int fd = irc_in_addr_is_ipv4(&irc_nsaddr_list[i].addr) ? s_fd(&res_socket_v4) : s_fd(&res_socket_v6);
+ if (os_sendto_nonb(fd, msg, len, NULL, 0, &irc_nsaddr_list[i]) == IO_SUCCESS)
++sent;
+ }
return(sent);
}
unsigned int rc;
int answer_count;
- assert(ev_socket(ev) == &res_socket);
+ assert((ev_socket(ev) == &res_socket_v4) || (ev_socket(ev) == &res_socket_v6));
sock = ev_socket(ev);
if (IO_SUCCESS != os_recvfrom_nonb(s_fd(sock), buf, sizeof(buf), &rc, &lsin)
socklen_t slen;
int family;
+ assert(irc != 0);
slen = sizeof(sin6);
- if (0 <= compat_fd) {
- if (0 == getsockname(compat_fd, (struct sockaddr*)&sin6, &slen))
- family = sin6.sin6_family;
- else if (irc_in_addr_is_ipv4(&VirtualHost.addr))
- family = AF_INET;
- else
- family = AF_INET6;
- } else {
- if (irc_in_addr_is_ipv4(&irc->addr))
- family = AF_INET;
- else
- family = AF_INET6;
- }
+ 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))
+ family = AF_INET;
+ else
+ family = AF_INET6;
memset(v6, 0, sizeof(*v6));
- if (!irc) {
- memset(v6, 0, sizeof(v6));
- v6->sin6_family = AF_INET6;
- return sizeof(*v6);
- }
- else if ((family == AF_INET) && irc_in_addr_is_ipv4(&irc->addr)) {
+ if (family == AF_INET) {
struct sockaddr_in *v4 = (struct sockaddr_in*)v6;
v4->sin_family = AF_INET;
memcpy(&v4->sin_addr, &irc->addr.in6_16[6], sizeof(v4->sin_addr));
int sockaddr_from_irc(struct sockaddr_in *v4, const struct irc_sockaddr *irc, int compat_fd)
{
+ assert(irc != 0);
v4->sin_family = AF_INET;
if (irc) {
assert(!irc->addr.in6_16[0] && !irc->addr.in6_16[1] && !irc->addr.in6_16[2] && !irc->addr.in6_16[3] && !irc->addr.in6_16[4] && (!irc->addr.in6_16[5] || irc->addr.in6_16[5] == 0xffff));
errno = 0;
size = sockaddr_from_irc(&addr, peer, fd);
+ 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)
*count_out = (unsigned) res;
struct sockaddr_native addr;
int size, fd;
+ assert(local != 0);
size = sockaddr_from_irc(&addr, local, -1);
fd = socket(addr.sn_family, type, 0);
if (fd < 0) {
struct Client* LocalClientArray[MAXCONNECTIONS];
/** Maximum file descriptor in current use. */
int HighestFd = -1;
-/** Default local address for outbound connections. */
-struct irc_sockaddr VirtualHost;
+/** Default local address for outbound IPv4 connections. */
+struct irc_sockaddr VirtualHost_v4;
+/** Default local address for outbound IPv6 connections. */
+struct irc_sockaddr VirtualHost_v6;
/** Temporary buffer for reading data from a peer. */
static char readbuf[SERVER_TCP_WINDOW];
*/
if (irc_in_addr_valid(&aconf->origin.addr))
local = &aconf->origin;
+ else if (irc_in_addr_is_ipv4(&aconf->address.addr))
+ local = &VirtualHost_v4;
else
- local = &VirtualHost;
+ local = &VirtualHost_v6;
cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr));
if (cli_fd(cptr) < 0)
return 0;
#define UPINGTIMEOUT 60 /**< Timeout waiting for ping responses */
static struct UPing* pingList = 0; /**< Linked list of UPing structs */
-static int UPingFileDescriptor = -1; /**< UDP listener socket for upings */
-static struct Socket upingSock; /**< Socket struct for upings */
+static struct Socket upingSock_v4; /**< Socket struct for IPv4 upings */
+static struct Socket upingSock_v6; /**< Socket struct for IPv6 upings */
/** Start iteration of uping list.
* @return Start of uping list.
}
/** Callback for uping listener socket.
+ * Reads a uping from the socket and respond, but not more than 10
+ * times per second.
* @param[in] ev I/O event for uping socket.
*/
static void uping_echo_callback(struct Event* ev)
{
+ struct Socket *sock;
+ struct irc_sockaddr from;
+ unsigned int len = 0;
+ static time_t last = 0;
+ static int counter = 0;
+ char buf[BUFSIZE + 1];
+
assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
+ sock = ev_socket(ev);
+ assert(sock == &upingSock_v4 || sock == &upingSock_v6);
- uping_echo();
+ Debug((DEBUG_DEBUG, "UPING: uping_echo"));
+
+ if (IO_SUCCESS != os_recvfrom_nonb(s_fd(sock), buf, BUFSIZE, &len, &from))
+ return;
+ /*
+ * count em even if we're getting flooded so we can tell we're getting
+ * flooded.
+ */
+ ++ServerStats->uping_recv;
+ if (len < 19)
+ return;
+ else if (CurrentTime != last) {
+ counter = 0;
+ last = CurrentTime;
+ } else if (++counter > 10)
+ return;
+ os_sendto_nonb(s_fd(sock), buf, len, NULL, 0, &from);
}
/** Initialize a UDP socket for upings.
- * @returns File descriptor of UDP socket (-1 on error).
+ * @returns 0 on success, -1 on error.
*/
int uping_init(void)
{
struct irc_sockaddr from;
int fd;
- memcpy(&from, &VirtualHost, sizeof(from));
+ memcpy(&from, &VirtualHost_v4, sizeof(from));
from.port = atoi(UDP_PORT);
- fd = os_socket(&from, SOCK_DGRAM, "UDP listener socket");
+ fd = os_socket(&from, SOCK_DGRAM, "IPv4 uping listener");
if (fd < 0)
return -1;
- if (!socket_add(&upingSock, uping_echo_callback, 0, SS_DATAGRAM,
- SOCK_EVENT_READABLE, fd)) {
+ if (!socket_add(&upingSock_v4, uping_echo_callback, 0, SS_DATAGRAM,
+ SOCK_EVENT_READABLE, fd)) {
Debug((DEBUG_ERROR, "UPING: Unable to queue fd to event system"));
close(fd);
return -1;
}
- UPingFileDescriptor = fd;
- return fd;
-}
-
-/** Read a uping from the socket and respond (but not more than 10
- * times per second).
- */
-void uping_echo()
-{
- struct irc_sockaddr from;
- unsigned int len = 0;
- static time_t last = 0;
- static int counter = 0;
- char buf[BUFSIZE + 1];
-
- Debug((DEBUG_DEBUG, "UPING: uping_echo"));
+ memcpy(&from, &VirtualHost_v6, sizeof(from));
+ from.port = atoi(UDP_PORT);
- if (IO_SUCCESS != os_recvfrom_nonb(UPingFileDescriptor, buf, BUFSIZE, &len, &from))
- return;
- /*
- * count em even if we're getting flooded so we can tell we're getting
- * flooded.
- */
- ++ServerStats->uping_recv;
- if (CurrentTime == last) {
- if (++counter > 10)
- return;
- }
- else {
- counter = 0;
- last = CurrentTime;
+ fd = os_socket(&from, SOCK_DGRAM, "IPv6 uping listener");
+ if (fd < 0)
+ return -1;
+ if (!socket_add(&upingSock_v6, uping_echo_callback, 0, SS_DATAGRAM,
+ SOCK_EVENT_READABLE, fd)) {
+ Debug((DEBUG_ERROR, "UPING: Unable to queue fd to event system"));
+ close(fd);
+ return -1;
}
- if (len < 19)
- return;
- os_sendto_nonb(UPingFileDescriptor, buf, len, NULL, 0, &from);
+
+ return 0;
}
{
int fd;
struct UPing* pptr;
+ struct irc_sockaddr *local;
assert(0 != sptr);
assert(0 != aconf);
if (IsUPing(sptr))
uping_cancel(sptr, sptr); /* Cancel previous ping request */
- fd = os_socket(NULL, SOCK_DGRAM, "UDP ping socket");
+ local = irc_in_addr_is_ipv4(&aconf->address.addr) ? &VirtualHost_v4 : &VirtualHost_v6;
+ fd = os_socket(local, SOCK_DGRAM, "Outbound uping socket");
if (fd < 0)
return 0;