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