]> jfr.im git - irc/quakenet/newserv.git/blob - nterface/esockets.c
Added new nonce logic to esockets.
[irc/quakenet/newserv.git] / nterface / esockets.c
1 /*
2 Easy async socket library with HELIX encryption and authentication
3 Copyright (C) 2004-2005 Chris Porter.
4
5 v1.03
6 - changed nonce logic
7 v1.02
8 - added some \n stripping in crypto code
9 v1.01
10 - noticed small problem in _read, if ret == -1 && errno != EAGAIN then it would mess up
11 - now disconnects on write buffer filling up
12 - increased buffer size and maximum queue size
13 */
14
15 #include "esockets.h"
16 #include <stdio.h>
17 #include <sys/poll.h>
18 #include <errno.h>
19 #include <signal.h>
20 #include <stdlib.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <limits.h>
25 #include <stdarg.h>
26 #include <netinet/in.h>
27
28 #include "../lib/sha1.h"
29 #include "../core/events.h"
30
31 struct esocket *socklist = NULL;
32 char signal_set = 0;
33 unsigned short token = 1;
34
35 void sigpipe_handler(int moo) { }
36
37 unsigned short esocket_token(void) {
38 return token++;
39 }
40
41 struct esocket *esocket_add(int fd, char socket_type, struct esocket_events *events, unsigned short token) {
42 int flags;
43 struct esocket *newsock = (struct esocket *)malloc(sizeof(struct esocket));
44 if(!newsock)
45 return NULL;
46
47 memcpy(&newsock->events, events, sizeof(newsock->events));
48
49 newsock->socket_type = socket_type;
50
51 switch(socket_type) {
52 case ESOCKET_LISTENING:
53 /* listening sockets require POLLIN, which is triggered on connect */
54 flags = POLLIN;
55 newsock->socket_status = ST_LISTENING;
56 break;
57 case ESOCKET_OUTGOING:
58 /* outgoing connections require POLLOUT (triggered on connect) */
59 flags = POLLOUT;
60 newsock->socket_status = ST_CONNECTING;
61 break;
62 case ESOCKET_OUTGOING_CONNECTED:
63 /* outgoing connections that have connected (think localhost) require just POLLIN */
64 flags = POLLIN;
65 newsock->socket_status = ST_CONNECTED;
66 break;
67 case ESOCKET_INCOMING:
68 /* sockets that have just connected to us require (initially) POLLIN */
69 flags = POLLIN;
70 newsock->socket_status = ST_CONNECTED;
71 break;
72 default:
73 return NULL;
74 }
75
76 registerhandler(fd, flags | POLLERR | POLLHUP, esocket_poll_event);
77 newsock->fd = fd;
78 newsock->next = socklist;
79
80 newsock->in.on_parse = buffer_parse_ascii;
81 newsock->in.startpos = newsock->in.curpos = newsock->in.writepos = newsock->in.data;
82 newsock->in.buffer_size = MAX_ASCII_LINE_SIZE;
83 newsock->in.packet_length = 0;
84 newsock->out.head = NULL;
85 newsock->out.end = NULL;
86 newsock->out.count = 0;
87 newsock->token = token;
88 newsock->tag = NULL;
89
90 if(!signal_set) {
91 signal(SIGPIPE, sigpipe_handler);
92 signal_set = 1;
93 }
94
95 socklist = newsock;
96
97 return newsock;
98 }
99
100 struct esocket *find_esocket_from_fd(int fd) {
101 struct esocket *p = socklist;
102
103 for(;p;p=p->next)
104 if(p->fd == fd)
105 return p;
106
107 return NULL;
108 }
109
110 void esocket_clean_by_token(unsigned short token) {
111 struct esocket *cp = socklist, *np;
112
113 /* not efficient but boohoo */
114 for(;cp;) {
115 if(cp->token == token) {
116 np = cp->next;
117 esocket_disconnect(cp);
118 cp = np;
119 } else {
120 cp = cp->next;
121 }
122 }
123 }
124
125 void esocket_poll_event(int fd, short events) {
126 struct esocket *active = find_esocket_from_fd(fd);
127
128 if(!active)
129 return;
130
131 switch(active->socket_status) {
132 case ST_LISTENING:
133 active->events.on_accept(active);
134 break;
135 case ST_CONNECTING:
136 if(events & (POLLERR | POLLHUP)) {
137 esocket_disconnect(active);
138 return;
139 }
140 if(events & POLLOUT) { /* connected if connecting! */
141 deregisterhandler(active->fd, 0);
142 registerhandler(active->fd, POLLIN | POLLERR | POLLHUP, esocket_poll_event);
143 active->socket_status = ST_CONNECTED;
144 active->events.on_connect(active);
145 }
146 break;
147 case ST_CONNECTED:
148 case ST_BLANK:
149 if(events & (POLLERR | POLLHUP)) {
150 esocket_disconnect(active);
151 return;
152 }
153 if(events & POLLOUT) { /* flush buffer */
154 if(esocket_raw_write(active, NULL, 0)) {
155 esocket_disconnect(active);
156 return;
157 }
158 return;
159 }
160 if(events & POLLIN) { /* read buffer */
161 int ret = esocket_read(active);
162 if(ret) {
163 if(ret != BUF_ERROR)
164 esocket_disconnect(active);
165 return;
166 }
167 }
168
169 break;
170 }
171 }
172
173 void esocket_disconnect(struct esocket *active) {
174 struct esocket *l = NULL, *p = socklist;
175
176 if(active->events.on_disconnect)
177 active->events.on_disconnect(active);
178
179 for(;p;l=p,p=p->next)
180 if(p == active) {
181 struct esocket_packet *pkt = p->out.head, *npkt;
182 if(l) {
183 l->next = p->next;
184 } else {
185 socklist = p->next;
186 }
187
188 deregisterhandler(p->fd, 1);
189
190 for(;pkt;) {
191 npkt = pkt->next;
192 free(pkt->line);
193 free(pkt);
194 pkt = npkt;
195 }
196
197 free(p);
198 break;
199 }
200 }
201
202 void esocket_disconnect_when_complete(struct esocket *active) {
203 if(active->out.count) {
204 active->socket_status = ST_BLANK;
205 } else {
206 esocket_disconnect(active);
207 }
208 }
209
210 int esocket_read(struct esocket *sock) {
211 struct esocket_in_buffer *buf = &sock->in;
212 int ret, bytesread = read(sock->fd, buf->writepos, buf->buffer_size - (buf->writepos - buf->data));
213
214 if(!bytesread || ((bytesread == -1) && (errno != EAGAIN)))
215 return 1;
216
217 if((bytesread == -1) && (errno == EAGAIN))
218 return 0;
219
220 buf->writepos+=bytesread;
221
222 do {
223 ret = buf->on_parse(sock);
224 if((ret != BUF_CONT) && ret)
225 return ret;
226 } while(ret);
227
228 if((buf->curpos == (buf->data + buf->buffer_size)) && (buf->startpos == buf->data))
229 return 1;
230
231 if(buf->startpos != buf->curpos) {
232 int moveback = buf->writepos - buf->startpos;
233 memmove(buf->data, buf->startpos, moveback);
234 buf->writepos = buf->data + moveback;
235 } else {
236 buf->writepos = buf->data;
237 }
238
239 buf->curpos = buf->writepos;
240 buf->startpos = buf->data;
241
242 return 0;
243 }
244
245 struct esocket_packet *esocket_new_packet(struct esocket_out_buffer *buf, char *buffer, int bytes) {
246 struct esocket_packet *nw;
247
248 if(buf->count == MAX_OUT_QUEUE_SIZE)
249 return NULL;
250
251 nw = malloc(sizeof(struct esocket_packet));
252 if(!nw)
253 return NULL;
254
255 nw->line = malloc(bytes);
256 if(!nw->line) {
257 free(nw);
258 return NULL;
259 }
260
261 if(!buf->head) {
262 buf->head = nw;
263 } else {
264 buf->end->next = nw;
265 }
266
267 buf->end = nw;
268
269 nw->next = NULL;
270 nw->size = bytes;
271
272 memcpy(nw->line, buffer, bytes);
273
274 buf->count++;
275
276 return nw;
277 }
278
279 int esocket_raw_write(struct esocket *sock, char *buffer, int bytes) {
280 struct esocket_out_buffer *buf = &sock->out;
281
282 if((bytes > USHRT_MAX) || (!buffer && bytes) || (buffer && !bytes))
283 return 1;
284
285 if(bytes) { /* if we're not flushing */
286 if(buf->count) { /* if we're currently blocked */
287 if(!esocket_new_packet(buf, buffer, bytes))
288 return 1;
289 return 0;
290 } else { /* not currently blocked */
291 int ret;
292 for(;;) {
293 ret = write(sock->fd, buffer, bytes);
294 if(ret == bytes) {
295 return 0;
296 } else if(ret == -1) { /* something bad happened */
297 switch(errno) {
298 case EAGAIN: /* was going to block, store the data in the buffer */
299 if(!esocket_new_packet(buf, buffer, bytes))
300 return 1;
301
302 deregisterhandler(sock->fd, 0); /* now we need to ignore the socket until it's unblocked */
303 registerhandler(sock->fd, POLLOUT | POLLERR | POLLHUP, esocket_poll_event);
304
305 return 0;
306 break;
307 case EPIPE: /* if there's some weird code disconnect the socket */
308 default:
309 return 1;
310 break;
311 }
312 } else { /* less than total was written, try again */
313 buffer+=ret;
314 bytes-=ret;
315 }
316 }
317 }
318 } else if(buf->count) { /* if we're just flushing the buffer */
319 int ret;
320 for(;;) {
321 ret = write(sock->fd, buf->head->line, buf->head->size);
322 if(!ret) {
323 return 0;
324 } else if(ret == buf->head->size) {
325 struct esocket_packet *p = buf->head;
326 buf->head = buf->head->next;
327
328 free(p->line);
329 free(p);
330
331 buf->count--;
332 if(!buf->head) { /* if we've exhausted the buffer */
333 buf->end = NULL;
334
335 if(sock->socket_status == ST_BLANK) {
336 esocket_disconnect(sock);
337 } else {
338 deregisterhandler(sock->fd, 0);
339
340 registerhandler(sock->fd, POLLIN | POLLERR | POLLHUP, esocket_poll_event);
341 }
342 return 0;
343 }
344 } else if(ret == -1) {
345 switch(errno) {
346 case EAGAIN: /* was going to block, wait until we're called again */
347 return 0;
348 break;
349
350 case EPIPE: /* if there's some weird code disconnect the socket */
351 default:
352 return 1;
353 break;
354 }
355 } else {
356 buf->head->line+=ret;
357 buf->head->size-=ret;
358 }
359 }
360 return 0;
361 }
362
363 /* something went wrong */
364 return 1;
365 }
366
367 unsigned char *increase_nonce(unsigned char *nonce) {
368 u_int64_t *inonce = (u_int64_t *)(nonce + 8);
369 *inonce = htonq(ntohq(*inonce) + 1);
370 return nonce;
371 }
372
373 int esocket_write(struct esocket *sock, char *buffer, int bytes) {
374 int ret;
375 if(sock->in.on_parse == buffer_parse_ascii) {
376 ret = esocket_raw_write(sock, buffer, bytes);
377 } else {
378 unsigned char mac[MAC_LEN];
379 char newbuf[MAX_BUFSIZE + USED_MAC_LEN + sizeof(packet_t)];
380 packet_t packetlength;
381 if(bytes > MAX_BUFSIZE)
382 return 1;
383 packetlength = htons(bytes + USED_MAC_LEN);
384
385 memcpy(newbuf, &packetlength, sizeof(packet_t));
386 h_nonce(&sock->keysend, increase_nonce(sock->sendnonce));
387 h_encrypt(&sock->keysend, (unsigned char *)buffer, bytes, mac);
388
389 memcpy(newbuf + sizeof(packet_t), buffer, bytes);
390 memcpy(newbuf + sizeof(packet_t) + bytes, mac, USED_MAC_LEN);
391
392 ret = esocket_raw_write(sock, newbuf, bytes + sizeof(packet_t) + USED_MAC_LEN);
393 }
394
395 /* AWOOGA!! */
396 if(ret)
397 esocket_disconnect(sock);
398
399 return ret;
400 }
401
402 int esocket_write_line(struct esocket *sock, char *format, ...) {
403 char nbuf[MAX_ASCII_LINE_SIZE];
404 va_list va;
405 int len;
406
407 va_start(va, format);
408
409 if(sock->in.on_parse == buffer_parse_ascii) {
410 vsnprintf(nbuf, sizeof(nbuf) - 1, format, va); /* snprintf() and vsnprintf() will write at most size-1 of the characters, one for \n */
411 } else {
412 vsnprintf(nbuf, sizeof(nbuf), format, va);
413 }
414 va_end(va);
415
416 len = strlen(nbuf);
417
418 if(sock->in.on_parse == buffer_parse_ascii)
419 nbuf[len++] = '\n';
420
421 nbuf[len] = '\0';
422
423 return esocket_write(sock, nbuf, len);
424 }
425
426 int buffer_parse_ascii(struct esocket *sock) {
427 struct esocket_in_buffer *buf = &sock->in;
428
429 for(;buf->curpos<buf->writepos;buf->curpos++) {
430 if((*buf->curpos == '\n') || !*buf->curpos) {
431 int ret;
432 char *newline = buf->startpos;
433
434 *buf->curpos = '\0';
435
436 buf->startpos = buf->curpos + 1;
437
438 ret = sock->events.on_line(sock, newline);
439 if(ret)
440 return ret;
441
442 if(buf->curpos + 1 < buf->writepos) {
443 buf->curpos++;
444 return BUF_CONT;
445 }
446 }
447 }
448
449 return 0;
450 }
451
452 int buffer_parse_crypt(struct esocket *sock) {
453 struct esocket_in_buffer *buf = &sock->in;
454 unsigned char mac[MAC_LEN];
455
456 if(!buf->packet_length) {
457 if(buf->writepos - buf->startpos > sizeof(packet_t)) {
458 memcpy(&buf->packet_length, buf->startpos, sizeof(packet_t));
459 buf->startpos = buf->startpos + sizeof(packet_t);
460 buf->curpos = buf->startpos;
461
462 buf->packet_length = ntohs(buf->packet_length);
463 if((buf->packet_length > buf->buffer_size - sizeof(packet_t)) || (buf->packet_length <= 0))
464 return 1;
465
466 } else {
467 buf->curpos = buf->writepos;
468 return 0;
469 }
470 }
471
472 if(buf->packet_length <= buf->writepos - buf->startpos) {
473 int ret;
474 char *newline, *p;
475 h_nonce(&sock->keyreceive, increase_nonce(sock->recvnonce));
476 h_decrypt(&sock->keyreceive, (unsigned char *)buf->startpos, buf->packet_length - USED_MAC_LEN, mac);
477
478 if(memcmp(mac, buf->startpos + buf->packet_length - USED_MAC_LEN, USED_MAC_LEN))
479 return 1;
480
481 p = newline = buf->startpos;
482 newline[buf->packet_length - USED_MAC_LEN] = '\0';
483
484 for(;*p;p++) /* shouldn't happen */
485 if(*p == '\n')
486 *p = '\0';
487
488 buf->startpos = buf->startpos + buf->packet_length;
489 buf->packet_length = 0;
490
491 ret = sock->events.on_line(sock, newline);
492 if(ret)
493 return ret;
494
495 return BUF_CONT;
496 }
497
498 buf->curpos = buf->writepos;
499 return 0;
500 }
501
502 void switch_buffer_mode(struct esocket *sock, char *key, unsigned char *ournonce, unsigned char *theirnonce) {
503 unsigned char ukey[20];
504 SHA1_CTX context;
505
506 memcpy(sock->sendnonce, ournonce, sizeof(sock->sendnonce));
507 memcpy(sock->recvnonce, theirnonce, sizeof(sock->recvnonce));
508
509 SHA1Init(&context);
510 SHA1Update(&context, (unsigned char *)key, strlen(key));
511 SHA1Update(&context, (unsigned char *)" ", 1);
512 /* not sure if this is cryptographically secure! */
513 SHA1Update(&context, (unsigned char *)ournonce, NONCE_LEN);
514 SHA1Final(ukey, &context);
515
516 sock->in.on_parse = buffer_parse_crypt;
517 sock->in.buffer_size = MAX_BINARY_LINE_SIZE;
518
519 h_key(&sock->keysend, ukey, sizeof(ukey));
520
521 SHA1Init(&context);
522 SHA1Update(&context, (unsigned char *)key, strlen(key));
523 SHA1Update(&context, (unsigned char *)" ", 1);
524 SHA1Update(&context, (unsigned char *)theirnonce, NONCE_LEN);
525 SHA1Final(ukey, &context);
526
527 h_key(&sock->keyreceive, ukey, sizeof(ukey));
528 }
529