1
2 /*
3 Clear Channel 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 force all channels to be created without
8 any encryption method. This makes reverse-engineering much, much
9 easier.
10
11 It also outputs the messages sent to and from the client to stdout
12 as hex pairs. If compiled with USE_HEXDUMP, output will be printed
13 via `hexdump -C`
14
15 All it really does is nab all Channel Create messages, strip the
16 offered ciphers portion from the message and replace it with an
17 empty ciphers list.
18
19 Christopher O'Brien <siege@preoccupied.net>
20 */
21
22
23 #include <netinet/in.h>
24 #include <netdb.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/socket.h>
29 #include <unistd.h>
30
31 #include <glib.h>
32 #include <glib.h>
33
34 #include <mw_common.h>
35 #include <mw_message.h>
36
37
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;
52 static struct proxy_side server;
53
54
hexdump(const char * txt,const guchar * buf,gsize len)55 static void hexdump(const char *txt, const guchar *buf, gsize len) {
56 FILE *fp;
57
58 if(txt) fprintf(stdout, "\n%s\n", txt);
59 fflush(stdout);
60
61 fp = popen("hexdump -C", "w");
62 fwrite(buf, len, 1, fp);
63 fflush(fp);
64 pclose(fp);
65 }
66
67
put_msg(struct mwMessage * msg,struct mwOpaque * o)68 static void put_msg(struct mwMessage *msg, struct mwOpaque *o) {
69 struct mwPutBuffer *b;
70
71 b = mwPutBuffer_new();
72 mwMessage_put(b, msg);
73 mwPutBuffer_finalize(o, b);
74
75 b = mwPutBuffer_new();
76 mwOpaque_put(b, o);
77 mwOpaque_clear(o);
78 mwPutBuffer_finalize(o, b);
79 }
80
81
side_buf_free(struct proxy_side * s)82 static void side_buf_free(struct proxy_side *s) {
83 g_free(s->buf);
84 s->buf = NULL;
85 s->buf_size = 0;
86 s->buf_recv = 0;
87 }
88
89
munge_redir()90 static void munge_redir() {
91 struct mwMessage *msg;
92 struct mwOpaque o = { 0, 0 };
93
94 msg = mwMessage_new(mwMessage_LOGIN_CONTINUE);
95 put_msg(msg, &o);
96 mwMessage_free(msg);
97
98 server.forward(o.data, o.len);
99
100 mwOpaque_clear(&o);
101 }
102
103
munge_create(struct proxy_side * side,struct mwMsgChannelCreate * msg)104 static void munge_create(struct proxy_side *side,
105 struct mwMsgChannelCreate *msg) {
106
107 struct mwOpaque o = { 0, 0 };
108 GList *l;
109
110 for(l = msg->encrypt.items; l; l = l->next) {
111 mwEncryptItem_clear(l->data);
112 g_free(l->data);
113 }
114 g_list_free(msg->encrypt.items);
115 msg->encrypt.items = NULL;
116
117 msg->encrypt.mode = 0x00;
118 msg->encrypt.extra = 0x00;
119 msg->encrypt.flag = FALSE;
120
121 put_msg(MW_MESSAGE(msg), &o);
122 side->forward(o.data, o.len);
123 mwOpaque_clear(&o);
124 }
125
126
side_process(struct proxy_side * s,const guchar * buf,gsize len)127 static void side_process(struct proxy_side *s, const guchar *buf, gsize len) {
128 struct mwOpaque o = { .len = len, .data = (guchar *) buf };
129 struct mwGetBuffer *b;
130 guint16 type;
131
132 if(! len) return;
133
134 b = mwGetBuffer_wrap(&o);
135 type = guint16_peek(b);
136
137 switch(type) {
138 case mwMessage_LOGIN_REDIRECT:
139 munge_redir();
140 break;
141
142 case mwMessage_CHANNEL_CREATE:
143 {
144 struct mwMessage *msg = mwMessage_get(b);
145 munge_create(s, (struct mwMsgChannelCreate *) msg);
146 mwMessage_free(msg);
147 break;
148 }
149
150 default:
151 {
152 struct mwPutBuffer *pb = mwPutBuffer_new();
153 struct mwOpaque po = { 0, 0 };
154 mwOpaque_put(pb, &o);
155 mwPutBuffer_finalize(&po, pb);
156 s->forward(po.data, po.len);
157 mwOpaque_clear(&po);
158 }
159 }
160
161 mwGetBuffer_free(b);
162 }
163
164
165 #define ADVANCE(b, n, count) { b += count; n -= count; }
166
167
168 /* handle input to complete an existing buffer */
side_recv_cont(struct proxy_side * s,const guchar * b,gsize n)169 static gsize side_recv_cont(struct proxy_side *s, const guchar *b, gsize n) {
170
171 gsize x = s->buf_size - s->buf_recv;
172
173 if(n < x) {
174 memcpy(s->buf+s->buf_recv, b, n);
175 s->buf_recv += n;
176 return 0;
177
178 } else {
179 memcpy(s->buf+s->buf_recv, b, x);
180 ADVANCE(b, n, x);
181
182 if(s->buf_size == 4) {
183 struct mwOpaque o = { .len = 4, .data = s->buf };
184 struct mwGetBuffer *gb = mwGetBuffer_wrap(&o);
185 x = guint32_peek(gb);
186 mwGetBuffer_free(gb);
187
188 if(n < x) {
189 guchar *t;
190 x += 4;
191 t = (guchar *) g_malloc(x);
192 memcpy(t, s->buf, 4);
193 memcpy(t+4, b, n);
194
195 side_buf_free(s);
196
197 s->buf = t;
198 s->buf_size = x;
199 s->buf_recv = n + 4;
200 return 0;
201
202 } else {
203 side_buf_free(s);
204 side_process(s, b, x);
205 ADVANCE(b, n, x);
206 }
207
208 } else {
209 side_process(s, s->buf+4, s->buf_size-4);
210 side_buf_free(s);
211 }
212 }
213
214 return n;
215 }
216
217
218 /* handle input when there's nothing previously buffered */
side_recv_empty(struct proxy_side * s,const guchar * b,gsize n)219 static gsize side_recv_empty(struct proxy_side *s, const guchar *b, gsize n) {
220 struct mwOpaque o = { .len = n, .data = (guchar *) b };
221 struct mwGetBuffer *gb;
222 gsize x;
223
224 if(n < 4) {
225 s->buf = (guchar *) g_malloc0(4);
226 memcpy(s->buf, b, n);
227 s->buf_size = 4;
228 s->buf_recv = n;
229 return 0;
230 }
231
232 gb = mwGetBuffer_wrap(&o);
233 x = guint32_peek(gb);
234 mwGetBuffer_free(gb);
235 if(! x) return n - 4;
236
237 if(n < (x + 4)) {
238
239 x += 4;
240 s->buf = (guchar *) g_malloc(x);
241 memcpy(s->buf, b, n);
242 s->buf_size = x;
243 s->buf_recv = n;
244 return 0;
245
246 } else {
247 ADVANCE(b, n, 4);
248 side_process(s, b, x);
249 ADVANCE(b, n, x);
250
251 return n;
252 }
253 }
254
255
side_recv(struct proxy_side * s,const guchar * b,gsize n)256 static gsize side_recv(struct proxy_side *s, const guchar *b, gsize n) {
257
258 if(n && (s->buf_size == 0) && (*b & 0x80)) {
259 ADVANCE(b, n, 1);
260 }
261
262 if(n == 0) {
263 return 0;
264
265 } else if(s->buf_size > 0) {
266 return side_recv_cont(s, b, n);
267
268 } else {
269 return side_recv_empty(s, b, n);
270 }
271 }
272
273
feed_buf(struct proxy_side * side,const guchar * buf,gsize n)274 static void feed_buf(struct proxy_side *side, const guchar *buf, gsize n) {
275 guchar *b = (guchar *) buf;
276 gsize remain = 0;
277
278 g_return_if_fail(side != NULL);
279
280 while(n > 0) {
281 remain = side_recv(side, b, n);
282 b += (n - remain);
283 n = remain;
284 }
285 }
286
287
read_recv(struct proxy_side * side)288 static int read_recv(struct proxy_side *side) {
289 guchar buf[2048];
290 int len;
291
292 len = read(side->sock, buf, 2048);
293 if(len > 0) feed_buf(side, buf, (gsize) len);
294
295 return len;
296 }
297
298
done()299 static void done() {
300 close(client.sock);
301 close(server.sock);
302 exit(0);
303 }
304
305
read_cb(GIOChannel * chan,GIOCondition cond,gpointer data)306 static gboolean read_cb(GIOChannel *chan,
307 GIOCondition cond,
308 gpointer data) {
309
310 struct proxy_side *side = data;
311 int ret = 0;
312
313 if(cond & G_IO_IN) {
314 ret = read_recv(side);
315 if(ret > 0) return TRUE;
316 }
317
318 if(side->sock) {
319 g_source_remove(side->chan_io);
320 close(side->sock);
321 side->sock = 0;
322 side->chan = NULL;
323 side->chan_io = 0;
324 }
325
326 done();
327
328 return FALSE;
329 }
330
331
client_cb(const guchar * buf,gsize len)332 static void client_cb(const guchar *buf, gsize len) {
333 if(server.sock) {
334 hexdump("client -> server", buf, len);
335 write(server.sock, buf, len);
336 }
337 }
338
339
listen_cb(GIOChannel * chan,GIOCondition cond,gpointer data)340 static gboolean listen_cb(GIOChannel *chan,
341 GIOCondition cond,
342 gpointer data) {
343
344 struct sockaddr_in rem;
345 guint len = sizeof(rem);
346 struct proxy_side *side = data;
347 int sock;
348
349 sock = accept(side->sock, (struct sockaddr *) &rem, &len);
350 g_assert(sock > 0);
351
352 g_source_remove(side->chan_io);
353 side->sock = sock;
354 side->chan = g_io_channel_unix_new(sock);
355 side->chan_io = g_io_add_watch(side->chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
356 read_cb, side);
357
358 return FALSE;
359 }
360
361
init_client(int port)362 static void init_client(int port) {
363 /* start listening on the local port specifier */
364
365 struct sockaddr_in sin;
366 int sock;
367
368 sock = socket(PF_INET, SOCK_STREAM, 0);
369 g_assert(sock >= 0);
370
371 memset(&sin, 0, sizeof(struct sockaddr_in));
372 sin.sin_family = PF_INET;
373 sin.sin_port = htons(port);
374 sin.sin_addr.s_addr = htonl(INADDR_ANY);
375
376 if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
377 g_assert_not_reached();
378
379 if(listen(sock, 1) < 0)
380 g_assert_not_reached();
381
382 client.forward = client_cb;
383 client.sock = sock;
384 client.chan = g_io_channel_unix_new(sock);
385 client.chan_io = g_io_add_watch(client.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
386 listen_cb, &client);
387 }
388
389
server_cb(const guchar * buf,gsize len)390 static void server_cb(const guchar *buf, gsize len) {
391 if(client.sock) {
392 hexdump("server -> client", buf, len);
393 write(client.sock, buf, len);
394 }
395 }
396
397
398 /* address lookup used by init_sock */
init_sockaddr(struct sockaddr_in * addr,const char * host,int port)399 static void init_sockaddr(struct sockaddr_in *addr,
400 const char *host, int port) {
401
402 struct hostent *hostinfo;
403
404 addr->sin_family = AF_INET;
405 addr->sin_port = htons (port);
406 hostinfo = gethostbyname(host);
407 if(hostinfo == NULL) {
408 fprintf(stderr, "Unknown host %s.\n", host);
409 exit(1);
410 }
411 addr->sin_addr = *(struct in_addr *) hostinfo->h_addr;
412 }
413
414
init_server(const char * host,int port)415 static void init_server(const char *host, int port) {
416 /* connect to server on host/port */
417 struct sockaddr_in srvrname;
418 int sock;
419
420 sock = socket(PF_INET, SOCK_STREAM, 0);
421 if(sock < 0) {
422 fprintf(stderr, "socket failure");
423 exit(1);
424 }
425
426 init_sockaddr(&srvrname, host, port);
427 connect(sock, (struct sockaddr *)&srvrname, sizeof(srvrname));
428
429 server.forward = server_cb;
430 server.sock = sock;
431 server.chan = g_io_channel_unix_new(sock);
432 server.chan_io = g_io_add_watch(server.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
433 read_cb, &server);
434 }
435
436
main(int argc,char * argv[])437 int main(int argc, char *argv[]) {
438 char *host = NULL;
439 int client_port = 0, server_port = 0;
440
441 memset(&client, 0, sizeof(struct proxy_side));
442 memset(&server, 0, sizeof(struct proxy_side));
443
444 if(argc > 1) {
445 char *z;
446
447 host = argv[1];
448 z = host;
449
450 host = strchr(z, ':');
451 if(host) *host++ = '\0';
452 client_port = atoi(z);
453
454 z = strchr(host, ':');
455 if(z) *z++ = '\0';
456 server_port = atoi(z);
457 }
458
459 if(!host || !*host || !client_port || !server_port) {
460 fprintf(stderr,
461 ( " Usage: %s local_port:remote_host:remote_port\n"
462 " Creates a locally-running sametime proxy which enforces"
463 " unencrypted channels\n" ),
464 argv[0]);
465 exit(1);
466 }
467
468 /* @todo create signal handlers to cleanup sockets */
469
470 init_client(client_port);
471 init_server(host, server_port);
472
473 g_main_loop_run(g_main_loop_new(NULL, FALSE));
474 return 0;
475 }
476
477