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