diff options
-rw-r--r-- | include/connection.h | 6 | ||||
-rw-r--r-- | include/servers.h | 2 | ||||
-rw-r--r-- | src/InspIRCd.layout | 30 | ||||
-rw-r--r-- | src/connection.cpp | 21 | ||||
-rw-r--r-- | src/inspircd.cpp | 325 | ||||
-rw-r--r-- | src/users.cpp | 19 |
6 files changed, 345 insertions, 58 deletions
diff --git a/include/connection.h b/include/connection.h index a8f7372d9..793f6d321 100644 --- a/include/connection.h +++ b/include/connection.h @@ -20,6 +20,7 @@ #define PT_SYN_ONLY 0 #define PT_ACK_ONLY 1 #define PT_SYN_WITH_DATA 2 +#define PT_KEY_EXCHANGE 3 class packet : public classbase @@ -54,13 +55,14 @@ class connection : public classbase time_t signon; time_t idle_lastmsg; time_t nping; + char internal_addr[1024]; connection(); bool CreateListener(char* host, int p); bool BeginLink(char* targethost, int port, char* password); void TerminateLink(char* targethost); - bool SendPacket(char *message, char* host, int port); - bool RecvPacket(char *message, char* host, int &prt); + bool SendPacket(char *message, char* host, int port, long ourkey); + bool RecvPacket(char *message, char* host, int &prt, long &theirkey); bool SendSYN(char* host, int port); bool SendACK(char* host, int port, int reply_id); long GenKey(); diff --git a/include/servers.h b/include/servers.h index 6e10b62cc..9bf16defc 100644 --- a/include/servers.h +++ b/include/servers.h @@ -58,7 +58,5 @@ class serverrec : public connection -typedef std::map<std::string, serverrec*> server_list; - #endif diff --git a/src/InspIRCd.layout b/src/InspIRCd.layout index 76868c48f..b54226867 100644 --- a/src/InspIRCd.layout +++ b/src/InspIRCd.layout @@ -1,6 +1,6 @@ [Editors] Focused=1 -Order=1,7,3,2,0,6,5,4,25 +Order=1,7,3,2,0,6,5,4,25,24,-1 [Editor_0] Open=1 @@ -13,9 +13,9 @@ LeftChar=1 [Editor_1] Open=1 Top=1 -CursorCol=1 -CursorRow=3562 -TopLine=3521 +CursorCol=4 +CursorRow=1129 +TopLine=1078 LeftChar=1 [Editor_2] @@ -91,7 +91,7 @@ TopLine=1 LeftChar=1 [Editor_11] -Open=0 +Open=1 Top=0 CursorCol=1 CursorRow=1 @@ -107,10 +107,10 @@ TopLine=120 LeftChar=1 [Editor_13] -Open=0 +Open=1 Top=0 -CursorCol=12 -CursorRow=31 +CursorCol=60 +CursorRow=64 TopLine=20 LeftChar=1 @@ -171,11 +171,11 @@ TopLine=232 LeftChar=1 [Editor_21] -Open=0 +Open=1 Top=0 CursorCol=1 -CursorRow=1 -TopLine=1 +CursorRow=25 +TopLine=10 LeftChar=1 [Editor_22] @@ -195,11 +195,11 @@ TopLine=1 LeftChar=1 [Editor_24] -Open=0 +Open=1 Top=0 -CursorCol=1 -CursorRow=1 -TopLine=1 +CursorCol=71 +CursorRow=101 +TopLine=84 LeftChar=1 [Editor_25] Open=1 diff --git a/src/connection.cpp b/src/connection.cpp index 33eb405ad..eb0af9833 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -86,8 +86,7 @@ bool connection::BeginLink(char* targethost, int port, char* password) { sprintf(connect,"S %s %s :%s",getservername().c_str(),password,getserverdesc().c_str()); this->haspassed = false; - this->SendPacket(connect, targethost, port); - return true; + return this->SendPacket(connect, targethost, port, 0); } return false; } @@ -99,7 +98,7 @@ void connection::TerminateLink(char* targethost) // host: in dot notation a.b.c.d // port: host byte order -bool connection::SendPacket(char *message, char* host, int port) +bool connection::SendPacket(char *message, char* host, int port, long ourkey) { sockaddr_in host_address; in_addr addy; @@ -115,14 +114,17 @@ bool connection::SendPacket(char *message, char* host, int port) strcpy(p.data,message); p.type = PT_SYN_WITH_DATA; - p.key = key; + p.key = ourkey; + + FOREACH_MOD OnPacketTransmit(p.data); - FOREACH_MOD OnPacketTransmit(p.data); + log(DEBUG,"main: Connection::SendPacket() sent '%s' to %s:%d",p.data,host,port); // returns false if the packet could not be sent (e.g. target host down) - if (sendto(fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0) + if (sendto(this->fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0) { + log(DEBUG,"sendto() failed for Connection::SendPacket() with a packet of size %d",sizeof(p)); return false; } return true; @@ -213,7 +215,7 @@ long connection::GenKey() // host: in dot notation a.b.c.d // port: host byte order -bool connection::RecvPacket(char *message, char* host, int &prt) +bool connection::RecvPacket(char *message, char* host, int &prt, long &theirkey) { // returns false if no packet waiting for receive, e.g. EAGAIN or ECONNRESET sockaddr_in host_address; @@ -230,6 +232,8 @@ bool connection::RecvPacket(char *message, char* host, int &prt) return false; } + log(DEBUG,"connection::RecvPacket(): received packet type %d '%s'",p.type,p.data); + if (p.type == PT_SYN_ONLY) { strcpy(message,p.data); @@ -251,10 +255,13 @@ bool connection::RecvPacket(char *message, char* host, int &prt) { strcpy(message,p.data); strcpy(host,inet_ntoa(host_address.sin_addr)); + theirkey = p.key; prt = ntohs(host_address.sin_port); SendACK(host,this->port,p.id); + return true; } + log(DEBUG,"connection::RecvPacket(): Invalid packet type %d (protocol error)",p.type); return true; } diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 996a1ee88..bb081f720 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -142,7 +142,7 @@ typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, InAddr_HashComp typedef std::deque<command_t> command_table; serverrec* me[32]; -server_list* servers; +serverrec* servers[255]; user_hash clientlist; chan_hash chanlist; @@ -160,6 +160,10 @@ int boundPortCount = 0; int portCount = 0, UDPportCount = 0, ports[MAXSOCKS]; int defaultRoute = 0; +connection C; + +long MyKey = C.GenKey(); + /* prototypes */ int has_channel(userrec *u, chanrec *c); @@ -981,11 +985,14 @@ int usercount(chanrec *c) strcpy(list,""); for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) { - if (has_channel(i->second,c)) + if (i->second) { - if (isnick(i->second->nick)) + if (has_channel(i->second,c)) { - count++; + if ((isnick(i->second->nick)) && (i->second->registered == 7)) + { + count++; + } } } } @@ -1068,9 +1075,11 @@ chanrec* add_channel(userrec *user, char* cname, char* key) } } } + log(DEBUG,"add_channel: no key"); if (Ptr->inviteonly) { + log(DEBUG,"add_channel: channel is +i"); if (user->IsInvited(Ptr->name)) { /* user was invited to channel */ @@ -1082,6 +1091,7 @@ chanrec* add_channel(userrec *user, char* cname, char* key) return NULL; } } + log(DEBUG,"add_channel: channel is not +i"); if (Ptr->limit) { @@ -1092,6 +1102,8 @@ chanrec* add_channel(userrec *user, char* cname, char* key) } } + log(DEBUG,"add_channel: about to walk banlist"); + /* check user against the channel banlist */ for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++) { @@ -1102,17 +1114,24 @@ chanrec* add_channel(userrec *user, char* cname, char* key) } } + log(DEBUG,"add_channel: bans checked"); + user->RemoveInvite(Ptr->name); + + log(DEBUG,"add_channel: invites removed"); } created = 1; } + log(DEBUG,"Passed channel checks"); for (i =0; i != MAXCHANS; i++) { if (user->chans[i].channel == NULL) { + log(DEBUG,"Adding into their channel list"); + if (created == 2) { /* first user in is given ops */ @@ -1124,6 +1143,9 @@ chanrec* add_channel(userrec *user, char* cname, char* key) } user->chans[i].channel = Ptr; WriteChannel(Ptr,user,"JOIN :%s",Ptr->name); + + log(DEBUG,"Sent JOIN to client"); + if (Ptr->topicset) { WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic); @@ -2451,16 +2473,26 @@ void kill_link(userrec *user,char* reason) Blocking(user->fd); close(user->fd); NonBlocking(user->fd); - AddWhoWas(user); + + bool do_purge = false; + + if (user->registered == 7) { + AddWhoWas(user); + do_purge = true; + } if (iter != clientlist.end()) { - log(DEBUG,"deleting user hash value %p",iter->second); - delete iter->second; + log(DEBUG,"deleting user hash value %d",iter->second); + if (iter->second) { + delete iter->second; + } clientlist.erase(iter); } - purge_empty_chans(); + if (do_purge) { + purge_empty_chans(); + } } @@ -3549,22 +3581,64 @@ void handle_stats(char **parameters, int pcnt, userrec *user) void handle_connect(char **parameters, int pcnt, userrec *user) { - WriteServ(user->fd,"NOTICE %s :*** Connecting to %s port %s...",user->nick,parameters[0],parameters[1]); + char Link_ServerName[1024]; + char Link_IPAddr[1024]; + char Link_Port[1024]; + char Link_Pass[1024]; + int LinkPort; + bool found = false; + + for (int i = 0; i < ConfValueEnum("link"); i++) + { + ConfValue("link","name",i,Link_ServerName); + ConfValue("link","ipaddr",i,Link_IPAddr); + ConfValue("link","port",i,Link_Port); + ConfValue("link","sendpass",i,Link_Pass); + log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass); + LinkPort = atoi(Link_Port); + if (match(Link_ServerName,parameters[0])) { + found = true; + } + } + + if (!found) { + WriteServ(user->fd,"NOTICE %s :*** Failed to connect to %s: No servers matching this pattern are configured for linking.",user->nick,parameters[0]); + return; + } + + // TODO: Perform a check here to stop a server being linked twice! + + WriteServ(user->fd,"NOTICE %s :*** Connecting to %s (%s) port %s...",user->nick,Link_ServerName,Link_IPAddr,Link_Port); + if (me[defaultRoute]) { - if (!me[defaultRoute]->BeginLink(parameters[0],atoi(parameters[1]),"password")) - { - WriteServ(user->fd,"NOTICE %s :*** Failed to send auth packet to %s!",user->nick,parameters[0]); + + // at this point parameters[0] is an ip in a string. + // TODO: Look this up from the <link> blocks instead! + for (int j = 0; j < 255; j++) { + if (servers[j] == NULL) { + servers[j] = new serverrec; + strcpy(servers[j]->internal_addr,Link_IPAddr); + strcpy(servers[j]->name,Link_ServerName); + log(DEBUG,"Allocated new serverrec"); + if (!me[defaultRoute]->BeginLink(Link_IPAddr,LinkPort,Link_Pass)) + { + WriteServ(user->fd,"NOTICE %s :*** Failed to send auth packet to %s!",user->nick,Link_IPAddr); + } + return; + } } + WriteServ(user->fd,"NOTICE %s :*** Failed to create server record for address %s!",user->nick,Link_IPAddr); } else { - WriteServ(user->fd,"NOTICE %s :No default route is defined for server connections on this server",user->nick); + WriteServ(user->fd,"NOTICE %s :No default route is defined for server connections on this server. You must define a server connection to be default route so that sockets can be bound to it.",user->nick); } } void handle_squit(char **parameters, int pcnt, userrec *user) { + // send out an squit across the mesh and then clear the server list (for local squit) } void handle_oper(char **parameters, int pcnt, userrec *user) @@ -3975,7 +4049,7 @@ void SetupCommandTable(void) createcommand("PASS",handle_pass,0,1); createcommand("TRACE",handle_trace,'o',0); createcommand("WHOWAS",handle_whowas,0,1); - createcommand("CONNECT",handle_connect,'o',2); + createcommand("CONNECT",handle_connect,'o',1); createcommand("SQUIT",handle_squit,'o',1); } @@ -4013,8 +4087,207 @@ void process_buffer(userrec *user) process_command(user,cmd); } -void handle_link_packet(char* udp_msg, char* udp_host, int udp_port, serverrec *serv) +void process_restricted_commands(char token,char* params,serverrec* source,serverrec* reply, char* udp_host,int udp_port) { + WriteOpers("Secure-UDP-Channel: Token='%c', Params='%s'",token,params); +} + + +void handle_link_packet(long theirkey, char* udp_msg, char* udp_host, int udp_port, serverrec *serv) +{ + char response[10240]; + char token = udp_msg[0]; + char* params = udp_msg + 2; + char finalparam[1024]; + strcpy(finalparam," :xxxx"); + if (strstr(params," :")) { + strncpy(finalparam,strstr(params," :"),1024); + } + if (token == 'S') { + // S test.chatspike.net password :ChatSpike InspIRCd test server + char* servername = strtok(params," "); + char* password = strtok(NULL," "); + char* serverdesc = finalparam+2; + WriteOpers("CONNECT from %s (%s)",servername,udp_host,password,serverdesc); + + + char Link_ServerName[1024]; + char Link_IPAddr[1024]; + char Link_Port[1024]; + char Link_Pass[1024]; + char Link_SendPass[1024]; + int LinkPort = 0; + + // search for a corresponding <link> block in the config files + for (int i = 0; i < ConfValueEnum("link"); i++) + { + ConfValue("link","name",i,Link_ServerName); + ConfValue("link","ipaddr",i,Link_IPAddr); + ConfValue("link","port",i,Link_Port); + ConfValue("link","recvpass",i,Link_Pass); + ConfValue("link","sendpass",i,Link_SendPass); + log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass); + LinkPort = atoi(Link_Port); + if (!strcasecmp(Link_ServerName,servername)) { + if (!strcasecmp(Link_IPAddr,udp_host)) { + if (LinkPort == udp_port) { + // we have a matching link line - + // send a 'diminutive' server message back... + snprintf(response,10240,"s %s %s :%s",ServerName,Link_SendPass,ServerDesc); + serv->SendPacket(response,udp_host,udp_port,0); + WriteOpers("CONNECT from %s accepted, authenticating",servername); + for (int j = 0; j < 255; j++) { + if (servers[j] == NULL) { + servers[j] = new serverrec; + strcpy(servers[j]->internal_addr,udp_host); + strcpy(servers[j]->name,servername); + // create a server record for this server + snprintf(response,10240,"O %d",MyKey); + serv->SendPacket(response,udp_host,udp_port,0); + return; + } + } + WriteOpers("Internal error connecting to %s, failed to create server record!",servername); + return; + } + else { + log(DEBUG,"Port numbers '%d' and '%d' don't match",LinkPort,udp_port); + } + } + else { + log(DEBUG,"IP Addresses '%s' and '%s' don't match",Link_IPAddr,udp_host); + } + } + else { + log(DEBUG,"Server names '%s' and '%s' don't match",Link_ServerName,servername); + } + } + serv->SendPacket("E :Access is denied (no matching link block)",udp_host,udp_port,0); + WriteOpers("CONNECT from %s denied, no matching link block",servername); + return; + } + else + if (token == 'O') { + // if this is received, this means the server-ip that sent it said "OK" to credentials. + // only when a server says this do we exchange keys. The server MUST have an entry in the servers + // array, which is only added by an 'S' packet or BeginLink(). + for (int i = 0; i < 255; i++) { + if (servers[i] != NULL) { + if (!strcasecmp(servers[i]->internal_addr,udp_host)) { + servers[i]->key = atoi(params); + log(DEBUG,"Key for this server is now %d",servers[i]->key); + serv->SendPacket("Z blah blah",udp_host,udp_port,MyKey); + return; + } + } + } + WriteOpers("\2WARNING!\2 Server ip %s attempted a key exchange, but is not in the authentication state! Possible intrusion attempt!",udp_host); + } + else + if (token == 's') { + // S test.chatspike.net password :ChatSpike InspIRCd test server + char* servername = strtok(params," "); + char* password = strtok(NULL," "); + char* serverdesc = finalparam+2; + + // TODO: we should do a check here to ensure that this server is one we recently initiated a + // link with, and didnt hear an 's' or 'E' back from yet (these are the only two valid responses + // to an 'S' command. If we didn't recently send an 'S' to this server, theyre trying to spoof + // a connect, so put out an oper alert! + + + + + // for now, just accept all, we'll fix that later. + WriteOpers("%s accepted our link credentials ",servername); + + char Link_ServerName[1024]; + char Link_IPAddr[1024]; + char Link_Port[1024]; + char Link_Pass[1024]; + char Link_SendPass[1024]; + int LinkPort = 0; + + // search for a corresponding <link> block in the config files + for (int i = 0; i < ConfValueEnum("link"); i++) + { + ConfValue("link","name",i,Link_ServerName); + ConfValue("link","ipaddr",i,Link_IPAddr); + ConfValue("link","port",i,Link_Port); + ConfValue("link","recvpass",i,Link_Pass); + ConfValue("link","sendpass",i,Link_SendPass); + log(DEBUG,"(%d) Comparing against name='%s', ipaddr='%s', port='%s', recvpass='%s'",i,Link_ServerName,Link_IPAddr,Link_Port,Link_Pass); + LinkPort = atoi(Link_Port); + if (!strcasecmp(Link_ServerName,servername)) { + if (!strcasecmp(Link_IPAddr,udp_host)) { + if (LinkPort == udp_port) { + // matching link at this end too, we're all done! + // at this point we must begin key exchange and insert this + // server into our 'active' table. + for (int j = 0; j < 255; j++) { + if (servers[j] != NULL) { + if (!strcasecmp(servers[j]->internal_addr,udp_host)) { + WriteOpers("Server %s authenticated, exchanging server keys...",servername); + snprintf(response,10240,"O %d",MyKey); + serv->SendPacket(response,udp_host,udp_port,0); + return; + } + } + } + WriteOpers("\2WARNING!\2 %s sent us an authentication packet but we are not authenticating with this server right noe! Possible intrusion attempt!",udp_host); + return; + + } + else { + log(DEBUG,"Port numbers '%d' and '%d' don't match",LinkPort,udp_port); + } + } + else { + log(DEBUG,"IP Addresses '%s' and '%s' don't match",Link_IPAddr,udp_host); + } + } + else { + log(DEBUG,"Server names '%s' and '%s' don't match",Link_ServerName,servername); + } + } + serv->SendPacket("E :Access is denied (no matching link block)",udp_host,udp_port,0); + WriteOpers("CONNECT from %s denied, no matching link block",servername); + return; + } + else + if (token == 'E') { + char* error_message = finalparam+2; + WriteOpers("ERROR from %s: %s",udp_host,error_message); + // remove this server from any lists + for (int j = 0; j < 255; j++) { + if (servers[j] != NULL) { + if (!strcasecmp(servers[j]->internal_addr,udp_host)) { + delete servers[j]; + return; + } + } + } + return; + } + else { + + serverrec* source_server = NULL; + + for (int j = 0; j < 255; j++) { + if (servers[j] != NULL) { + if (!strcasecmp(servers[j]->internal_addr,udp_host)) { + if (servers[j]->key == theirkey) { + // found a valid key for this server, can process restricted stuff here + process_restricted_commands(token,params,servers[j],serv,udp_host,udp_port); + + return; + } + } + } + } + + log(DEBUG,"Unrecognised token or unauthenticated host in datagram from %s:%d: %c",udp_host,udp_port,token); + } } int InspIRCd(void) @@ -4131,9 +4404,6 @@ int InspIRCd(void) MODCOUNT = count - 1; log(DEBUG,"Total loaded modules: %d",MODCOUNT+1); - servers = new server_list; - servers->clear(); - printf("\nInspIRCd is now running!\n"); startup_time = time(NULL); @@ -4205,13 +4475,18 @@ int InspIRCd(void) for (int x = 0; x != UDPportCount; x++) { - if (me[x]->RecvPacket(udp_msg, udp_host, udp_port)) - { - FOREACH_MOD OnPacketReceive(udp_msg); - WriteOpers("UDP Link Packet: '%s' from %s:%d:%d [route%d]",udp_msg,udp_host,udp_port,me[x]->port,x); - // Packets must go back via the route they arrived on :) - handle_link_packet(udp_msg, udp_host, udp_port, me[x]); - } + long theirkey = 0; + if (me[x]->RecvPacket(udp_msg, udp_host, udp_port, theirkey)) + { + if (strlen(udp_msg)<1) { + log(DEBUG,"Invalid datagram from %s:%d:%d [route%d]",udp_host,udp_port,me[x]->port,x); + } + else { + FOREACH_MOD OnPacketReceive(udp_msg); + // Packets must go back via the route they arrived on :) + handle_link_packet(theirkey, udp_msg, udp_host, udp_port, me[x]); + } + } } for (user_hash::iterator count2 = clientlist.begin(); count2 != clientlist.end(); count2++) diff --git a/src/users.cpp b/src/users.cpp index b179fabdd..4a9ada90d 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -50,11 +50,14 @@ bool userrec::IsInvited(char* channel) { for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) { - if (!strcasecmp(i->channel,channel)) - { - return true; + if (i->channel) { + if (!strcasecmp(i->channel,channel)) + { + return true; + } } } + return false; } void userrec::InviteTo(char* channel) @@ -68,10 +71,12 @@ void userrec::RemoveInvite(char* channel) { for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) { - if (!strcasecmp(i->channel,channel)) - { - invites.erase(i); - return; + if (i->channel) { + if (!strcasecmp(i->channel,channel)) + { + invites.erase(i); + return; + } } } } |