/* * ------------------------------------------------------- * Copyright (C) 2002-2007 Tommi Saviranta <wnd@iki.fi> * (C) 2002 Lee Hardy <lee@leeh.co.uk> * (C) 1998-2002 Sebastian Kienzl <zap@riot.org> * ------------------------------------------------------- * 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 General Public License for more details. */ #ifdef HAVE_CONFIG_H#include <config.h>#endif /* ifdef HAVE_CONFIG_H */ #include "irc.h"#include "common.h"#include "conntype.h"#include "llist.h"#include "perm.h" #include <fcntl.h>#include <errno.h>#include <netdb.h>#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h> #if HAVE_STRINGS_H#include <strings.h>#endif /* Guess this needs to go somewhere */typedef unsigned short u_short; /* #define DEBUG */ #ifdef HAVE_HSTRERROR#ifndef HAVE_HSTRERROR_PROTOconst char *hstrerror(int err);#endif /* ifndef HAVE_HSTRERROR_PROTO */#endif /* ifdef HAVE_HSTRERROR */ /* va_copy */#ifndef va_copy#ifdef HAVE___VA_COPY#define va_copy __va_copy#else /* ifdef HAVE___VA_COPY *//* we may need "memcpy(&dest, &src, sizeof(va_list))" on some systems */#define va_copy(dest, src) ((dest) = (src))#endif /* ifdef else HAVE___VA_COPY */#endif /* ifndef va_copy */ #define HEAD 1#define TAIL 2 static void track_highest(void);static void track_add(int s);static void track_del(int s);static int irc_write_smart(connection_type *connection, int queue, char *format, va_list va); struct hostent *hostinfo = NULL;#ifdef IPV6struct sockaddr_in6 addr;#elsestruct sockaddr_in addr;#endif const char *net_errstr; #define TRACK 512int track_socks[TRACK]; int highest_socket = 0; int msgtimer; /* Message timer... */llist_list msg_queue; /* Message queue */ static voidtrack_highest(void){ int i; highest_socket = 0; for (i = 0; i < TRACK; i++) { if (track_socks[i] > highest_socket) { highest_socket = track_socks[i]; } }} /* void track_highest(void) */ static voidtrack_add(int s){ int i = 0; while (track_socks[i] && i < TRACK) { i++; } if (i < TRACK) { track_socks[i] = s; } track_highest();} /* void track_add(int s) */ static voidtrack_del(int s){ int i; for (i = 0; i < TRACK; i++) { if (track_socks[i] == s) { track_socks[i] = 0; } } track_highest();} /* void track_del(int s) */ /* * Creates a socket. * * Returns number of opened socket or -1 if something went wrong. */intsock_open(void){ int i; #ifdef IPV6 if ((i = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0)#else if ((i = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)#endif { net_errstr = strerror(errno); return -1; } track_add(i); sock_setreuse(i); /* local reuse by default */ return i;} /* int sock_open(void) */ intrawsock_close(int sock){ if (! sock) return 1; track_del(sock); close(sock); return 1;} /* int rawsock_close(int sock) */ intsock_close(connection_type *connection){ rawsock_close(connection->socket); connection->socket = 0; return 1;} /* int sock_close(connection_type *connection) */ intsock_setnonblock(int sock){ if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { net_errstr = strerror(errno); return 0; } else { return 1; }} /* int sock_setnonblock(int sock) */ intsock_setblock(int sock){ int flags; flags = fcntl(sock, F_GETFL, 0); if (flags == -1) { net_errstr = strerror(errno); return 0; } flags &= ~O_NONBLOCK; if (fcntl(sock, F_SETFL, flags) < 0) { net_errstr = strerror(errno); return 0; } return 1;} /* int sock_setblock(int sock) */ intsock_setreuse(int sock){ int i = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof(i)) < 0) { net_errstr = strerror(errno); return 0; } else { return 1; }} /* int sock_setreuse(int sock) */ struct hostent *name_lookup(char *host){#ifdef IPV6 hostinfo = gethostbyname2(host, AF_INET6); if (hostinfo != NULL) { return hostinfo; }#else /* IPV6 */ hostinfo = gethostbyname(host); if (hostinfo != NULL) { return hostinfo; }#endif /* IPV6 */ /* TODO: hstrerror is obsolete */#ifdef HAVE_HSTRERROR net_errstr = (const char *) hstrerror(h_errno);#else net_errstr = "unable to resolve";#endif return NULL;} /* struct hostent *name_lookup(char *host) */ #ifdef IPV6intsock_bind(int sock, char *bindhost, int port){ /* We'd better cast &addr to void * to keep Digital-UNIX happy. */ memset((void *) &addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_addr = in6addr_any; addr.sin6_family = AF_INET6; if (bindhost) { if (! name_lookup(bindhost)) { return 0; } memcpy((char *) &addr.sin6_addr, hostinfo->h_addr, hostinfo->h_length); addr.sin6_family = hostinfo->h_addrtype; } addr.sin6_port = htons((u_short)port); if (bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in6)) < 0) { net_errstr = strerror(errno); return 0; } return 1;} /* int sock_bind(int sock, char *bindhost, int port) */ intsock_bindlookedup(int sock, int port){ /* We'd better cast &addr to void * to keep Digital-UNIX happy. */ memset((void *) &addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_addr = in6addr_any; addr.sin6_family = AF_INET6; if (hostinfo) { memcpy((char *) &addr.sin6_addr, hostinfo->h_addr, hostinfo->h_length); addr.sin6_family = hostinfo->h_addrtype; } addr.sin6_port = htons((u_short)port); if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0) { net_errstr = strerror(errno); return 0; } return 1;} /* int sock_bindlookedup(int sock, int port) */ #else intsock_bind(int sock, char *bindhost, int port){ /* We'd better cast &addr to void * to keep Digital-UNIX happy. */ memset((void *) &addr, 0, sizeof(struct sockaddr_in)); addr.sin_addr.s_addr = INADDR_ANY; addr.sin_family = AF_INET; if (bindhost) { if (name_lookup(bindhost) == NULL) { return 0; } memcpy((char *) &addr.sin_addr, hostinfo->h_addr, hostinfo->h_length); addr.sin_family = hostinfo->h_addrtype; } addr.sin_port = htons((u_short) port); if (bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr)) < 0) { net_errstr = strerror(errno); return 0; } return 1;} /* int sock_bind(int sock, char *bindhost, int port) */ intsock_bindlookedup(int sock, int port){ /* We'd better cast &addr to void * to keep Digital-UNIX happy. */ memset((void *) &addr, 0, sizeof(struct sockaddr_in)); addr.sin_addr.s_addr = INADDR_ANY; addr.sin_family = AF_INET; if (hostinfo) { memcpy((char *) &addr.sin_addr, hostinfo->h_addr, hostinfo->h_length); addr.sin_family = hostinfo->h_addrtype; } addr.sin_port = htons((u_short) port); if (bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr)) < 0) { net_errstr = strerror(errno); return 0; } return 1;} /* int sock_bindlookedup(int sock, int port) */ #endif intsock_listen(int sock){ if (! sock_setnonblock(sock)) { return 0; } if (listen(sock, QUEUESIZE) < 0) { net_errstr = strerror(errno); return 0; } return 1;} /* int sock_listen(int sock) */ /* * Accept socket. Return socket. * * If checkperm is non-zero, a check is made to be sure connecting IP is allowed * to establish a connection with us. If connection is unauthorized, connection * will be closed and function returns -1. */typedef int socklen_t; intsock_accept(int sock, char **s, int checkperm){ socklen_t temp; int store;#ifdef IPV6 char ip[40]; char ipv6[512];#else char *ip;#endif int perm; #ifdef IPV6 temp = sizeof(struct sockaddr_in6);#else temp = sizeof(struct sockaddr_in);#endif if ((store = accept(sock, (struct sockaddr *) &addr, &temp)) < 0) { net_errstr = strerror(errno); return 0; } #ifdef IPV6 inet_ntop(AF_INET6, (char *) &addr.sin6_addr, ip, sizeof(addr.sin6_addr));#else ip = inet_ntoa(addr.sin_addr);#endif perm = is_perm(&connhostlist, ip); #ifdef IPV6 if (! getnameinfo((struct sockaddr *) &addr, sizeof(addr), ipv6, sizeof(ipv6), 0, 0, 0)) { *s = xstrdup(ipv6); perm |= is_perm(&connhostlist, *s); } else { *s = xstrdup(ip); } #else hostinfo = gethostbyaddr((char *) &addr.sin_addr.s_addr, sizeof(struct in_addr), AF_INET); if (hostinfo) { *s = xstrdup(hostinfo->h_name); perm |= is_perm(&connhostlist, *s); } else { *s = xstrdup(ip); }#endif if (! checkperm || perm) { track_add(store); return store; } else { close(store); return -1; }} /* int sock_accept(int sock, char **s, int checkperm) */ /* * Send data to all connected clients. */intirc_mwrite(clientlist_type *clients, char *format, ...){ llist_node *client; va_list va; int ret; if (clients->connected == 0) { return 0; } ret = 0; va_start(va, format); for (client = clients->clients->head; client != NULL; client = client->next) { va_list cva; /* * Having '"%s", buffer' instead of plain 'buffer' is essential * because we don't want our string processed any further by * va. */Lines 1–500 of 853. Load more
/* * ------------------------------------------------------- * Copyright (C) 2002-2007 Tommi Saviranta <wnd@iki.fi> * (C) 2002 Lee Hardy <lee@leeh.co.uk> * (C) 1998-2002 Sebastian Kienzl <zap@riot.org> * ------------------------------------------------------- * 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 General Public License for more details. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif /* ifdef HAVE_CONFIG_H */ #include "irc.h" #include "common.h" #include "conntype.h" #include "llist.h" #include "perm.h" #include <fcntl.h> #include <errno.h> #include <netdb.h> #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #if HAVE_STRINGS_H #include <strings.h> #endif /* Guess this needs to go somewhere */ typedef unsigned short u_short; /* #define DEBUG */ #ifdef HAVE_HSTRERROR #ifndef HAVE_HSTRERROR_PROTO const char *hstrerror(int err); #endif /* ifndef HAVE_HSTRERROR_PROTO */ #endif /* ifdef HAVE_HSTRERROR */ /* va_copy */ #ifndef va_copy #ifdef HAVE___VA_COPY #define va_copy __va_copy #else /* ifdef HAVE___VA_COPY */ /* we may need "memcpy(&dest, &src, sizeof(va_list))" on some systems */ #define va_copy(dest, src) ((dest) = (src)) #endif /* ifdef else HAVE___VA_COPY */ #endif /* ifndef va_copy */ #define HEAD 1 #define TAIL 2 static void track_highest(void); static void track_add(int s); static void track_del(int s); static int irc_write_smart(connection_type *connection, int queue, char *format, va_list va); struct hostent *hostinfo = NULL; #ifdef IPV6 struct sockaddr_in6 addr; #else struct sockaddr_in addr; #endif const char *net_errstr; #define TRACK 512 int track_socks[TRACK]; int highest_socket = 0; int msgtimer; /* Message timer... */ llist_list msg_queue; /* Message queue */ static void track_highest(void) { int i; highest_socket = 0; for (i = 0; i < TRACK; i++) { if (track_socks[i] > highest_socket) { highest_socket = track_socks[i]; } } } /* void track_highest(void) */ static void track_add(int s) { int i = 0; while (track_socks[i] && i < TRACK) { i++; } if (i < TRACK) { track_socks[i] = s; } track_highest(); } /* void track_add(int s) */ static void track_del(int s) { int i; for (i = 0; i < TRACK; i++) { if (track_socks[i] == s) { track_socks[i] = 0; } } track_highest(); } /* void track_del(int s) */ /* * Creates a socket. * * Returns number of opened socket or -1 if something went wrong. */ int sock_open(void) { int i; #ifdef IPV6 if ((i = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0) #else if ((i = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) #endif { net_errstr = strerror(errno); return -1; } track_add(i); sock_setreuse(i); /* local reuse by default */ return i; } /* int sock_open(void) */ int rawsock_close(int sock) { if (! sock) return 1; track_del(sock); close(sock); return 1; } /* int rawsock_close(int sock) */ int sock_close(connection_type *connection) { rawsock_close(connection->socket); connection->socket = 0; return 1; } /* int sock_close(connection_type *connection) */ int sock_setnonblock(int sock) { if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { net_errstr = strerror(errno); return 0; } else { return 1; } } /* int sock_setnonblock(int sock) */ int sock_setblock(int sock) { int flags; flags = fcntl(sock, F_GETFL, 0); if (flags == -1) { net_errstr = strerror(errno); return 0; } flags &= ~O_NONBLOCK; if (fcntl(sock, F_SETFL, flags) < 0) { net_errstr = strerror(errno); return 0; } return 1; } /* int sock_setblock(int sock) */ int sock_setreuse(int sock) { int i = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof(i)) < 0) { net_errstr = strerror(errno); return 0; } else { return 1; } } /* int sock_setreuse(int sock) */ struct hostent * name_lookup(char *host) { #ifdef IPV6 hostinfo = gethostbyname2(host, AF_INET6); if (hostinfo != NULL) { return hostinfo; } #else /* IPV6 */ hostinfo = gethostbyname(host); if (hostinfo != NULL) { return hostinfo; } #endif /* IPV6 */ /* TODO: hstrerror is obsolete */ #ifdef HAVE_HSTRERROR net_errstr = (const char *) hstrerror(h_errno); #else net_errstr = "unable to resolve"; #endif return NULL; } /* struct hostent *name_lookup(char *host) */ #ifdef IPV6 int sock_bind(int sock, char *bindhost, int port) { /* We'd better cast &addr to void * to keep Digital-UNIX happy. */ memset((void *) &addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_addr = in6addr_any; addr.sin6_family = AF_INET6; if (bindhost) { if (! name_lookup(bindhost)) { return 0; } memcpy((char *) &addr.sin6_addr, hostinfo->h_addr, hostinfo->h_length); addr.sin6_family = hostinfo->h_addrtype; } addr.sin6_port = htons((u_short)port); if (bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in6)) < 0) { net_errstr = strerror(errno); return 0; } return 1; } /* int sock_bind(int sock, char *bindhost, int port) */ int sock_bindlookedup(int sock, int port) { /* We'd better cast &addr to void * to keep Digital-UNIX happy. */ memset((void *) &addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_addr = in6addr_any; addr.sin6_family = AF_INET6; if (hostinfo) { memcpy((char *) &addr.sin6_addr, hostinfo->h_addr, hostinfo->h_length); addr.sin6_family = hostinfo->h_addrtype; } addr.sin6_port = htons((u_short)port); if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0) { net_errstr = strerror(errno); return 0; } return 1; } /* int sock_bindlookedup(int sock, int port) */ #else int sock_bind(int sock, char *bindhost, int port) { /* We'd better cast &addr to void * to keep Digital-UNIX happy. */ memset((void *) &addr, 0, sizeof(struct sockaddr_in)); addr.sin_addr.s_addr = INADDR_ANY; addr.sin_family = AF_INET; if (bindhost) { if (name_lookup(bindhost) == NULL) { return 0; } memcpy((char *) &addr.sin_addr, hostinfo->h_addr, hostinfo->h_length); addr.sin_family = hostinfo->h_addrtype; } addr.sin_port = htons((u_short) port); if (bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr)) < 0) { net_errstr = strerror(errno); return 0; } return 1; } /* int sock_bind(int sock, char *bindhost, int port) */ int sock_bindlookedup(int sock, int port) { /* We'd better cast &addr to void * to keep Digital-UNIX happy. */ memset((void *) &addr, 0, sizeof(struct sockaddr_in)); addr.sin_addr.s_addr = INADDR_ANY; addr.sin_family = AF_INET; if (hostinfo) { memcpy((char *) &addr.sin_addr, hostinfo->h_addr, hostinfo->h_length); addr.sin_family = hostinfo->h_addrtype; } addr.sin_port = htons((u_short) port); if (bind(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr)) < 0) { net_errstr = strerror(errno); return 0; } return 1; } /* int sock_bindlookedup(int sock, int port) */ #endif int sock_listen(int sock) { if (! sock_setnonblock(sock)) { return 0; } if (listen(sock, QUEUESIZE) < 0) { net_errstr = strerror(errno); return 0; } return 1; } /* int sock_listen(int sock) */ /* * Accept socket. Return socket. * * If checkperm is non-zero, a check is made to be sure connecting IP is allowed * to establish a connection with us. If connection is unauthorized, connection * will be closed and function returns -1. */ typedef int socklen_t; int sock_accept(int sock, char **s, int checkperm) { socklen_t temp; int store; #ifdef IPV6 char ip[40]; char ipv6[512]; #else char *ip; #endif int perm; #ifdef IPV6 temp = sizeof(struct sockaddr_in6); #else temp = sizeof(struct sockaddr_in); #endif if ((store = accept(sock, (struct sockaddr *) &addr, &temp)) < 0) { net_errstr = strerror(errno); return 0; } #ifdef IPV6 inet_ntop(AF_INET6, (char *) &addr.sin6_addr, ip, sizeof(addr.sin6_addr)); #else ip = inet_ntoa(addr.sin_addr); #endif perm = is_perm(&connhostlist, ip); #ifdef IPV6 if (! getnameinfo((struct sockaddr *) &addr, sizeof(addr), ipv6, sizeof(ipv6), 0, 0, 0)) { *s = xstrdup(ipv6); perm |= is_perm(&connhostlist, *s); } else { *s = xstrdup(ip); } #else hostinfo = gethostbyaddr((char *) &addr.sin_addr.s_addr, sizeof(struct in_addr), AF_INET); if (hostinfo) { *s = xstrdup(hostinfo->h_name); perm |= is_perm(&connhostlist, *s); } else { *s = xstrdup(ip); } #endif if (! checkperm || perm) { track_add(store); return store; } else { close(store); return -1; } } /* int sock_accept(int sock, char **s, int checkperm) */ /* * Send data to all connected clients. */ int irc_mwrite(clientlist_type *clients, char *format, ...) { llist_node *client; va_list va; int ret; if (clients->connected == 0) { return 0; } ret = 0; va_start(va, format); for (client = clients->clients->head; client != NULL; client = client->next) { va_list cva; /* * Having '"%s", buffer' instead of plain 'buffer' is essential * because we don't want our string processed any further by * va. */