]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/connection.cpp
Fixes
[user/henk/code/inspircd.git] / src / connection.cpp
1 #include <connection.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <sys/errno.h>
5 #include <sys/ioctl.h>
6 #include <sys/utsname.h>
7 #include <errno.h>
8 #include <vector>
9 #include "inspircd.h"
10 #include "modules.h"
11
12 extern std::vector<Module*> modules;
13 extern std::vector<ircd_module*> factory;
14
15 extern int MODCOUNT;
16
17 #define STATE_CLEAR 1
18 #define STATE_WAIT_FOR_ACK 2
19
20 packet::packet()
21 {
22         srand(time(NULL));
23         id = random();
24 }
25
26 packet::~packet()
27 {
28 }
29
30 connection::connection()
31 {
32         key = GenKey();
33         fd = 0;
34         state = STATE_CLEAR;
35 }
36
37
38 bool connection::CreateListener(char* host, int p)
39 {
40         sockaddr_in host_address;
41         int flags;
42         in_addr addy;
43         int on = 0;
44         struct linger linger = { 0 };
45         
46         fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
47         if (fd <= 0)
48         {
49                 return false;
50         }
51
52         memset((void*)&host_address, 0, sizeof(host_address));
53
54         host_address.sin_family = AF_INET;
55
56         if (!strcmp(host,""))
57         {
58                 host_address.sin_addr.s_addr = htonl(INADDR_ANY);
59         }
60         else
61         {
62                 inet_aton(host,&addy);
63                 host_address.sin_addr = addy;
64         }
65
66         host_address.sin_port = htons(p);
67
68         if (bind(fd,(sockaddr*)&host_address,sizeof(host_address))<0)
69         {
70                 return false;
71         }
72
73         // make the socket non-blocking
74         flags = fcntl(fd, F_GETFL, 0);
75         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
76
77         this->port = p;
78
79     setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(const char*)&on,sizeof(on));
80     linger.l_onoff = 1;
81     linger.l_linger = 0;
82     setsockopt(fd,SOL_SOCKET,SO_LINGER,(const char*)&linger,sizeof(linger));
83
84         return true;
85 }
86
87 bool connection::BeginLink(char* targethost, int port, char* password)
88 {
89         char connect[MAXBUF];
90         
91         if (this->fd)
92         {
93                 sprintf(connect,"S %s %s :%s",getservername().c_str(),password,getserverdesc().c_str());
94                 this->haspassed = false;
95                 return this->SendPacket(connect, targethost, port, 0);
96         }
97         return false;
98 }
99
100 // targethost: in dot notation a.b.c.d
101 void connection::TerminateLink(char* targethost)
102 {
103 }
104
105 // host: in dot notation a.b.c.d
106 // port: host byte order
107 bool connection::SendPacket(char *message, char* host, int port, long ourkey)
108 {
109         sockaddr_in host_address;
110         in_addr addy;
111         packet p;
112
113         memset((void*)&host_address, 0, sizeof(host_address));
114
115         host_address.sin_family = AF_INET;
116         inet_aton(host,&addy);
117         host_address.sin_addr = addy;
118
119         host_address.sin_port = htons(port);
120
121         strcpy(p.data,message);
122         p.type = PT_SYN_WITH_DATA;
123         p.key = ourkey;
124
125
126         FOREACH_MOD OnPacketTransmit(p.data);
127
128         log(DEBUG,"main: Connection::SendPacket() sent '%s' to %s:%d",p.data,host,port);
129
130         // returns false if the packet could not be sent (e.g. target host down)
131         if (sendto(this->fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0)
132         {
133                 log(DEBUG,"sendto() failed for Connection::SendPacket() with a packet of size %d: %s",sizeof(p),strerror(errno));
134                 return false;
135         }
136         this->state = STATE_WAIT_FOR_ACK;
137
138
139         // host_address remains unchanged. we only want to receive from where we just sent the packet to.
140         
141         // retry the packet up to 5 times
142         for (int retries = 0; retries < 5; retries++)
143         {
144                 socklen_t host_address_size;
145                 host_address.sin_family=AF_INET;
146                 host_address_size=sizeof(host_address);
147         
148                 // wait for ack, or timeout.
149                 // if reached a timeout, send again.
150                 // the packet id in the ack must match that in the original packet
151                 // this MUST operate in lock/step fashion!!!
152                 int cycles = 0;
153                 packet p2;
154                 do 
155                 {
156                         fd_set sfd;
157                         timeval tval;
158                         tval.tv_usec = 100;
159                         tval.tv_sec = 0;
160                         FD_ZERO(&sfd);
161                         FD_SET(fd,&sfd);
162                         int res = select(65535, &sfd, NULL, NULL, &tval);
163                         cycles++;
164                 }
165                 while ((recvfrom(fd,&p2,sizeof(p2),0,(sockaddr*)&host_address,&host_address_size)<0) && (cycles < 10));
166                 
167                 if (cycles >= 10)
168                 {
169                         log(DEFAULT,"ERROR! connection::SendPacket() waited >10000 nanosecs for an ACK. Will resend up to 5 times");
170                 }
171                 else
172                 {
173                         if (p2.type != PT_ACK_ONLY)
174                         {
175                                 packet_buf pb;
176                                 pb.p.id = p.id;
177                                 pb.p.key = p.key;
178                                 pb.p.type = p.type;
179                                 strcpy(pb.host,inet_ntoa(host_address.sin_addr));
180                                 pb.port = ntohs(host_address.sin_port);
181                                 this->buffer.push_back(pb);
182                                 
183                                 log(DEFAULT,"ERROR! connection::SendPacket() received a data response and was expecting an ACK!!!");
184                                 this->state = STATE_CLEAR;
185                                 return true;
186                         }
187
188                         if (p2.id != p.id)
189                         {
190                                 log(DEFAULT,"ERROR! connection::SendPacket() received an ack for a packet it didnt send!");
191                                 this->state = STATE_CLEAR;
192                                 return false;
193                         }
194                         else
195                         {
196                                 log(DEFAULT,"Successfully received ACK");
197                                 this->state = STATE_CLEAR;
198                                 return true;
199                                 break;
200                         }
201                 }
202         }
203         log(DEFAULT,"We never received an ack. Something fishy going on, host is dead.");
204         this->state = STATE_CLEAR;
205         return false;
206
207 }
208
209 bool connection::SendSYN(char* host, int port)
210 {
211         sockaddr_in host_address;
212         in_addr addy;
213         packet p;
214
215         memset((void*)&host_address, 0, sizeof(host_address));
216
217         host_address.sin_family = AF_INET;
218         inet_aton(host,&addy);
219         host_address.sin_addr = addy;
220
221         host_address.sin_port = htons(port);
222
223         p.type = PT_SYN_ONLY;
224         p.key = key;
225         strcpy(p.data,"");
226
227         if (sendto(fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0)
228         {
229                 return false;
230         }
231         return true;
232
233 }
234
235 bool connection::SendACK(char* host, int port, int reply_id)
236 {
237         sockaddr_in host_address;
238         in_addr addy;
239         packet p;
240
241         memset((void*)&host_address, 0, sizeof(host_address));
242
243         host_address.sin_family = AF_INET;
244         inet_aton(host,&addy);
245         host_address.sin_addr = addy;
246
247         host_address.sin_port = htons(port);
248
249         p.type = PT_ACK_ONLY;
250         p.key = key;
251         p.id = reply_id;
252         strcpy(p.data,"");
253
254         if (sendto(fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0)
255         {
256                 return false;
257         }
258
259 }
260
261
262 // Generates a server key. This is pseudo-random.
263 // the server always uses the same server-key in all communications
264 // across the network. All other servers must remember the server key
265 // of servers in the network, e.g.:
266 //
267 // ServerA:  key=5555555555
268 // ServerB:  key=6666666666
269 // I am ServerC: key=77777777777
270 //
271 // If ServerC sees a packet from ServerA, and the key stored for ServerA
272 // is 0, then cache the key as the servers key.
273 // after this point, any packet from ServerA which does not contain its key,
274 // 555555555, will be silently dropped.
275 // This should prevent blind spoofing, as to fake a server you must know its
276 // assigned key, and to do that you must receive messages that are origintated
277 // from it or hack the running executable.
278 //
279 // During the AUTH phase (when server passwords are checked, the key in any
280 // packet MUST be 0). Only the initial SERVER/PASS packets may have a key
281 // of 0 (and any ACK responses to them).
282 //
283
284 long connection::GenKey()
285 {
286         srand(time(NULL));
287         return (random()*time(NULL));
288 }
289
290 // host: in dot notation a.b.c.d
291 // port: host byte order
292 bool connection::RecvPacket(char *message, char* host, int &prt, long &theirkey)
293 {
294         // returns false if no packet waiting for receive, e.g. EAGAIN or ECONNRESET
295         sockaddr_in host_address;
296         socklen_t host_address_size;
297         packet p;
298         
299         memset((void*)&host_address, 0, sizeof(host_address));
300
301         host_address.sin_family=AF_INET;
302         host_address_size=sizeof(host_address);
303
304         //int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
305         if (recvfrom(fd,&p,sizeof(p),0,(sockaddr*)&host_address,&host_address_size)<0)
306         {
307                 if (this->buffer.size() != -1)
308                 {
309                         log(DEBUG,"Fetching a buffered packet");
310
311                         strcpy(message,buffer[0].p.data);
312                         theirkey = buffer[0].p.key;
313                         strcpy(host,buffer[0].host);
314                         prt = buffer[0].port;
315                         
316                         buffer.erase(0);
317                         
318                         return true;
319                 }
320                 return false;
321         }
322
323         log(DEBUG,"connection::RecvPacket(): received packet type %d '%s' from '%s'",p.type,p.data,inet_ntoa(host_address.sin_addr));
324
325         if (p.type == PT_SYN_ONLY)
326         {
327                 strcpy(message,p.data);
328                 strcpy(host,inet_ntoa(host_address.sin_addr));
329                 prt = ntohs(host_address.sin_port);
330                 SendACK(host,this->port,p.id);
331                 return false;
332         }
333
334         if (p.type == PT_ACK_ONLY)
335         {
336                 strcpy(message,p.data);
337                 strcpy(host,inet_ntoa(host_address.sin_addr));
338                 prt = ntohs(host_address.sin_port);
339                 this->state = STATE_CLEAR;
340                 return false;
341         }
342
343         if (p.type == PT_SYN_WITH_DATA)
344         {
345                 strcpy(message,p.data);
346                 strcpy(host,inet_ntoa(host_address.sin_addr));
347                 theirkey = p.key;
348                 prt = ntohs(host_address.sin_port); // the port we received it on
349                 SendACK(host,prt,p.id);
350
351                 if (this->buffer.size() != -1)
352                 {
353                         log(DEBUG,"Fetching a buffered packet");
354                         packet_buf pb;
355                         pb.p.id = p.id;
356                         pb.p.key = p.key;
357                         pb.p.type = p.type;
358                         strcpy(pb.host,inet_ntoa(host_address.sin_addr));
359                         pb.port = ntohs(host_address.sin_port);
360                         this->buffer.push_back(pb);
361
362                         strcpy(message,buffer[0].p.data);
363                         theirkey = buffer[0].p.key;
364                         strcpy(host,buffer[0].host);
365                         prt = buffer[0].port;
366                         
367                         buffer.erase(0);
368                 }
369
370                 return true;
371         }
372
373         log(DEBUG,"connection::RecvPacket(): Invalid packet type %d (protocol error)",p.type);
374         return true;
375 }
376