configure.in: Check for struct sockaddr.sa_len and struct addrinfo.
Also check for freeaddrinfo, getaddrinfo and getnameinfo.
src/common.h: Define irc_in_addr and macros to operate on it. Declare
irc_ntop(), irc_ntop_mask(), irc_pton(), irc_check_mask() and
irc_ntoa(). Remove declaration for parse_ipmask() and undefine
INADDR_NONE, INADDR_LOOPBACK and MATCH_IPMASK().
src/compat.h (struct addrinfo): Define if it and some flags if not
defined by the system.
(getaddrinfo): Declare if necessary.
(getnameinfo): Likewise.
(freeaddrinfo): Likewise.
src/compat.c (memcpy): Do not try to fall back onto bcopy.
(getaddrinfo): Define if it is not defined by the system.
(freeaddrinfo): Likewise.
src/gline.c (gline_alternate_target): Gut in preparation of a
necessary rewrite. Blah.
src/hash.h (struct userNode): Change type of ip field.
src/ioset.c (ioset_connect): Update to support non-IPv4 protocols.
src/main.c (uplink_insert): Update to support non-IPv4 protocols.
src/mod-snoop.c (snoop_new_user): Use irc_ntoa() instead of inet_ntoa().
src/mod-sockcheck.c (sockcheck_cache_info): Update address field type
and length of hostname field.
(sockcheck_conf): Update type of local_addr.
(sockcheck_issue_gline): Update to use irc_ntop().
(expand_var): Get client IPv4 address from its new place.
(sockcheck_decide): Do not print the IP twice.
(sockcheck_begin_test): Remove unnecessary typecast.
(sockcheck_start_client): Do not print the IP twice.
(sockcheck_queue_address): Use irc_in_addr_t and irc_ntoa() to form
the target hostname.
(cmd_hostscan): Update manipulation functions to use new macros and
functions for irc_in_addr_t.
(cmd_clearhost): Likewise.
(sockcheck_new_user): Likewise.
(sockcheck_read_conf): Use getaddrinfo() instead of IPv4-only
functions.
src/nickserv.c (cmd_register): Use newer validity checks for IP.
src/opserv.c (IDENT_DATA): Use irc_ntoa() instead of inet_ntoa().
(struct opservDiscrim): Update ip_mask and ip_mask_bits type.
(cmd_whois): Use irc_ntoa() instead of inet_ntoa().
(opserv_new_user_check): Use irc_ntop() instead of inet_ntoa() and
update to newer validity check macros.
(opserv_user_cleanup): Use irc_ntop() instead of inet_ntoa().
(cmd_addtrust): Update to irc_in_addr_t and its functions.
(foreach_matching_user): Use irc_pton() instead of the mess that
existed before.
(opserv_discrim_create): Use irc_pton() instead of parse_ipmask().
(discrim_match): Use irc_check_mask() instead of MATCH_IPMASK(), and
remove ip_mask_str check.
(opserv_discrim_search): Decide whether an IP match is fully
qualified based on ip_mask_bits instead of ip_mask_str.
(trace_domains_func): Add IPv6 support.
(opserv_staff_alert): Update to new IP validity check macro.
src/proto.h (struct uplinkNode): Fix type of bind_addr field.
src/proto-bahamut.c (AddUser): Use irc_in_addr_t.
(AddService): Default to an all-zero IP instead of loopback.
(AddClone): Likewise.
(irc_user): Use new layout for IPv4 in irc_in_addr_t.
(cmd_nick): Likewise.
src/proto-common.c (create_socket_client): Remove unnecessary
typecast.
(generate_hostmask): Update to use irc_in_addr_t and support
functions instead of IPv4-specific things.
src/proto-p10.c (irc_p10_pton): New function.
(irc_p10_ntop): New function.
(irc_user): Use irc_p10_ntop().
(AddClone): Use irc_p10_pton().
src/tools.c (ctype): New array holding values of characters as hex.
(irc_ntop): New function.
(irc_ntop_mask): New function.
(irc_pton_ip4): New helper function.
(irc_pton): New function.
(irc_ntoa): New function.
(irc_check_mask): New function.
(user_matches_glob): Use irc_ntoa() instead of inet_ntoa().
(parse_ipmask): Delete this function.
git-archimport-id: srvx@srvx.net--2005-srvx/srvx--devo--1.3--patch-28
# arch-tag: automatic-ChangeLog--srvx@srvx.net--2005-srvx/srvx--devo--1.3
#
+2005-10-08 14:33:12 GMT Michael Poole <mdpoole@troilus.org> patch-28
+
+ Summary:
+ Add IPv6 support.
+ Revision:
+ srvx--devo--1.3--patch-28
+
+ configure.in: Check for struct sockaddr.sa_len and struct addrinfo.
+ Also check for freeaddrinfo, getaddrinfo and getnameinfo.
+
+ src/common.h: Define irc_in_addr and macros to operate on it. Declare
+ irc_ntop(), irc_ntop_mask(), irc_pton(), irc_check_mask() and
+ irc_ntoa(). Remove declaration for parse_ipmask() and undefine
+ INADDR_NONE, INADDR_LOOPBACK and MATCH_IPMASK().
+
+ src/compat.h (struct addrinfo): Define if it and some flags if not
+ defined by the system.
+ (getaddrinfo): Declare if necessary.
+ (getnameinfo): Likewise.
+ (freeaddrinfo): Likewise.
+
+ src/compat.c (memcpy): Do not try to fall back onto bcopy.
+ (getaddrinfo): Define if it is not defined by the system.
+ (freeaddrinfo): Likewise.
+
+ src/gline.c (gline_alternate_target): Gut in preparation of a
+ necessary rewrite. Blah.
+
+ src/hash.h (struct userNode): Change type of ip field.
+
+ src/ioset.c (ioset_connect): Update to support non-IPv4 protocols.
+
+ src/main.c (uplink_insert): Update to support non-IPv4 protocols.
+
+ src/mod-snoop.c (snoop_new_user): Use irc_ntoa() instead of inet_ntoa().
+
+ src/mod-sockcheck.c (sockcheck_cache_info): Update address field type
+ and length of hostname field.
+ (sockcheck_conf): Update type of local_addr.
+ (sockcheck_issue_gline): Update to use irc_ntop().
+ (expand_var): Get client IPv4 address from its new place.
+ (sockcheck_decide): Do not print the IP twice.
+ (sockcheck_begin_test): Remove unnecessary typecast.
+ (sockcheck_start_client): Do not print the IP twice.
+ (sockcheck_queue_address): Use irc_in_addr_t and irc_ntoa() to form
+ the target hostname.
+ (cmd_hostscan): Update manipulation functions to use new macros and
+ functions for irc_in_addr_t.
+ (cmd_clearhost): Likewise.
+ (sockcheck_new_user): Likewise.
+ (sockcheck_read_conf): Use getaddrinfo() instead of IPv4-only
+ functions.
+
+ src/nickserv.c (cmd_register): Use newer validity checks for IP.
+
+ src/opserv.c (IDENT_DATA): Use irc_ntoa() instead of inet_ntoa().
+ (struct opservDiscrim): Update ip_mask and ip_mask_bits type.
+ (cmd_whois): Use irc_ntoa() instead of inet_ntoa().
+ (opserv_new_user_check): Use irc_ntop() instead of inet_ntoa() and
+ update to newer validity check macros.
+ (opserv_user_cleanup): Use irc_ntop() instead of inet_ntoa().
+ (cmd_addtrust): Update to irc_in_addr_t and its functions.
+ (foreach_matching_user): Use irc_pton() instead of the mess that
+ existed before.
+ (opserv_discrim_create): Use irc_pton() instead of parse_ipmask().
+ (discrim_match): Use irc_check_mask() instead of MATCH_IPMASK(), and
+ remove ip_mask_str check.
+ (opserv_discrim_search): Decide whether an IP match is fully
+ qualified based on ip_mask_bits instead of ip_mask_str.
+ (trace_domains_func): Add IPv6 support.
+ (opserv_staff_alert): Update to new IP validity check macro.
+
+ src/proto.h (struct uplinkNode): Fix type of bind_addr field.
+
+ src/proto-bahamut.c (AddUser): Use irc_in_addr_t.
+ (AddService): Default to an all-zero IP instead of loopback.
+ (AddClone): Likewise.
+ (irc_user): Use new layout for IPv4 in irc_in_addr_t.
+ (cmd_nick): Likewise.
+
+ src/proto-common.c (create_socket_client): Remove unnecessary
+ typecast.
+ (generate_hostmask): Update to use irc_in_addr_t and support
+ functions instead of IPv4-specific things.
+
+ src/proto-p10.c (irc_p10_pton): New function.
+ (irc_p10_ntop): New function.
+ (irc_user): Use irc_p10_ntop().
+ (AddClone): Use irc_p10_pton().
+
+ src/tools.c (ctype): New array holding values of characters as hex.
+ (irc_ntop): New function.
+ (irc_ntop_mask): New function.
+ (irc_pton_ip4): New helper function.
+ (irc_pton): New function.
+ (irc_ntoa): New function.
+ (irc_check_mask): New function.
+ (user_matches_glob): Use irc_ntoa() instead of inet_ntoa().
+ (parse_ipmask): Delete this function.
+
+ modified files:
+ ChangeLog configure.in src/common.h src/compat.c src/compat.h
+ src/gline.c src/hash.h src/ioset.c src/main.c src/mod-snoop.c
+ src/mod-sockcheck.c src/nickserv.c src/opserv.c
+ src/proto-bahamut.c src/proto-common.c src/proto-p10.c
+ src/proto.h src/tools.c
+
+
2005-10-07 02:51:12 GMT Michael Poole <mdpoole@troilus.org> patch-27
Summary:
[AC_DEFINE(HAVE_DIRENT_D_TYPE, 1, [Define if struct dirent exists and includes the d_type element.])],,[#include <dirent.h>])
dnl portability stuff, hurray! -Jedi
+AC_CHECK_MEMBER([struct sockaddr.sa_len],
+ [AC_DEFINE([HAVE_SOCKADDR_SA_LEN],,[Define if struct sockaddr has sa_len field])],
+ [],[#include <sys/types.h>
+#include <sys/socket.h>])
+AC_CHECK_MEMBER([struct addrinfo.ai_flags],
+ [AC_DEFINE([HAVE_STRUCT_ADDRINFO],,[Define if struct addrinfo declared])],
+ [],[#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>])
AC_CHECK_FUNCS(gettimeofday)
if test $ac_cv_func_gettimeofday = no; then
AC_CHECK_FUNCS(ftime,,AC_MSG_ERROR([ftime or gettimeofday required. srvx build will fail.]))
fi
dnl We have fallbacks in case these are missing, so just check for them.
-AC_CHECK_FUNCS(bcopy getpagesize memcpy memset strdup strerror strsignal localtime_r setrlimit inet_ntoa getopt getopt_long regcomp regexec regfree sysconf,,)
+AC_CHECK_FUNCS(freeaddrinfo getaddrinfo getnameinfo getpagesize memcpy memset strdup strerror strsignal localtime_r setrlimit getopt getopt_long regcomp regexec regfree sysconf,,)
dnl Check for absolutely required library functions.
AC_CHECK_FUNCS(select socket strcspn strspn strtod strtoul,,AC_MSG_ERROR([a required function was not found. srvx build will fail.]))
#define false 0
#endif
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffffL
-#endif
-#ifndef INADDR_LOOPBACK
-#define INADDR_LOOPBACK 0x7f000001L
-#endif
-
#define ArrayLength(x) (sizeof(x)/sizeof(x[0]))
#define safestrncpy(dest, src, len) do { char *d = (dest); const char *s = (src); size_t l = strlen(s)+1; if ((len) < l) l = (len); memmove(d, s, l); d[l-1] = 0; } while (0)
extern int quit_services;
extern struct log_type *MAIN_LOG;
+typedef union irc_in_addr {
+ uint32_t in6_32[4];
+ uint16_t in6[8];
+ uint8_t in6_8[16];
+} irc_in_addr_t;
+
+#define irc_in_addr_is_valid(ADDR) (((ADDR).in6[0] && (ADDR).in6[0] != 65535) \
+ || (ADDR).in6[1] != (ADDR).in6[0] \
+ || (ADDR).in6[2] != (ADDR).in6[0] \
+ || (ADDR).in6[3] != (ADDR).in6[0] \
+ || (ADDR).in6[4] != (ADDR).in6[0] \
+ || (ADDR).in6[5] != (ADDR).in6[0] \
+ || (ADDR).in6[6] != (ADDR).in6[0] \
+ || (ADDR).in6[7] != (ADDR).in6[0])
+#define irc_in_addr_is_ipv4(ADDR) (!(ADDR).in6[0] && !(ADDR).in6[1] \
+ && !(ADDR).in6[2] && !(ADDR).in6[3] \
+ && !(ADDR).in6[4] && (ADDR).in6[6] \
+ && (!(ADDR).in6[5] || (ADDR).in6[5] == 65535))
+#define irc_in_addr_is_ipv6(ADDR) !irc_in_addr_is_ipv4(ADDR)
+#define irc_in_addr_is_loopback(ADDR) (irc_in_addr_is_ipv4(ADDR) ? (ADDR).in6_8[12] == 127 \
+ : (ADDR).in6[0] == 0 && (ADDR).in6[1] == 0 \
+ && (ADDR).in6[2] == 0 && (ADDR).in6[3] == 0 \
+ && (ADDR).in6[4] == 0 && (ADDR).in6[5] == 0 \
+ && (ADDR).in6[6] == 0 && (ADDR).in6[7] == 1)
+#define IRC_NTOP_MAX_SIZE 40
+unsigned int irc_ntop(char *output, unsigned int out_size, const irc_in_addr_t *addr);
+#define IRC_NTOP_MASK_MAX_SIZE (IRC_NTOP_MAX_SIZE + 4)
+unsigned int irc_ntop_mask(char *output, unsigned int out_size, const irc_in_addr_t *addr, unsigned char bits);
+unsigned int irc_pton(irc_in_addr_t *addr, unsigned char *bits, const char *input);
+unsigned int irc_check_mask(const irc_in_addr_t *check, const irc_in_addr_t *mask, unsigned char bits);
+const char *irc_ntoa(const irc_in_addr_t *addr);
+
int create_socket_client(struct uplinkNode *target);
void close_socket(void);
unsigned long ParseInterval(const char *interval);
unsigned long ParseVolume(const char *volume);
-int parse_ipmask(const char *str, struct in_addr *addr, unsigned long *mask);
-#define MATCH_IPMASK(test, addr, mask) (((ntohl(test.s_addr) & mask) ^ (ntohl(addr.s_addr) & mask)) == 0)
#define MD5_CRYPT_LENGTH 42
/* buffer[] must be at least MD5_CRYPT_LENGTH bytes long */
#ifndef HAVE_MEMCPY
extern void * memcpy(void * dest, void const * src, unsigned long n)
{
-#ifdef HAVE_BCOPY
- bcopy(src,dest,n);
- return dest;
-#else
/* very slow, your fault for not having memcpy()*/
unsigned char * td=dest;
unsigned char * ts=src;
for (i=0; i<n; i++)
td[i] = ts[i];
return dest;
-#endif
}
#endif
return "Unknown error";
}
#endif
+
+#ifndef HAVE_GETADDRINFO
+
+int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
+{
+ /* Only support IPv4 if OS doesn't provide this function. */
+ struct sockaddr_in sin;
+
+ if (hints && hints->ai_family != AF_INET)
+ return 1;
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+
+ if (node) {
+ if (hints && hints->ai_flags & AI_NUMERICHOST) {
+ if (!inet_aton(node, &sin.sin_addr))
+ return 2;
+ } else {
+ struct hostent *he;
+ he = gethostbyname(node);
+ if (!he)
+ return 3;
+ memcpy(&sin.sin_addr, he->h_addr, he->h_length);
+ }
+ } else if (hints && hints->ai_flags & AI_PASSIVE) {
+ /* leave it unspecifed */
+ } else {
+ inet_aton("127.0.0.1", &sin.sin_addr);
+ }
+
+ if (!service)
+ sin.sin_port = ntohs(0);
+ else if (!(sin.sin_port = ntohs(atoi(service))))
+ return 4;
+
+ *res = calloc(1, sizeof(**res) + sizeof(sin));
+ (*res)->ai_family = sin.sin_family;
+ (*res)->ai_socktype = hints && hints->ai_socktype ? hints->ai_socktype : SOCK_STREAM;
+ (*res)->ai_protocol = hints && hints->ai_socktype ? hints->ai_socktype : 0;
+ (*res)->ai_addrlen = sizeof(sin);
+ (*res)->ai_addr = (struct sockaddr*)(*res + 1);
+ memcpy((*res)->ai_addr, &sin, (*res)->ai_addrlen);
+ (*res)->ai_canonname = 0;
+ (*res)->ai_next = 0;
+ return 0;
+}
+
+/* TODO: implement fallback getnameinfo() */
+
+void freeaddrinfo(struct addrinfo *res)
+{
+ struct addrinfo *next;
+ for (; res; res = next) {
+ next = res->ai_next;
+ free(res);
+ }
+}
+
+#endif
#include <sys/types.h>
#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
extern char const * strerror(int errornum);
#endif
+#ifndef HAVE_STRUCT_ADDRINFO
+
+struct addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ struct sockaddr *ai_addr;
+ char *ai_canonname;
+ struct addrinfo *ai_next;
+};
+
+#define AI_PASSIVE 1
+#define AI_CANONNAME 2
+
+#endif /* !defined(HAVE_STRUCT_ADDRINFO) */
+
+#ifndef HAVE_GETADDRINFO
+
+int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
+int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
+void freeaddrinfo(struct addrinfo *res);
+
+#endif
+
#endif /* COMPAT_H */
gline_alternate_target(const char *target)
{
const char *hostname;
- unsigned long ip;
- char *res;
/* If no host part, bail. */
if (!(hostname = strchr(target, '@')))
/* If host part contains wildcards, bail. */
if (hostname[strcspn(hostname, "*?/")])
return NULL;
- /* If host part looks like an IP, parse it that way. */
- if (!hostname[strspn(hostname+1, "0123456789.")+1]) {
- struct in_addr in;
- struct hostent *he;
- if (inet_aton(hostname+1, &in)
- && (he = gethostbyaddr((char*)&in, sizeof(in), AF_INET))) {
- res = malloc((hostname - target) + 2 + strlen(he->h_name));
- sprintf(res, "%.*s@%s", (int)(hostname - target), target, he->h_name);
- return res;
- } else
- return NULL;
- } else if (getipbyname(hostname+1, &ip)) {
- res = malloc((hostname - target) + 18);
- sprintf(res, "%.*s@%lu.%lu.%lu.%lu", (int)(hostname - target), target, ip & 255, (ip >> 8) & 255, (ip >> 16) & 255, (ip >> 24) & 255);
- return res;
- } else
- return NULL;
+ /* Get parsed address and canonical name for host. */
+#if 0
+ irc_in_addr_t in; /* move this to the right place */
+ if (irc_pton(&in, NULL, hostname+1)) {
+ if (getnameinfo(/*TODO*/))
+ return NULL;
+ } else if (!getaddrinfo(/*TODO*/)) {
+ } else return NULL;
+#else
+ return NULL;
+#endif
}
struct gline *
unsigned int num_local : 18;
#endif
unsigned int dead : 1; /* Is user waiting to be recycled? */
- struct in_addr ip; /* User's IP address */
+ irc_in_addr_t ip; /* User's IP address */
long modes; /* user flags +isw etc... */
time_t timestamp; /* Time of last nick change */
ioset_connect(struct sockaddr *local, unsigned int sa_size, const char *peer, unsigned int port, int blocking, void *data, void (*connect_cb)(struct io_fd *fd, int error)) {
int fd, res;
struct io_fd *io_fd;
- struct sockaddr_in sin;
- unsigned long ip;
-
- if (!getipbyname(peer, &ip)) {
- log_module(MAIN_LOG, LOG_ERROR, "getipbyname(%s) failed.", peer);
+ struct addrinfo hints, *ai;
+ char portnum[10];
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = local ? local->sa_family : 0;
+ hints.ai_socktype = SOCK_STREAM;
+ snprintf(portnum, sizeof(portnum), "%u", port);
+ if (getaddrinfo(peer, portnum, &hints, &ai)) {
+ log_module(MAIN_LOG, LOG_ERROR, "getaddrinfo(%s, %s) failed.", peer, portnum);
return NULL;
}
- sin.sin_addr.s_addr = ip;
+
if (local) {
if ((fd = socket(local->sa_family, SOCK_STREAM, 0)) < 0) {
log_module(MAIN_LOG, LOG_ERROR, "socket() for %s returned errno %d (%s)", peer, errno, strerror(errno));
+ freeaddrinfo(ai);
return NULL;
}
if (bind(fd, local, sa_size) < 0) {
} else {
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
log_module(MAIN_LOG, LOG_ERROR, "socket() for %s returned errno %d (%s).", peer, errno, strerror(errno));
+ freeaddrinfo(ai);
return NULL;
}
}
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
+
if (blocking) {
- res = connect(fd, (struct sockaddr*)&sin, sizeof(sin));
+ res = connect(fd, ai->ai_addr, ai->ai_addrlen);
io_fd = ioset_add(fd);
} else {
io_fd = ioset_add(fd);
- res = connect(fd, (struct sockaddr*)&sin, sizeof(sin));
+ res = connect(fd, ai->ai_addr, ai->ai_addrlen);
}
+ freeaddrinfo(ai);
if (!io_fd) {
close(fd);
return NULL;
{
struct uplinkNode *uplink = malloc(sizeof(struct uplinkNode));
struct record_data *rd = data;
+ struct addrinfo hints, *ai;
int enabled = 1;
char *str;
- struct sockaddr_in *sin;
- unsigned long addr;
if(!uplink)
{
uplink->tries = 0;
str = database_get_data(rd->d.object, "bind_address", RECDB_QSTRING);
- uplink->bind_addr_len = sizeof(*sin);
- if (str && getipbyname(str, &addr))
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_socktype = SOCK_STREAM;
+ if (!getaddrinfo(str, NULL, &hints, &ai))
{
- sin = calloc(1, uplink->bind_addr_len);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = addr;
- uplink->bind_addr = sin;
- }
- else
+ uplink->bind_addr_len = ai->ai_addrlen;
+ uplink->bind_addr = calloc(1, ai->ai_addrlen);
+ memcpy(uplink->bind_addr, ai->ai_addr, ai->ai_addrlen);
+ freeaddrinfo(ai);
+ }
+ else
{
uplink->bind_addr = NULL;
uplink->bind_addr_len = 0;
if (!snoop_cfg.enabled) return 0;
if (user->uplink->burst && !snoop_cfg.show_bursts) return 0;
UPDATE_TIMESTAMP();
- SNOOP("$bNICK$b %s %s@%s [%s] on %s", user->nick, user->ident, user->hostname, inet_ntoa(user->ip), user->uplink->name);
+ SNOOP("$bNICK$b %s %s@%s [%s] on %s", user->nick, user->ident, user->hostname, irc_ntoa(&user->ip), user->uplink->name);
return 0;
}
};
typedef struct {
- enum sockcheck_decision decision;
- time_t last_touched;
+ irc_in_addr_t addr;
const char *reason;
- struct in_addr addr;
- char hostname[16];
+ time_t last_touched;
+ enum sockcheck_decision decision;
+ char hostname[IRC_NTOP_MAX_SIZE]; /* acts as key for checked_ip_dict */
} *sockcheck_cache_info;
DECLARE_LIST(sci_list, sockcheck_cache_info);
* state and the input). Mealy state machines require fewer states to
* match the same input than Moore machines (where the output is only
* a function of the current state).
- *
+ *
* A state is characterized by sending some data (possibly nothing),
* waiting a certain amount of time to receive one of zero or more
* responses, and a decision (accept, reject, continue to another
unsigned int max_read;
unsigned int gline_duration;
unsigned int max_cache_age;
- struct sockaddr_in *local_addr;
+ struct sockaddr *local_addr;
int local_addr_len;
} sockcheck_conf;
static void
sockcheck_issue_gline(sockcheck_cache_info sci)
{
- char *target = alloca(3+strlen(sci->hostname));
- strcpy(target, "*@");
- strcpy(target+2, sci->hostname);
- log_module(PC_LOG, LOG_INFO, "Issuing gline for client at IP %s hostname %s: %s", inet_ntoa(sci->addr), sci->hostname, sci->reason);
- gline_add("ProxyCheck", target, sockcheck_conf.gline_duration, sci->reason, now, 1);
+ char addr[IRC_NTOP_MAX_SIZE + 2] = {'*', '@', '\0'};
+ irc_ntop(addr + 2, sizeof(addr) - 2, &sci->addr);
+ log_module(PC_LOG, LOG_INFO, "Issuing gline for client at %s: %s", addr + 2, sci->reason);
+ gline_add("ProxyCheck", addr, sockcheck_conf.gline_duration, sci->reason, now, 1);
}
static struct sockcheck_client *
log_module(PC_LOG, LOG_INFO, "client %p: { addr = %p { decision = %s; last_touched = "FMT_TIME_T"; reason = %s; hostname = \"%s\" }; "
"test_index = %d; state = %p { port = %d; type = %s; template = \"%s\"; ... }; "
"fd = %p(%d); read = %p; read_size = %d; read_used = %d; read_pos = %d; }",
- client, client->addr, decs[client->addr->decision], client->addr->last_touched, client->addr->reason, client->addr->hostname,
+ client, client->addr, decs[client->addr->decision], client->addr->last_touched,
+ client->addr->reason, client->addr->hostname,
client->test_index, client->state,
(client->state ? client->state->port : 0),
(client->state ? decs[client->state->type] : "N/A"),
exp_length = strlen(expansion);
break;
case 'i':
- exp4 = client->addr->addr.s_addr;
+ exp4 = client->addr->addr.in6_32[3];
exp_length = sizeof(exp4);
expansion = (char*)&exp4;
break;
case ACCEPT:
/* do nothing */
if (SOCKCHECK_DEBUG) {
- log_module(PC_LOG, LOG_INFO, "Proxy check passed for client at IP %s hostname %s.", inet_ntoa(client->addr->addr), client->addr->hostname);
+ log_module(PC_LOG, LOG_INFO, "Proxy check passed for client at %s.", client->addr->hostname);
}
break;
case REJECT:
proxies_detected++;
sockcheck_issue_gline(client->addr);
if (SOCKCHECK_DEBUG) {
- log_module(PC_LOG, LOG_INFO, "Proxy check rejects client at IP %s hostname %s (%s)", inet_ntoa(client->addr->addr), client->addr->hostname, client->addr->reason);
+ log_module(PC_LOG, LOG_INFO, "Proxy check rejects client at %s (%s)", client->addr->hostname, client->addr->reason);
}
/* Don't compare test_index != 0 directly, because somebody
* else may have reordered the tests already. */
client->state = client->tests->list[client->test_index];
client->read_pos = 0;
client->read_used = 0;
- client->fd = io_fd = ioset_connect((struct sockaddr*)sockcheck_conf.local_addr, sizeof(struct sockaddr), client->addr->hostname, client->state->port, 0, client, sockcheck_connected);
+ client->fd = io_fd = ioset_connect(sockcheck_conf.local_addr, sockcheck_conf.local_addr_len, client->addr->hostname, client->state->port, 0, client, sockcheck_connected);
if (!io_fd) {
client->test_index++;
continue;
sockcheck_num_clients++;
if (!tests) return;
client = client_list[idx] = sockcheck_alloc_client(sci);
- log_module(PC_LOG, LOG_INFO, "Proxy-checking client at %s (%s) as client %d (%p) of %d.", inet_ntoa(sci->addr), sci->hostname, idx, client, sockcheck_num_clients);
+ log_module(PC_LOG, LOG_INFO, "Proxy-checking client at %s as client %d (%p) of %d.", sci->hostname, idx, client, sockcheck_num_clients);
client->test_rep = 0;
client->client_index = idx;
sockcheck_begin_test(client);
}
void
-sockcheck_queue_address(struct in_addr addr)
+sockcheck_queue_address(irc_in_addr_t addr)
{
sockcheck_cache_info sci;
- char *ipstr=inet_ntoa(addr);
+ const char *ipstr = irc_ntoa(&addr);
sci = dict_find(checked_ip_dict, ipstr, NULL);
if (sci) {
static MODCMD_FUNC(cmd_hostscan)
{
unsigned int n;
- unsigned long addr;
- struct in_addr ipaddr;
- char hnamebuf[64];
+ irc_in_addr_t ipaddr;
+ char hnamebuf[IRC_NTOP_MAX_SIZE];
for (n=1; n<argc; n++) {
struct userNode *un = GetUserH(argv[n]);
if (un) {
- if ((un->ip.s_addr == 0) || (ntohl(un->ip.s_addr) == INADDR_LOOPBACK)) {
+ if (!irc_in_addr_is_valid(un->ip)
+ || irc_in_addr_is_loopback(un->ip)) {
reply("PCMSG_UNSCANNABLE_IP", un->nick);
} else {
- strcpy(hnamebuf, inet_ntoa(un->ip));
+ irc_ntop(hnamebuf, sizeof(hnamebuf), &un->ip);
sockcheck_queue_address(un->ip);
reply("PCMSG_ADDRESS_QUEUED", hnamebuf);
}
} else {
char *scanhost = argv[n];
- if (getipbyname(scanhost, &addr)) {
- ipaddr.s_addr = htonl(addr);
+ if (!irc_pton(&ipaddr, NULL, scanhost)) {
sockcheck_queue_address(ipaddr);
reply("PCMSG_ADDRESS_QUEUED", scanhost);
} else {
static MODCMD_FUNC(cmd_clearhost)
{
unsigned int n;
- char hnamebuf[64];
+ char hnamebuf[IRC_NTOP_MAX_SIZE];
for (n=1; n<argc; n++) {
struct userNode *un = GetUserH(argv[n]);
const char *scanhost;
if (un) {
- strcpy(hnamebuf, inet_ntoa(un->ip));
+ irc_ntop(hnamebuf, sizeof(hnamebuf), &un->ip);
scanhost = hnamebuf;
} else {
scanhost = argv[n];
static int
sockcheck_new_user(struct userNode *user) {
/* If they have a bum IP, or are bursting in, don't proxy-check or G-line them. */
- if (user->ip.s_addr
- && (ntohl(user->ip.s_addr) != INADDR_LOOPBACK)
+ if (irc_in_addr_is_valid(user->ip)
+ && !irc_in_addr_is_loopback(user->ip)
&& !user->uplink->burst)
sockcheck_queue_address(user->ip);
return 0;
sockcheck_read_conf(void)
{
dict_t my_node;
+ struct addrinfo *ai;
const char *str;
/* set the defaults here in case the entire record is missing */
str = database_get_data(my_node, "gline_duration", RECDB_QSTRING);
if (str) sockcheck_conf.gline_duration = ParseInterval(str);
str = database_get_data(my_node, "address", RECDB_QSTRING);
- if (str) {
- struct sockaddr_in *sin;
- unsigned long addr;
-
- sockcheck_conf.local_addr_len = sizeof(*sin);
- if (getipbyname(str, &addr)) {
- sin = malloc(sockcheck_conf.local_addr_len);
- sin->sin_family = AF_INET;
- sin->sin_port = 0;
- sin->sin_addr.s_addr = addr;
-#ifdef HAVE_SIN_LEN
- sin->sin_len = 0;
-#endif
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- sockcheck_conf.local_addr = sin;
- } else {
- log_module(PC_LOG, LOG_ERROR, "Error: Unable to get host named `%s', not checking a specific address.", str);
- sockcheck_conf.local_addr = NULL;
- }
+ if (!getaddrinfo(str, NULL, NULL, &ai)) {
+ sockcheck_conf.local_addr_len = ai->ai_addrlen;
+ sockcheck_conf.local_addr = calloc(1, ai->ai_addrlen);
+ memcpy(sockcheck_conf.local_addr, ai->ai_addr, ai->ai_addrlen);
+ } else {
+ sockcheck_conf.local_addr_len = 0;
+ sockcheck_conf.local_addr = NULL;
+ log_module(PC_LOG, LOG_ERROR, "Error: Unable to get host named `%s', not checking a specific address.", str);
}
}
}
static NICKSERV_FUNC(cmd_register)
{
+ irc_in_addr_t ip;
struct handle_info *hi;
const char *email_addr, *password;
int no_auth;
string_list_append(hi->masks, strdup("*@*"));
} else {
string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
- if (user->ip.s_addr && user->hostname[strspn(user->hostname, "0123456789.")])
+ if (irc_in_addr_is_valid(user->ip) && !irc_pton(&ip, NULL, user->hostname))
string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
}
#define KEY_ISSUED "issued"
#define IDENT_FORMAT "%s [%s@%s/%s]"
-#define IDENT_DATA(user) user->nick, user->ident, user->hostname, inet_ntoa(user->ip)
+#define IDENT_DATA(user) user->nick, user->ident, user->hostname, irc_ntoa(&user->ip)
#define MAX_CHANNELS_WHOIS 50
#define OSMSG_PART_REASON "%s has no reason."
#define OSMSG_KICK_REQUESTED "Kick requested by %s."
typedef struct opservDiscrim {
struct chanNode *channel;
- char *mask_nick, *mask_ident, *mask_host, *mask_info, *server, *ip_mask_str, *reason, *accountmask;
- unsigned long limit, ip_mask;
- struct in_addr ip_addr;
+ char *mask_nick, *mask_ident, *mask_host, *mask_info, *server, *reason, *accountmask;
+ irc_in_addr_t ip_mask;
+ unsigned long limit;
+ time_t min_ts, max_ts;
unsigned int min_level, max_level, domain_depth, duration, min_clones, min_channels, max_channels;
+ unsigned char ip_mask_bits;
unsigned int match_opers : 1, option_log : 1;
unsigned int chan_req_modes : 2, chan_no_modes : 2;
int authed : 2, info_space : 2;
- time_t min_ts, max_ts;
} *discrim_t;
struct discrim_and_source {
reply("OSMSG_WHOIS_HOST", target->ident, target->hostname);
if (IsFakeHost(target))
reply("OSMSG_WHOIS_FAKEHOST", target->fakehost);
- reply("OSMSG_WHOIS_IP", inet_ntoa(target->ip));
+ reply("OSMSG_WHOIS_IP", irc_ntoa(&target->ip));
if (target->modes) {
bpos = 0;
#define buffer_cat(str) (herelen = strlen(str), memcpy(buffer+bpos, str, herelen), bpos += herelen)
{
struct opserv_hostinfo *ohi;
struct gag_entry *gag;
+ char addr[IRC_NTOP_MAX_SIZE];
/* Check to see if we should ignore them entirely. */
if (IsLocal(user) || IsService(user))
}
/* Add to host info struct */
- if (!(ohi = dict_find(opserv_hostinfo_dict, inet_ntoa(user->ip), NULL))) {
+ irc_ntop(addr, sizeof(addr), &user->ip);
+ if (!(ohi = dict_find(opserv_hostinfo_dict, addr, NULL))) {
ohi = calloc(1, sizeof(*ohi));
- dict_insert(opserv_hostinfo_dict, strdup(inet_ntoa(user->ip)), ohi);
+ dict_insert(opserv_hostinfo_dict, strdup(addr), ohi);
userList_init(&ohi->clients);
}
userList_append(&ohi->clients, user);
}
/* Only warn or G-line if there's an untrusted max and their IP is sane. */
- if (opserv_conf.untrusted_max && user->ip.s_addr && (ntohl(user->ip.s_addr) != INADDR_LOOPBACK)) {
- struct trusted_host *th = dict_find(opserv_trusted_hosts, inet_ntoa(user->ip), NULL);
+ if (opserv_conf.untrusted_max
+ && irc_in_addr_is_valid(user->ip)
+ && !irc_in_addr_is_loopback(user->ip)) {
+ struct trusted_host *th = dict_find(opserv_trusted_hosts, addr, NULL);
unsigned int limit = th ? th->limit : opserv_conf.untrusted_max;
if (!limit) {
/* 0 means unlimited hosts */
send_message(ohi->clients.list[nn], opserv, "OSMSG_CLONE_WARNING");
} else if (ohi->clients.used > limit) {
char target[18];
- sprintf(target, "*@%s", inet_ntoa(user->ip));
+ sprintf(target, "*@%s", addr);
gline_add(opserv->nick, target, opserv_conf.clone_gline_duration, "AUTO Excessive connections from a single host.", now, 1);
}
}
opserv_user_cleanup(struct userNode *user, UNUSED_ARG(struct userNode *killer), UNUSED_ARG(const char *why))
{
struct opserv_hostinfo *ohi;
+ char addr[IRC_NTOP_MAX_SIZE];
if (IsLocal(user)) {
/* Try to remove it from the reserved nick dict without
dict_remove(opserv_reserved_nick_dict, user->nick);
return;
}
- if ((ohi = dict_find(opserv_hostinfo_dict, inet_ntoa(user->ip), NULL))) {
+ irc_ntop(addr, sizeof(addr), &user->ip);
+ if ((ohi = dict_find(opserv_hostinfo_dict, addr, NULL))) {
userList_remove(&ohi->clients, user);
- if (ohi->clients.used == 0) dict_remove(opserv_hostinfo_dict, inet_ntoa(user->ip));
+ if (ohi->clients.used == 0)
+ dict_remove(opserv_hostinfo_dict, addr);
}
}
{
unsigned long interval;
char *reason, *tmp;
- struct in_addr tmpaddr;
+ irc_in_addr_t tmpaddr;
unsigned int count;
if (dict_find(opserv_trusted_hosts, argv[1], NULL)) {
return 0;
}
- if (!inet_aton(argv[1], &tmpaddr)) {
+ if (!irc_pton(&tmpaddr, NULL, argv[1])) {
reply("OSMSG_BAD_IP", argv[1]);
return 0;
}
discrim->info_space = -1;
dupmask = strdup(hostmask);
if (split_ircmask(dupmask, &discrim->mask_nick, &discrim->mask_ident, &discrim->mask_host)) {
- if (discrim->mask_host && !discrim->mask_host[strspn(discrim->mask_host, "0123456789.?*")]) {
- if (!parse_ipmask(discrim->mask_host, &discrim->ip_addr, &discrim->ip_mask)) {
- log_module(OS_LOG, LOG_ERROR, "Couldn't parse %s as an IP mask!", discrim->mask_host);
- free(discrim);
- free(dupmask);
- return 0;
- }
- discrim->mask_host = 0;
- }
+ if (!irc_pton(&discrim->ip_mask, &discrim->ip_mask_bits, discrim->mask_host))
+ discrim->ip_mask_bits = 0;
matched = opserv_discrim_search(discrim, func, extra);
} else {
log_module(OS_LOG, LOG_ERROR, "Couldn't split IRC mask for gag %s!", hostmask);
} else if (irccasecmp(argv[i], "server") == 0) {
discrim->server = argv[++i];
} else if (irccasecmp(argv[i], "ip") == 0) {
- j = parse_ipmask(argv[++i], &discrim->ip_addr, &discrim->ip_mask);
- if (!j) discrim->ip_mask_str = argv[i];
+ j = irc_pton(&discrim->ip_mask, &discrim->ip_mask_bits, argv[++i]);
+ if (!j) {
+ send_message(user, opserv, "OSMSG_BAD_IP", argv[i]);
+ goto fail;
+ }
} else if (irccasecmp(argv[i], "account") == 0) {
if (discrim->authed == 0) {
send_message(user, opserv, "OSMSG_ACCOUNTMASK_AUTHED");
|| (discrim->mask_info && !match_ircglob(user->info, discrim->mask_info))
|| (discrim->server && !match_ircglob(user->uplink->name, discrim->server))
|| (discrim->accountmask && (!user->handle_info || !match_ircglob(user->handle_info->handle, discrim->accountmask)))
- || (discrim->ip_mask && !MATCH_IPMASK(user->ip, discrim->ip_addr, discrim->ip_mask))) {
+ || (discrim->ip_mask_bits && !irc_check_mask(&user->ip, &discrim->ip_mask, discrim->ip_mask_bits))
+ )
+ return 0;
+ if (discrim->channel && !GetUserMode(discrim->channel, user))
return 0;
- }
- if (discrim->channel && !GetUserMode(discrim->channel, user)) return 0;
access = user->handle_info ? user->handle_info->opserv_level : 0;
if ((access < discrim->min_level)
|| (access > discrim->max_level)) {
return 0;
}
- if (discrim->ip_mask_str) {
- if (!match_ircglob(inet_ntoa(user->ip), discrim->ip_mask_str)) return 0;
- }
if (discrim->min_clones > 1) {
- struct opserv_hostinfo *ohi = dict_find(opserv_hostinfo_dict, inet_ntoa(user->ip), NULL);
- if (!ohi || (ohi->clients.used < discrim->min_clones)) return 0;
+ struct opserv_hostinfo *ohi = dict_find(opserv_hostinfo_dict, irc_ntoa(&user->ip), NULL);
+ if (!ohi || (ohi->clients.used < discrim->min_clones))
+ return 0;
}
return 1;
}
userList_append(&matched, mn->user);
}
}
- } else if (discrim->ip_mask_str && !discrim->ip_mask_str[strcspn(discrim->ip_mask_str, "?*")]) {
- struct opserv_hostinfo *ohi = dict_find(opserv_hostinfo_dict, discrim->ip_mask_str, NULL);
+ } else if (discrim->ip_mask_bits == 128) {
+ struct opserv_hostinfo *ohi = dict_find(opserv_hostinfo_dict, irc_ntoa(&discrim->ip_mask), NULL);
if (!ohi) {
userList_clean(&matched);
return 0;
trace_domains_func(struct userNode *match, void *extra)
{
struct discrim_and_source *das = extra;
+ irc_in_addr_t ip;
unsigned long *count;
unsigned int depth;
char *hostname;
+ char ipmask[IRC_NTOP_MASK_MAX_SIZE];
- if (!match->hostname[strspn(match->hostname, "0123456789.")]) {
- char ipmask[16];
- unsigned long matchip = ntohl(match->ip.s_addr);
- /* raw IP address.. use up to first three octets of IP */
- switch (das->discrim->domain_depth) {
- default:
- snprintf(ipmask, sizeof(ipmask), "%lu.%lu.%lu.*", (matchip>>24)&255, (matchip>>16)&255, (matchip>>8)&255);
- break;
- case 2:
- snprintf(ipmask, sizeof(ipmask), "%lu.%lu.*", (matchip>>24)&255, (matchip>>16)&255);
- break;
- case 1:
- snprintf(ipmask, sizeof(ipmask), "%lu.*", (matchip>>24)&255);
- break;
- }
+ if (irc_pton(&ip, NULL, match->hostname)) {
+ if (irc_in_addr_is_ipv4(ip)) {
+ unsigned long matchip = ntohl(ip.in6_32[3]);
+ /* raw IP address.. use up to first three octets of IP */
+ switch (das->discrim->domain_depth) {
+ default:
+ snprintf(ipmask, sizeof(ipmask), "%lu.%lu.%lu.*", (matchip>>24)&255, (matchip>>16)&255, (matchip>>8)&255);
+ break;
+ case 2:
+ snprintf(ipmask, sizeof(ipmask), "%lu.%lu.*", (matchip>>24)&255, (matchip>>16)&255);
+ break;
+ case 1:
+ snprintf(ipmask, sizeof(ipmask), "%lu.*", (matchip>>24)&255);
+ break;
+ }
+ } else if (irc_in_addr_is_ipv6(ip)) {
+ switch (das->discrim->domain_depth) {
+ case 1: depth = 16; goto ipv6_pfx;
+ case 2: depth = 24; goto ipv6_pfx;
+ case 3: depth = 32; goto ipv6_pfx;
+ default: depth = das->discrim->domain_depth;
+ ipv6_pfx:
+ irc_ntop_mask(ipmask, sizeof(ipmask), &ip, depth);
+ }
+ } else safestrncpy(ipmask, match->hostname, sizeof(ipmask));
+ ipmask[sizeof(ipmask) - 1] = '\0';
hostname = ipmask;
} else {
hostname = match->hostname + strlen(match->hostname);
- for (depth=das->discrim->domain_depth;
+ for (depth=das->discrim->domain_depth;
depth && (hostname > match->hostname);
depth--) {
hostname--;
else
return;
- if (user->ip.s_addr)
+ if (irc_in_addr_is_valid(user->ip))
send_channel_notice(opserv_conf.staff_auth_channel, opserv, IDENT_FORMAT" authed to %s account %s", IDENT_DATA(user), type, user->handle_info->handle);
else
send_channel_notice(opserv_conf.staff_auth_channel, opserv, "%s [%s@%s] authed to %s account %s", user->nick, user->ident, user->hostname, type, user->handle_info->handle);
}
struct userNode *
-AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *userinfo, time_t timestamp, struct in_addr realip, const char *stamp) {
+AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *userinfo, time_t timestamp, irc_in_addr_t realip, const char *stamp) {
struct userNode *uNode, *oldUser;
unsigned int nn;
AddService(const char *nick, const char *modes, const char *desc, const char *hostname) {
time_t timestamp = now;
struct userNode *old_user = GetUserH(nick);
- struct in_addr ipaddr = { INADDR_LOOPBACK };
+ static const irc_in_addr_t ipaddr;
if (old_user) {
if (IsLocal(old_user))
return old_user;
AddClone(const char *nick, const char *ident, const char *hostname, const char *desc) {
time_t timestamp = now;
struct userNode *old_user = GetUserH(nick);
- struct in_addr ipaddr = { INADDR_LOOPBACK };
+ static const irc_in_addr_t ipaddr;
if (old_user) {
if (IsLocal(old_user))
return old_user;
modes[modelen] = 0;
putsock("NICK %s %d "FMT_TIME_T" +%s %s %s %s %d %u :%s",
user->nick, user->uplink->hops+2, user->timestamp, modes,
- user->ident, user->hostname, user->uplink->name, 0, ntohl(user->ip.s_addr), user->info);
+ user->ident, user->hostname, user->uplink->name, 0, ntohl(user->ip.in6_32[3]), user->info);
}
void
/* new nick from a server */
char id[8];
unsigned long stamp;
- struct in_addr ip;
+ irc_in_addr_t ip;
if (argc < 10) return 0;
stamp = strtoul(argv[8], NULL, 0);
if (stamp) inttobase64(id, stamp, IDLEN);
- ip.s_addr = (argc > 10) ? atoi(argv[9]) : 0;
+ if (argc > 10)
+ ip.in6_32[3] = htonl(atoi(argv[9]));
un = AddUser(GetServerH(argv[7]), argv[1], argv[5], argv[6], argv[4], argv[argc-1], atoi(argv[3]), ip, (stamp ? id : 0));
}
return 1;
log_module(MAIN_LOG, LOG_INFO, "Connecting to %s:%i...", addr, port);
- socket_io_fd = ioset_connect((struct sockaddr*)cManager.uplink->bind_addr, sizeof(struct sockaddr), addr, port, 1, 0, NULL);
+ socket_io_fd = ioset_connect(cManager.uplink->bind_addr, cManager.uplink->bind_addr_len, addr, port, 1, 0, NULL);
if (!socket_io_fd) {
log_module(MAIN_LOG, LOG_ERROR, "Connection to uplink failed: %s (%d)", strerror(errno), errno);
target->state = DISCONNECTED;
char *
generate_hostmask(struct userNode *user, int options)
{
- char *nickname, *ident, *hostname;
- char *mask;
+ irc_in_addr_t ip;
+ char *nickname, *ident, *hostname, *mask;
int len, ii;
/* figure out string parts */
} else if (IsHiddenHost(user) && user->handle_info && hidden_host_suffix && !(options & GENMASK_NO_HIDING)) {
hostname = alloca(strlen(user->handle_info->handle) + strlen(hidden_host_suffix) + 2);
sprintf(hostname, "%s.%s", user->handle_info->handle, hidden_host_suffix);
- } else if (options & GENMASK_STRICT_HOST) {
- if (options & GENMASK_BYIP)
- hostname = inet_ntoa(user->ip);
- } else if ((options & GENMASK_BYIP) || !hostname[strspn(hostname, "0123456789.")]) {
- /* Should generate an IP-based hostmask. By popular acclaim, a /16
- * hostmask is used by default. */
- unsigned masked_ip, mask, masklen;
- masklen = 16;
- mask = ~0 << masklen;
- masked_ip = ntohl(user->ip.s_addr) & mask;
- hostname = alloca(32);
- if (options & GENMASK_SRVXMASK) {
- sprintf(hostname, "%d.%d.%d.%d/%d", (masked_ip>>24)&0xFF, (masked_ip>>16)&0xFF, (masked_ip>>8)&0xFF, masked_ip&0xFF, masklen);
+ } else if (options & GENMASK_STRICT_HOST && options & GENMASK_BYIP) {
+ hostname = (char*)irc_ntoa(&user->ip);
+ } else if ((options & GENMASK_BYIP) || irc_pton(&ip, NULL, hostname)) {
+ /* Should generate an IP-based hostmask. */
+ hostname = alloca(IRC_NTOP_MAX_SIZE);
+ hostname[IRC_NTOP_MAX_SIZE-1] = '\0';
+ if (irc_in_addr_is_ipv4(user->ip)) {
+ /* By popular acclaim, a /16 hostmask is used. */
+ sprintf(hostname, "%d.%d.*", user->ip.in6_8[12], user->ip.in6_8[13]);
+ } else if (irc_in_addr_is_ipv6(user->ip)) {
+ /* Who knows what the default mask should be? Use a /48 to start with. */
+ sprintf(hostname, "%x:%x:%x:*", user->ip.in6[0], user->ip.in6[1], user->ip.in6[2]);
} else {
- int ofs = 0;
- for (ii=0; ii<4; ii++) {
- if (masklen) {
- ofs += sprintf(hostname+ofs, "%d.", (masked_ip>>24)&0xFF);
- masklen -= 8;
- masked_ip <<= 8;
- } else {
- ofs += sprintf(hostname+ofs, "*.");
- }
- }
- /* Truncate the last . */
- hostname[ofs-1] = 0;
+ /* Unknown type; just copy IP directly. */
+ irc_ntop(hostname, IRC_NTOP_MAX_SIZE, &user->ip);
}
} else {
int cnt;
}
}
+static void
+irc_p10_pton(irc_in_addr_t *ip, const char *input)
+{
+ if (strlen(input) == 6) {
+ unsigned int value;
+ memset(ip, 0, 6 * sizeof(ip->in6[0]));
+ value = base64toint(input, 6);
+ ip->in6[6] = htons(value >> 16);
+ ip->in6[7] = htons(value & 65535);
+ } else {
+ unsigned int pos = 0;
+ do {
+ if (*input == '_') {
+ unsigned int left;
+ for (left = (25 - strlen(input)) / 3; left; left--)
+ ip->in6[pos++] = 0;
+ input++;
+ } else {
+ ip->in6[pos++] = ntohs(base64toint(input, 3));
+ input += 3;
+ }
+ } while (pos < 8);
+ }
+}
+
+static void
+irc_p10_ntop(char *output, const irc_in_addr_t *ip)
+{
+ if (irc_in_addr_is_ipv4(*ip)) {
+ unsigned int in4;
+ in4 = (ntohs(ip->in6[6]) << 16) | ntohs(ip->in6[7]);
+ inttobase64(output, in4, 6);
+ output[6] = '\0';
+ } else if (irc_in_addr_is_ipv6(*ip)) {
+ unsigned int max_start, max_zeros, curr_zeros, zero, ii;
+ /* Can start by printing out the leading non-zero parts. */
+ for (ii = 0; (ip->in6[ii]) && (ii < 8); ++ii) {
+ inttobase64(output, ntohs(ip->in6[ii]), 3);
+ output += 3;
+ }
+ /* Find the longest run of zeros. */
+ for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) {
+ if (!ip->in6[ii])
+ curr_zeros++;
+ else if (curr_zeros > max_zeros) {
+ max_start = ii - curr_zeros;
+ max_zeros = curr_zeros;
+ curr_zeros = 0;
+ }
+ }
+ if (curr_zeros > max_zeros) {
+ max_start = ii - curr_zeros;
+ max_zeros = curr_zeros;
+ curr_zeros = 0;
+ }
+ /* Print the rest of the address */
+ for (ii = zero; ii < 8; ) {
+ if ((ii == max_start) && max_zeros) {
+ *output++ = '_';
+ ii += max_zeros;
+ } else {
+ inttobase64(output, ntohs(ip->in6[ii]), 3);
+ output += 3;
+ }
+ }
+ *output = '\0';
+ } else {
+ strcpy(output, "???");
+ }
+}
+
void
irc_user(struct userNode *user)
{
- char b64ip[7];
+ char b64ip[25];
if (!user)
return;
- inttobase64(b64ip, ntohl(user->ip.s_addr), 6);
+ irc_p10_ntop(b64ip, &user->ip);
if (user->modes) {
int modelen;
char modes[32];
safestrncpy(uNode->info, userinfo, sizeof(uNode->info));
safestrncpy(uNode->hostname, hostname, sizeof(uNode->hostname));
safestrncpy(uNode->numeric, numeric, sizeof(uNode->numeric));
- uNode->ip.s_addr = htonl(base64toint(realip, 6));
+ irc_p10_pton(&uNode->ip, realip);
uNode->timestamp = timestamp;
modeList_init(&uNode->channels);
uNode->uplink = uplink;
char *host;
int port;
- struct sockaddr_in *bind_addr;
+ struct sockaddr *bind_addr;
int bind_addr_len;
char *password;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
+ 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,62, 0,63, 0, 0,
0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50,51, 0, 0, 0, 0, 0
};
+static const unsigned char ctype[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
+ 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
unsigned long int
base64toint(const char* s, int count)
{
return buf;
}
+unsigned int
+irc_ntop(char *output, unsigned int out_size, const irc_in_addr_t *addr)
+{
+ static const char hexdigits[] = "0123456789abcdef";
+ unsigned int pos;
+
+ assert(output);
+ assert(addr);
+
+ if (irc_in_addr_is_ipv4(*addr)) {
+ unsigned int ip4;
+
+ ip4 = (ntohs(addr->in6[6]) << 16) | ntohs(addr->in6[7]);
+ pos = snprintf(output, out_size, "%u.%u.%u.%u", (ip4 >> 24), (ip4 >> 16) & 255, (ip4 >> 8) & 255, ip4 & 255);
+ } else {
+ unsigned int part, max_start, max_zeros, curr_zeros, ii;
+
+ /* Find longest run of zeros. */
+ for (max_start = max_zeros = curr_zeros = ii = 0; ii < 8; ++ii) {
+ if (!addr->in6[ii])
+ curr_zeros++;
+ else if (curr_zeros > max_zeros) {
+ max_start = ii - curr_zeros;
+ max_zeros = curr_zeros;
+ curr_zeros = 0;
+ }
+ }
+ if (curr_zeros > max_zeros) {
+ max_start = ii - curr_zeros;
+ max_zeros = curr_zeros;
+ }
+
+ /* Print out address. */
+#define APPEND(CH) do { if (pos < out_size) output[pos] = (CH); pos++; } while (0)
+ for (pos = 0, ii = 0; ii < 8; ++ii) {
+ if ((max_zeros > 0) && (ii == max_start)) {
+ if (ii == 0)
+ APPEND(':');
+ APPEND(':');
+ ii += max_zeros - 1;
+ continue;
+ }
+ part = ntohs(addr->in6[ii]);
+ if (part >= 0x1000)
+ APPEND(hexdigits[part >> 12]);
+ if (part >= 0x100)
+ APPEND(hexdigits[(part >> 8) & 15]);
+ if (part >= 0x10)
+ APPEND(hexdigits[(part >> 4) & 15]);
+ APPEND(hexdigits[part & 15]);
+ if (ii < 7)
+ APPEND(':');
+ }
+#undef APPEND
+ output[pos < out_size ? pos : out_size - 1] = '\0';
+ }
+
+ return pos;
+}
+
+unsigned int
+irc_ntop_mask(char *output, unsigned int out_size, const irc_in_addr_t *addr, unsigned char bits)
+{
+ char base_addr[IRC_NTOP_MAX_SIZE];
+ int len;
+
+ if (bits >= 128)
+ return irc_ntop(output, out_size, addr);
+ if (!irc_ntop(base_addr, sizeof(base_addr), addr))
+ return 0;
+ len = snprintf(output, out_size, "%s/%d", base_addr, bits);
+ if ((unsigned int)len >= out_size)
+ return 0;
+ return len;
+}
+
+static unsigned int
+irc_pton_ip4(const char *input, unsigned char *pbits, uint32_t *output)
+{
+ unsigned int dots = 0, pos = 0, part = 0, ip = 0, bits = 32;
+
+ /* Intentionally no support for bizarre IPv4 formats (plain
+ * integers, octal or hex components) -- only vanilla dotted
+ * decimal quads, optionally with trailing /nn.
+ */
+ if (input[0] == '.')
+ return 0;
+ while (1) switch (input[pos]) {
+ default:
+ if (dots < 3)
+ return 0;
+ out:
+ ip |= part << (24 - 8 * dots++);
+ *output = htonl(ip);
+ if (pbits)
+ *pbits = bits;
+ return pos;
+ case '.':
+ if (input[++pos] == '.')
+ return 0;
+ ip |= part << (24 - 8 * dots++);
+ part = 0;
+ if (input[pos] == '*') {
+ while (input[++pos] == '*') ;
+ if (input[pos] != '\0')
+ return 0;
+ if (pbits)
+ *pbits = dots * 8;
+ *output = htonl(ip);
+ return pos;
+ }
+ break;
+ case '/':
+ if (!pbits || !isdigit(input[pos + 1]))
+ return 0;
+ for (bits = 0; isdigit(input[++pos]); )
+ bits = bits * 10 + input[pos] - '0';
+ if (bits > 32)
+ return 0;
+ goto out;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ part = part * 10 + input[pos++] - '0';
+ if (part > 255)
+ return 0;
+ break;
+ }
+}
+
+unsigned int
+irc_pton(irc_in_addr_t *addr, unsigned char *bits, const char *input)
+{
+ const char *part_start = NULL;
+ char *colon;
+ char *dot;
+ unsigned int part = 0, pos = 0, ii = 0, cpos = 8;
+
+ assert(input);
+ memset(addr, 0, sizeof(*addr));
+ colon = strchr(input, ':');
+ dot = strchr(input, '.');
+
+ if (colon && (!dot || (dot > colon))) {
+ /* Parse IPv6, possibly like ::127.0.0.1.
+ * This is pretty straightforward; the only trick is borrowed
+ * from Paul Vixie (BIND): when it sees a "::" continue as if
+ * it were a single ":", but note where it happened, and fill
+ * with zeros afterwards.
+ */
+ if (input[pos] == ':') {
+ if ((input[pos+1] != ':') || (input[pos+2] == ':'))
+ return 0;
+ cpos = 0;
+ pos += 2;
+ part_start = input + pos;
+ }
+ while (ii < 8) switch (input[pos]) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ part = (part << 4) | (ctype[(unsigned char)input[pos++]] & 15);
+ if (part > 0xffff)
+ return 0;
+ break;
+ case ':':
+ part_start = input + ++pos;
+ if (input[pos] == '.')
+ return 0;
+ addr->in6[ii++] = htons(part);
+ part = 0;
+ if (input[pos] == ':') {
+ if (cpos < 8)
+ return 0;
+ cpos = ii;
+ }
+ break;
+ case '.': {
+ uint32_t ip4;
+ unsigned int len;
+ len = irc_pton_ip4(part_start, bits, &ip4);
+ if (!len || (ii > 6))
+ return 0;
+ memcpy(addr->in6 + ii, &ip4, sizeof(ip4));
+ if (bits)
+ *bits += 96;
+ ii += 2;
+ pos = part_start + len - input;
+ goto finish;
+ }
+ case '/':
+ if (!bits || !isdigit(input[pos + 1]))
+ return 0;
+ addr->in6[ii++] = htons(part);
+ for (part = 0; isdigit(input[++pos]); )
+ part = part * 10 + input[pos] - '0';
+ if (part > 128)
+ return 0;
+ *bits = part;
+ goto finish;
+ case '*':
+ while (input[++pos] == '*') ;
+ if (input[pos] != '\0' || cpos < 8)
+ return 0;
+ if (bits)
+ *bits = ii * 16;
+ return pos;
+ default:
+ addr->in6[ii++] = htons(part);
+ if (cpos == 8 && ii < 8)
+ return 0;
+ if (bits)
+ *bits = 128;
+ goto finish;
+ }
+ finish:
+ /* Shift stuff after "::" up and fill middle with zeros. */
+ if (cpos < 8) {
+ unsigned int jj;
+ for (jj = 0; jj < ii - cpos; jj++)
+ addr->in6[7 - jj] = addr->in6[ii - jj - 1];
+ for (jj = 0; jj < 8 - ii; jj++)
+ addr->in6[cpos + jj] = 0;
+ }
+ } else if (dot) {
+ unsigned int ip4;
+ pos = irc_pton_ip4(input, bits, &ip4);
+ if (pos) {
+ addr->in6[5] = htons(65535);
+ addr->in6[6] = htons(ntohl(ip4) >> 16);
+ addr->in6[7] = htons(ntohl(ip4) & 65535);
+ if (bits)
+ *bits += 96;
+ }
+ } else if (input[0] == '*') {
+ while (input[++pos] == '*') ;
+ if (input[pos] != '\0')
+ return 0;
+ if (bits)
+ *bits = 0;
+ }
+ return pos;
+}
+
+const char *irc_ntoa(const irc_in_addr_t *addr)
+{
+ static char ntoa[IRC_NTOP_MAX_SIZE];
+ irc_ntop(ntoa, sizeof(ntoa), addr);
+ return ntoa;
+}
+
+unsigned int
+irc_check_mask(const irc_in_addr_t *check, const irc_in_addr_t *mask, unsigned char bits)
+{
+ unsigned int ii;
+
+ for (ii = 0; (ii < 8) && (bits > 16); bits -= 16, ++ii)
+ if (check->in6[ii] != mask->in6[ii])
+ return 0;
+ if (ii < 8 && bits > 0
+ && (ntohs(check->in6[ii] ^ mask->in6[ii]) >> (16 - bits)))
+ return 0;
+ return 1;
+}
+
static char irc_tolower[256];
#undef tolower
#define tolower(X) irc_tolower[(unsigned char)(X)]
glob = marker + 1;
/* If it might be an IP glob, test that. */
if (!glob[strspn(glob, "0123456789./*?")]
- && match_ircglob(inet_ntoa(user->ip), glob))
+ && match_ircglob(irc_ntoa(&user->ip), glob))
return 1;
/* Check for a fakehost match. */
if (IsFakeHost(user) && match_ircglob(user->fakehost, glob))
- return 1;
+ return 1;
/* Check for an account match. */
if (hidden_host_suffix && user->handle_info) {
char hidden_host[HOSTLEN+1];
return accum + partial;
}
-int
-parse_ipmask(const char *str, struct in_addr *addr, unsigned long *mask)
-{
- int accum, pos;
- unsigned long t_a, t_m;
-
- t_a = t_m = pos = 0;
- if (addr)
- addr->s_addr = htonl(t_a);
- if (mask)
- *mask = t_m;
- while (*str) {
- if (!isdigit(*str))
- return 0;
- accum = 0;
- do {
- accum = (accum * 10) + *str++ - '0';
- } while (isdigit(*str));
- if (accum > 255)
- return 0;
- t_a = (t_a << 8) | accum;
- t_m = (t_m << 8) | 255;
- pos += 8;
- if (*str == '.') {
- str++;
- while (*str == '*') {
- str++;
- if (*str == '.') {
- t_a <<= 8;
- t_m <<= 8;
- pos += 8;
- str++;
- } else if (*str == 0) {
- t_a <<= 32 - pos;
- t_m <<= 32 - pos;
- pos = 32;
- goto out;
- } else
- return 0;
- }
- } else if (*str == '/') {
- int start = pos;
- accum = 0;
- do {
- accum = (accum * 10) + *str++ - '0';
- } while (isdigit(*str));
- while (pos < start+accum && pos < 32) {
- t_a = (t_a << 1) | 0;
- t_m = (t_m << 1) | 1;
- pos++;
- }
- if (pos != start+accum)
- return 0;
- } else if (*str == 0)
- break;
- else
- return 0;
- }
-out:
- if (pos != 32)
- return 0;
- if (addr)
- addr->s_addr = htonl(t_a);
- if (mask)
- *mask = t_m;
- return 1;
-}
-
char *
unsplit_string(char *set[], unsigned int max, char *dest)
{