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
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);
}
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
* 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);
*
* 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
#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.
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;
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;
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;
/* 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);
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;
/* 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)));
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;
}