diff options
author | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2004-04-14 17:15:07 +0000 |
---|---|---|
committer | brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7> | 2004-04-14 17:15:07 +0000 |
commit | 4a9c4b5983afba8dd6b1b3fcee78f2b65d975216 (patch) | |
tree | 7ef50d29234c389dc0bf4efcb3fc02a77992de49 /src/connection.cpp | |
parent | bcc0d749055e337417ae694afaad278c9b84b8bb (diff) |
Changed server to server links from UDP to TCP due to data loss problems
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@570 e03df62e-2008-0410-955e-edbf42e46eb7
Diffstat (limited to 'src/connection.cpp')
-rw-r--r-- | src/connection.cpp | 298 |
1 files changed, 154 insertions, 144 deletions
diff --git a/src/connection.cpp b/src/connection.cpp index 4867cc55b..e2be63c33 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -4,14 +4,19 @@ #include <sys/errno.h> #include <sys/ioctl.h> #include <sys/utsname.h> +#include <vector> +#include <string> #include "inspircd.h" #include "modules.h" +using namespace std; + extern std::vector<Module*> modules; extern std::vector<ircd_module*> factory; extern int MODCOUNT; + packet::packet() { srand(time(NULL)); @@ -37,7 +42,7 @@ bool connection::CreateListener(char* host, int p) int on = 0; struct linger linger = { 0 }; - fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd <= 0) { return false; @@ -81,195 +86,200 @@ bool connection::CreateListener(char* host, int p) int recvbuf = 32768; setsockopt(fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); setsockopt(fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf)); + + listen(this->fd,5); return true; } +bool ircd_connector::SetHostAddress(char* host, int port) +{ + memset((void*)&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + inet_aton(host,&addr.sin_addr); + addr.sin_port = htons(port); + return true; +} + +bool ircd_connector::MakeOutboundConnection(char* host, int port) +{ + hostent* hoste = gethostbyname(host); + if (!hoste) + { + WriteOpers("Failed to look up hostname for %s, using as an ip address",host); + this->SetHostAddress(host,port); + } + else + { + WriteOpers("Found hostname for %s",host); + this->SetHostAddress(hoste->h_addr,port); + } + + this->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (this->fd >= 0) + { + if(connect(this->fd, (sockaddr*)&addr,sizeof(addr))) + { + WriteOpers("connect() failed for %s",host); + return false; + } + int flags = fcntl(this->fd, F_GETFL, 0); + fcntl(this->fd, F_SETFL, flags | O_NONBLOCK); + int sendbuf = 32768; + int recvbuf = 32768; + setsockopt(this->fd,SOL_SOCKET,SO_SNDBUF,(const void *)&sendbuf,sizeof(sendbuf)); + setsockopt(this->fd,SOL_SOCKET,SO_RCVBUF,(const void *)&recvbuf,sizeof(sendbuf)); + return true; + } + else + { + WriteOpers("socket() failed!"); + } + + return false; +} + -bool connection::BeginLink(char* targethost, int port, char* password) +bool connection::BeginLink(char* targethost, int port, char* password, char* servername) { char connect[MAXBUF]; + ircd_connector connector; + if (this->fd) { - sprintf(connect,"S %s %s :%s",getservername().c_str(),password,getserverdesc().c_str()); - this->haspassed = false; - return this->SendPacket(connect, targethost, port, 0); + if (connector.MakeOutboundConnection(targethost,port)) + { + // targethost has been turned into an ip... + // we dont want this as the server name. + connector.SetServerName(servername); + sprintf(connect,"S %s %s :%s",getservername().c_str(),password,getserverdesc().c_str()); + connector.SetState(STATE_NOAUTH_OUTBOUND); + this->connectors.push_back(connector); + return this->SendPacket(connect, servername); + } + else + { + WriteOpers("Could not create outbound connection to %s:%d",targethost,port); + } } return false; } -// targethost: in dot notation a.b.c.d -void connection::TerminateLink(char* targethost) +bool connection::AddIncoming(int fd,char* targethost) { + char connect[MAXBUF]; + + ircd_connector connector; + + // targethost has been turned into an ip... + // we dont want this as the server name. + connector.SetServerName(targethost); + connector.SetDescriptor(fd); + connector.SetState(STATE_NOAUTH_INBOUND); + this->connectors.push_back(connector); + return true; } -// host: in dot notation a.b.c.d -// port: host byte order -bool connection::SendPacket(char *message, char* host, int port, long ourkey) +void connection::TerminateLink(char* targethost) { - sockaddr_in host_address; - in_addr addy; - packet p; - - memset((void*)&host_address, 0, sizeof(host_address)); - - host_address.sin_family = AF_INET; - inet_aton(host,&addy); - host_address.sin_addr = addy; - - host_address.sin_port = htons(port); - - strcpy(p.data,message); - p.type = PT_SYN_WITH_DATA; - p.key = ourkey; - - - FOREACH_MOD OnPacketTransmit(p.data); + // this locates the targethost in the connection::connectors vector of the class, + // and terminates it by sending it an SQUIT token and closing its descriptor. + // TerminateLink with a null string causes a terminate of ALL links +} - 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(this->fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0) +// Returns a pointer to the connector for 'host' +ircd_connector* connection::FindHost(std::string host) +{ + for (int i = 0; i < this->connectors.size(); i++) { - log(DEBUG,"sendto() failed for Connection::SendPacket() with a packet of size %d",sizeof(p)); - return false; + if (this->connectors[i].GetServerName() == host) + { + return &this->connectors[i]; + } } - return true; - + return NULL; } -bool connection::SendSYN(char* host, int port) +std::string ircd_connector::GetServerName() { - sockaddr_in host_address; - in_addr addy; - packet p; - - memset((void*)&host_address, 0, sizeof(host_address)); - - host_address.sin_family = AF_INET; - inet_aton(host,&addy); - host_address.sin_addr = addy; - - host_address.sin_port = htons(port); - - p.type = PT_SYN_ONLY; - p.key = key; - strcpy(p.data,""); - - if (sendto(fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0) - { - return false; - } - return true; - + return this->servername; } -bool connection::SendACK(char* host, int port, int reply_id) +void ircd_connector::SetServerName(std::string serv) { - sockaddr_in host_address; - in_addr addy; - packet p; - - memset((void*)&host_address, 0, sizeof(host_address)); - - host_address.sin_family = AF_INET; - inet_aton(host,&addy); - host_address.sin_addr = addy; - - host_address.sin_port = htons(port); + this->servername = serv; +} - p.type = PT_ACK_ONLY; - p.key = key; - p.id = reply_id; - strcpy(p.data,""); - if (sendto(fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0) - { - return false; - } - return true; +int ircd_connector::GetDescriptor() +{ + return this->fd; +} +int ircd_connector::GetState() +{ + return this->state; } -// Generates a server key. This is pseudo-random. -// the server always uses the same server-key in all communications -// across the network. All other servers must remember the server key -// of servers in the network, e.g.: -// -// ServerA: key=5555555555 -// ServerB: key=6666666666 -// I am ServerC: key=77777777777 -// -// If ServerC sees a packet from ServerA, and the key stored for ServerA -// is 0, then cache the key as the servers key. -// after this point, any packet from ServerA which does not contain its key, -// 555555555, will be silently dropped. -// This should prevent blind spoofing, as to fake a server you must know its -// assigned key, and to do that you must receive messages that are origintated -// from it or hack the running executable. -// -// During the AUTH phase (when server passwords are checked, the key in any -// packet MUST be 0). Only the initial SERVER/PASS packets may have a key -// of 0 (and any ACK responses to them). -// +void ircd_connector::SetState(int state) +{ + this->state = state; +} -long connection::GenKey() +void ircd_connector::SetDescriptor(int fd) { - srand(time(NULL)); - return (random()*time(NULL)); + this->fd = fd; } -// host: in dot notation a.b.c.d -// port: host byte order -bool connection::RecvPacket(char *message, char* host, int &prt, long &theirkey) +bool connection::SendPacket(char *message, char* host) { - // returns false if no packet waiting for receive, e.g. EAGAIN or ECONNRESET - sockaddr_in host_address; - socklen_t host_address_size; - packet p; + ircd_connector* cn = this->FindHost(host); - memset((void*)&host_address, 0, sizeof(host_address)); - - host_address.sin_family=AF_INET; - host_address_size=sizeof(host_address); - - if (recvfrom(fd,&p,sizeof(p),0,(sockaddr*)&host_address,&host_address_size)<0) + if (cn) { - 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); - strcpy(host,inet_ntoa(host_address.sin_addr)); - prt = ntohs(host_address.sin_port); - SendACK(host,this->port,p.id); - return false; + log(DEBUG,"main: Connection::SendPacket() sent '%s' to %s",message,cn->GetServerName().c_str()); + + strncat(message,"\n",MAXBUF); + // returns false if the packet could not be sent (e.g. target host down) + if (send(cn->GetDescriptor(),message,strlen(message),0)<0) + { + log(DEBUG,"send() failed for Connection::SendPacket(): %s",strerror(errno)); + return false; + } + return true; } +} - if (p.type == PT_ACK_ONLY) - { - strcpy(message,p.data); - strcpy(host,inet_ntoa(host_address.sin_addr)); - prt = ntohs(host_address.sin_port); - return false; - } +// receives a packet from any where there is data waiting, first come, first served +// fills the message and host values with the host where the data came from. - if (p.type == PT_SYN_WITH_DATA) +bool connection::RecvPacket(char *message, char* host) +{ + for (int i = 0; i < this->connectors.size(); i++) { - 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; + // returns false if the packet could not be sent (e.g. target host down) + int rcvsize = 0; + if (rcvsize = recv(this->connectors[i].GetDescriptor(),message,MAXBUF,0)) + { + if (rcvsize > 0) + { + // something new on this socket, fill the return values and bail + strncpy(host,this->connectors[i].GetServerName().c_str(),160); + message[rcvsize-1] = 0; + return true; + } + } } + // nothing new yet -- message and host will be undefined + return false; +} - log(DEBUG,"connection::RecvPacket(): Invalid packet type %d (protocol error)",p.type); - return true; +long connection::GenKey() +{ + srand(time(NULL)); + return (random()*time(NULL)); } |