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