]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/connection.cpp
Fixes to packet handling
[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         buffer.clear();
36 }
37
38
39 bool connection::CreateListener(char* host, int p)
40 {
41         sockaddr_in host_address;
42         int flags;
43         in_addr addy;
44         int on = 0;
45         struct linger linger = { 0 };
46         
47         fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
48         if (fd <= 0)
49         {
50                 return false;
51         }
52
53         memset((void*)&host_address, 0, sizeof(host_address));
54
55         host_address.sin_family = AF_INET;
56
57         if (!strcmp(host,""))
58         {
59                 host_address.sin_addr.s_addr = htonl(INADDR_ANY);
60         }
61         else
62         {
63                 inet_aton(host,&addy);
64                 host_address.sin_addr = addy;
65         }
66
67         host_address.sin_port = htons(p);
68
69         if (bind(fd,(sockaddr*)&host_address,sizeof(host_address))<0)
70         {
71                 return false;
72         }
73
74         // make the socket non-blocking
75         flags = fcntl(fd, F_GETFL, 0);
76         fcntl(fd, F_SETFL, flags | O_NONBLOCK);
77
78         this->port = p;
79
80         setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(const char*)&on,sizeof(on));
81         linger.l_onoff = 1;
82         linger.l_linger = 0;
83         setsockopt(fd,SOL_SOCKET,SO_LINGER,(const char*)&linger,sizeof(linger));
84
85         buffer.clear();
86         
87         return true;
88 }
89
90 bool connection::BeginLink(char* targethost, int port, char* password)
91 {
92         char connect[MAXBUF];
93         
94         if (this->fd)
95         {
96                 sprintf(connect,"S %s %s :%s",getservername().c_str(),password,getserverdesc().c_str());
97                 this->haspassed = false;
98                 return this->SendPacket(connect, targethost, port, 0);
99         }
100         return false;
101 }
102
103 // targethost: in dot notation a.b.c.d
104 void connection::TerminateLink(char* targethost)
105 {
106 }
107
108 // host: in dot notation a.b.c.d
109 // port: host byte order
110 bool connection::SendPacket(char *message, char* host, int port, long ourkey)
111 {
112         sockaddr_in host_address;
113         in_addr addy;
114         packet p;
115
116         memset((void*)&host_address, 0, sizeof(host_address));
117
118         host_address.sin_family = AF_INET;
119         inet_aton(host,&addy);
120         host_address.sin_addr = addy;
121
122         host_address.sin_port = htons(port);
123
124         strcpy(p.data,message);
125         p.type = PT_SYN_WITH_DATA;
126         p.key = ourkey;
127
128
129         FOREACH_MOD OnPacketTransmit(p.data);
130
131         log(DEBUG,"main: Connection::SendPacket() sent '%s' to %s:%d",p.data,host,port);
132
133         // returns false if the packet could not be sent (e.g. target host down)
134         if (sendto(this->fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0)
135         {
136                 log(DEBUG,"sendto() failed for Connection::SendPacket() with a packet of size %d: %s",sizeof(p),strerror(errno));
137                 return false;
138         }
139
140         this->state = STATE_CLEAR;
141         return true;
142 }
143
144 bool connection::SendSYN(char* host, int port)
145 {
146         sockaddr_in host_address;
147         in_addr addy;
148         packet p;
149
150         memset((void*)&host_address, 0, sizeof(host_address));
151
152         host_address.sin_family = AF_INET;
153         inet_aton(host,&addy);
154         host_address.sin_addr = addy;
155
156         host_address.sin_port = htons(port);
157
158         p.type = PT_SYN_ONLY;
159         p.key = key;
160         strcpy(p.data,"");
161
162         if (sendto(fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0)
163         {
164                 return false;
165         }
166         return true;
167
168 }
169
170 bool connection::SendACK(char* host, int port, int reply_id)
171 {
172         sockaddr_in host_address;
173         in_addr addy;
174         packet p;
175
176         memset((void*)&host_address, 0, sizeof(host_address));
177
178         host_address.sin_family = AF_INET;
179         inet_aton(host,&addy);
180         host_address.sin_addr = addy;
181
182         host_address.sin_port = htons(port);
183
184         p.type = PT_ACK_ONLY;
185         p.key = key;
186         p.id = reply_id;
187         strcpy(p.data,"");
188
189         if (sendto(fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0)
190         {
191                 return false;
192         }
193
194 }
195
196
197 // Generates a server key. This is pseudo-random.
198 // the server always uses the same server-key in all communications
199 // across the network. All other servers must remember the server key
200 // of servers in the network, e.g.:
201 //
202 // ServerA:  key=5555555555
203 // ServerB:  key=6666666666
204 // I am ServerC: key=77777777777
205 //
206 // If ServerC sees a packet from ServerA, and the key stored for ServerA
207 // is 0, then cache the key as the servers key.
208 // after this point, any packet from ServerA which does not contain its key,
209 // 555555555, will be silently dropped.
210 // This should prevent blind spoofing, as to fake a server you must know its
211 // assigned key, and to do that you must receive messages that are origintated
212 // from it or hack the running executable.
213 //
214 // During the AUTH phase (when server passwords are checked, the key in any
215 // packet MUST be 0). Only the initial SERVER/PASS packets may have a key
216 // of 0 (and any ACK responses to them).
217 //
218
219 long connection::GenKey()
220 {
221         srand(time(NULL));
222         return (random()*time(NULL));
223 }
224
225 // host: in dot notation a.b.c.d
226 // port: host byte order
227 bool connection::RecvPacket(char *message, char* host, int &prt, long &theirkey)
228 {
229         // returns false if no packet waiting for receive, e.g. EAGAIN or ECONNRESET
230         sockaddr_in host_address;
231         socklen_t host_address_size;
232         packet p;
233         
234         memset((void*)&host_address, 0, sizeof(host_address));
235
236         host_address.sin_family=AF_INET;
237         host_address_size=sizeof(host_address);
238
239         //int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
240         if (recvfrom(fd,&p,sizeof(p),0,(sockaddr*)&host_address,&host_address_size)<0)
241         {
242                 return false;
243         }
244
245         log(DEBUG,"connection::RecvPacket(): received packet type %d '%s' from '%s'",p.type,p.data,inet_ntoa(host_address.sin_addr));
246
247         if (p.type == PT_SYN_ONLY)
248         {
249                 strcpy(message,p.data);
250                 strcpy(host,inet_ntoa(host_address.sin_addr));
251                 prt = ntohs(host_address.sin_port);
252                 SendACK(host,this->port,p.id);
253                 return false;
254         }
255
256         if (p.type == PT_ACK_ONLY)
257         {
258                 strcpy(message,p.data);
259                 strcpy(host,inet_ntoa(host_address.sin_addr));
260                 prt = ntohs(host_address.sin_port);
261                 this->state = STATE_CLEAR;
262                 return false;
263         }
264
265         if (p.type == PT_SYN_WITH_DATA)
266         {
267                 strcpy(message,p.data);
268                 strcpy(host,inet_ntoa(host_address.sin_addr));
269                 theirkey = p.key;
270                 prt = ntohs(host_address.sin_port); // the port we received it on
271                 SendACK(host,prt,p.id);
272                 return true;
273         }
274
275         log(DEBUG,"connection::RecvPacket(): Invalid packet type %d (protocol error)",p.type);
276         return true;
277 }
278