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