/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "networklib.h" int string2int(const char * str) { /* ----------------------------------------------------------------------------- * Convert a string to int * * @param const char *, the given string * @return int -1 if the given string do not represent an integer * -------------------------------------------------------------------------- */ const char *pts = str; int result_int = 0; while(*pts != '\0') { if ((*pts >= 48) && (*pts <= 57)) result_int = result_int*10 + (*pts - 48); else return -1; pts++; } return result_int; } int read_buffer(int fd, void * buffer, int count) { /* ----------------------------------------------------------------------------- * Read to buffer * * @param int, the file descriptor to read on * @param void *, the buffer where to store * @param int, the max number of character to read * @return int the number of character read or -1 if an error occurss * -------------------------------------------------------------------------- */ int status = 0, n; while(status < count) { n = read(fd, (void *)&((char *)buffer)[status], count - status); if (n < 1) { /* end-of-file (0) or an error occurs (-1) */ if (status == 0) return n; else return status; } status += n; } return status; } int write_buffer(int fd, const void * buffer, int count) { /* ----------------------------------------------------------------------------- * Write buffer to a file descriptor * * @param int, the file descriptor to write on * @param void *, the buffer that must be written to file descriptor * @param int, the max number of character to read * @return int the number of character written or -1 if an error occurs * -------------------------------------------------------------------------- */ int status = 0, n; while(status < count) { n = write(fd, (const void *)&((char *)buffer)[status], count - status); if (n < 1) { /* an error occurs (-1) */ if (status == 0) return n; else return status; } status += n; } return status; } int xsend(int socket, int flags, const char * str, ...) { /* ----------------------------------------------------------------------------- * Write buffer to a socket * * @param int, the socket file descriptor to write on * @param int, flags that are passed to send() function * @param const char *, printf format * @param ... * @return int the number of character written or -1 if an error occurs * -------------------------------------------------------------------------- */ va_list args; char *result = NULL; int retour; va_start(args, str); vasprintf(&result, str, args); va_end(args); if (result != NULL) { retour = send(socket, result, strlen(result), flags); free(result); switch(errno) { case EBADF: case ENOTSOCK: case EFAULT: case EMSGSIZE: case EAGAIN: case ENOBUFS: case EINTR: case ENOMEM: case EINVAL: case EPIPE: return -1; break; default: return retour; break; } } return -1; } int readline(int fd, char * buffer, int maxlen) { /* ----------------------------------------------------------------------------- * Read line to buffer * * @param int, the file descriptor to read on * @param char *, the buffer where to store * @param int, the max number of character to read * @return int the number of character read * -------------------------------------------------------------------------- */ int count = 0, status; while(count < maxlen) { /* Read one character */ if ((status = read_buffer(fd, (void *)&((char *)buffer)[count], 1)) <= 0) { /* Nothing to read */ return count; } else { if (buffer[count] == '\n'){ buffer[count + 1] = '\0'; return count + 1; } } count += status; } buffer[count] = 0; return 0; } int copy(int fd_in, int fd_out, unsigned long maxlen) { /* ----------------------------------------------------------------------------- * Copy data to one file descriptor to another * * @param int, the file descriptor to read on * @param int, the file descriptor to write on * @param int, the max number of character to read * @return int * -------------------------------------------------------------------------- */ char buffer[BUF_SIZE]; int data_in; unsigned long remaining; remaining = maxlen; while ((remaining != 0) || (maxlen == 0)) { if ((remaining == 0) || (BUF_SIZE < remaining)) { data_in = read(fd_in, buffer, BUF_SIZE); } else { data_in = read(fd_in, buffer, remaining); } if (data_in < 1) return data_in; write_buffer(fd_out, buffer, data_in); if (maxlen != 0) remaining -= data_in; } return 1; } char * getfqdn(const char * host) { /* ----------------------------------------------------------------------------- * Get full hostname by IP address or a name * * @param const char *, the IP address in human readable format or a host * @return char * * -------------------------------------------------------------------------- */ struct hostent *host_info; u_long ip_addr; static char fqdn[200]; if (isipv4(host)) { ip_addr = inet_addr(host); host_info = gethostbyaddr((char *)&ip_addr, sizeof(struct in_addr), AF_INET); } else { host_info = gethostbyname(host); } if (!host_info) { logmsg(LOG_ERR, "%s (%d)", strerror(errno), errno); return (char *)NULL; } if (host_info->h_aliases[0]) { strncpy(fqdn, host_info->h_aliases[0], sizeof(fqdn)); } else { strncpy(fqdn, host_info->h_name, sizeof(fqdn)); } return fqdn; } char * getmyfqdn() { /* ----------------------------------------------------------------------------- * Get full hostname of the current machine * * @return char * * -------------------------------------------------------------------------- */ char hostname[200]; gethostname(hostname, sizeof(hostname)); return getfqdn(hostname); } char *get_host(const char *host) { /* ----------------------------------------------------------------------------- * Get full hostname by IP address or a name * * @param const char *, the IP address in human readable format or a host * @return char *, * if they are alternate names for the given parameters * they will be returned with a \n separator * -------------------------------------------------------------------------- */ struct hostent *host_info; static char hosts[300]; u_long ip_addr; char **aliases; if (isipv4(host)) { ip_addr = inet_addr(host); host_info = gethostbyaddr((char *)&ip_addr, sizeof(struct in_addr), AF_INET); } else { host_info = gethostbyname(host); } if (!host_info) { logmsg(LOG_ERR, "%s (%d)", hstrerror(h_errno), h_errno); return (char *)NULL; } snprintf(hosts, sizeof(hosts), "%s", host_info->h_name); for (aliases = host_info->h_aliases; *aliases != 0; aliases++) { strlcat(hosts, "\n", sizeof(hosts)); strlcat(hosts, *aliases, sizeof(hosts)); } return hosts; } char *get_ip(const char *host) { /* ----------------------------------------------------------------------------- * Get IP addressby host * * @param const char *, the hostname * @return char * * if they are alternate IP addresses for the given parameters * they will be returned with a \n separator * -------------------------------------------------------------------------- */ struct hostent *host_info; static char ip[300]; u_long ip_addr; struct in_addr in; char **ip_list; if (isipv4(host)) { ip_addr = inet_addr(host); host_info = gethostbyaddr((char *)&ip_addr, sizeof(struct in_addr), AF_INET); } else { host_info = gethostbyname(host); } if (!host_info) { logmsg(LOG_ERR, "%s (%d)", hstrerror(h_errno), h_errno); return (char *)NULL; } *ip = '\0'; for (ip_list = host_info->h_addr_list; *ip_list != 0; ip_list++) { memcpy(&in.s_addr, *ip_list, sizeof (in.s_addr)); strlcat(ip, "\n", sizeof(ip)); strlcat(ip, inet_ntoa(in), sizeof(ip)); } return ip+1; } int isipv4(const char *ip) { /* ----------------------------------------------------------------------------- * Check if the given IP is a valid IPV4 address in human readable format * e.g : 127.0.0.1 * * @param const char *, the IP to check * @return int * -------------------------------------------------------------------------- */ const int dots = 3; const char *pts = ip; int number = 0, count_dots = 0; while(*pts != '\0') { if ((*pts >= 48) && (*pts <= 57)) { number = number*10 + (*pts - 48); } else if (*pts == '.') { if ((number >= 0) && (number <= 255)) { number = 0; count_dots++; } else { return 0; } } else { return 0; } pts++; } if ((count_dots == dots) && (number >= 0) && (number <= 255)) return 1; else return 0; } unsigned int sockaddr_localinfo(int sockid, struct sockaddr_in * socketaddr) { /* ----------------------------------------------------------------------------- * Get local peer info from a socket file descriptor * * @param int, the socket file descriptor * @param struct sockaddr_in *, the struct info to fill * @return int * -------------------------------------------------------------------------- */ socklen_t size; size = sizeof(struct sockaddr_in); if (getsockname(sockid, (struct sockaddr *)socketaddr, &size) != 0) { logmsg(LOG_ERR, "%s (%d)", strerror(errno), errno); return 0; } return 1; } short getlocalport(int sockid) { /* ----------------------------------------------------------------------------- * Get local port info from a socket file descriptor * * @param int, the socket file descriptor * @return short, the local port or -1 * -------------------------------------------------------------------------- */ struct sockaddr_in socketaddr; if (sockaddr_localinfo(sockid, &socketaddr)) { return ntohs(socketaddr.sin_port); } return -1; } char * getlocaladdr(int sockid) { /* ----------------------------------------------------------------------------- * Get local IP address info from a socket file descriptor * * @param int, the socket file descriptor * @return char * * -------------------------------------------------------------------------- */ struct sockaddr_in socketaddr; if (sockaddr_localinfo(sockid, &socketaddr)) { return inet_ntoa(socketaddr.sin_addr); } return NULL; } unsigned int sockaddr_peerinfo(int sockid, struct sockaddr_in * socketaddr) { /* ----------------------------------------------------------------------------- * Get Remote peer info from a socket file descriptor * * @param int, the socket file descriptor * @param struct sockaddr_in *, the struct info to fill * @return int * -------------------------------------------------------------------------- */ socklen_t size; size = sizeof(struct sockaddr_in); if (getpeername(sockid, (struct sockaddr *)socketaddr, &size) != 0) { logmsg(LOG_ERR, "%s (%d)", strerror(errno), errno); return 0; } return 1; } short getforeignport(int sockid) { /* ----------------------------------------------------------------------------- * Get remote port info from a socket file descriptor * * @param int, the socket file descriptor * @return short, the local port or -1 * -------------------------------------------------------------------------- */ struct sockaddr_in socketaddr; if (sockaddr_peerinfo(sockid, &socketaddr)) { return ntohs(socketaddr.sin_port); } return -1; } char *getforeignaddr(int sockid) { /* ----------------------------------------------------------------------------- * Get remote IP address info from a socket file descriptor * * @param int, the socket file descriptor * @return char * * -------------------------------------------------------------------------- */ struct sockaddr_in socketaddr; if (sockaddr_peerinfo(sockid, &socketaddr)) { return inet_ntoa(socketaddr.sin_addr); } return NULL; } void socketaddr_init(struct sockaddr_in * socketaddr) { /* ----------------------------------------------------------------------------- * Init a sockaddr_in struct * * @param struct sockaddr_in * -------------------------------------------------------------------------- */ memset(socketaddr, 0, sizeof(struct sockaddr_in)); socketaddr->sin_family = AF_INET; } int socketaddr_service(struct sockaddr_in * socketaddr, const char * service, const char * proto) { /* ----------------------------------------------------------------------------- * Init a sockaddr_in struct to the given service and protocol * * @param struct sockaddr_in * @param const char *, name service or port number * @param const char *, name protocol * @return int * -------------------------------------------------------------------------- */ struct servent * service_info; int port; if (strcmp(service, "0") == 0) { socketaddr->sin_port = 0; } else { service_info = getservbyname(service, proto); if (service_info) { socketaddr->sin_port = service_info->s_port; } else { /* service is a port number */ port = string2int(service); if (port != -1) { socketaddr->sin_port = htons((u_short)port); } else { logmsg(LOG_ERR, "%s (%d)", strerror(errno), errno); return 0; } } } return 1; } int socketaddr_host(struct sockaddr_in * socketaddr, const char * host) { /* ----------------------------------------------------------------------------- * Init a sockaddr_in struct to the given host * * @param struct sockaddr_in * @param const char *, hostname or IP address * @return int * -------------------------------------------------------------------------- */ struct hostent * host_info; host_info = gethostbyname(host); if (!host_info) { logmsg(LOG_ERR, "%s (%d)\n", strerror(errno), errno); return 0; } memcpy(&socketaddr->sin_addr, host_info->h_addr, host_info->h_length); return 1; } int resolveproto(const char * proto) { /* ----------------------------------------------------------------------------- * Resolve protocol by name * * @param const char *, name protocol like "tcp", "udp" * @return int or -1 * -------------------------------------------------------------------------- */ struct protoent * proto_info; proto_info = getprotobyname(proto); if (!proto_info) { logmsg(LOG_ERR, "%s (%d)\n", strerror(errno), errno); return -1; } return proto_info->p_proto; } int prototype(const char * proto) { /* ----------------------------------------------------------------------------- * Resolve IPV4 protocol by name * * @param const char *, name protocol like "tcp", "udp" * @return int or -1 * -------------------------------------------------------------------------- */ if (strcmp(proto, "tcp") == 0) return SOCK_STREAM; if (strcmp(proto, "udp") == 0) return SOCK_DGRAM; logmsg(LOG_ERR, "Unknown protocol %s", proto); return -1; } #ifdef USE_UNIX_SOCKET int create_unix_socket (const char *filename) { /* ----------------------------------------------------------------------------- * Create an Unix socket * * @param const char *, socket file name * @return int, the server socket file descriptor or -1 * -------------------------------------------------------------------------- */ struct sockaddr_un socketaddr; int sockid; int trueval = TRUE; size_t size; sockid = socket (PF_UNIX, SOCK_STREAM, 0); if (sockid < 0) { logmsg(LOG_ERR, "%s (%d) : Create Unix Socket error", strerror(errno), errno); return -1; } socketaddr.sun_family = AF_UNIX; strlcpy(socketaddr.sun_path, filename, sizeof(socketaddr.sun_path)); #if defined __Linux__ size = offsetof(struct sockaddr_un, sun_path) + strlen (socketaddr.sun_path) + 1; #endif #if defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ socketaddr.sun_len = sizeof(socketaddr.sun_len) + sizeof(socketaddr.sun_family) + strlen (socketaddr.sun_path) + 1; size = socketaddr.sun_len; #endif setsockopt(sockid, SOL_SOCKET, SO_REUSEADDR, &trueval, sizeof(trueval)); if (!access(socketaddr.sun_path, F_OK)) unlink(socketaddr.sun_path); if (bind (sockid, (struct sockaddr *) &socketaddr, size) < 0) { logmsg(LOG_ERR, "%s (%d) : Bind Unix Socket error", strerror(errno), errno); return -1; } if (listen(sockid, 5) < 0) { logmsg(LOG_ERR, "%s (%d) : Listen Unix Socket error", strerror(errno), errno); return -1; } return sockid; } #endif int open_unix_fd(const char *filename) { /* ----------------------------------------------------------------------------- * Connect to an Unix socket * * @param const char *, the socket file name * @return int, the client socket file descriptor * -------------------------------------------------------------------------- */ struct sockaddr_un socketaddr; int sockid; socketaddr.sun_family = AF_UNIX; strlcpy(socketaddr.sun_path, filename, sizeof(socketaddr.sun_path)); sockid = socket(PF_UNIX, SOCK_STREAM, 0); if (sockid == -1) return -1; if (connect(sockid, (struct sockaddr *)&socketaddr, sizeof(socketaddr)) < 0) { logmsg(LOG_ERR, "%s (%d)\n", strerror(errno), errno); return -1; } return sockid; } int client_connect(const char * host, const char * port, const char * proto) { /* ----------------------------------------------------------------------------- * Connect to a hostname, with the given port and protocol * * @param const char *, hostname * @param const char *, port number or name service * @param const char *, name protocol * @return int, the client socket descriptor or -1 * -------------------------------------------------------------------------- */ struct sockaddr_in socketaddr; int sockid; socketaddr_init(&socketaddr); socketaddr_service(&socketaddr, port, proto); socketaddr_host(&socketaddr, host); sockid = socket(PF_INET, prototype(proto), resolveproto(proto)); if (sockid < 0) { logmsg(LOG_ERR, "%s (%d) : Create Socket error", strerror(errno), errno); return -1; } if (connect(sockid, (struct sockaddr *)&socketaddr, sizeof(socketaddr)) < 0) { logmsg(LOG_ERR, "%s (%d) : Connect Socket error", strerror(errno), errno); return -1; } return sockid; } int server_init(const char * port, const char * proto) { /* ----------------------------------------------------------------------------- * Init a server with the given port and protocol * * @param const char *, port number or name service * @param const char *, name protocol * @return int, the server socket descriptor or -1 * -------------------------------------------------------------------------- */ struct sockaddr_in socketaddr; int mastersock; int trueval = TRUE; socketaddr_init(&socketaddr); socketaddr.sin_addr.s_addr = INADDR_ANY; if (port != NULL) socketaddr_service(&socketaddr, port, proto); mastersock = socket(PF_INET, prototype(proto), resolveproto(proto)); if (mastersock < 0) { logmsg(LOG_ERR, "%s (%d) : Create Server Socket error", strerror(errno), errno); return -1; } setsockopt(mastersock, SOL_SOCKET, SO_REUSEADDR, &trueval, sizeof(trueval)); if (bind(mastersock, (struct sockaddr *) &socketaddr, sizeof(socketaddr)) < 0) { logmsg(LOG_ERR, "%s (%d) : Bind Socket error", strerror(errno), errno); return -1; } if (prototype(proto) == SOCK_STREAM) { if (listen(mastersock, 5) < 0) { logmsg(LOG_ERR, "%s (%d) : Listen Socket error", strerror(errno), errno); return -1; } } return mastersock; }