IPv6 support.

all references to struct sockaddr/in_addr have been
removed from src/ngircd.
libngipaddr (in src/ipaddr/) hides all the gory details.
See src/ipaddr/ng_ipaddr.h for API description.
This commit is contained in:
Florian Westphal 2008-02-26 23:50:35 +01:00
parent c31ad221a6
commit feb31e4200
18 changed files with 826 additions and 288 deletions

View File

@ -12,6 +12,7 @@
ngIRCd HEAD
- Add IPv6 support.
- Install a LaunchDaemon script to start/stop ngIRCd on Mac OS X.
- Implemented IRC commands INFO, SUMMON (dummy), and USERS (dummy) and
enhanced test suite to check these commands. (Dana Dahlstrom)
@ -758,4 +759,4 @@ ngIRCd 0.0.1, 31.12.2001
--
$Id: ChangeLog,v 1.343 2008/02/26 20:35:43 alex Exp $
$Id: ChangeLog,v 1.344 2008/02/26 22:05:42 fw Exp $

3
NEWS
View File

@ -12,6 +12,7 @@
ngIRCd HEAD
- Added IPv6 support.
- Implemented IRC commands INFO, SUMMON (dummy), and USERS (dummy) and
enhanced test suite to check these commands. (Dana Dahlstrom)
- IRC_WHO now supports search patterns and will test this
@ -263,4 +264,4 @@ ngIRCd 0.0.1, 31.12.2001
--
$Id: NEWS,v 1.87 2008/02/17 13:26:41 alex Exp $
$Id: NEWS,v 1.88 2008/02/26 22:05:42 fw Exp $

View File

