1
2 /*
3 Logging Sametime Proxy Utility
4 The Meanwhile Project
5
6 This is a tool which can act as a proxy between a client and a
7 sametime server, which will log all messages to stdout. It will also
8 munge channel creation messages in order to be able to decrypt any
9 encrypted data sent over a channel, and will log decrypted chunks to
10 stdout as well. This makes reverse-engineering of services much,
11 much easier.
12
13 The idea is simple, but the implementation made my head hurt.
14
15 Christopher O'Brien <siege@preoccupied.net>
16 */
17
18
19 #include <netinet/in.h>
20 #include <netdb.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/socket.h>
25 #include <unistd.h>
26
27 #include <glib.h>
28 #include <glib.h>
29
30 #include <mw_cipher.h>
31 #include <mw_common.h>
32 #include <mw_message.h>
33
34
35 /** one side of the proxy (either the client side or the server
36 side). The forward method for one should push data into the socket
37 of the other. */
38 struct proxy_side {
39 int sock;
40 GIOChannel *chan;
41 gint chan_io;
42
43 guchar *buf;
44 gsize buf_size;
45 gsize buf_recv;
46
47 void (*forward)(const guchar *buf, gsize len);
48 };
49
50
51 static struct proxy_side client; /**< side facing the client */
52 static struct proxy_side server; /**< side facing the server */
53
54
55 static char *host = NULL;
56 static int client_port = 0;
57 static int server_port = 0;
58
59
60 static int counter = 0;
61 static int listen_sock = 0;
62 static GIOChannel *listen_chan = NULL;
63 static gint listen_io = 0;
64
65
66
67
68
69 /** given one side, get the other */
70 #define OTHER_SIDE(side) \
71 ((side == &client)? &server: &client)
72
73
74 /** encryption state information used in the RC2/40 cipher */
75 struct rc2_40enc {
76 guchar outgoing_iv[8];
77 int outgoing_key[64];
78 guchar incoming_iv[8];
79 int incoming_key[64];
80 };
81
82
83 /* re-usable rc2 40 stuff */
84 static int session_key[64] = {
85 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 };
90
91
92 /** encryption state information used in the RC2/128 cipher */
93 struct rc2_128enc {
94 guchar outgoing_iv[8];
95 guchar incoming_iv[8];
96 int shared_key[64];
97 };
98
99
100 /* re-usable rc2 128 stuff */
101 static struct mwMpi *private_key;
102 static struct mwOpaque public_key;
103
104
105 /** represents a channel. The channel has a left side and a right
106 side. The left side is the creator of the channel. The right side
107 is the target of the channel. Each side has its own encryption
108 state information, so an incoming message from either side can
109 be decrypted, then re-encrypted for the other side. */
110 struct channel {
111 guint32 id;
112
113 /* login id of creator or NULL if created by client side */
114 char *creator;
115
116 /* the offer from the left side */
117 struct mwEncryptOffer offer;
118
119 /** the mode of encryption */
120 enum {
121 enc_none = 0, /**< nothing encrypted */
122 enc_easy, /**< easy (rc2/40) encryption */
123 enc_hard, /**< hard (rc2/128) encryption */
124 } enc_mode;
125
126 /** encryption data for the left side */
127 union {
128 struct rc2_40enc easy;
129 struct rc2_128enc hard;
130 } left_enc;
131
132 /** encryption data for the right side */
133 union {
134 struct rc2_40enc easy;
135 struct rc2_128enc hard;
136 } right_enc;
137
138 struct proxy_side *left; /**< proxy side acting as the left side */
139 struct proxy_side *right; /**< proxy side acting as the right side */
140 };
141
142
143 /* collection of channels */
144 static GHashTable *channels;
145
146
147 #define PUT_CHANNEL(chan) \
148 g_hash_table_insert(channels, GUINT_TO_POINTER((chan)->id), (chan))
149
150 #define GET_CHANNEL(id) \
151 g_hash_table_lookup(channels, GUINT_TO_POINTER(id))
152
153 #define REMOVE_CHANNEL(id) \
154 g_hash_table_remove(channels, GUINT_TO_POINTER(id))
155
156
157 /** print a message to stdout and use hexdump to print a data chunk */
hexdump_vprintf(const guchar * buf,gsize len,const char * txt,va_list args)158 static void hexdump_vprintf(const guchar *buf, gsize len,
159 const char *txt, va_list args) {
160 FILE *fp;
161
162 if(txt) {
163 fputc('\n', stdout);
164 vfprintf(stdout, txt, args);
165 fputc('\n', stdout);
166 }
167 fflush(stdout);
168
169 fp = popen("hexdump -C", "w");
170 fwrite(buf, len, 1, fp);
171 fflush(fp);
172 pclose(fp);
173 }
174
175
176 /** print a message to stdout and use hexdump to print a data chunk */
hexdump_printf(const guchar * buf,gsize len,const char * txt,...)177 static void hexdump_printf(const guchar *buf, gsize len,
178 const char *txt, ...) {
179 va_list args;
180 va_start(args, txt);
181 hexdump_vprintf(buf, len, txt, args);
182 va_end(args);
183 }
184
185
186 /** serialize a message for sending */
put_msg(struct mwMessage * msg,struct mwOpaque * o)187 static void put_msg(struct mwMessage *msg, struct mwOpaque *o) {
188 struct mwPutBuffer *b;
189
190 b = mwPutBuffer_new();
191 mwMessage_put(b, msg);
192 mwPutBuffer_finalize(o, b);
193
194 b = mwPutBuffer_new();
195 mwOpaque_put(b, o);
196 mwOpaque_clear(o);
197 mwPutBuffer_finalize(o, b);
198 }
199
200
key_copy(int to[64],int from[64])201 static void key_copy(int to[64], int from[64]) {
202 int i = 64;
203 while(i--) to[i] = from[i];
204 }
205
206
207 /* we don't want to be redirected away from the proxy, so eat any
208 redirect messages from the server and respond with a login cont */
munge_redir()209 static void munge_redir() {
210 struct mwMessage *msg;
211 struct mwOpaque o = { 0, 0 };
212
213 msg = mwMessage_new(mwMessage_LOGIN_CONTINUE);
214 put_msg(msg, &o);
215 mwMessage_free(msg);
216
217 server.forward(o.data, o.len);
218
219 mwOpaque_clear(&o);
220 }
221
222
223 /* handle receipt of channel create messages from either side,
224 recording the offered ciphers, and munging it to instead include
225 our own key as applicable, then sending it on */
munge_create(struct proxy_side * side,struct mwMsgChannelCreate * msg)226 static void munge_create(struct proxy_side *side,
227 struct mwMsgChannelCreate *msg) {
228
229 struct mwOpaque o = { 0, 0 };
230 GList *l;
231 struct channel *c;
232
233 /* create a new channel on the side */
234 c = g_new0(struct channel, 1);
235 c->id = msg->channel;
236 c->left = side;
237 c->right = OTHER_SIDE(side);
238
239 if(msg->creator_flag) {
240 c->creator = g_strdup(msg->creator.login_id);
241 }
242
243 /* record the mode and encryption items */
244 c->offer.mode = msg->encrypt.mode;
245 c->offer.items = msg->encrypt.items;
246 c->offer.extra = msg->encrypt.extra;
247 c->offer.flag = msg->encrypt.flag;
248
249 PUT_CHANNEL(c);
250
251 /* replace the encryption items with our own as applicable */
252 if(msg->encrypt.items) {
253 l = msg->encrypt.items;
254 msg->encrypt.items = NULL; /* steal them */
255
256 for(; l; l = l->next) {
257 struct mwEncryptItem *i1, *i2;
258
259 /* the original we've stolen */
260 i1 = l->data;
261
262 /* the munged replacement */
263 i2 = g_new0(struct mwEncryptItem, 1);
264 i2->id = i1->id;
265
266 switch(i1->id) {
267 case mwCipher_RC2_128:
268 printf("munging an offered RC2/128\n");
269 mwOpaque_clone(&i2->info, &public_key);
270 break;
271 case mwCipher_RC2_40:
272 printf("munging an offered RC2/40\n");
273 default:
274 ;
275 }
276
277 msg->encrypt.items = g_list_append(msg->encrypt.items, i2);
278 }
279 }
280
281 put_msg(MW_MESSAGE(msg), &o);
282 side->forward(o.data, o.len);
283 mwOpaque_clear(&o);
284 }
285
286
287 /* find an enc item by id in a list of items */
find_item(GList * items,guint16 id)288 struct mwEncryptItem *find_item(GList *items, guint16 id) {
289 GList *ltmp;
290 for(ltmp = items; ltmp; ltmp = ltmp->next) {
291 struct mwEncryptItem *i = ltmp->data;
292 if(i->id == id) return i;
293 }
294 return NULL;
295 }
296
297
298 /* handle acceptance of a channel */
munge_accept(struct proxy_side * side,struct mwMsgChannelAccept * msg)299 static void munge_accept(struct proxy_side *side,
300 struct mwMsgChannelAccept *msg) {
301
302 struct mwOpaque o = {0,0};
303 struct channel *chan;
304 struct mwEncryptItem *item;
305
306 chan = GET_CHANNEL(msg->head.channel);
307 item = msg->encrypt.item;
308
309 if(! item) {
310 /* cut to the chase */
311 put_msg(MW_MESSAGE(msg), &o);
312 side->forward(o.data, o.len);
313 mwOpaque_clear(&o);
314 return;
315 }
316
317 /* init right-side encryption with our enc and accepted enc */
318 switch(item->id) {
319 case mwCipher_RC2_128: {
320 struct mwMpi *remote, *shared;
321 struct mwOpaque k;
322
323 remote = mwMpi_new();
324 shared = mwMpi_new();
325
326 printf("right side accepted RC2/128\n");
327
328 mwMpi_import(remote, &item->info);
329 mwMpi_calculateDHShared(shared, remote, private_key);
330 mwMpi_export(shared, &k);
331
332 chan->enc_mode = enc_hard;
333
334 mwIV_init(chan->right_enc.hard.outgoing_iv);
335 mwIV_init(chan->right_enc.hard.incoming_iv);
336 mwKeyExpand(chan->right_enc.hard.shared_key, k.data+(k.len-16), 16);
337
338 mwMpi_free(remote);
339 mwMpi_free(shared);
340 mwOpaque_clear(&k);
341 break;
342 }
343 case mwCipher_RC2_40: {
344 char *who;
345
346 printf("right side accepted RC2/40\n");
347
348 chan->enc_mode = enc_easy;
349
350 mwIV_init(chan->right_enc.easy.outgoing_iv);
351 mwIV_init(chan->right_enc.easy.incoming_iv);
352
353 if(msg->acceptor_flag) {
354 who = msg->acceptor.login_id;
355 printf("right side is the server\n");
356 printf("server is %s\n", who);
357 mwKeyExpand(chan->right_enc.easy.incoming_key, (guchar *) who, 5);
358 key_copy(chan->right_enc.easy.outgoing_key, session_key);
359
360 } else {
361 who = chan->creator;
362 printf("right side is the client\n");
363 printf("server is %s\n", who);
364 key_copy(chan->right_enc.easy.incoming_key, session_key);
365 mwKeyExpand(chan->right_enc.easy.outgoing_key, (guchar *) who, 5);
366 }
367
368 break;
369 }
370 default:
371 chan->enc_mode = enc_none;
372 break;
373 }
374
375 /* init left-side encryption with offered enc and our enc, munge accept */
376 switch(item->id) {
377 case mwCipher_RC2_128: {
378 struct mwMpi *remote, *shared;
379 struct mwOpaque k;
380 struct mwEncryptItem *offered;
381
382 remote = mwMpi_new();
383 shared = mwMpi_new();
384
385 printf("accepting left side with RC2/128\n");
386
387 offered = find_item(chan->offer.items, mwCipher_RC2_128);
388 mwMpi_import(remote, &offered->info);
389 mwMpi_calculateDHShared(shared, remote, private_key);
390 mwMpi_export(shared, &k);
391
392 mwIV_init(chan->left_enc.hard.outgoing_iv);
393 mwIV_init(chan->left_enc.hard.incoming_iv);
394 mwKeyExpand(chan->left_enc.hard.shared_key, k.data+(k.len-16), 16);
395
396 mwMpi_free(remote);
397 mwMpi_free(shared);
398 mwOpaque_clear(&k);
399
400 /* munge accept with out public key */
401 mwOpaque_clear(&item->info);
402 mwOpaque_clone(&item->info, &public_key);
403 break;
404 }
405 case mwCipher_RC2_40:
406 printf("accepting left side with RC2/40\n");
407
408 mwIV_init(chan->left_enc.easy.outgoing_iv);
409 mwIV_init(chan->left_enc.easy.incoming_iv);
410
411 key_copy(chan->left_enc.easy.outgoing_key,
412 chan->right_enc.easy.incoming_key);
413
414 key_copy(chan->left_enc.easy.incoming_key,
415 chan->right_enc.easy.outgoing_key);
416 break;
417
418 default:
419 ;
420 }
421
422 put_msg(MW_MESSAGE(msg), &o);
423 side->forward(o.data, o.len);
424 mwOpaque_clear(&o);
425 }
426
427
dec(struct channel * chan,struct proxy_side * side,struct mwOpaque * to,struct mwOpaque * from)428 static void dec(struct channel *chan, struct proxy_side *side,
429 struct mwOpaque *to, struct mwOpaque *from) {
430
431 switch(chan->enc_mode) {
432 case enc_easy: {
433 if(chan->left == side) {
434 /* left side decrypt */
435 mwDecryptExpanded(chan->left_enc.easy.incoming_key,
436 chan->left_enc.easy.incoming_iv,
437 from, to);
438 } else {
439 /* right side decrypt */
440 mwDecryptExpanded(chan->right_enc.easy.incoming_key,
441 chan->right_enc.easy.incoming_iv,
442 from, to);
443 }
444 break;
445 }
446 case enc_hard: {
447 if(chan->left == side) {
448 /* left side decrypt */
449 mwDecryptExpanded(chan->left_enc.hard.shared_key,
450 chan->left_enc.hard.incoming_iv,
451 from, to);
452 } else {
453 /* right side decrypt */
454 mwDecryptExpanded(chan->right_enc.hard.shared_key,
455 chan->right_enc.hard.incoming_iv,
456 from, to);
457 }
458 break;
459 }
460 }
461 }
462
463
enc(struct channel * chan,struct proxy_side * side,struct mwOpaque * to,struct mwOpaque * from)464 static void enc(struct channel *chan, struct proxy_side *side,
465 struct mwOpaque *to, struct mwOpaque *from) {
466
467 switch(chan->enc_mode) {
468 case enc_easy: {
469 if(chan->left == side) {
470 /* left side encrypt */
471 mwEncryptExpanded(chan->left_enc.easy.outgoing_key,
472 chan->left_enc.easy.outgoing_iv,
473 from, to);
474 } else {
475 /* right side encrypt */
476 mwEncryptExpanded(chan->right_enc.easy.outgoing_key,
477 chan->right_enc.easy.outgoing_iv,
478 from, to);
479 }
480 break;
481 }
482 case enc_hard: {
483 if(chan->left == side) {
484 /* left side encrypt */
485 mwEncryptExpanded(chan->left_enc.hard.shared_key,
486 chan->left_enc.hard.outgoing_iv,
487 from, to);
488 } else {
489 /* right side encrypt */
490 mwEncryptExpanded(chan->right_enc.hard.shared_key,
491 chan->right_enc.hard.outgoing_iv,
492 from, to);
493 }
494 break;
495 }
496 }
497 }
498
499
munge_channel(struct proxy_side * side,struct mwMsgChannelSend * msg)500 static void munge_channel(struct proxy_side *side,
501 struct mwMsgChannelSend *msg) {
502
503 struct mwOpaque o = {0,0};
504
505 if(msg->head.options & mwMessageOption_ENCRYPT) {
506 struct mwOpaque d = {0,0};
507 struct channel *chan;
508
509 chan = GET_CHANNEL(msg->head.channel);
510
511 /* decrypt from side */
512 dec(chan, side, &d, &msg->data);
513
514 /* display */
515 hexdump_printf(d.data, d.len, "decrypted channel message data:",
516 msg->type);
517
518 /* encrypt to other side */
519 mwOpaque_clear(&msg->data);
520 enc(chan, OTHER_SIDE(side), &msg->data, &d);
521 mwOpaque_clear(&d);
522 }
523
524 /* send to other side */
525 put_msg(MW_MESSAGE(msg), &o);
526 side->forward(o.data, o.len);
527 mwOpaque_clear(&o);
528 }
529
530
531 /* handle destruction of a channel */
handle_destroy(struct proxy_side * side,struct mwMsgChannelDestroy * msg)532 static void handle_destroy(struct proxy_side *side,
533 struct mwMsgChannelDestroy *msg) {
534
535 struct channel *chan;
536 GList *l;
537
538 chan = GET_CHANNEL(msg->head.channel);
539 REMOVE_CHANNEL(msg->head.channel);
540
541 if(! chan) return;
542
543 for(l = chan->offer.items; l; l = l->next) {
544 mwEncryptItem_free(l->data);
545 }
546 g_list_free(chan->offer.items);
547 chan->offer.items = NULL;
548
549 g_free(chan->creator);
550 chan->creator = NULL;
551
552 g_free(chan);
553 }
554
555
forward(struct proxy_side * to,struct mwOpaque * data)556 static void forward(struct proxy_side *to,
557 struct mwOpaque *data) {
558
559 struct mwPutBuffer *pb = mwPutBuffer_new();
560 struct mwOpaque po = { 0, 0 };
561
562 mwOpaque_put(pb, data);
563 mwPutBuffer_finalize(&po, pb);
564 to->forward(po.data, po.len);
565 mwOpaque_clear(&po);
566 }
567
568
569 /* handle messages from either side */
side_process(struct proxy_side * s,const guchar * buf,gsize len)570 static void side_process(struct proxy_side *s, const guchar *buf, gsize len) {
571 struct mwOpaque o = { .len = len, .data = (guchar *) buf };
572 struct mwGetBuffer *b;
573 guint16 type;
574
575 if(! len) return;
576
577 if(s == &server) {
578 hexdump_printf(buf, len, "server -> client");
579 } else {
580 hexdump_printf(buf, len, "client -> server");
581 }
582
583 b = mwGetBuffer_wrap(&o);
584 type = guint16_peek(b);
585
586 switch(type) {
587 case mwMessage_LOGIN_ACK: {
588 struct mwMsgLoginAck *msg = (struct mwMsgLoginAck *) mwMessage_get(b);
589 printf("client is %s\n", msg->login.login_id);
590 mwKeyExpand(session_key, (guchar *) msg->login.login_id, 5);
591 mwMessage_free(MW_MESSAGE(msg));
592 forward(s, &o);
593 break;
594 }
595
596 case mwMessage_LOGIN_REDIRECT: {
597 munge_redir();
598 break;
599 }
600
601 case mwMessage_CHANNEL_CREATE: {
602 struct mwMessage *msg = mwMessage_get(b);
603 munge_create(s, (struct mwMsgChannelCreate *) msg);
604 mwMessage_free(msg);
605 break;
606 }
607
608 case mwMessage_CHANNEL_ACCEPT: {
609 struct mwMessage *msg = mwMessage_get(b);
610 munge_accept(s, (struct mwMsgChannelAccept *) msg);
611 mwMessage_free(msg);
612 break;
613 }
614
615 case mwMessage_CHANNEL_DESTROY: {
616 struct mwMessage *msg = mwMessage_get(b);
617 handle_destroy(s, (struct mwMsgChannelDestroy *) msg);
618 mwMessage_free(msg);
619 forward(s, &o);
620 break;
621 }
622
623 case mwMessage_CHANNEL_SEND: {
624 struct mwMessage *msg = mwMessage_get(b);
625 munge_channel(s, (struct mwMsgChannelSend *) msg);
626 mwMessage_free(msg);
627 break;
628 }
629
630 default:
631 forward(s, &o);
632 }
633
634 mwGetBuffer_free(b);
635 }
636
637
638 /** clean up a proxy side's inner buffer */
side_buf_free(struct proxy_side * s)639 static void side_buf_free(struct proxy_side *s) {
640 g_free(s->buf);
641 s->buf = NULL;
642 s->buf_size = 0;
643 s->buf_recv = 0;
644 }
645
646
647 #define ADVANCE(b, n, count) { b += count; n -= count; }
648
649
650 /** handle input to complete an existing buffer */
side_recv_cont(struct proxy_side * s,const guchar * b,gsize n)651 static gsize side_recv_cont(struct proxy_side *s, const guchar *b, gsize n) {
652
653 gsize x = s->buf_size - s->buf_recv;
654
655 if(n < x) {
656 memcpy(s->buf+s->buf_recv, b, n);
657 s->buf_recv += n;
658 return 0;
659
660 } else {
661 memcpy(s->buf+s->buf_recv, b, x);
662 ADVANCE(b, n, x);
663
664 if(s->buf_size == 4) {
665 struct mwOpaque o = { .len = 4, .data = s->buf };
666 struct mwGetBuffer *gb = mwGetBuffer_wrap(&o);
667 x = guint32_peek(gb);
668 mwGetBuffer_free(gb);
669
670 if(n < x) {
671 guchar *t;
672 x += 4;
673 t = (guchar *) g_malloc(x);
674 memcpy(t, s->buf, 4);
675 memcpy(t+4, b, n);
676
677 side_buf_free(s);
678
679 s->buf = t;
680 s->buf_size = x;
681 s->buf_recv = n + 4;
682 return 0;
683
684 } else {
685 side_buf_free(s);
686 side_process(s, b, x);
687 ADVANCE(b, n, x);
688 }
689
690 } else {
691 side_process(s, s->buf+4, s->buf_size-4);
692 side_buf_free(s);
693 }
694 }
695
696 return n;
697 }
698
699
700 /** handle input when there's nothing previously buffered */
side_recv_empty(struct proxy_side * s,const guchar * b,gsize n)701 static gsize side_recv_empty(struct proxy_side *s, const guchar *b, gsize n) {
702 struct mwOpaque o = { .len = n, .data = (guchar *) b };
703 struct mwGetBuffer *gb;
704 gsize x;
705
706 if(n < 4) {
707 s->buf = (guchar *) g_malloc0(4);
708 memcpy(s->buf, b, n);
709 s->buf_size = 4;
710 s->buf_recv = n;
711 return 0;
712 }
713
714 gb = mwGetBuffer_wrap(&o);
715 x = guint32_peek(gb);
716 mwGetBuffer_free(gb);
717 if(! x) return n - 4;
718
719 if(n < (x + 4)) {
720
721 x += 4;
722 s->buf = (guchar *) g_malloc(x);
723 memcpy(s->buf, b, n);
724 s->buf_size = x;
725 s->buf_recv = n;
726 return 0;
727
728 } else {
729 ADVANCE(b, n, 4);
730 side_process(s, b, x);
731 ADVANCE(b, n, x);
732
733 return n;
734 }
735 }
736
737
738 /** handle input in chunks */
side_recv(struct proxy_side * s,const guchar * b,gsize n)739 static gsize side_recv(struct proxy_side *s, const guchar *b, gsize n) {
740
741 if(n && (s->buf_size == 0) && (*b & 0x80)) {
742 ADVANCE(b, n, 1);
743 }
744
745 if(n == 0) {
746 return 0;
747
748 } else if(s->buf_size > 0) {
749 return side_recv_cont(s, b, n);
750
751 } else {
752 return side_recv_empty(s, b, n);
753 }
754 }
755
756
757 /** handle input */
feed_buf(struct proxy_side * side,const guchar * buf,gsize n)758 static void feed_buf(struct proxy_side *side, const guchar *buf, gsize n) {
759 guchar *b = (guchar *) buf;
760 gsize remain = 0;
761
762 g_return_if_fail(side != NULL);
763
764 while(n > 0) {
765 remain = side_recv(side, b, n);
766 b += (n - remain);
767 n = remain;
768 }
769 }
770
771
read_recv(struct proxy_side * side)772 static int read_recv(struct proxy_side *side) {
773 guchar buf[2048];
774 int len;
775
776 len = read(side->sock, buf, 2048);
777 if(len > 0) feed_buf(side, buf, (gsize) len);
778
779 return len;
780 }
781
782
783 static void init_listen();
784
785
side_done(struct proxy_side * side)786 static void side_done(struct proxy_side *side) {
787 if(side->sock) {
788 g_source_remove(side->chan_io);
789 close(side->sock);
790 side->sock = 0;
791 side->chan = NULL;
792 side->chan_io = 0;
793 }
794 }
795
796
done()797 static void done() {
798 printf("closing connection\n");
799
800 side_done(&client);
801 side_done(&server);
802
803 if(counter--) {
804 init_listen();
805 } else {
806 exit(0);
807 }
808 }
809
810
read_cb(GIOChannel * chan,GIOCondition cond,gpointer data)811 static gboolean read_cb(GIOChannel *chan,
812 GIOCondition cond,
813 gpointer data) {
814
815 struct proxy_side *side = data;
816 int ret = 0;
817
818 if(cond & G_IO_IN) {
819 ret = read_recv(side);
820 if(ret > 0) return TRUE;
821 }
822
823 done();
824
825 return FALSE;
826 }
827
828
client_cb(const guchar * buf,gsize len)829 static void client_cb(const guchar *buf, gsize len) {
830 if(server.sock) write(server.sock, buf, len);
831 }
832
833
834 /** setup the client */
init_client(int sock)835 static void init_client(int sock) {
836
837 client.forward = client_cb;
838 client.sock = sock;
839 client.chan = g_io_channel_unix_new(sock);
840 client.chan_io = g_io_add_watch(client.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
841 read_cb, &client);
842 }
843
844
server_cb(const guchar * buf,gsize len)845 static void server_cb(const guchar *buf, gsize len) {
846 if(client.sock) write(client.sock, buf, len);
847 }
848
849
850 /** generate a private/public DH keypair for internal (re)use */
init_rc2_128()851 static void init_rc2_128() {
852 struct mwMpi *public;
853
854 private_key = mwMpi_new();
855 public = mwMpi_new();
856
857 mwMpi_randDHKeypair(private_key, public);
858 mwMpi_export(public, &public_key);
859
860 mwMpi_free(public);
861 }
862
863
864 /** address lookup used by init_sock */
init_sockaddr(struct sockaddr_in * addr,const char * host,int port)865 static void init_sockaddr(struct sockaddr_in *addr,
866 const char *host, int port) {
867
868 struct hostent *hostinfo;
869
870 addr->sin_family = AF_INET;
871 addr->sin_port = htons (port);
872 hostinfo = gethostbyname(host);
873 if(hostinfo == NULL) {
874 fprintf(stderr, "Unknown host %s.\n", host);
875 exit(1);
876 }
877 addr->sin_addr = *(struct in_addr *) hostinfo->h_addr;
878 }
879
880
881 /** connect to server on host:port */
init_server()882 static void init_server() {
883 struct sockaddr_in srvrname;
884 int sock;
885
886 printf("connecting to %s:%i\n", host, server_port);
887
888 sock = socket(PF_INET, SOCK_STREAM, 0);
889 if(sock < 0) {
890 fprintf(stderr, "socket failure");
891 exit(1);
892 }
893
894 init_sockaddr(&srvrname, host, server_port);
895 connect(sock, (struct sockaddr *)&srvrname, sizeof(srvrname));
896
897 server.forward = server_cb;
898 server.sock = sock;
899 server.chan = g_io_channel_unix_new(sock);
900 server.chan_io = g_io_add_watch(server.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
901 read_cb, &server);
902
903 printf("connected to %s:%i\n", host, server_port);
904 }
905
906
907
listen_cb(GIOChannel * chan,GIOCondition cond,gpointer data)908 static gboolean listen_cb(GIOChannel *chan,
909 GIOCondition cond,
910 gpointer data) {
911
912 struct sockaddr_in rem;
913 guint len = sizeof(rem);
914 int sock;
915
916 printf("got connection\n");
917
918 sock = accept(listen_sock, (struct sockaddr *) &rem, &len);
919 /* g_assert(sock > 0); */
920
921 init_server();
922 init_client(sock);
923
924 listen_io = 0;
925
926 return FALSE;
927 }
928
929
init_listen()930 static void init_listen() {
931 if(! listen_sock) {
932 struct sockaddr_in sin;
933 int sock;
934
935 sock = socket(PF_INET, SOCK_STREAM, 0);
936 g_assert(sock >= 0);
937
938 memset(&sin, 0, sizeof(struct sockaddr_in));
939 sin.sin_family = PF_INET;
940 sin.sin_port = htons(client_port);
941 sin.sin_addr.s_addr = htonl(INADDR_ANY);
942
943 if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
944 g_assert_not_reached();
945
946 if(listen(sock, 1) < 0)
947 g_assert_not_reached();
948
949 listen_sock = sock;
950 listen_chan = g_io_channel_unix_new(sock);
951 }
952
953 if(! listen_io) {
954 listen_io = g_io_add_watch(listen_chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
955 listen_cb, NULL);
956 printf("listening on port %i\n", client_port);
957 }
958 }
959
960
main(int argc,char * argv[])961 int main(int argc, char *argv[]) {
962
963 memset(&client, 0, sizeof(struct proxy_side));
964 memset(&server, 0, sizeof(struct proxy_side));
965
966 if(argc > 1) {
967 char *z;
968
969 host = argv[1];
970 z = host;
971
972 host = strchr(z, ':');
973 if(host) *host++ = '\0';
974 client_port = atoi(z);
975
976 z = strchr(host, ':');
977 if(z) *z++ = '\0';
978 server_port = atoi(z);
979 }
980
981 if(argc > 2) {
982 counter = atoi(argv[2]);
983 }
984
985 if(!host || !*host || !client_port || !server_port) {
986 fprintf(stderr,
987 ( " Usage: %s local_port:remote_host:remote_port [n]\n"
988 " Creates a locally-running sametime proxy which enforces"
989 " unencrypted channels. Will drop the first n connections\n" ),
990 argv[0]);
991 exit(1);
992 }
993
994 /* @todo create signal handlers to cleanup sockets */
995
996 channels = g_hash_table_new(g_direct_hash, g_direct_equal);
997
998 init_rc2_128();
999 init_listen();
1000
1001 g_main_loop_run(g_main_loop_new(NULL, FALSE));
1002 return 0;
1003 }
1004
1005