X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fconn.c;h=07f26f319ca2a4ff8a646202d7e2d001fe5c2408;hp=4a2f49c1aae46d75644daab94c0d61ff0b2b34f2;hb=3a3b3225d42ede7a062fa5e4403a7f445baf518b;hpb=765c2f26ea29d5930d19dab5307c302e473e1120 diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c index 4a2f49c1..07f26f31 100644 --- a/src/ngircd/conn.c +++ b/src/ngircd/conn.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. * * 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 @@ -47,10 +47,6 @@ # include #endif -#ifdef HAVE_STDINT_H -# include /* e.g. for Mac OS X */ -#endif - #ifdef TCPWRAP # include /* for TCP Wrappers */ #endif @@ -67,6 +63,7 @@ #include "client.h" #include "class.h" #include "conf.h" +#include "conn-encoding.h" #include "conn-ssl.h" #include "conn-zip.h" #include "conn-func.h" @@ -82,13 +79,13 @@ #define SERVER_WAIT (NONE - 1) #define MAX_COMMANDS 3 -#define MAX_COMMANDS_SERVER 10 -#define MAX_COMMANDS_SERVICE MAX_COMMANDS_SERVER +#define MAX_COMMANDS_SERVER_MIN 10 +#define MAX_COMMANDS_SERVICE 10 static bool Handle_Write PARAMS(( CONN_ID Idx )); static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len )); -static int New_Connection PARAMS(( int Sock )); +static int New_Connection PARAMS(( int Sock, bool IsSSL )); static CONN_ID Socket2Index PARAMS(( int Sock )); static void Read_Request PARAMS(( CONN_ID Idx )); static unsigned int Handle_Buffer PARAMS(( CONN_ID Idx )); @@ -134,7 +131,7 @@ static void cb_listen(int sock, short irrelevant) { (void) irrelevant; - (void) New_Connection(sock); + (void) New_Connection(sock, false); } @@ -152,7 +149,7 @@ cb_listen_ssl(int sock, short irrelevant) int fd; (void) irrelevant; - fd = New_Connection(sock); + fd = New_Connection(sock, true); if (fd < 0) return; io_event_setcb(My_Connections[fd].sock, cb_clientserver_ssl); @@ -208,7 +205,7 @@ cb_connserver(int sock, UNUSED short what) My_Connections[idx].host, Conf_Server[server].port, idx, strerror(err)); - Conn_Close(idx, "Can't connect!", NULL, false); + Conn_Close(idx, "Can't connect", NULL, false); if (ng_ipaddr_af(&Conf_Server[server].dst_addr[0])) { /* more addresses to try... */ @@ -285,7 +282,7 @@ cb_connserver_login_ssl(int sock, short unused) return; case -1: Log(LOG_ERR, "SSL connection on socket %d failed!", sock); - Conn_Close(idx, "Can't connect!", NULL, false); + Conn_Close(idx, "Can't connect", NULL, false); return; } @@ -370,7 +367,7 @@ cb_clientserver_ssl(int sock, short what) /** - * Initialite connecion module. + * Initialize connecion module. */ GLOBAL void Conn_Init( void ) @@ -571,7 +568,7 @@ InitSinaddrListenAddr(ng_ipaddr_t *addr, const char *listen_addrstr, UINT16 Port ret = ng_ipaddr_init(addr, listen_addrstr, Port); if (!ret) { assert(listen_addrstr); - Log(LOG_CRIT, "Can't bind to [%s]:%u: can't convert ip address \"%s\"", + Log(LOG_CRIT, "Can't bind to [%s]:%u: can't convert ip address \"%s\"!", listen_addrstr, Port, listen_addrstr); } return ret; @@ -623,8 +620,9 @@ NewListener(const char *listen_addr, UINT16 Port) af = ng_ipaddr_af(&addr); sock = socket(af, SOCK_STREAM, 0); - if( sock < 0 ) { - Log(LOG_CRIT, "Can't create socket (af %d) : %s!", af, strerror(errno)); + if (sock < 0) { + Log(LOG_CRIT, "Can't create socket (af %d) : %s!", af, + strerror(errno)); return -1; } @@ -634,22 +632,23 @@ NewListener(const char *listen_addr, UINT16 Port) return -1; if (bind(sock, (struct sockaddr *)&addr, ng_ipaddr_salen(&addr)) != 0) { - Log(LOG_CRIT, "Can't bind socket to address %s:%d - %s", - ng_ipaddr_tostr(&addr), Port, strerror(errno)); + Log(LOG_CRIT, "Can't bind socket to address %s:%d - %s!", + ng_ipaddr_tostr(&addr), Port, strerror(errno)); close(sock); return -1; } - if( listen( sock, 10 ) != 0 ) { - Log( LOG_CRIT, "Can't listen on socket: %s!", strerror( errno )); - close( sock ); + if (listen(sock, 10) != 0) { + Log(LOG_CRIT, "Can't listen on socket: %s!", strerror(errno)); + close(sock); return -1; } /* keep fd in list so we can close it when ngircd restarts/shuts down */ - if (!array_catb( &My_Listeners,(char*) &sock, sizeof(int) )) { - Log( LOG_CRIT, "Can't add socket to My_Listeners array: %s!", strerror( errno )); - close( sock ); + if (!array_catb(&My_Listeners, (char *)&sock, sizeof(int))) { + Log(LOG_CRIT, "Can't add socket to My_Listeners array: %s!", + strerror(errno)); + close(sock); return -1; } @@ -865,6 +864,9 @@ va_dcl #endif { char buffer[COMMAND_LEN]; +#ifdef ICONV + char *ptr, *message; +#endif size_t len; bool ok; va_list ap; @@ -905,6 +907,16 @@ va_dcl CUT_TXTSUFFIX); } +#ifdef ICONV + ptr = strchr(buffer + 1, ':'); + if (ptr) { + ptr++; + message = Conn_EncodingTo(Idx, ptr); + if (message != ptr) + strlcpy(ptr, message, sizeof(buffer) - (ptr - buffer)); + } +#endif + #ifdef SNIFFER if (NGIRCd_Sniffer) Log(LOG_DEBUG, " -> connection %d: '%s'.", Idx, buffer); @@ -918,6 +930,30 @@ va_dcl return ok; } /* Conn_WriteStr */ +GLOBAL char* +Conn_Password( CONN_ID Idx ) +{ + assert( Idx > NONE ); + if (My_Connections[Idx].pwd == NULL) + return (char*)"\0"; + else + return My_Connections[Idx].pwd; +} /* Conn_Password */ + +GLOBAL void +Conn_SetPassword( CONN_ID Idx, const char *Pwd ) +{ + assert( Idx > NONE ); + + if (My_Connections[Idx].pwd) + free(My_Connections[Idx].pwd); + + My_Connections[Idx].pwd = strdup(Pwd); + if (My_Connections[Idx].pwd == NULL) { + Log(LOG_EMERG, "Can't allocate memory! [Conn_SetPassword]"); + exit(1); + } +} /* Conn_SetPassword */ /** * Append Data to the outbound write buffer of a connection. @@ -936,22 +972,25 @@ Conn_Write( CONN_ID Idx, char *Data, size_t Len ) assert( Data != NULL ); assert( Len > 0 ); - c = Conn_GetClient(Idx); - assert( c != NULL); - - /* Servers do get special write buffer limits, so they can generate - * all the messages that are required while peering. */ - if (Client_Type(c) == CLIENT_SERVER) - writebuf_limit = WRITEBUFFER_SLINK_LEN; - /* Is the socket still open? A previous call to Conn_Write() * may have closed the connection due to a fatal error. * In this case it is sufficient to return an error, as well. */ - if( My_Connections[Idx].sock <= NONE ) { + if (My_Connections[Idx].sock <= NONE) { LogDebug("Skipped write on closed socket (connection %d).", Idx); return false; } + /* Make sure that there still exists a CLIENT structure associated + * with this connection and check if this is a server or not: */ + c = Conn_GetClient(Idx); + if (c) { + /* Servers do get special write buffer limits, so they can + * generate all the messages that are required while peering. */ + if (Client_Type(c) == CLIENT_SERVER) + writebuf_limit = WRITEBUFFER_SLINK_LEN; + } else + LogDebug("Write on socket without client (connection %d)!?", Idx); + #ifdef ZLIB if ( Conn_OPTION_ISSET( &My_Connections[Idx], CONN_ZIP )) { /* Compressed link: @@ -1014,7 +1053,7 @@ Conn_Write( CONN_ID Idx, char *Data, size_t Len ) GLOBAL void Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClient ) { - /* Close connection. Open pipes of asyncronous resolver + /* Close connection. Open pipes of asynchronous resolver * sub-processes are closed down. */ CLIENT *c; @@ -1041,7 +1080,7 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie Conn_OPTION_ADD( &My_Connections[Idx], CONN_ISCLOSING ); port = ng_ipaddr_getport(&My_Connections[Idx].addr); - Log(LOG_INFO, "Shutting down connection %d (%s) with %s:%d ...", Idx, + Log(LOG_INFO, "Shutting down connection %d (%s) with \"%s:%d\" ...", Idx, LogMsg ? LogMsg : FwdMsg, My_Connections[Idx].host, port); /* Search client, if any */ @@ -1115,7 +1154,7 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie in_p = (int)(( in_k * 100 ) / in_z_k ); out_p = (int)(( out_k * 100 ) / out_z_k ); Log(LOG_INFO, - "Connection %d with %s:%d closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).", + "Connection %d with \"%s:%d\" closed (in: %.1fk/%.1fk/%d%%, out: %.1fk/%.1fk/%d%%).", Idx, My_Connections[Idx].host, port, in_k, in_z_k, in_p, out_k, out_z_k, out_p); } @@ -1123,7 +1162,7 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie #endif { Log(LOG_INFO, - "Connection %d with %s:%d closed (in: %.1fk, out: %.1fk).", + "Connection %d with \"%s:%d\" closed (in: %.1fk, out: %.1fk).", Idx, My_Connections[Idx].host, port, in_k, out_k); } @@ -1143,6 +1182,8 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie array_free(&My_Connections[Idx].rbuf); array_free(&My_Connections[Idx].wbuf); + if (My_Connections[Idx].pwd != NULL) + free(My_Connections[Idx].pwd); /* Clean up connection structure (=free it) */ Init_Conn_Struct( Idx ); @@ -1223,6 +1264,20 @@ Conn_SyncServerStruct(void) } /* SyncServerStruct */ +/** + * Get IP address string of a connection. + * + * @param Idx Connection index. + * @return Pointer to a global buffer containing the IP address as string. + */ +GLOBAL const char * +Conn_GetIPAInfo(CONN_ID Idx) +{ + assert(Idx > NONE); + return ng_ipaddr_tostr(&My_Connections[Idx].addr); +} + + /** * Send out data of write buffer; connect new sockets. * @@ -1319,17 +1374,18 @@ Count_Connections(ng_ipaddr_t *a) * Initialize new client connection on a listening socket. * * @param Sock Listening socket descriptor. + * @param IsSSL true if this socket expects SSL-encrypted data. * @returns Accepted socket descriptor or -1 on error. */ static int -New_Connection(int Sock) +New_Connection(int Sock, UNUSED bool IsSSL) { #ifdef TCPWRAP struct request_info req; #endif ng_ipaddr_t new_addr; char ip_str[NG_INET_ADDRSTRLEN]; - int new_sock, new_sock_len, identsock; + int new_sock, new_sock_len; CLIENT *c; long cnt; @@ -1421,7 +1477,7 @@ New_Connection(int Sock) return -1; } - c = Client_NewLocal(new_sock, ip_str, CLIENT_UNKNOWN, false); + c = Client_NewLocal(new_sock, NULL, CLIENT_UNKNOWN, false); if (!c) { Log(LOG_ALERT, "Can't accept connection: can't create client structure!"); @@ -1446,33 +1502,59 @@ New_Connection(int Sock) Client_SetHostname(c, My_Connections[new_sock].host); - Log(LOG_INFO, "Accepted connection %d from %s:%d on socket %d.", + Log(LOG_INFO, "Accepted connection %d from \"%s:%d\" on socket %d.", new_sock, My_Connections[new_sock].host, ng_ipaddr_getport(&new_addr), Sock); + Account_Connection(); + +#ifdef SSL_SUPPORT + /* Delay connection initalization until SSL handshake is finished */ + if (!IsSSL) +#endif + Conn_StartLogin(new_sock); + + return new_sock; +} /* New_Connection */ + + +/** + * Finish connection initialization, start resolver subprocess. + * + * @param Idx Connection index. + */ +GLOBAL void +Conn_StartLogin(CONN_ID Idx) +{ + int ident_sock = -1; + + assert(Idx >= 0); + + /* Nothing to do if DNS (and resolver subprocess) is disabled */ + if (!Conf_DNS) + return; - identsock = new_sock; #ifdef IDENTAUTH - if (!Conf_Ident) - identsock = -1; + /* Should we make an IDENT request? */ + if (Conf_Ident) + ident_sock = My_Connections[Idx].sock; #endif - if (Conf_DNS) { - if (Conf_NoticeAuth) { + + if (Conf_NoticeAuth) { + /* Send "NOTICE AUTH" messages to the client */ #ifdef IDENTAUTH - if (Conf_Ident) - (void)Conn_WriteStr(new_sock, - "NOTICE AUTH :*** Looking up your hostname and checking ident"); - else + if (Conf_Ident) + (void)Conn_WriteStr(Idx, + "NOTICE AUTH :*** Looking up your hostname and checking ident"); + else #endif - (void)Conn_WriteStr(new_sock, - "NOTICE AUTH :*** Looking up your hostname"); - } - Resolve_Addr(&My_Connections[new_sock].proc_stat, &new_addr, - identsock, cb_Read_Resolver_Result); + (void)Conn_WriteStr(Idx, + "NOTICE AUTH :*** Looking up your hostname"); + (void)Handle_Write(Idx); } - Account_Connection(); - return new_sock; -} /* New_Connection */ + Resolve_Addr(&My_Connections[Idx].proc_stat, &My_Connections[Idx].addr, + ident_sock, cb_Read_Resolver_Result); +} /** @@ -1549,13 +1631,10 @@ Read_Request( CONN_ID Idx ) #endif len = read(My_Connections[Idx].sock, readbuf, sizeof(readbuf)); if (len == 0) { - Log(LOG_INFO, "%s:%u (%s) is closing the connection ...", - My_Connections[Idx].host, - (unsigned int) ng_ipaddr_getport(&My_Connections[Idx].addr), - ng_ipaddr_tostr(&My_Connections[Idx].addr)); - Conn_Close(Idx, - "Socket closed!", "Client closed connection", - false); + LogDebug("Client \"%s:%u\" is closing connection %d ...", + My_Connections[Idx].host, + ng_ipaddr_tostr(&My_Connections[Idx].addr), Idx); + Conn_Close(Idx, NULL, "Client closed connection", false); return; } @@ -1563,7 +1642,7 @@ Read_Request( CONN_ID Idx ) if( errno == EAGAIN ) return; Log(LOG_ERR, "Read error on connection %d (socket %d): %s!", Idx, My_Connections[Idx].sock, strerror(errno)); - Conn_Close(Idx, "Read error!", "Client closed connection", + Conn_Close(Idx, "Read error", "Client closed connection", false); return; } @@ -1572,7 +1651,7 @@ Read_Request( CONN_ID Idx ) if (!array_catb(&My_Connections[Idx].zip.rbuf, readbuf, (size_t) len)) { Log(LOG_ERR, - "Could not append recieved data to zip input buffer (connection %d): %d bytes!", + "Could not append received data to zip input buffer (connection %d): %d bytes!", Idx, len); Conn_Close(Idx, "Receive buffer space exhausted", NULL, false); @@ -1583,7 +1662,7 @@ Read_Request( CONN_ID Idx ) { if (!array_catb( &My_Connections[Idx].rbuf, readbuf, len)) { Log(LOG_ERR, - "Could not append recieved data to input buffer (connection %d): %d bytes!", + "Could not append received data to input buffer (connection %d): %d bytes!", Idx, len); Conn_Close(Idx, "Receive buffer space exhausted", NULL, false ); } @@ -1657,16 +1736,15 @@ Handle_Buffer(CONN_ID Idx) assert(c != NULL); - /* Servers do get special command limits, so they can process - * all the messages that are required while peering. */ + /* Servers get special command limits that depend on the user count */ switch (Client_Type(c)) { case CLIENT_SERVER: - /* Allow servers to send more commands in the first 10 secods + maxcmd = (int)(Client_UserCount() / 5) + + MAX_COMMANDS_SERVER_MIN; + /* Allow servers to handle even more commands while peering * to speed up server login and network synchronisation. */ - if (starttime - Client_StartTime(c) < 10) - maxcmd = MAX_COMMANDS_SERVER * 5; - else - maxcmd = MAX_COMMANDS_SERVER; + if (Conn_LastPing(Idx) == 0) + maxcmd *= 5; break; case CLIENT_SERVICE: maxcmd = MAX_COMMANDS_SERVICE; break; @@ -1823,17 +1901,17 @@ Check_Connections(void) if (My_Connections[i].lastping < time(NULL) - Conf_PongTimeout) { /* Timeout */ - LogDebug - ("Connection %d: Ping timeout: %d seconds.", - i, Conf_PongTimeout); - snprintf(msg, sizeof(msg), "Ping timeout: %d seconds", Conf_PongTimeout); + snprintf(msg, sizeof(msg), + "Ping timeout: %d seconds", + Conf_PongTimeout); + LogDebug("Connection %d: %s.", i, msg); Conn_Close(i, NULL, msg, true); } } else if (My_Connections[i].lastdata < time(NULL) - Conf_PingTimeout) { /* We need to send a PING ... */ LogDebug("Connection %d: sending PING ...", i); - My_Connections[i].lastping = time(NULL); + Conn_UpdatePing(i); Conn_WriteStr(i, "PING :%s", Client_ID(Client_ThisServer())); } @@ -1919,6 +1997,14 @@ New_Server( int Server , ng_ipaddr_t *dest) assert( Server > NONE ); + /* Make sure that the remote server hasn't re-linked to this server + * asynchronously on its own */ + if (Conf_Server[Server].conn_id > NONE) { + Log(LOG_INFO, + "Connection to \"%s\" meanwhile re-established, aborting preparation."); + return; + } + if (!ng_ipaddr_tostr_r(dest, ip_str)) { Log(LOG_WARNING, "New_Server: Could not convert IP to string"); return; @@ -1992,7 +2078,8 @@ New_Server( int Server , ng_ipaddr_t *dest) Client_SetToken( c, TOKEN_OUTBOUND ); /* Register connection */ - Conf_Server[Server].conn_id = new_sock; + if (!Conf_SetServer(Server, new_sock)) + return; My_Connections[new_sock].sock = new_sock; My_Connections[new_sock].addr = *dest; My_Connections[new_sock].client = c; @@ -2032,6 +2119,11 @@ Init_Conn_Struct(CONN_ID Idx) My_Connections[Idx].lastdata = now; My_Connections[Idx].lastprivmsg = now; Proc_InitStruct(&My_Connections[Idx].proc_stat); + +#ifdef ICONV + My_Connections[Idx].iconv_from = (iconv_t)(-1); + My_Connections[Idx].iconv_to = (iconv_t)(-1); +#endif } /* Init_Conn_Struct */ @@ -2158,6 +2250,7 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) char *identptr; #ifdef IDENTAUTH char readbuf[HOST_LEN + 2 + CLIENT_USER_LEN]; + char *ptr; #else char readbuf[HOST_LEN + 1]; #endif @@ -2206,15 +2299,37 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) Client_SetHostname(c, readbuf); if (Conf_NoticeAuth) (void)Conn_WriteStr(i, - "NOTICE AUTH :*** Found your hostname"); + "NOTICE AUTH :*** Found your hostname: %s", + My_Connections[i].host); #ifdef IDENTAUTH ++identptr; if (*identptr) { - Log(LOG_INFO, "IDENT lookup for connection %d: \"%s\".", i, identptr); - Client_SetUser(c, identptr, true); - if (Conf_NoticeAuth) + ptr = identptr; + while (*ptr) { + if ((*ptr < '0' || *ptr > '9') && + (*ptr < 'A' || *ptr > 'Z') && + (*ptr < 'a' || *ptr > 'z')) + break; + ptr++; + } + if (*ptr) { + /* Erroneous IDENT reply */ + Log(LOG_NOTICE, + "Got invalid IDENT reply for connection %d! Ignored.", + i); + } else { + Log(LOG_INFO, + "IDENT lookup for connection %d: \"%s\".", + i, identptr); + Client_SetUser(c, identptr, true); + } + if (Conf_NoticeAuth) { (void)Conn_WriteStr(i, - "NOTICE AUTH :*** Got ident response"); + "NOTICE AUTH :*** Got %sident response%s%s", + *ptr ? "invalid " : "", + *ptr ? "" : ": ", + *ptr ? "" : identptr); + } } else { Log(LOG_INFO, "IDENT lookup for connection %d: no result.", i); if (Conf_NoticeAuth && Conf_Ident) @@ -2222,6 +2337,11 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events ) "NOTICE AUTH :*** No ident response"); } #endif + + if (Conf_NoticeAuth) + (void)Handle_Write(i); + + Class_HandleServerBans(c); } #ifdef DEBUG else Log( LOG_DEBUG, "Resolver: discarding result for already registered connection %d.", i );