From f1ec26a07ce7b93b19dab0f9f330f01205bc4e82 Mon Sep 17 00:00:00 2001 From: binki Date: Fri, 28 May 2010 04:30:22 +0000 Subject: [PATCH] - Partially fixed bug where IPv4 addresses were randomly mishandled by the cgiirc code, resulting in the sockhost/hostmask being set to something like ::ffff:127.0.0.1, which confused the s2s protocol. Reported by tabrisnet (#0003907). Also, reject incorrectly formed hostnames from WEBIRC command. --- Changes | 4 ++++ include/h.h | 1 + src/modules/m_pass.c | 39 +++++++++++++++++++++++++-------------- src/res.c | 5 +++++ src/s_bsd.c | 2 +- src/socket.c | 3 +++ 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/Changes b/Changes index 1dc23c985..84ed2b5f4 100644 --- a/Changes +++ b/Changes @@ -1971,3 +1971,7 @@ - Fixed bug in CVS where the ban exempt (+e) handling was reversed: if a non-matching +e was present, one could walk through bans. Reported by tabrisnet (#0003909). Bug was caused by chained/stacked extbans. +- Partially fixed bug where IPv4 addresses were randomly mishandled by the + cgiirc code, resulting in the sockhost/hostmask being set to something like + ::ffff:127.0.0.1, which confused the s2s protocol. Reported by tabrisnet + (#0003907). Also, reject incorrectly formed hostnames from WEBIRC command. diff --git a/include/h.h b/include/h.h index ee68650da..fce954c70 100644 --- a/include/h.h +++ b/include/h.h @@ -256,6 +256,7 @@ extern int get_sockerr(aClient *); extern int inetport(aClient *, char *, int); extern void init_sys(); extern void init_modef(); +extern int verify_hostname(char *name); #ifdef NO_FDLIST extern int read_message(time_t); diff --git a/src/modules/m_pass.c b/src/modules/m_pass.c index ca03f9fc8..76c2ba688 100644 --- a/src/modules/m_pass.c +++ b/src/modules/m_pass.c @@ -148,8 +148,9 @@ ConfigItem_ban *bconf; int docgiirc(aClient *cptr, char *ip, char *host) { #ifdef INET6 -char ipbuf[64], crap[32]; + char ipbuf[64]; #endif + char *sockhost; if (IsCGIIRC(cptr)) return exit_client(cptr, cptr, &me, "Double CGI:IRC request (already identified)"); @@ -157,18 +158,20 @@ char ipbuf[64], crap[32]; if (host && !strcmp(ip, host)) host = NULL; /* host did not resolve, make it NULL */ - /* STEP 1: Update cptr->ip */ -#ifdef INET6 - /* Transform ipv4 to ::ffff:ipv4 if needed */ - if (inet_pton(AF_INET, ip, crap) != 0) + /* STEP 1: Update cptr->ip + inet_pton() returns 1 on success, 0 on bad input, -1 on bad AF */ + if(inet_pton(AFINET, ip, &cptr->ip) != 1) { - snprintf(ipbuf, sizeof(ipbuf), "::ffff:%s", ip); - ip = ipbuf; - } -#endif - - if (inet_pton(AFINET, ip, &cptr->ip) <= 0) +#ifndef INET6 + /* then we have an invalid IP */ return exit_client(cptr, cptr, &me, "Invalid IP address"); +#else + /* The address may be IPv4. We have to try ::ffff:ipv4 */ + snprintf(ipbuf, sizeof(ipbuf), "::ffff:%s", ip); + if(inet_pton(AFINET, ipbuf, &cptr->ip) != 1) + return exit_client(cptr, cptr, &me, "Invalid IP address"); +#endif + } /* STEP 2: Update GetIP() */ if (cptr->user) @@ -187,11 +190,19 @@ char ipbuf[64], crap[32]; cptr->hostp = NULL; } /* (create new) */ - if (host) + if (host && verify_hostname(host)) cptr->hostp = unreal_create_hostent(host, &cptr->ip); - /* STEP 4: Update sockhost */ - strlcpy(cptr->sockhost, ip, sizeof(cptr->sockhost)); + /* STEP 4: Update sockhost + Make sure that if this any IPv4 address is _not_ prefixed with + "::ffff:" by using Inet_ia2p(). + */ + sockhost = Inet_ia2p(&cptr->ip); + if(!sockhost) + { + return exit_client(cptr, cptr, &me, "Error processing CGI:IRC IP address."); + } + strlcpy(cptr->sockhost, sockhost, sizeof(cptr->sockhost)); SetCGIIRC(cptr); diff --git a/src/res.c b/src/res.c index 38e4618dd..3a3213dcf 100644 --- a/src/res.c +++ b/src/res.c @@ -282,6 +282,11 @@ char ipv6 = r->ipv6; #endif } +/* + returns: + 1 = good hostname + 0 = bad hostname + */ int verify_hostname(char *name) { char *p; diff --git a/src/s_bsd.c b/src/s_bsd.c index c4a0d5f46..ff49081ee 100644 --- a/src/s_bsd.c +++ b/src/s_bsd.c @@ -1041,7 +1041,7 @@ void set_sock_opts(int fd, aClient *cptr) /* We deal with both IPv4 and IPv6 in one (listen) socket. * This used to be on by default, but FreeBSD, and much later Linux * sometimes as well, seem to default it to IPv6 only ('1'). - * We now have this new fancy option to turn it on in Unreal, + * We now have this new fancy option to turn it off in Unreal, * instead of requiring our users to sysctl. */ opt = 0; diff --git a/src/socket.c b/src/socket.c index 8c1d69f1f..eb004a0dc 100644 --- a/src/socket.c +++ b/src/socket.c @@ -199,6 +199,9 @@ char *Inet_si2p(struct SOCKADDR_IN *sin) return (Inet_si2pB(sin, buf, sizeof(buf))); } +/* + May return NULL if inet_ntop() fails. + */ char *Inet_ia2p(struct IN_ADDR *ia) { #ifndef INET6