Blame samples/nocipher_proxy.c

Packit 16808d
Packit 16808d
/*
Packit 16808d
  Clear Channel Sametime Proxy Utility
Packit 16808d
  The Meanwhile Project
Packit 16808d
Packit 16808d
  This is a tool which can act as a proxy between a client and a
Packit 16808d
  sametime server, which will force all channels to be created without
Packit 16808d
  any encryption method. This makes reverse-engineering much, much
Packit 16808d
  easier.
Packit 16808d
Packit 16808d
  It also outputs the messages sent to and from the client to stdout
Packit 16808d
  as hex pairs. If compiled with USE_HEXDUMP, output will be printed
Packit 16808d
  via `hexdump -C`
Packit 16808d
  
Packit 16808d
  All it really does is nab all Channel Create messages, strip the
Packit 16808d
  offered ciphers portion from the message and replace it with an
Packit 16808d
  empty ciphers list.
Packit 16808d
Packit 16808d
  Christopher O'Brien <siege@preoccupied.net>
Packit 16808d
*/
Packit 16808d
Packit 16808d
Packit 16808d
#include <netinet/in.h>
Packit 16808d
#include <netdb.h>
Packit 16808d
#include <stdlib.h>
Packit 16808d
#include <stdio.h>
Packit 16808d
#include <string.h>
Packit 16808d
#include <sys/socket.h>
Packit 16808d
#include <unistd.h>
Packit 16808d
Packit 16808d
#include <glib.h>
Packit 16808d
Packit 16808d
#include <mw_common.h>
Packit 16808d
#include <mw_message.h>
Packit 16808d
Packit 16808d
Packit 16808d
struct proxy_side {
Packit 16808d
  int sock;
Packit 16808d
  GIOChannel *chan;
Packit 16808d
  gint chan_io;
Packit 16808d
Packit 16808d
  guchar *buf;
Packit 16808d
  gsize buf_size;
Packit 16808d
  gsize buf_recv;
Packit 16808d
Packit 16808d
  void (*forward)(const guchar *buf, gsize len);
Packit 16808d
};
Packit 16808d
Packit 16808d
Packit 16808d
static struct proxy_side client;
Packit 16808d
static struct proxy_side server;
Packit 16808d
Packit 16808d
Packit 16808d
static void hexdump(const char *txt, const guchar *buf, gsize len) {
Packit 16808d
  FILE *fp;
Packit 16808d
Packit 16808d
  if(txt) fprintf(stdout, "\n%s\n", txt);
Packit 16808d
  fflush(stdout);
Packit 16808d
Packit 16808d
  fp = popen("hexdump -C", "w");
Packit 16808d
  fwrite(buf, len, 1, fp);
Packit 16808d
  fflush(fp);
Packit 16808d
  pclose(fp);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void put_msg(struct mwMessage *msg, struct mwOpaque *o) {
Packit 16808d
  struct mwPutBuffer *b;
Packit 16808d
Packit 16808d
  b = mwPutBuffer_new();
Packit 16808d
  mwMessage_put(b, msg);
Packit 16808d
  mwPutBuffer_finalize(o, b);
Packit 16808d
  
Packit 16808d
  b = mwPutBuffer_new();
Packit 16808d
  mwOpaque_put(b, o);
Packit 16808d
  mwOpaque_clear(o);
Packit 16808d
  mwPutBuffer_finalize(o, b);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void side_buf_free(struct proxy_side *s) {
Packit 16808d
  g_free(s->buf);
Packit 16808d
  s->buf = NULL;
Packit 16808d
  s->buf_size = 0;
Packit 16808d
  s->buf_recv = 0;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void munge_redir() {
Packit 16808d
  struct mwMessage *msg;
Packit 16808d
  struct mwOpaque o = { 0, 0 };
Packit 16808d
Packit 16808d
  msg = mwMessage_new(mwMessage_LOGIN_CONTINUE);
Packit 16808d
  put_msg(msg, &o);
Packit 16808d
  mwMessage_free(msg);
Packit 16808d
Packit 16808d
  server.forward(o.data, o.len);
Packit 16808d
Packit 16808d
  mwOpaque_clear(&o);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void munge_create(struct proxy_side *side,
Packit 16808d
			 struct mwMsgChannelCreate *msg) {
Packit 16808d
Packit 16808d
  struct mwOpaque o = { 0, 0 };
Packit 16808d
  GList *l;
Packit 16808d
Packit 16808d
  for(l = msg->encrypt.items; l; l = l->next) {
Packit 16808d
    mwEncryptItem_clear(l->data);
Packit 16808d
    g_free(l->data);
Packit 16808d
  }
Packit 16808d
  g_list_free(msg->encrypt.items);
Packit 16808d
  msg->encrypt.items = NULL;
Packit 16808d
Packit 16808d
  msg->encrypt.mode = 0x00;
Packit 16808d
  msg->encrypt.extra = 0x00;
Packit 16808d
  msg->encrypt.flag = FALSE;
Packit 16808d
Packit 16808d
  put_msg(MW_MESSAGE(msg), &o);
Packit 16808d
  side->forward(o.data, o.len);
Packit 16808d
  mwOpaque_clear(&o);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void side_process(struct proxy_side *s, const guchar *buf, gsize len) {
Packit 16808d
  struct mwOpaque o = { .len = len, .data = (guchar *) buf };
Packit 16808d
  struct mwGetBuffer *b;
Packit 16808d
  guint16 type;
Packit 16808d
Packit 16808d
  if(! len) return;
Packit 16808d
Packit 16808d
  b = mwGetBuffer_wrap(&o);
Packit 16808d
  type = guint16_peek(b);
Packit 16808d
Packit 16808d
  switch(type) {
Packit 16808d
  case mwMessage_LOGIN_REDIRECT:
Packit 16808d
    munge_redir();
Packit 16808d
    break;
Packit 16808d
Packit 16808d
  case mwMessage_CHANNEL_CREATE:
Packit 16808d
    {
Packit 16808d
      struct mwMessage *msg = mwMessage_get(b);
Packit 16808d
      munge_create(s, (struct mwMsgChannelCreate *) msg);
Packit 16808d
      mwMessage_free(msg);
Packit 16808d
      break;
Packit 16808d
    }
Packit 16808d
    
Packit 16808d
  default:
Packit 16808d
    {
Packit 16808d
      struct mwPutBuffer *pb = mwPutBuffer_new();
Packit 16808d
      struct mwOpaque po = { 0, 0 };
Packit 16808d
      mwOpaque_put(pb, &o);
Packit 16808d
      mwPutBuffer_finalize(&po, pb);
Packit 16808d
      s->forward(po.data, po.len);
Packit 16808d
      mwOpaque_clear(&po);
Packit 16808d
    }
Packit 16808d
  }
Packit 16808d
Packit 16808d
  mwGetBuffer_free(b);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
#define ADVANCE(b, n, count) { b += count; n -= count; }
Packit 16808d
Packit 16808d
Packit 16808d
/* handle input to complete an existing buffer */
Packit 16808d
static gsize side_recv_cont(struct proxy_side *s, const guchar *b, gsize n) {
Packit 16808d
Packit 16808d
  gsize x = s->buf_size - s->buf_recv;
Packit 16808d
Packit 16808d
  if(n < x) {
Packit 16808d
    memcpy(s->buf+s->buf_recv, b, n);
Packit 16808d
    s->buf_recv += n;
Packit 16808d
    return 0;
Packit 16808d
    
Packit 16808d
  } else {
Packit 16808d
    memcpy(s->buf+s->buf_recv, b, x);
Packit 16808d
    ADVANCE(b, n, x);
Packit 16808d
    
Packit 16808d
    if(s->buf_size == 4) {
Packit 16808d
      struct mwOpaque o = { .len = 4, .data = s->buf };
Packit 16808d
      struct mwGetBuffer *gb = mwGetBuffer_wrap(&o);
Packit 16808d
      x = guint32_peek(gb);
Packit 16808d
      mwGetBuffer_free(gb);
Packit 16808d
Packit 16808d
      if(n < x) {
Packit 16808d
	guchar *t;
Packit 16808d
	x += 4;
Packit 16808d
	t = (guchar *) g_malloc(x);
Packit 16808d
	memcpy(t, s->buf, 4);
Packit 16808d
	memcpy(t+4, b, n);
Packit 16808d
	
Packit 16808d
	side_buf_free(s);
Packit 16808d
	
Packit 16808d
	s->buf = t;
Packit 16808d
	s->buf_size = x;
Packit 16808d
	s->buf_recv = n + 4;
Packit 16808d
	return 0;
Packit 16808d
	
Packit 16808d
      } else {
Packit 16808d
	side_buf_free(s);
Packit 16808d
	side_process(s, b, x);
Packit 16808d
	ADVANCE(b, n, x);
Packit 16808d
      }
Packit 16808d
      
Packit 16808d
    } else {
Packit 16808d
      side_process(s, s->buf+4, s->buf_size-4);
Packit 16808d
      side_buf_free(s);
Packit 16808d
    }
Packit 16808d
  }
Packit 16808d
Packit 16808d
  return n;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
/* handle input when there's nothing previously buffered */
Packit 16808d
static gsize side_recv_empty(struct proxy_side *s, const guchar *b, gsize n) {
Packit 16808d
  struct mwOpaque o = { .len = n, .data = (guchar *) b };
Packit 16808d
  struct mwGetBuffer *gb;
Packit 16808d
  gsize x;
Packit 16808d
Packit 16808d
  if(n < 4) {
Packit 16808d
    s->buf = (guchar *) g_malloc0(4);
Packit 16808d
    memcpy(s->buf, b, n);
Packit 16808d
    s->buf_size = 4;
Packit 16808d
    s->buf_recv = n;
Packit 16808d
    return 0;
Packit 16808d
  }
Packit 16808d
  
Packit 16808d
  gb = mwGetBuffer_wrap(&o);
Packit 16808d
  x = guint32_peek(gb);
Packit 16808d
  mwGetBuffer_free(gb);
Packit 16808d
  if(! x) return n - 4;
Packit 16808d
Packit 16808d
  if(n < (x + 4)) {
Packit 16808d
Packit 16808d
    x += 4;
Packit 16808d
    s->buf = (guchar *) g_malloc(x);
Packit 16808d
    memcpy(s->buf, b, n);
Packit 16808d
    s->buf_size = x;
Packit 16808d
    s->buf_recv = n;
Packit 16808d
    return 0;
Packit 16808d
    
Packit 16808d
  } else {
Packit 16808d
    ADVANCE(b, n, 4);
Packit 16808d
    side_process(s, b, x);
Packit 16808d
    ADVANCE(b, n, x);
Packit 16808d
Packit 16808d
    return n;
Packit 16808d
  }
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static gsize side_recv(struct proxy_side *s, const guchar *b, gsize n) {
Packit 16808d
Packit 16808d
  if(n && (s->buf_size == 0) && (*b & 0x80)) {
Packit 16808d
    ADVANCE(b, n, 1);
Packit 16808d
  }
Packit 16808d
Packit 16808d
  if(n == 0) {
Packit 16808d
    return 0;
Packit 16808d
Packit 16808d
  } else if(s->buf_size > 0) {
Packit 16808d
    return side_recv_cont(s, b, n);
Packit 16808d
Packit 16808d
  } else {
Packit 16808d
    return side_recv_empty(s, b, n);
Packit 16808d
  }
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void feed_buf(struct proxy_side *side, const guchar *buf, gsize n) {
Packit 16808d
  guchar *b = (guchar *) buf;
Packit 16808d
  gsize remain = 0;
Packit 16808d
  
Packit 16808d
  g_return_if_fail(side != NULL);
Packit 16808d
Packit 16808d
  while(n > 0) {
Packit 16808d
    remain = side_recv(side, b, n);
Packit 16808d
    b += (n - remain);
Packit 16808d
    n = remain;
Packit 16808d
  }
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static int read_recv(struct proxy_side *side) {
Packit 16808d
  guchar buf[2048];
Packit 16808d
  int len;
Packit 16808d
Packit 16808d
  len = read(side->sock, buf, 2048);
Packit 16808d
  if(len > 0) feed_buf(side, buf, (gsize) len);
Packit 16808d
Packit 16808d
  return len;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void done() {
Packit 16808d
  close(client.sock);
Packit 16808d
  close(server.sock);
Packit 16808d
  exit(0);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static gboolean read_cb(GIOChannel *chan,
Packit 16808d
			GIOCondition cond,
Packit 16808d
			gpointer data) {
Packit 16808d
Packit 16808d
  struct proxy_side *side = data;
Packit 16808d
  int ret = 0;
Packit 16808d
Packit 16808d
  if(cond & G_IO_IN) {
Packit 16808d
    ret = read_recv(side);
Packit 16808d
    if(ret > 0) return TRUE;
Packit 16808d
  }
Packit 16808d
Packit 16808d
  if(side->sock) {
Packit 16808d
    g_source_remove(side->chan_io);
Packit 16808d
    close(side->sock);
Packit 16808d
    side->sock = 0;
Packit 16808d
    side->chan = NULL;
Packit 16808d
    side->chan_io = 0;
Packit 16808d
  }
Packit 16808d
Packit 16808d
  done();
Packit 16808d
  
Packit 16808d
  return FALSE;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void client_cb(const guchar *buf, gsize len) {
Packit 16808d
  if(server.sock) {
Packit 16808d
    hexdump("client -> server", buf, len);
Packit 16808d
    write(server.sock, buf, len);
Packit 16808d
  }
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static gboolean listen_cb(GIOChannel *chan,
Packit 16808d
			  GIOCondition cond,
Packit 16808d
			  gpointer data) {
Packit 16808d
Packit 16808d
  struct sockaddr_in rem;
Packit 16808d
  guint len = sizeof(rem);
Packit 16808d
  struct proxy_side *side = data;
Packit 16808d
  int sock;
Packit 16808d
  
Packit 16808d
  sock = accept(side->sock, (struct sockaddr *) &rem, &len;;
Packit 16808d
  g_assert(sock > 0);
Packit 16808d
Packit 16808d
  g_source_remove(side->chan_io);
Packit 16808d
  side->sock = sock;
Packit 16808d
  side->chan = g_io_channel_unix_new(sock);
Packit 16808d
  side->chan_io = g_io_add_watch(side->chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit 16808d
				 read_cb, side);
Packit 16808d
Packit 16808d
  return FALSE;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void init_client(int port) {
Packit 16808d
  /* start listening on the local port specifier */
Packit 16808d
Packit 16808d
  struct sockaddr_in sin;
Packit 16808d
  int sock;
Packit 16808d
Packit 16808d
  sock = socket(PF_INET, SOCK_STREAM, 0);
Packit 16808d
  g_assert(sock >= 0);
Packit 16808d
Packit 16808d
  memset(&sin, 0, sizeof(struct sockaddr_in));
Packit 16808d
  sin.sin_family = PF_INET;
Packit 16808d
  sin.sin_port = htons(port);
Packit 16808d
  sin.sin_addr.s_addr = htonl(INADDR_ANY);
Packit 16808d
Packit 16808d
  if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
Packit 16808d
    g_assert_not_reached();
Packit 16808d
Packit 16808d
  if(listen(sock, 1) < 0)
Packit 16808d
    g_assert_not_reached();
Packit 16808d
Packit 16808d
  client.forward = client_cb;
Packit 16808d
  client.sock = sock;
Packit 16808d
  client.chan = g_io_channel_unix_new(sock);
Packit 16808d
  client.chan_io = g_io_add_watch(client.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit 16808d
				  listen_cb, &client);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void server_cb(const guchar *buf, gsize len) {
Packit 16808d
  if(client.sock) {
Packit 16808d
    hexdump("server -> client", buf, len);
Packit 16808d
    write(client.sock, buf, len);
Packit 16808d
  }
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
/* address lookup used by init_sock */
Packit 16808d
static void init_sockaddr(struct sockaddr_in *addr,
Packit 16808d
			  const char *host, int port) {
Packit 16808d
Packit 16808d
  struct hostent *hostinfo;
Packit 16808d
Packit 16808d
  addr->sin_family = AF_INET;
Packit 16808d
  addr->sin_port = htons (port);
Packit 16808d
  hostinfo = gethostbyname(host);
Packit 16808d
  if(hostinfo == NULL) {
Packit 16808d
    fprintf(stderr, "Unknown host %s.\n", host);
Packit 16808d
    exit(1);
Packit 16808d
  }
Packit 16808d
  addr->sin_addr = *(struct in_addr *) hostinfo->h_addr;
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
static void init_server(const char *host, int port) {
Packit 16808d
  /* connect to server on host/port */
Packit 16808d
  struct sockaddr_in srvrname;
Packit 16808d
  int sock;
Packit 16808d
Packit 16808d
  sock = socket(PF_INET, SOCK_STREAM, 0);
Packit 16808d
  if(sock < 0) {
Packit 16808d
    fprintf(stderr, "socket failure");
Packit 16808d
    exit(1);
Packit 16808d
  }
Packit 16808d
  
Packit 16808d
  init_sockaddr(&srvrname, host, port);
Packit 16808d
  connect(sock, (struct sockaddr *)&srvrname, sizeof(srvrname));
Packit 16808d
Packit 16808d
  server.forward = server_cb;
Packit 16808d
  server.sock = sock;
Packit 16808d
  server.chan = g_io_channel_unix_new(sock);
Packit 16808d
  server.chan_io = g_io_add_watch(server.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
Packit 16808d
				  read_cb, &server);
Packit 16808d
}
Packit 16808d
Packit 16808d
Packit 16808d
int main(int argc, char *argv[]) {
Packit 16808d
  char *host = NULL;
Packit 16808d
  int client_port = 0, server_port = 0;
Packit 16808d
Packit 16808d
  memset(&client, 0, sizeof(struct proxy_side));
Packit 16808d
  memset(&server, 0, sizeof(struct proxy_side));
Packit 16808d
Packit 16808d
  if(argc > 1) {
Packit 16808d
    char *z;
Packit 16808d
Packit 16808d
    host = argv[1];
Packit 16808d
    z = host;
Packit 16808d
Packit 16808d
    host = strchr(z, ':');
Packit 16808d
    if(host) *host++ = '\0';
Packit 16808d
    client_port = atoi(z);
Packit 16808d
Packit 16808d
    z = strchr(host, ':');
Packit 16808d
    if(z) *z++ = '\0';
Packit 16808d
    server_port = atoi(z);
Packit 16808d
  }
Packit 16808d
Packit 16808d
  if(!host || !*host || !client_port || !server_port) {
Packit 16808d
    fprintf(stderr,
Packit 16808d
	    ( " Usage: %s local_port:remote_host:remote_port\n"
Packit 16808d
	      " Creates a locally-running sametime proxy which enforces"
Packit 16808d
	      " unencrypted channels\n" ),
Packit 16808d
	    argv[0]);
Packit 16808d
    exit(1);
Packit 16808d
  }
Packit 16808d
Packit 16808d
  /* @todo create signal handlers to cleanup sockets */
Packit 16808d
Packit 16808d
  init_client(client_port);
Packit 16808d
  init_server(host, server_port);
Packit 16808d
Packit 16808d
  g_main_loop_run(g_main_loop_new(NULL, FALSE)); 
Packit 16808d
  return 0;
Packit 16808d
}
Packit 16808d