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