]> 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         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         break;
143
144 }
145
146 bool connection::SendSYN(char* host, int port)
147 {
148         sockaddr_in host_address;
149         in_addr addy;
150         packet p;
151
152         memset((void*)&host_address, 0, sizeof(host_address));
153
154         host_address.sin_family = AF_INET;
155         inet_aton(host,&addy);
156         host_address.sin_addr = addy;
157
158         host_address.sin_port = htons(port);
159
160         p.type = PT_SYN_ONLY;
161         p.key = key;
162         strcpy(p.data,"");
163
164         if (sendto(fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0)
165         {
166                 return false;
167         }
168         return true;
169
170 }
171
172 bool connection::SendACK(char* host, int port, int reply_id)
173 {
174         sockaddr_in host_address;
175         in_addr addy;
176         packet p;
177
178         memset((void*)&host_address, 0, sizeof(host_address));
179
180         host_address.sin_family = AF_INET;
181         inet_aton(host,&addy);
182         host_address.sin_addr = addy;
183
184         host_address.sin_port = htons(port);
185
186         p.type = PT_ACK_ONLY;
187         p.key = key;
188         p.id = reply_id;
189         strcpy(p.data,"");
190
191         if (sendto(fd,&p,sizeof(p),0,(sockaddr*)&host_address,sizeof(host_address))<0)
192         {
193                 return false;
194         }
195
196 }
197
198
199 // Generates a server key. This is pseudo-random.
200 // the server always uses the same server-key in all communications
201 // across the network. All other servers must remember the server key
202 // of servers in the network, e.g.:
203 //
204 // ServerA:  key=5555555555
205 // ServerB:  key=6666666666
206 // I am ServerC: key=77777777777
207 //
208 // If ServerC sees a packet from ServerA, and the key stored for ServerA
209 // is 0, then cache the key as the servers key.
210 // after this point, any packet from ServerA which does not contain its key,
211 // 555555555, will be silently dropped.
212 // This should prevent blind spoofing, as to fake a server you must know its
213 // assigned key, and to do that you must receive messages that are origintated
214 // from it or hack the running executable.
215 //
216 // During the AUTH phase (when server passwords are checked, the key in any
217 // packet MUST be 0). Only the initial SERVER/PASS packets may have a key
218 // of 0 (and any ACK responses to them).
219 //
220
221 long connection::GenKey()
222 {
223         srand(time(NULL));
224         return (random()*time(NULL));
225 }
226
227 // host: in dot notation a.b.c.d
228 // port: host byte order
229 bool connection::RecvPacket(char *message, char* host, int &prt, long &theirkey)
230 {
231         // returns false if no packet waiting for receive, e.g. EAGAIN or ECONNRESET
232         sockaddr_in host_address;
233         socklen_t host_address_size;
234         packet p;
235         
236         memset((void*)&host_address, 0, sizeof(host_address));
237
238         host_address.sin_family=AF_INET;
239         host_address_size=sizeof(host_address);
240
241         //int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
242         if (recvfrom(fd,&p,sizeof(p),0,(sockaddr*)&host_address,&host_address_size)<0)
243         {
244                 return false;
245         }
246
247         log(DEBUG,"connection::RecvPacket(): received packet type %d '%s' from '%s'",p.type,p.data,inet_ntoa(host_address.sin_addr));
248
249         if (p.type == PT_SYN_ONLY)
250         {
251                 strcpy(message,p.data);
252                 strcpy(host,inet_ntoa(host_address.sin_addr));
253                 prt = ntohs(host_address.sin_port);
254                 SendACK(host,this->port,p.id);
255                 return false;
256         }
257
258         if (p.type == PT_ACK_ONLY)
259         {
260                 strcpy(message,p.data);
261                 strcpy(host,inet_ntoa(host_address.sin_addr));
262                 prt = ntohs(host_address.sin_port);
263                 this->state = STATE_CLEAR;
264                 return false;
265         }
266
267         if (p.type == PT_SYN_WITH_DATA)
268         {
269                 strcpy(message,p.data);
270                 strcpy(host,inet_ntoa(host_address.sin_addr));
271                 theirkey = p.key;
272                 prt = ntohs(host_address.sin_port); // the port we received it on
273                 SendACK(host,prt,p.id);
274                 return true;
275         }
276
277         log(DEBUG,"connection::RecvPacket(): Invalid packet type %d (protocol error)",p.type);
278         return true;
279 }
280