@ -8,7 +8,7 @@
# (at your option) any later version.
# Please read the file COPYING, README and AUTHORS for more information.
#
# $Id: configure.in,v 1.125 2006/12/26 16:00:45 alex Exp $
# $Id: configure.in,v 1.126 2008/02/26 22:04:15 fw Exp $
#
# -- Initialisation --
@ -30,6 +30,7 @@ AH_TEMPLATE([SYSLOG], [Define if syslog should be used for logging])
AH_TEMPLATE([ZLIB], [Define if zlib compression should be enabled])
AH_TEMPLATE([TCPWRAP], [Define if TCP wrappers should be used])
AH_TEMPLATE([IRCPLUS], [Define if IRC+ protocol should be used])
AH_TEMPLATE([WANT_IPV6], [Define if IPV6 protocol should be enabled])
AH_TEMPLATE([ZEROCONF], [Define if support for Zeroconf should be included])
AH_TEMPLATE([IDENTAUTH], [Define if the server should do IDENT requests])
@ -426,6 +427,19 @@ if test "$x_ircplus_on" = "yes"; then
AC_DEFINE(IRCPLUS, 1)
fi
# enable support for IPv6?
x_ipv6_on=no
AC_ARG_ENABLE(ipv6,
[ --enable-ipv6, enable IPv6 protocol support],
if test "$enableval" = "yes"; then x_ipv6_on=yes; fi
)
if test "$x_ipv6_on" = "yes"; then
AC_CHECK_FUNCS([ \
getaddrinfo getnameinfo \
],,AC_MSG_ERROR([required function missing for IPv6 support!]))
AC_DEFINE(WANT_IPV6, 1)
fi
# compile in IRC "sniffer"?
x_sniffer_on=no; x_debug_on=no
@ -477,6 +491,7 @@ AC_OUTPUT([ \
doc/src/Makefile \
src/Makefile \
src/portab/Makefile \
src/ipaddr/Makefile \
src/tool/Makefile \
src/ngircd/Makefile \
src/testsuite/Makefile \
@ -572,6 +587,8 @@ test "$x_identauth_on" = "yes" \
echo $ECHO_N " I/O backend: $ECHO_C"
echo "\"$x_io_backend\""
echo $ECHO_N " IPv6 protocol: $ECHO_C"
echo "$x_ipv6_on"
echo
# -eof-

View File

@ -8,10 +8,10 @@
# (at your option) any later version.
# Please read the file COPYING, README and AUTHORS for more information.
#
# $Id: Makefile.am,v 1.7 2005/07/22 21:01:03 alex Exp $
# $Id: Makefile.am,v 1.8 2008/02/26 22:04:15 fw Exp $
#
SUBDIRS = portab tool ngircd testsuite
SUBDIRS = portab tool ipaddr ngircd testsuite
maintainer-clean-local:
rm -f Makefile Makefile.in config.h config.h.in stamp-h.in

3
src/ipaddr/.cvsignore Normal file
View File

@ -0,0 +1,3 @@
Makefile
Makefile.in
.deps

14
src/ipaddr/Makefile.am Normal file
View File

@ -0,0 +1,14 @@
AUTOMAKE_OPTIONS = ansi2knr
INCLUDES = -I$(srcdir)/../portab
noinst_LIBRARIES = libngipaddr.a
libngipaddr_a_SOURCES = ng_ipaddr.c
noinst_HEADERS = ng_ipaddr.h
maintainer-clean-local:
rm -f Makefile Makefile.in
# -eof-

170
src/ipaddr/ng_ipaddr.c Normal file
View File

@ -0,0 +1,170 @@
/*
* Functions for AF_ agnostic ipv4/ipv6 handling.
*
* (c) 2008 Florian Westphal <fw@strlen.de>, public domain.
*/
#include "portab.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_GETADDRINFO
#include <netdb.h>
#include <sys/types.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#include "ng_ipaddr.h"
GLOBAL bool
ng_ipaddr_init(ng_ipaddr_t *addr, const char *ip_str, UINT16 port)
{
#ifdef HAVE_GETADDRINFO
int ret;
char portstr[64];
struct addrinfo *res0;
struct addrinfo hints = {
#ifndef WANT_IPV6 /* only accept v4 addresses */
.ai_family = AF_INET,
#endif
.ai_flags = AI_NUMERICHOST
};
if (ip_str == NULL)
hints.ai_flags |= AI_PASSIVE;
/* silly, but ngircd stores UINT16 in server config, not string */
snprintf(portstr, sizeof(portstr), "%u", (unsigned int) port);
ret = getaddrinfo(ip_str, portstr, &hints, &res0);
assert(ret == 0);
if (ret != 0)
return false;
assert(sizeof(*addr) >= res0->ai_addrlen);
if (sizeof(*addr) >= res0->ai_addrlen)
memcpy(addr, res0->ai_addr, res0->ai_addrlen);
else
ret = -1;
freeaddrinfo(res0);
return ret == 0;
#else /* HAVE_GETADDRINFO */
if (ip_str == NULL)
ip_str = "0.0.0.0";
addr->sin4.sin_family = AF_INET;
# ifdef HAVE_INET_ATON
if (inet_aton(ip_str, &addr->sin4.sin_addr) == 0)
return false;
# else
addr->sin4.sin_addr.s_addr = inet_addr(ip_str);
if (addr->sin4.sin_addr.s_addr == (unsigned) -1)
return false;
# endif
ng_ipaddr_setport(addr, port);
return true;
#endif /* HAVE_GETADDRINFO */
}
GLOBAL void
ng_ipaddr_setport(ng_ipaddr_t *a, UINT16 port)
{
#ifdef WANT_IPV6
int af;
assert(a != NULL);
af = a->sa.sa_family;
assert(af == AF_INET || af == AF_INET6);
switch (af) {
case AF_INET:
a->sin4.sin_port = htons(port);
break;
case AF_INET6:
a->sin6.sin6_port = htons(port);
break;
}
#else /* WANT_IPV6 */
assert(a != NULL);
assert(a->sin4.sin_family == AF_INET);
a->sin4.sin_port = htons(port);
#endif /* WANT_IPV6 */
}
GLOBAL bool
ng_ipaddr_ipequal(const ng_ipaddr_t *a, const ng_ipaddr_t *b)
{
assert(a != NULL);
assert(b != NULL);
#ifdef WANT_IPV6
if (a->sa.sa_family != b->sa.sa_family)
return false;
assert(ng_ipaddr_salen(a) == ng_ipaddr_salen(b));
switch (a->sa.sa_family) {
case AF_INET6:
return IN6_ARE_ADDR_EQUAL(&a->sin6.sin6_addr, &b->sin6.sin6_addr);
case AF_INET:
return memcmp(&a->sin4.sin_addr, &b->sin4.sin_addr, sizeof(a->sin4.sin_addr)) == 0;
}
return false;
#else
assert(a->sin4.sin_family == AF_INET);
assert(b->sin4.sin_family == AF_INET);
return memcmp(&a->sin4.sin_addr, &b->sin4.sin_addr, sizeof(a->sin4.sin_addr)) == 0;
#endif
}
#ifdef WANT_IPV6
GLOBAL const char *
ng_ipaddr_tostr(const ng_ipaddr_t *addr)
{
static char strbuf[NG_INET_ADDRSTRLEN];
strbuf[0] = 0;
ng_ipaddr_tostr_r(addr, strbuf);
return strbuf;
}
/* str must be at least NG_INET_ADDRSTRLEN bytes long */
GLOBAL bool
ng_ipaddr_tostr_r(const ng_ipaddr_t *addr, char *str)
{
#ifdef HAVE_GETNAMEINFO
const struct sockaddr *sa = (const struct sockaddr *) addr;
int ret;
*str = 0;
ret = getnameinfo(sa, ng_ipaddr_salen(addr),
str, NG_INET_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
/*
* avoid leading ':'.
* causes mis-interpretation of client host in e.g. /WHOIS
*/
if (*str == ':') {
char tmp[NG_INET_ADDRSTRLEN] = "0";
ret = getnameinfo(sa, ng_ipaddr_salen(addr),
tmp+1, sizeof(tmp) -1, NULL, 0, NI_NUMERICHOST);
if (ret == 0)
strlcpy(str, tmp, NG_INET_ADDRSTRLEN);
}
assert (ret == 0);
return ret == 0;
#else
abort(); /* WANT_IPV6 depends on HAVE_GETNAMEINFO */
#endif
}
#endif /* WANT_IPV6 */
/* -eof- */

115
src/ipaddr/ng_ipaddr.h Normal file
View File

@ -0,0 +1,115 @@
/*
* Functions for AF_ agnostic ipv4/ipv6 handling.
*
* (c) 2008 Florian Westphal <fw@strlen.de>, public domain.
*/
#ifndef NG_IPADDR_HDR
#define NG_IPADDR_HDR
#include "portab.h"
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#else
# define PF_INET AF_INET
#endif
#ifdef WANT_IPV6
#define NG_INET_ADDRSTRLEN INET6_ADDRSTRLEN
#else
#define NG_INET_ADDRSTRLEN 16
#endif
#ifdef WANT_IPV6
typedef union {
struct sockaddr sa;
struct sockaddr_in sin4;
struct sockaddr_in6 sin6;
} ng_ipaddr_t;
#else
/* assume compiler can't deal with typedef struct {... */
struct NG_IP_ADDR_DONTUSE {
struct sockaddr_in sin4;
};
typedef struct NG_IP_ADDR_DONTUSE ng_ipaddr_t;
#endif
static inline int
ng_ipaddr_af(const ng_ipaddr_t *a)
{
#ifdef WANT_IPV6
return a->sa.sa_family;
#else
assert(a->sin4.sin_family == 0 || a->sin4.sin_family == AF_INET);
return a->sin4.sin_family;
#endif
}
static inline socklen_t
ng_ipaddr_salen(const ng_ipaddr_t *a)
{
#ifdef WANT_IPV6
assert(a->sa.sa_family == AF_INET || a->sa.sa_family == AF_INET6);
if (a->sa.sa_family == AF_INET6)
return sizeof(a->sin6);
#endif
assert(a->sin4.sin_family == AF_INET);
return sizeof(a->sin4);
}
static inline UINT16
ng_ipaddr_getport(const ng_ipaddr_t *a)
{
#ifdef WANT_IPV6
int af = a->sa.sa_family;
assert(af == AF_INET || af == AF_INET6);
if (af == AF_INET6)
return ntohs(a->sin6.sin6_port);
#endif /* WANT_IPV6 */
assert(a->sin4.sin_family == AF_INET);
return ntohs(a->sin4.sin_port);
}
/*
* init a ng_ipaddr_t object.
* @param addr: pointer to ng_ipaddr_t to initialize.
* @param ip_str: ip address in dotted-decimal (ipv4) or hexadecimal (ipv6) notation
* if ip_str is NULL it is treated as 0.0.0.0/[::]
* @param port: transport layer port number to use.
*/
GLOBAL bool ng_ipaddr_init PARAMS((ng_ipaddr_t *addr, const char *ip_str, UINT16 port));
/* set sin4/sin6_port, depending on a->sa_family */
GLOBAL void ng_ipaddr_setport PARAMS((ng_ipaddr_t *a, UINT16 port));
/* return true if a and b have the same IP address. If a and b have different AF, return false. */
GLOBAL bool ng_ipaddr_ipequal PARAMS((const ng_ipaddr_t *a, const ng_ipaddr_t *b));
#ifdef WANT_IPV6
/* convert struct sockaddr to string, returns pointer to static buffer */
GLOBAL const char *ng_ipaddr_tostr PARAMS((const ng_ipaddr_t *addr));
/* convert struct sockaddr to string. dest must be NG_INET_ADDRSTRLEN bytes long */
GLOBAL bool ng_ipaddr_tostr_r PARAMS((const ng_ipaddr_t *addr, char *dest));
#else
static inline const char *
ng_ipaddr_tostr(const ng_ipaddr_t *addr) { return inet_ntoa(addr->sin4.sin_addr); }
static inline bool
ng_ipaddr_tostr_r(const ng_ipaddr_t *addr, char *d)
{
strlcpy(d, inet_ntoa(addr->sin4.sin_addr), NG_INET_ADDRSTRLEN);
return true;
}
#endif
#endif
/* -eof- */

View File

@ -8,12 +8,12 @@
# (at your option) any later version.
# Please read the file COPYING, README and AUTHORS for more information.
#
# $Id: Makefile.am,v 1.50 2007/11/21 12:16:36 alex Exp $
# $Id: Makefile.am,v 1.51 2008/02/26 22:04:17 fw Exp $
#
AUTOMAKE_OPTIONS = ../portab/ansi2knr
INCLUDES = -I$(srcdir)/../portab -I$(srcdir)/../tool
INCLUDES = -I$(srcdir)/../portab -I$(srcdir)/../tool -I$(srcdir)/../ipaddr
LINTARGS = -weak -warnunixlib +unixlib -booltype BOOLEAN \
-varuse -retvalother -emptyret -unrecog
@ -25,9 +25,9 @@ ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \
irc-mode.c irc-op.c irc-oper.c irc-server.c irc-write.c lists.c log.c \
match.c numeric.c parse.c rendezvous.c resolve.c
ngircd_LDFLAGS = -L../portab -L../tool
ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr
ngircd_LDADD = -lngportab -lngtool
ngircd_LDADD = -lngportab -lngtool -lngipaddr
noinst_HEADERS = ngircd.h array.h channel.h client.h conf.h conn.h conn-func.h \
conn-zip.h hash.h io.h irc.h irc-channel.h irc-info.h irc-login.h \

View File

@ -14,7 +14,7 @@
#include "portab.h"
static char UNUSED id[] = "$Id: conf.c,v 1.103 2007/11/23 16:26:04 fw Exp $";
static char UNUSED id[] = "$Id: conf.c,v 1.104 2008/02/26 22:04:17 fw Exp $";
#include "imp.h"
#include <assert.h>
@ -938,7 +938,7 @@ Handle_SERVER( int Line, char *Var, char *Arg )
return;
}
if (strcasecmp(Var, "Bind") == 0) {
if (ngt_IPStrToBin(Arg, &New_Server.bind_addr))
if (ng_ipaddr_init(&New_Server.bind_addr, Arg, 0))
return;
Config_Error(LOG_ERR, "%s, line %d (section \"Server\"): Can't parse IP address \"%s\"",
@ -1213,7 +1213,7 @@ Init_Server_Struct( CONF_SERVER *Server )
Resolve_Init(&Server->res_stat);
Server->conn_id = NONE;
Server->bind_addr.s_addr = htonl(INADDR_ANY);
memset(&Server->bind_addr, 0, sizeof(&Server->bind_addr));
} /* Init_Server_Struct */

View File

@ -8,7 +8,7 @@
* (at your option) any later version.
* Please read the file COPYING, README and AUTHORS for more information.
*
* $Id: conf.h,v 1.47 2007/11/23 16:28:37 fw Exp $
* $Id: conf.h,v 1.48 2008/02/26 22:04:17 fw Exp $
*
* Configuration management (header)
*/
@ -22,6 +22,8 @@
#include "defines.h"
#include "array.h"
#include "portab.h"
#include "tool.h"
#include "ng_ipaddr.h"
typedef struct _Conf_Oper
{
@ -42,7 +44,8 @@ typedef struct _Conf_Server
RES_STAT res_stat; /* Status of the resolver */
int flags; /* Flags */
CONN_ID conn_id; /* ID of server connection or NONE */
struct in_addr bind_addr; /* source address to use for outgoing connections */
ng_ipaddr_t bind_addr; /* source address to use for outgoing connections */
ng_ipaddr_t dst_addr[2]; /* list of addresses to connect to */
} CONF_SERVER;
typedef struct _Conf_Channel
@ -121,6 +124,12 @@ GLOBAL bool Conf_OperCanMode;
/* Disable all DNS functions? */
GLOBAL bool Conf_NoDNS;
/* don't listen for incoming ipv6 connections, even if OS supports it? */
GLOBAL bool Conf_NoListenIpv6;
/* don't connect to remote systems unsign ipv6? */
GLOBAL bool Conf_NoConnectIpv6;
/* If an IRC op gives chanop privileges without being a chanop,
* ircd2 will ignore the command. This enables a workaround:
* It masks the command as coming from the server */

View File

@ -17,7 +17,7 @@
#include "portab.h"
#include "io.h"
static char UNUSED id[] = "$Id: conn.c,v 1.220 2007/12/13 01:30:16 fw Exp $";
static char UNUSED id[] = "$Id: conn.c,v 1.221 2008/02/26 22:04:17 fw Exp $";
#include "imp.h"
#include <assert.h>
@ -86,10 +86,9 @@ static void Check_Connections PARAMS(( void ));
static void Check_Servers PARAMS(( void ));
static void Init_Conn_Struct PARAMS(( CONN_ID Idx ));
static bool Init_Socket PARAMS(( int Sock ));
static void New_Server PARAMS(( int Server, struct in_addr *dest));
static void New_Server PARAMS(( int Server, ng_ipaddr_t *dest ));
static void Simple_Message PARAMS(( int Sock, const char *Msg ));
static int Count_Connections PARAMS(( struct sockaddr_in addr ));
static int NewListener PARAMS(( const UINT16 Port ));
static int NewListener PARAMS(( int af, const UINT16 Port ));
static array My_Listeners;
static array My_ConnArray;
@ -144,10 +143,28 @@ cb_connserver(int sock, UNUSED short what)
Conf_Server[Conf_GetServer(idx)].port,
idx, strerror(err));
res = Conf_GetServer(idx);
assert(res >= 0);
Conn_Close(idx, "Can't connect!", NULL, false);
if (res < 0)
return;
if (ng_ipaddr_af(&Conf_Server[res].dst_addr[0])) {
/* more addresses to try... */
New_Server(res, &Conf_Server[res].dst_addr[0]);
/* connection to dst_addr[0] in progress, remove this address... */
Conf_Server[res].dst_addr[0] = Conf_Server[res].dst_addr[1];
memset(&Conf_Server[res].dst_addr[1], 0, sizeof(&Conf_Server[res].dst_addr[1]));
}
return;
}
res = Conf_GetServer(idx);
assert(res >= 0);
if (res >= 0) /* connect succeeded, remove all additional addresses */
memset(&Conf_Server[res].dst_addr, 0, sizeof(&Conf_Server[res].dst_addr));
Conn_OPTION_DEL( &My_Connections[idx], CONN_ISCONNECTING );
server_login(idx);
}
@ -255,7 +272,7 @@ Conn_Exit( void )
static unsigned int
ports_initlisteners(array *a, void (*func)(int,short))
ports_initlisteners(array *a, int af, void (*func)(int,short))
{
unsigned int created = 0;
size_t len;
@ -265,7 +282,7 @@ ports_initlisteners(array *a, void (*func)(int,short))
len = array_length(a, sizeof (UINT16));
port = array_start(a);
while(len--) {
fd = NewListener( *port );
fd = NewListener(af, *port);
if (fd < 0) {
port++;
continue;
@ -290,14 +307,18 @@ Conn_InitListeners( void )
{
/* Initialize ports on which the server should accept connections */
unsigned int created;
unsigned int created = 0;
if (!io_library_init(CONNECTION_POOL)) {
Log(LOG_EMERG, "Cannot initialize IO routines: %s", strerror(errno));
return -1;
}
created = ports_initlisteners(&Conf_ListenPorts, cb_listen);
#ifdef WANT_IPV6
if (!Conf_NoListenIpv6)
created = ports_initlisteners(&Conf_ListenPorts, AF_INET6, cb_listen);
#endif
created += ports_initlisteners(&Conf_ListenPorts, AF_INET, cb_listen);
return created;
} /* Conn_InitListeners */
@ -327,68 +348,75 @@ Conn_ExitListeners( void )
} /* Conn_ExitListeners */
static void
InitSinaddr(struct sockaddr_in *addr, UINT16 Port)
static bool
InitSinaddrListenAddr(int af, ng_ipaddr_t *addr, UINT16 Port)
{
struct in_addr inaddr;
bool ret;
const char *listen_addrstr = NULL;
#ifdef WANT_IPV6
if (af == AF_INET)
listen_addrstr = "0.0.0.0";
#else
(void)af;
#endif
if (Conf_ListenAddress[0]) /* overrides V4/V6 atm */
listen_addrstr = Conf_ListenAddress;
memset(addr, 0, sizeof(*addr));
memset( &inaddr, 0, sizeof(inaddr));
addr->sin_family = AF_INET;
addr->sin_port = htons(Port);
inaddr.s_addr = htonl(INADDR_ANY);
addr->sin_addr = inaddr;
ret = ng_ipaddr_init(addr, listen_addrstr, Port);
if (!ret) {
if (!listen_addrstr)
listen_addrstr = "";
Log(LOG_CRIT, "Can't bind to %s:%u: can't convert ip address \"%s\"",
listen_addrstr, Port, listen_addrstr);
}
return ret;
}
static bool
InitSinaddrListenAddr(struct sockaddr_in *addr, UINT16 Port)
static void
set_v6_only(int af, int sock)
{
struct in_addr inaddr;
#if defined(IPV6_V6ONLY) && defined(WANT_IPV6)
int on = 1;
InitSinaddr(addr, Port);
if (af != AF_INET6)
return;
if (!Conf_ListenAddress[0])
return true;
if (!ngt_IPStrToBin(Conf_ListenAddress, &inaddr)) {
Log( LOG_CRIT, "Can't bind to %s:%u: can't convert ip address \"%s\"",
Conf_ListenAddress, Port, Conf_ListenAddress);
return false;
}
addr->sin_addr = inaddr;
return true;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)))
Log(LOG_ERR, "Could not set IPV6_V6ONLY: %s", strerror(errno));
#else
(void)af;
(void)sock;
#endif
}
/* return new listening port file descriptor or -1 on failure */
static int
NewListener( const UINT16 Port )
NewListener(int af, const UINT16 Port)
{
/* Create new listening socket on specified port */
struct sockaddr_in addr;
ng_ipaddr_t addr;
int sock;
#ifdef ZEROCONF
char name[CLIENT_ID_LEN], *info;
#endif
if (!InitSinaddrListenAddr(af, &addr, Port))
return -1;
InitSinaddrListenAddr(&addr, Port);
addr.sin_family = AF_INET;
addr.sin_port = htons( Port );
sock = socket( PF_INET, SOCK_STREAM, 0);
sock = socket(ng_ipaddr_af(&addr), SOCK_STREAM, 0);
if( sock < 0 ) {
Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno ));
return -1;
}
af = ng_ipaddr_af(&addr);
set_v6_only(af, sock);
if( ! Init_Socket( sock )) return -1;
if (bind(sock, (struct sockaddr *)&addr, (socklen_t)sizeof(addr)) != 0) {
if (bind(sock, (struct sockaddr *)&addr, ng_ipaddr_salen(&addr)) != 0) {
Log( LOG_CRIT, "Can't bind socket (port %d) : %s!", Port, strerror( errno ));
close( sock );
return -1;
@ -407,8 +435,12 @@ NewListener( const UINT16 Port )
return -1;
}
if( Conf_ListenAddress[0]) Log( LOG_INFO, "Now listening on %s:%d (socket %d).", Conf_ListenAddress, Port, sock );
else Log( LOG_INFO, "Now listening on 0.0.0.0:%d (socket %d).", Port, sock );
#ifdef WANT_IPV6
if (af == AF_INET6)
Log(LOG_INFO, "Now listening on [%s]:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock);
else
#endif
Log(LOG_INFO, "Now listening on %s:%d (socket %d).", ng_ipaddr_tostr(&addr), Port, sock);
#ifdef ZEROCONF
/* Get best server description text */
@ -709,6 +741,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
CLIENT *c;
char *txt;
double in_k, out_k;
UINT16 port;
#ifdef ZLIB
double in_z_k, out_z_k;
int in_p, out_p;
@ -736,9 +769,9 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
if (! txt)
txt = "Reason unknown";
port = ng_ipaddr_getport(&My_Connections[Idx].addr);
Log(LOG_INFO, "Shutting down connection %d (%s) with %s:%d ...", Idx,
LogMsg ? LogMsg : FwdMsg, My_Connections[Idx].host,
ntohs(My_Connections[Idx].addr.sin_port));
LogMsg ? LogMsg : FwdMsg, My_Connections[Idx].host, port);
/* Search client, if any */
c = Conn_GetClient( Idx );
@ -778,7 +811,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
Log(LOG_CRIT,
"Error closing connection %d (socket %d) with %s:%d - %s! (ignored)",
Idx, My_Connections[Idx].sock, My_Connections[Idx].host,
ntohs(My_Connections[Idx].addr.sin_port), strerror(errno));
port, strerror(errno));
}
/* Mark socket as invalid: */
@ -807,8 +840,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
out_p = (int)(( out_k * 100 ) / out_z_k );
Log(LOG_INFO,
"Connection %d with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).",
Idx, My_Connections[Idx].host,
ntohs(My_Connections[Idx].addr.sin_port),
Idx, My_Connections[Idx].host, port,
in_k, in_z_k, in_p, out_k, out_z_k, out_p);
}
else
@ -816,8 +848,7 @@ Conn_Close( CONN_ID Idx, char *LogMsg, char *FwdMsg, bool InformClient )
{
Log(LOG_INFO,
"Connection %d with %s:%d closed (in: %.1fk, out: %.1fk).",
Idx, My_Connections[Idx].host,
ntohs(My_Connections[Idx].addr.sin_port),
Idx, My_Connections[Idx].host, port,
in_k, out_k);
}
@ -940,6 +971,22 @@ Handle_Write( CONN_ID Idx )
} /* Handle_Write */
static int
Count_Connections(ng_ipaddr_t *a)
{
int i, cnt;
cnt = 0;
for (i = 0; i < Pool_Size; i++) {
if (My_Connections[i].sock <= NONE)
continue;
if (ng_ipaddr_ipequal(&My_Connections[i].addr, a))
cnt++;
}
return cnt;
} /* Count_Connections */
static int
New_Connection( int Sock )
{
@ -949,14 +996,16 @@ New_Connection( int Sock )
#ifdef TCPWRAP
struct request_info req;
#endif
struct sockaddr_in new_addr;
ng_ipaddr_t new_addr;
char ip_str[NG_INET_ADDRSTRLEN];
int new_sock, new_sock_len, new_Pool_Size;
CLIENT *c;
long cnt;
assert( Sock > NONE );
/* Connection auf Listen-Socket annehmen */
new_sock_len = (int)sizeof new_addr;
new_sock_len = (int)sizeof(new_addr);
new_sock = accept(Sock, (struct sockaddr *)&new_addr,
(socklen_t *)&new_sock_len);
if (new_sock < 0) {
@ -964,14 +1013,18 @@ New_Connection( int Sock )
return -1;
}
if (!ng_ipaddr_tostr_r(&new_addr, ip_str)) {
Log(LOG_CRIT, "fd %d: Can't convert IP address!", new_sock);
Simple_Message(new_sock, "ERROR :Internal Server Error");
close(new_sock);
}
#ifdef TCPWRAP
/* Validate socket using TCP Wrappers */
request_init( &req, RQ_DAEMON, PACKAGE_NAME, RQ_FILE, new_sock, RQ_CLIENT_SIN, &new_addr, NULL );
fromhost(&req);
if( ! hosts_access( &req ))
{
/* Access denied! */
Log( deny_severity, "Refused connection from %s (by TCP Wrappers)!", inet_ntoa( new_addr.sin_addr ));
if (!hosts_access(&req)) {
Log (deny_severity, "Refused connection from %s (by TCP Wrappers)!", ip_str);
Simple_Message( new_sock, "ERROR :Connection refused" );
close( new_sock );
return -1;
@ -981,13 +1034,12 @@ New_Connection( int Sock )
/* Socket initialisieren */
if (!Init_Socket( new_sock ))
return -1;
/* Check IP-based connection limit */
cnt = Count_Connections( new_addr );
if(( Conf_MaxConnectionsIP > 0 ) && ( cnt >= Conf_MaxConnectionsIP ))
{
cnt = Count_Connections(&new_addr);
if ((Conf_MaxConnectionsIP > 0) && (cnt >= Conf_MaxConnectionsIP)) {
/* Access denied, too many connections from this IP address! */
Log( LOG_ERR, "Refused connection from %s: too may connections (%ld) from this IP address!", inet_ntoa( new_addr.sin_addr ), cnt);
Log( LOG_ERR, "Refused connection from %s: too may connections (%ld) from this IP address!", ip_str, cnt);
Simple_Message( new_sock, "ERROR :Connection refused, too many connections from your IP address!" );
close( new_sock );
return -1;
@ -1029,7 +1081,7 @@ New_Connection( int Sock )
return -1;
}
c = Client_NewLocal( new_sock, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWN, false );
c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false );
if( ! c ) {
Log(LOG_ALERT, "Can't accept connection: can't create client structure!");
Simple_Message(new_sock, "ERROR :Internal error");
@ -1043,13 +1095,12 @@ New_Connection( int Sock )
My_Connections[new_sock].client = c;
Log( LOG_INFO, "Accepted connection %d from %s:%d on socket %d.", new_sock,
inet_ntoa( new_addr.sin_addr ), ntohs( new_addr.sin_port), Sock );
ip_str, ng_ipaddr_getport(&new_addr), Sock);
/* Hostnamen ermitteln */
strlcpy( My_Connections[new_sock].host, inet_ntoa( new_addr.sin_addr ),
sizeof( My_Connections[new_sock].host ));
strlcpy(My_Connections[new_sock].host, ip_str, sizeof(My_Connections[new_sock].host));
Client_SetHostname( c, My_Connections[new_sock].host );
Client_SetHostname(c, My_Connections[new_sock].host);
if (!Conf_NoDNS)
Resolve_Addr(&My_Connections[new_sock].res_stat, &new_addr,
@ -1107,10 +1158,10 @@ Read_Request( CONN_ID Idx )
len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf));
if (len == 0) {
Log(LOG_INFO, "%s:%d (%s) is closing the connection ...",
My_Connections[Idx].host,
ntohs(My_Connections[Idx].addr.sin_port),
inet_ntoa( My_Connections[Idx].addr.sin_addr));
Log(LOG_INFO, "%s:%u (%s) is closing the connection ...",
My_Connections[Idx].host,
(unsigned int) ng_ipaddr_getport(&My_Connections[Idx].addr),
ng_ipaddr_tostr(&My_Connections[Idx].addr));
Conn_Close(Idx,
"Socket closed!", "Client closed connection",
false);
@ -1367,37 +1418,44 @@ Check_Servers( void )
static void
New_Server( int Server , struct in_addr *dest)
New_Server( int Server , ng_ipaddr_t *dest)
{
/* Establish new server link */
struct sockaddr_in local_addr;
struct sockaddr_in new_addr;
int res, new_sock;
char ip_str[NG_INET_ADDRSTRLEN];
int af_dest, res, new_sock;
CLIENT *c;
assert( Server > NONE );
memset(&new_addr, 0, sizeof( new_addr ));
new_addr.sin_family = AF_INET;
new_addr.sin_addr = *dest;
new_addr.sin_port = htons( Conf_Server[Server].port );
if (!ng_ipaddr_tostr_r(dest, ip_str)) {
Log(LOG_WARNING, "New_Server: Could not convert IP to string");
return;
}
new_sock = socket( PF_INET, SOCK_STREAM, 0 );
if ( new_sock < 0 ) {
Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d ... ",
Conf_Server[Server].host, ip_str, Conf_Server[Server].port );
af_dest = ng_ipaddr_af(dest);
new_sock = socket(af_dest, SOCK_STREAM, 0);
if (new_sock < 0) {
Log( LOG_CRIT, "Can't create socket: %s!", strerror( errno ));
return;
}
if( ! Init_Socket( new_sock )) return;
if (!Init_Socket(new_sock))
return;
/* if we fail to bind, just continue and let connect() pick a source address */
InitSinaddr(&local_addr, 0);
local_addr.sin_addr = Conf_Server[Server].bind_addr;
if (bind(new_sock, (struct sockaddr *)&local_addr, (socklen_t)sizeof(local_addr)))
Log(LOG_WARNING, "Can't bind socket to %s: %s!", inet_ntoa(Conf_Server[Server].bind_addr), strerror( errno ));
res = connect(new_sock, (struct sockaddr *)&new_addr,
(socklen_t)sizeof(new_addr));
/* is a bind address configured? */
res = ng_ipaddr_af(&Conf_Server[Server].bind_addr);
/* if yes, bind now. If it fails, warn and let connect() pick a source address */
if (res && bind(new_sock, (struct sockaddr *) &Conf_Server[Server].bind_addr,
ng_ipaddr_salen(&Conf_Server[Server].bind_addr)))
{
ng_ipaddr_tostr_r(&Conf_Server[Server].bind_addr, ip_str);
Log(LOG_WARNING, "Can't bind socket to %s: %s!", ip_str, strerror(errno));
}
ng_ipaddr_setport(dest, Conf_Server[Server].port);
res = connect(new_sock, (struct sockaddr *) dest, ng_ipaddr_salen(dest));
if(( res != 0 ) && ( errno != EINPROGRESS )) {
Log( LOG_CRIT, "Can't connect socket: %s!", strerror( errno ));
close( new_sock );
@ -1418,8 +1476,9 @@ New_Server( int Server , struct in_addr *dest)
Init_Conn_Struct(new_sock);
c = Client_NewLocal( new_sock, inet_ntoa( new_addr.sin_addr ), CLIENT_UNKNOWNSERVER, false );
if( ! c ) {
ng_ipaddr_tostr_r(dest, ip_str);
c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWNSERVER, false);
if (!c) {
Log( LOG_ALERT, "Can't establish connection: can't create client structure!" );
close( new_sock );
return;
@ -1431,7 +1490,7 @@ New_Server( int Server , struct in_addr *dest)
/* Register connection */
Conf_Server[Server].conn_id = new_sock;
My_Connections[new_sock].sock = new_sock;
My_Connections[new_sock].addr = new_addr;
My_Connections[new_sock].addr = *dest;
My_Connections[new_sock].client = c;
strlcpy( My_Connections[new_sock].host, Conf_Server[Server].host,
sizeof(My_Connections[new_sock].host ));
@ -1510,8 +1569,9 @@ cb_Connect_to_Server(int fd, UNUSED short events)
/* Read result of resolver sub-process from pipe and start connection */
int i;
size_t len;
struct in_addr dest_addr;
char readbuf[HOST_LEN + 1];
ng_ipaddr_t dest_addrs[4]; /* we can handle at most 3; but we read up to
four so we can log the 'more than we can handle'
condition */
LogDebug("Resolver: Got forward lookup callback on fd %d, events %d", fd, events);
@ -1528,23 +1588,28 @@ cb_Connect_to_Server(int fd, UNUSED short events)
}
/* Read result from pipe */
len = Resolve_Read(&Conf_Server[i].res_stat, readbuf, sizeof(readbuf)-1);
len = Resolve_Read(&Conf_Server[i].res_stat, dest_addrs, sizeof(dest_addrs));
if (len == 0)
return;
readbuf[len] = '\0';
LogDebug("Got result from resolver: \"%s\" (%u bytes read).", readbuf, len);
assert((len % sizeof(ng_ipaddr_t)) == 0);
if (!ngt_IPStrToBin(readbuf, &dest_addr)) {
Log(LOG_ERR, "Can't connect to \"%s\": can't convert ip address %s!",
Conf_Server[i].host, readbuf);
return;
LogDebug("Got result from resolver: %u structs (%u bytes).", len/sizeof(ng_ipaddr_t), len);
memset(&Conf_Server[i].dst_addr, 0, sizeof(&Conf_Server[i].dst_addr));
if (len > sizeof(ng_ipaddr_t)) {
/* more than one address for this hostname, remember them
* in case first address is unreachable/not available */
len -= sizeof(ng_ipaddr_t);
if (len > sizeof(&Conf_Server[i].dst_addr)) {
len = sizeof(&Conf_Server[i].dst_addr);
Log(LOG_NOTICE, "Notice: Resolver returned more IP Addresses for host than we can handle,"
" additional addresses dropped");
}
memcpy(&Conf_Server[i].dst_addr, &dest_addrs[1], len);
}
Log( LOG_INFO, "Establishing connection to \"%s\", %s, port %d ... ",
Conf_Server[i].host, readbuf, Conf_Server[i].port );
/* connect() */
New_Server(i, &dest_addr);
New_Server(i, dest_addrs);
} /* cb_Read_Forward_Lookup */
@ -1643,19 +1708,6 @@ Simple_Message( int Sock, const char *Msg )
} /* Simple_Error */
static int
Count_Connections( struct sockaddr_in addr_in )
{
int i, cnt;
cnt = 0;
for( i = 0; i < Pool_Size; i++ ) {
if(( My_Connections[i].sock > NONE ) && ( My_Connections[i].addr.sin_addr.s_addr == addr_in.sin_addr.s_addr )) cnt++;
}
return cnt;
} /* Count_Connections */
GLOBAL CLIENT *
Conn_GetClient( CONN_ID Idx )
{

View File

@ -8,7 +8,7 @@
* (at your option) any later version.
* Please read the file COPYING, README and AUTHORS for more information.
*
* $Id: conn.h,v 1.45 2007/10/04 15:03:56 alex Exp $
* $Id: conn.h,v 1.46 2008/02/26 22:04:17 fw Exp $
*
* Connection management (header)
*/
@ -38,6 +38,8 @@ typedef int CONN_ID;
#include "defines.h"
#include "resolve.h"
#include "array.h"
#include "tool.h"
#include "ng_ipaddr.h"
#ifdef ZLIB
#include <zlib.h>
@ -54,7 +56,7 @@ typedef struct _ZipData
typedef struct _Connection
{
int sock; /* Socket handle */
struct sockaddr_in addr; /* Client address */
ng_ipaddr_t addr; /* Client address */
RES_STAT res_stat; /* Status of resolver process */
char host[HOST_LEN]; /* Hostname */
array rbuf; /* Read buffer */

View File

@ -12,7 +12,7 @@
#include "portab.h"
static char UNUSED id[] = "$Id: ngircd.c,v 1.117 2007/11/21 12:16:36 alex Exp $";
static char UNUSED id[] = "$Id: ngircd.c,v 1.118 2008/02/26 22:04:17 fw Exp $";
/**
* @file
@ -397,7 +397,12 @@ Fill_Version( void )
strlcat( NGIRCd_VersionAddition, "IRCPLUS", sizeof NGIRCd_VersionAddition );
#endif
#ifdef WANT_IPV6
if (NGIRCd_VersionAddition[0])
strlcat(NGIRCd_VersionAddition, "+", sizeof(NGIRCd_VersionAddition));
strlcat(NGIRCd_VersionAddition, "IPv6", sizeof(NGIRCd_VersionAddition));
#endif
if( NGIRCd_VersionAddition[0] )
strlcat( NGIRCd_VersionAddition, "-", sizeof( NGIRCd_VersionAddition ));

View File

@ -14,7 +14,7 @@
#include "portab.h"
static char UNUSED id[] = "$Id: resolve.c,v 1.28 2008/01/02 11:03:29 fw Exp $";
static char UNUSED id[] = "$Id: resolve.c,v 1.29 2008/02/26 22:04:17 fw Exp $";
#include "imp.h"
#include <assert.h>
@ -35,20 +35,16 @@ static char UNUSED id[] = "$Id: resolve.c,v 1.28 2008/01/02 11:03:29 fw Exp $";
#include "conn.h"
#include "defines.h"
#include "log.h"
#include "tool.h"
#include "exp.h"
#include "resolve.h"
#include "io.h"
static void Do_ResolveAddr PARAMS(( struct sockaddr_in *Addr, int Sock, int w_fd ));
static void Do_ResolveAddr PARAMS(( const ng_ipaddr_t *Addr, int Sock, int w_fd ));
static void Do_ResolveName PARAMS(( const char *Host, int w_fd ));
static bool register_callback PARAMS((RES_STAT *s, void (*cbfunc)(int, short)));
#ifdef h_errno
static char *Get_Error PARAMS(( int H_Error ));
#endif
static pid_t
Resolver_fork(int *pipefds)
@ -82,7 +78,7 @@ Resolver_fork(int *pipefds)
* Resolve IP (asynchronous!).
*/
GLOBAL bool
Resolve_Addr(RES_STAT * s, struct sockaddr_in *Addr, int identsock,
Resolve_Addr(RES_STAT * s, const ng_ipaddr_t *Addr, int identsock,
void (*cbfunc) (int, short))
{
int pipefd[2];
@ -92,9 +88,8 @@ Resolve_Addr(RES_STAT * s, struct sockaddr_in *Addr, int identsock,
pid = Resolver_fork(pipefd);
if (pid > 0) {
#ifdef DEBUG
Log( LOG_DEBUG, "Resolver for %s created (PID %d).", inet_ntoa( Addr->sin_addr ), pid );
#endif
Log(LOG_DEBUG, "Resolver for %s created (PID %d).", ng_ipaddr_tostr(Addr), pid);
s->pid = pid;
s->resolver_fd = pipefd[0];
return register_callback(s, cbfunc);
@ -147,92 +142,294 @@ Resolve_Init(RES_STAT *s)
}
#ifndef WANT_IPV6
#ifdef h_errno
static char *
Get_Error( int H_Error )
{
/* Get error message for H_Error */
switch( H_Error ) {
case HOST_NOT_FOUND:
return "host not found";
case NO_DATA:
return "name valid but no IP address defined";
case NO_RECOVERY:
return "name server error";
case TRY_AGAIN:
return "name server temporary not available";
}
return "unknown error";
}
#endif /* h_errno */
#endif /* WANT_IPV6 */
/* Do "IDENT" (aka "AUTH") lookup and append result to resolved_addr array */
static void
Do_ResolveAddr( struct sockaddr_in *Addr, int identsock, int w_fd )
Do_IdentQuery(int identsock, array *resolved_addr)
{
#ifdef IDENTAUTH
char *res;
assert(identsock >= 0);
#ifdef DEBUG
Log_Resolver(LOG_DEBUG, "Doing IDENT lookup on socket %d ...", identsock);
#endif
if (identsock < 0)
return;
res = ident_id( identsock, 10 );
#ifdef DEBUG
Log_Resolver(LOG_DEBUG, "Ok, IDENT lookup on socket %d done: \"%s\"",
identsock, res ? res : "(NULL)" );
#endif
if (!res) /* no result */
return;
if (!array_cats(resolved_addr, res))
Log_Resolver(LOG_WARNING, "Resolver: Cannot copy IDENT result: %s!", strerror(errno));
free(res);
#else
(void) identsock;
(void) resolved_addr;
#endif
}
/**
* perform reverse DNS lookup and put result string into resbuf.
* If no hostname could be obtained, this function stores the string representation of
* the IP address in resbuf and returns false.
* @param IpAddr ip address to resolve
* @param resbuf result buffer to store DNS name/string representation of ip address
* @reslen size of result buffer (must be >= NGT_INET_ADDRSTRLEN)
* @return true if reverse lookup successful, false otherwise
*/
static bool
ReverseLookup(const ng_ipaddr_t *IpAddr, char *resbuf, size_t reslen)
{
char tmp_ip_str[NG_INET_ADDRSTRLEN];
const char *errmsg;
#ifdef HAVE_GETNAMEINFO
static const char funcname[]="getnameinfo";
int res;
*resbuf = 0;
res = getnameinfo((struct sockaddr *) IpAddr, ng_ipaddr_salen(IpAddr),
resbuf, reslen, NULL, 0, NI_NAMEREQD);
if (res == 0)
return true;
if (res == EAI_SYSTEM)
errmsg = strerror(errno);
else
errmsg = gai_strerror(res);
#else
const struct sockaddr_in *Addr = (const struct sockaddr_in *) IpAddr;
struct hostent *h;
static const char funcname[]="gethostbyaddr";
h = gethostbyaddr((char *)&Addr->sin_addr, sizeof(Addr->sin_addr), AF_INET);
if (h) {
if (strlcpy(resbuf, h->h_name, reslen) < reslen)
return true;
errmsg = "hostname too long";
} else {
# ifdef h_errno
errmsg = Get_Error(h_errno);
# else
errmsg = "unknown error";
# endif /* h_errno */
}
#endif /* HAVE_GETNAMEINFO */
assert(errmsg);
assert(reslen >= NG_INET_ADDRSTRLEN);
ng_ipaddr_tostr_r(IpAddr, tmp_ip_str);
Log_Resolver(LOG_WARNING, "%s: Can't resolve address \"%s\": %s",
funcname, tmp_ip_str, errmsg);
strlcpy(resbuf, tmp_ip_str, reslen);
return false;
}
/**
* perform DNS lookup of given host name and fill IpAddr with a list of
* ip addresses associated with that name.
* ip addresses found are stored in the "array *IpAddr" argument (type ng_ipaddr_t)
* @param hostname The domain name to look up.
* @param IpAddr pointer to empty and initialized array to store results
* @return true if lookup successful, false if domain name not found
*/
static bool
ForwardLookup(const char *hostname, array *IpAddr)
{
ng_ipaddr_t addr;
#ifdef HAVE_GETADDRINFO
int res;
struct addrinfo *a, *ai_results;
static const struct addrinfo hints = {
#ifndef WANT_IPV6
.ai_family = AF_INET,
#endif
#ifdef AI_ADDRCONFIG /* glibc has this, but not e.g. netbsd 4.0 */
.ai_flags = AI_ADDRCONFIG,
#endif
.ai_socktype = SOCK_STREAM,
.ai_protocol = IPPROTO_TCP
};
res = getaddrinfo(hostname, NULL, &hints, &ai_results);
switch (res) {
case 0: break;
case EAI_SYSTEM:
Log_Resolver(LOG_WARNING, "Can't resolve \"%s\": %s", hostname, strerror(errno));
return false;
default:
Log_Resolver(LOG_WARNING, "Can't resolve \"%s\": %s", hostname, gai_strerror(res));
return false;
}
for (a = ai_results; a != NULL; a = a->ai_next) {
assert(a->ai_addrlen <= sizeof(addr));
if (a->ai_addrlen > sizeof(addr))
continue;
memcpy(&addr, a->ai_addr, a->ai_addrlen);
if (!array_catb(IpAddr, (char *)&addr, sizeof(addr)))
break;
}
freeaddrinfo(ai_results);
return a == NULL;
#else
struct hostent *h = gethostbyname(hostname);
if (!h) {
#ifdef h_errno
Log_Resolver(LOG_WARNING, "Can't resolve \"%s\": %s", hostname, Get_Error(h_errno));
#else
Log_Resolver(LOG_WARNING, "Can't resolve \"%s\"", hostname);
#endif
return false;
}
memset(&addr, 0, sizeof(addr));
addr.sin4.sin_family = AF_INET;
memcpy(&addr.sin4.sin_addr, h->h_addr, sizeof(struct in_addr));