From: Pekka Riikonen Date: Wed, 28 Nov 2001 21:51:59 +0000 (+0000) Subject: updates. X-Git-Tag: silc.toolkit.0.7~13 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=e4b63806b89601e4e787c239b39b1bee33e46f7e updates. --- diff --git a/CHANGES b/CHANGES index e88cd101..84a339e2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +Wed Nov 28 23:46:09 EET 2001 Pekka Riikonen ' + + * Added silc_net_gethostby[addr/name] into the + lib/silcutil/silcnet.[ch]. Added IPv6 support to Unix network + routines. Added silc_net_is_ip[4/6]. Affected file is + lib/silcutil/unix/silcunixnet.c. All routines that take + address as argument now supports both IPv4 and IPv6 addresses. + Mon Nov 26 18:09:48 EET 2001 Pekka Riikonen ' * Fixed LIST command reply sending in server. Affected file diff --git a/lib/silcutil/silcnet.c b/lib/silcutil/silcnet.c index 0101faae..f7795865 100644 --- a/lib/silcutil/silcnet.c +++ b/lib/silcutil/silcnet.c @@ -44,13 +44,125 @@ int silc_net_get_socket_opt(int sock, int level, int option, return getsockopt(sock, level, option, optval, opt_len); } +/* Checks whether IP address sent as argument is valid IPv4 address. */ + +bool silc_net_is_ip4(const char *addr) +{ + int count = 0; + + while (*addr) { + if (*addr != '.' && !isdigit(*addr)) + return FALSE; + if (*addr == '.') + count++; + addr++; + } + + if (count != 3) + return FALSE; + + return TRUE; +} + +/* Checks whether IP address sent as argument is valid IPv6 address. */ + +bool silc_net_is_ip6(const char *addr) +{ + /* XXX does this work with all kinds of IPv6 addresses? */ + while (*addr) { + if (*addr != ':' && !isxdigit(*addr)) + return FALSE; + addr++; + } + + return TRUE; +} + /* Checks whether IP address sent as argument is valid IP address. */ bool silc_net_is_ip(const char *addr) { - struct in_addr tmp; - int len = sizeof(tmp); - return silc_net_addr2bin(addr, (unsigned char *)&tmp.s_addr, len); + if (silc_net_is_ip4(addr)) + return TRUE; + return silc_net_is_ip6(addr); +} + +/* Resolves IP address for hostname. */ + +bool silc_net_gethostbyname(const char *name, char *address, + uint32 address_len) +{ +#ifdef HAVE_IPV6 + struct addrinfo hints, *ai; + char hbuf[NI_MAXHOST]; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(name, NULL, &hints, &ai)) + return FALSE; + + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, + sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) + return FALSE; + + if (!inet_ntop(ai->ai_family, ai->ai_addr, address, address_len)) + return FALSE; + + freeaddrinfo(ai); +#else + struct hostent *hp; + struct in_addr ip; + char *tmp; + + hp = gethostbyname(name); + if (!hp) + return FALSE; + + memcpy(&ip.s_addr, hp->h_addr_list[0], 4); + tmp = inet_ntoa(ip); + if (!tmp) + return FALSE; + if (address_len < strlen(tmp)) + return FALSE; + memset(address, 0, address_len); + strncpy(address, tmp, strlen(tmp)); +#endif + + return TRUE; +} + +/* Resolves hostname by IP address. */ + +bool silc_net_gethostbyaddr(const char *addr, char *name, uint32 name_len) +{ +#ifdef HAVE_IPV6 + struct addrinfo req, *ai; + + memset(&req, 0, sizeof(req)); + req.ai_socktype = SOCK_STREAM; + req.ai_flags = AI_CANONNAME; + + if (getaddrinfo(addr, NULL, &req, &ai)) + return FALSE; + if (name_len < strlen(ai->ai_canonname)) + return FALSE; + memset(name, 0, name_len); + strncpy(name, ai->ai_canonname, strlen(ai->ai_canonname)); + + freeaddrinfo(ai); +#else + struct hostent *hp; + + hp = gethostbyaddr(addr, strlen(addr), AF_INET); + if (!hp) + return FALSE; + if (name_len < strlen(hp->h_name)) + return FALSE; + memset(name, 0, name_len); + strncpy(name, hp->h_name, strlen(hp->h_name)); +#endif + + return TRUE; } /* Performs lookups for remote name and IP address. This peforms reverse @@ -217,45 +329,29 @@ uint16 silc_net_get_local_port(int sock) char *silc_net_localhost(void) { - char hostname[256]; - struct hostent *dest; - char *h; + char hostname[256], ip_addr[64]; if (gethostname(hostname, sizeof(hostname))) return NULL; - dest = gethostbyname(hostname); - if (!dest) + if (!silc_net_gethostbyname(hostname, ip_addr, sizeof(ip_addr))) return strdup(hostname); - h = strdup(dest->h_name); - dest = gethostbyaddr((char *)dest->h_addr_list[0], - sizeof(struct in_addr), AF_INET); - if (!dest) - return h; - - silc_free(h); - return strdup(dest->h_name); + silc_net_gethostbyaddr(ip_addr, hostname, sizeof(hostname)); + return strdup(hostname); } /* Returns local IP address */ char *silc_net_localip(void) { - char hostname[256]; - struct hostent *dest; - struct in_addr ip; - char *ips; + char hostname[256], ip_addr[64]; if (gethostname(hostname, sizeof(hostname))) return NULL; - dest = gethostbyname(hostname); - if (!dest) + if (!silc_net_gethostbyname(hostname, ip_addr, sizeof(ip_addr))) return NULL; - memcpy(&ip.s_addr, dest->h_addr_list[0], 4); - ips = inet_ntoa(ip); - - return strdup(ips); + return strdup(ip_addr); } diff --git a/lib/silcutil/silcnet.h b/lib/silcutil/silcnet.h index b9978d6e..69f49221 100644 --- a/lib/silcutil/silcnet.h +++ b/lib/silcutil/silcnet.h @@ -177,6 +177,32 @@ int silc_net_set_socket_opt(int sock, int level, int option, int on); int silc_net_get_socket_opt(int sock, int level, int option, void *optval, int *opt_len); +/****f* silcutil/SilcNetAPI/silc_net_is_ip4 + * + * SYNOPSIS + * + * bool silc_net_is_ip4(const char *addr); + * + * DESCRIPTION + * + * Checks whether IP address sent as argument is valid IPv4 address. + * + ***/ +bool silc_net_is_ip4(const char *addr); + +/****f* silcutil/SilcNetAPI/silc_net_is_ip6 + * + * SYNOPSIS + * + * bool silc_net_is_ip6(const char *addr); + * + * DESCRIPTION + * + * Checks whether IP address sent as argument is valid IPv6 address. + * + ***/ +bool silc_net_is_ip6(const char *addr); + /****f* silcutil/SilcNetAPI/silc_net_is_ip * * SYNOPSIS @@ -186,6 +212,7 @@ int silc_net_get_socket_opt(int sock, int level, int option, * DESCRIPTION * * Checks whether IP address sent as argument is valid IP address. + * This supports both IPv4 and IPv6 addresses. * ***/ bool silc_net_is_ip(const char *addr); @@ -194,17 +221,52 @@ bool silc_net_is_ip(const char *addr); * * SYNOPSIS * - * bool silc_net_addr2bin(const char *addr, unsigned char *bin, - * uint32 bin_len); + * bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len); * * DESCRIPTION * * Converts the IP number string from numbers-and-dots notation to - * binary form in network byte order. + * binary form in network byte order. The address can be either + * IPv4 or IPv6 address. * ***/ bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len); +/****f* silcutil/SilcNetAPI/silc_net_gethostbyname + * + * SYNOPSIS + * + * bool silc_net_gethostbyname(const char *name, char *address, + * uint32 address_len); + * + * DESCRIPTION + * + * Resolves the IP address of the hostname indicated by the `host' + * This returns TRUE and the IP address of the host, or FALSE + * if the address could not be resolved. This is synchronous + * function and will block the calling process. + * + ***/ +bool silc_net_gethostbyname(const char *name, char *address, + uint32 address_len); + +/****f* silcutil/SilcNetAPI/silc_net_gethostbyaddr + * + * SYNOPSIS + * + * bool silc_net_gethostbyaddr(const char *addr, char *name, + * uint32 name_len); + * + * DESCRIPTION + * + * Resolves the hostname of the IP address indicated by the `addr' + * This returns TRUE and the resolved hostname, or FALSE on error. + * The `addr' may be either IPv4 or IPv6 address. This is + * synchronous function and will block the calling process. + * + ***/ +bool silc_net_gethostbyaddr(const char *addr, char *name, uint32 name_len); + /****f* silcutil/SilcNetAPI/silc_net_check_host_by_sock * * SYNOPSIS diff --git a/lib/silcutil/unix/silcunixnet.c b/lib/silcutil/unix/silcunixnet.c index 72d47641..d1f6384c 100644 --- a/lib/silcutil/unix/silcunixnet.c +++ b/lib/silcutil/unix/silcunixnet.c @@ -22,6 +22,66 @@ #include "silcincludes.h" #include "silcnet.h" +#ifdef HAVE_IPV6 +#define SIZEOF_SOCKADDR(so) ((so).sa.sa_family == AF_INET6 ? \ + sizeof(so.sin6) : sizeof(so.sin)) +#else +#define SIZEOF_SOCKADDR(so) (sizeof(so.sin)) +#endif + +typedef union { + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef HAVE_IPV6 + struct sockaddr_in6 sin6; +#endif +} SilcSockaddr; + +static bool silc_net_set_sockaddr(SilcSockaddr *addr, const char *ip_addr, + int port) +{ + int len; + + memset(addr, 0, sizeof(*addr)); + + /* Check for IPv4 and IPv6 addresses */ + if (ip_addr) { + if (!silc_net_is_ip(ip_addr)) { + SILC_LOG_ERROR(("%s is not IP address", ip_addr)); + return FALSE; + } + + if (silc_net_is_ip4(ip_addr)) { + /* IPv4 address */ + len = sizeof(addr->sin.sin_addr); + silc_net_addr2bin(ip_addr, + (unsigned char *)&addr->sin.sin_addr.s_addr, len); + addr->sin.sin_family = AF_INET; + addr->sin.sin_port = port ? htons(port) : 0; + } else { +#ifdef HAVE_IPV6 + /* IPv6 address */ + len = sizeof(addr->sin6.sin6_addr); + silc_net_addr2bin(ip_addr, + (unsigned char *)&addr->sin6.sin6_addr, len); + addr->sin6.sin6_family = AF_INET6; + addr->sin6.sin6_port = port ? htons(port) : 0; +#else + SILC_LOG_ERROR(("IPv6 support is not compiled in")); + return FALSE; +#endif + } + } else { + /* Any address */ + addr->sin.sin_family = AF_INET; + addr->sin.sin_addr.s_addr = INADDR_ANY; + if (port) + addr->sin.sin_port = htons(port); + } + + return TRUE; +} + /* This function creates server or daemon or listener or what ever. This does not fork a new process, it must be done by the caller if caller wants to create a child process. This is used by the SILC server. @@ -31,13 +91,16 @@ int silc_net_create_server(int port, const char *ip_addr) { int sock, rval; - struct sockaddr_in server; - int len = sizeof(server.sin_addr); + SilcSockaddr server; SILC_LOG_DEBUG(("Creating a new server listener")); + /* Set sockaddr for server */ + if (!silc_net_set_sockaddr(&server, ip_addr, port)) + return -1; + /* Create the socket */ - sock = socket(AF_INET, SOCK_STREAM, 0); + sock = socket(server.sin.sin_family, SOCK_STREAM, 0); if (sock < 0) { SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno))); return -1; @@ -50,21 +113,8 @@ int silc_net_create_server(int port, const char *ip_addr) return -1; } - /* Set the socket information for bind() */ - memset(&server, 0, sizeof(server)); - server.sin_family = AF_INET; - if (port) - server.sin_port = htons(port); - - /* Convert IP address to network byte order */ - if (ip_addr) { - silc_net_addr2bin(ip_addr, (unsigned char *)&server.sin_addr.s_addr, len); - } - else - server.sin_addr.s_addr = INADDR_ANY; - /* Bind the server socket */ - rval = bind(sock, (struct sockaddr *)&server, sizeof(server)); + rval = bind(sock, &server.sa, SIZEOF_SOCKADDR(server)); if (rval < 0) { SILC_LOG_DEBUG(("Cannot bind socket: %s", strerror(errno))); return -1; @@ -103,27 +153,24 @@ int silc_net_create_connection(const char *local_ip, int port, const char *host) { int sock, rval; - struct hostent *dest; - struct sockaddr_in desthost; + char ip_addr[64]; + SilcSockaddr desthost; SILC_LOG_DEBUG(("Creating connection to host %s port %d", host, port)); /* Do host lookup */ - dest = gethostbyname(host); - if (!dest) { + if (!silc_net_gethostbyname(host, ip_addr, sizeof(ip_addr))) { SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the " "IP address", host)); return -1; } - /* Set socket information */ - memset(&desthost, 0, sizeof(desthost)); - desthost.sin_port = htons(port); - desthost.sin_family = AF_INET; - memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr)); + /* Set sockaddr for this connection */ + if (!silc_net_set_sockaddr(&desthost, ip_addr, port)) + return -1; /* Create the connection socket */ - sock = socket(AF_INET, SOCK_STREAM, 0); + sock = socket(desthost.sin.sin_family, SOCK_STREAM, 0); if (sock < 0) { SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno))); return -1; @@ -131,28 +178,15 @@ int silc_net_create_connection(const char *local_ip, int port, /* Bind to the local address if provided */ if (local_ip) { - struct sockaddr_in local; - int local_len = sizeof(local.sin_addr); - - /* Set the socket information for bind() */ - memset(&local, 0, sizeof(local)); - local.sin_family = AF_INET; - - /* Convert IP address to network byte order */ - silc_net_addr2bin(local_ip, (unsigned char *)&local.sin_addr.s_addr, - local_len); - - /* Bind the local socket */ - rval = bind(sock, (struct sockaddr *)&local, sizeof(local)); - if (rval < 0) { - SILC_LOG_ERROR(("Cannot connect to remote host: " - "cannot bind socket: %s", strerror(errno))); - return -1; - } + SilcSockaddr local; + + /* Set sockaddr for local listener, and try to bind it. */ + if (silc_net_set_sockaddr(&local, local_ip, 0)) + bind(sock, &local.sa, sizeof(local)); } /* Connect to the host */ - rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost)); + rval = connect(sock, &desthost.sa, sizeof(desthost)); if (rval < 0) { SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno))); shutdown(sock, 2); @@ -180,28 +214,25 @@ int silc_net_create_connection_async(const char *local_ip, int port, const char *host) { int sock, rval; - struct hostent *dest; - struct sockaddr_in desthost; + char ip_addr[64]; + SilcSockaddr desthost; SILC_LOG_DEBUG(("Creating connection (async) to host %s port %d", host, port)); /* Do host lookup */ - dest = gethostbyname(host); - if (!dest) { + if (!silc_net_gethostbyname(host, ip_addr, sizeof(ip_addr))) { SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the " "IP address", host)); return -1; } - /* Set socket information */ - memset(&desthost, 0, sizeof(desthost)); - desthost.sin_port = htons(port); - desthost.sin_family = AF_INET; - memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr)); + /* Set sockaddr for this connection */ + if (!silc_net_set_sockaddr(&desthost, ip_addr, port)) + return -1; /* Create the connection socket */ - sock = socket(AF_INET, SOCK_STREAM, 0); + sock = socket(desthost.sin.sin_family, SOCK_STREAM, 0); if (sock < 0) { SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno))); return -1; @@ -209,31 +240,18 @@ int silc_net_create_connection_async(const char *local_ip, int port, /* Bind to the local address if provided */ if (local_ip) { - struct sockaddr_in local; - int local_len = sizeof(local.sin_addr); - - /* Set the socket information for bind() */ - memset(&local, 0, sizeof(local)); - local.sin_family = AF_INET; - - /* Convert IP address to network byte order */ - silc_net_addr2bin(local_ip, (unsigned char *)&local.sin_addr.s_addr, - local_len); - - /* Bind the local socket */ - rval = bind(sock, (struct sockaddr *)&local, sizeof(local)); - if (rval < 0) { - SILC_LOG_ERROR(("Cannot connect to remote host: " - "cannot bind socket: %s", strerror(errno))); - return -1; - } + SilcSockaddr local; + + /* Set sockaddr for local listener, and try to bind it. */ + if (silc_net_set_sockaddr(&local, local_ip, 0)) + bind(sock, &local.sa, sizeof(local)); } /* Set the socket to non-blocking mode */ silc_net_set_socket_nonblock(sock); /* Connect to the host */ - rval = connect(sock, (struct sockaddr *)&desthost, sizeof(desthost)); + rval = connect(sock, &desthost.sa, sizeof(desthost)); if (rval < 0) { if (errno != EINPROGRESS) { SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno))); @@ -273,14 +291,25 @@ int silc_net_set_socket_nonblock(int sock) bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len) { - struct in_addr tmp; - int ret; - - ret = inet_aton(addr, &tmp); - - if (bin_len < 4) - return FALSE; + int ret = 0; + + if (silc_net_is_ip4(addr)) { + /* IPv4 address */ + struct in_addr tmp; + ret = inet_aton(addr, &tmp); + if (bin_len < 4) + return FALSE; + + memcpy(bin, (unsigned char *)&tmp.s_addr, 4); +#ifdef HAVE_IPV6 + } else { + /* IPv6 address */ + if (bin_len < 16) + return FALSE; + + ret = inet_pton(AF_INET6, addr, &bin); +#endif /* HAVE_IPV6 */ + } - memcpy(bin, (unsigned char *)&tmp.s_addr, 4); return ret != 0; } diff --git a/lib/silcutil/win32/silcwin32net.c b/lib/silcutil/win32/silcwin32net.c index fd8228ea..928a40de 100644 --- a/lib/silcutil/win32/silcwin32net.c +++ b/lib/silcutil/win32/silcwin32net.c @@ -19,6 +19,8 @@ */ /* $Id$ */ +/* XXX IPv6 support missing */ + #include "silcincludes.h" #include "silcnet.h" diff --git a/prepare b/prepare index 4d4af282..9d1d8e08 100755 --- a/prepare +++ b/prepare @@ -39,7 +39,6 @@ # SILC_VERSION=0.6.2 # Base version - ############################################################################# echo "Preparing SILC source tree for configuration and compilation..."