|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/*
|
|
Packit |
ee6627 |
Logging Sametime Proxy Utility
|
|
Packit |
ee6627 |
The Meanwhile Project
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
This is a tool which can act as a proxy between a client and a
|
|
Packit |
ee6627 |
sametime server, which will log all messages to stdout. It will also
|
|
Packit |
ee6627 |
munge channel creation messages in order to be able to decrypt any
|
|
Packit |
ee6627 |
encrypted data sent over a channel, and will log decrypted chunks to
|
|
Packit |
ee6627 |
stdout as well. This makes reverse-engineering of services much,
|
|
Packit |
ee6627 |
much easier.
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
The idea is simple, but the implementation made my head hurt.
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
Christopher O'Brien <siege@preoccupied.net>
|
|
Packit |
ee6627 |
*/
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
#include <netinet/in.h>
|
|
Packit |
ee6627 |
#include <netdb.h>
|
|
Packit |
ee6627 |
#include <stdlib.h>
|
|
Packit |
ee6627 |
#include <stdio.h>
|
|
Packit |
ee6627 |
#include <string.h>
|
|
Packit |
ee6627 |
#include <sys/socket.h>
|
|
Packit |
ee6627 |
#include <unistd.h>
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
#include <glib.h>
|
|
Packit |
ee6627 |
#include <glib/glist.h>
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
#include <mw_cipher.h>
|
|
Packit |
ee6627 |
#include <mw_common.h>
|
|
Packit |
ee6627 |
#include <mw_message.h>
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** one side of the proxy (either the client side or the server
|
|
Packit |
ee6627 |
side). The forward method for one should push data into the socket
|
|
Packit |
ee6627 |
of the other. */
|
|
Packit |
ee6627 |
struct proxy_side {
|
|
Packit |
ee6627 |
int sock;
|
|
Packit |
ee6627 |
GIOChannel *chan;
|
|
Packit |
ee6627 |
gint chan_io;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
guchar *buf;
|
|
Packit |
ee6627 |
gsize buf_size;
|
|
Packit |
ee6627 |
gsize buf_recv;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
void (*forward)(const guchar *buf, gsize len);
|
|
Packit |
ee6627 |
};
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static struct proxy_side client; /**< side facing the client */
|
|
Packit |
ee6627 |
static struct proxy_side server; /**< side facing the server */
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static char *host = NULL;
|
|
Packit |
ee6627 |
static int client_port = 0;
|
|
Packit |
ee6627 |
static int server_port = 0;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static int counter = 0;
|
|
Packit |
ee6627 |
static int listen_sock = 0;
|
|
Packit |
ee6627 |
static GIOChannel *listen_chan = NULL;
|
|
Packit |
ee6627 |
static gint listen_io = 0;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** given one side, get the other */
|
|
Packit |
ee6627 |
#define OTHER_SIDE(side) \
|
|
Packit |
ee6627 |
((side == &client)? &server: &client)
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** encryption state information used in the RC2/40 cipher */
|
|
Packit |
ee6627 |
struct rc2_40enc {
|
|
Packit |
ee6627 |
guchar outgoing_iv[8];
|
|
Packit |
ee6627 |
int outgoing_key[64];
|
|
Packit |
ee6627 |
guchar incoming_iv[8];
|
|
Packit |
ee6627 |
int incoming_key[64];
|
|
Packit |
ee6627 |
};
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* re-usable rc2 40 stuff */
|
|
Packit |
ee6627 |
static int session_key[64] = {
|
|
Packit |
ee6627 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit |
ee6627 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit |
ee6627 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit |
ee6627 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit |
ee6627 |
};
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** encryption state information used in the RC2/128 cipher */
|
|
Packit |
ee6627 |
struct rc2_128enc {
|
|
Packit |
ee6627 |
guchar outgoing_iv[8];
|
|
Packit |
ee6627 |
guchar incoming_iv[8];
|
|
Packit |
ee6627 |
int shared_key[64];
|
|
Packit |
ee6627 |
};
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* re-usable rc2 128 stuff */
|
|
Packit |
ee6627 |
static struct mwMpi *private_key;
|
|
Packit |
ee6627 |
static struct mwOpaque public_key;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** represents a channel. The channel has a left side and a right
|
|
Packit |
ee6627 |
side. The left side is the creator of the channel. The right side
|
|
Packit |
ee6627 |
is the target of the channel. Each side has its own encryption
|
|
Packit |
ee6627 |
state information, so an incoming message from either side can
|
|
Packit |
ee6627 |
be decrypted, then re-encrypted for the other side. */
|
|
Packit |
ee6627 |
struct channel {
|
|
Packit |
ee6627 |
guint32 id;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* login id of creator or NULL if created by client side */
|
|
Packit |
ee6627 |
char *creator;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* the offer from the left side */
|
|
Packit |
ee6627 |
struct mwEncryptOffer offer;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** the mode of encryption */
|
|
Packit |
ee6627 |
enum {
|
|
Packit |
ee6627 |
enc_none = 0, /**< nothing encrypted */
|
|
Packit |
ee6627 |
enc_easy, /**< easy (rc2/40) encryption */
|
|
Packit |
ee6627 |
enc_hard, /**< hard (rc2/128) encryption */
|
|
Packit |
ee6627 |
} enc_mode;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** encryption data for the left side */
|
|
Packit |
ee6627 |
union {
|
|
Packit |
ee6627 |
struct rc2_40enc easy;
|
|
Packit |
ee6627 |
struct rc2_128enc hard;
|
|
Packit |
ee6627 |
} left_enc;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** encryption data for the right side */
|
|
Packit |
ee6627 |
union {
|
|
Packit |
ee6627 |
struct rc2_40enc easy;
|
|
Packit |
ee6627 |
struct rc2_128enc hard;
|
|
Packit |
ee6627 |
} right_enc;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
struct proxy_side *left; /**< proxy side acting as the left side */
|
|
Packit |
ee6627 |
struct proxy_side *right; /**< proxy side acting as the right side */
|
|
Packit |
ee6627 |
};
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* collection of channels */
|
|
Packit |
ee6627 |
static GHashTable *channels;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
#define PUT_CHANNEL(chan) \
|
|
Packit |
ee6627 |
g_hash_table_insert(channels, GUINT_TO_POINTER((chan)->id), (chan))
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
#define GET_CHANNEL(id) \
|
|
Packit |
ee6627 |
g_hash_table_lookup(channels, GUINT_TO_POINTER(id))
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
#define REMOVE_CHANNEL(id) \
|
|
Packit |
ee6627 |
g_hash_table_remove(channels, GUINT_TO_POINTER(id))
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** print a message to stdout and use hexdump to print a data chunk */
|
|
Packit |
ee6627 |
static void hexdump_vprintf(const guchar *buf, gsize len,
|
|
Packit |
ee6627 |
const char *txt, va_list args) {
|
|
Packit |
ee6627 |
FILE *fp;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(txt) {
|
|
Packit |
ee6627 |
fputc('\n', stdout);
|
|
Packit |
ee6627 |
vfprintf(stdout, txt, args);
|
|
Packit |
ee6627 |
fputc('\n', stdout);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
fflush(stdout);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
fp = popen("hexdump -C", "w");
|
|
Packit |
ee6627 |
fwrite(buf, len, 1, fp);
|
|
Packit |
ee6627 |
fflush(fp);
|
|
Packit |
ee6627 |
pclose(fp);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** print a message to stdout and use hexdump to print a data chunk */
|
|
Packit |
ee6627 |
static void hexdump_printf(const guchar *buf, gsize len,
|
|
Packit |
ee6627 |
const char *txt, ...) {
|
|
Packit |
ee6627 |
va_list args;
|
|
Packit |
ee6627 |
va_start(args, txt);
|
|
Packit |
ee6627 |
hexdump_vprintf(buf, len, txt, args);
|
|
Packit |
ee6627 |
va_end(args);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** serialize a message for sending */
|
|
Packit |
ee6627 |
static void put_msg(struct mwMessage *msg, struct mwOpaque *o) {
|
|
Packit |
ee6627 |
struct mwPutBuffer *b;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
b = mwPutBuffer_new();
|
|
Packit |
ee6627 |
mwMessage_put(b, msg);
|
|
Packit |
ee6627 |
mwPutBuffer_finalize(o, b);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
b = mwPutBuffer_new();
|
|
Packit |
ee6627 |
mwOpaque_put(b, o);
|
|
Packit |
ee6627 |
mwOpaque_clear(o);
|
|
Packit |
ee6627 |
mwPutBuffer_finalize(o, b);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static void key_copy(int to[64], int from[64]) {
|
|
Packit |
ee6627 |
int i = 64;
|
|
Packit |
ee6627 |
while(i--) to[i] = from[i];
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* we don't want to be redirected away from the proxy, so eat any
|
|
Packit |
ee6627 |
redirect messages from the server and respond with a login cont */
|
|
Packit |
ee6627 |
static void munge_redir() {
|
|
Packit |
ee6627 |
struct mwMessage *msg;
|
|
Packit |
ee6627 |
struct mwOpaque o = { 0, 0 };
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
msg = mwMessage_new(mwMessage_LOGIN_CONTINUE);
|
|
Packit |
ee6627 |
put_msg(msg, &o);
|
|
Packit |
ee6627 |
mwMessage_free(msg);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
server.forward(o.data, o.len);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwOpaque_clear(&o);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* handle receipt of channel create messages from either side,
|
|
Packit |
ee6627 |
recording the offered ciphers, and munging it to instead include
|
|
Packit |
ee6627 |
our own key as applicable, then sending it on */
|
|
Packit |
ee6627 |
static void munge_create(struct proxy_side *side,
|
|
Packit |
ee6627 |
struct mwMsgChannelCreate *msg) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
struct mwOpaque o = { 0, 0 };
|
|
Packit |
ee6627 |
GList *l;
|
|
Packit |
ee6627 |
struct channel *c;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* create a new channel on the side */
|
|
Packit |
ee6627 |
c = g_new0(struct channel, 1);
|
|
Packit |
ee6627 |
c->id = msg->channel;
|
|
Packit |
ee6627 |
c->left = side;
|
|
Packit |
ee6627 |
c->right = OTHER_SIDE(side);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(msg->creator_flag) {
|
|
Packit |
ee6627 |
c->creator = g_strdup(msg->creator.login_id);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* record the mode and encryption items */
|
|
Packit |
ee6627 |
c->offer.mode = msg->encrypt.mode;
|
|
Packit |
ee6627 |
c->offer.items = msg->encrypt.items;
|
|
Packit |
ee6627 |
c->offer.extra = msg->encrypt.extra;
|
|
Packit |
ee6627 |
c->offer.flag = msg->encrypt.flag;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
PUT_CHANNEL(c);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* replace the encryption items with our own as applicable */
|
|
Packit |
ee6627 |
if(msg->encrypt.items) {
|
|
Packit |
ee6627 |
l = msg->encrypt.items;
|
|
Packit |
ee6627 |
msg->encrypt.items = NULL; /* steal them */
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
for(; l; l = l->next) {
|
|
Packit |
ee6627 |
struct mwEncryptItem *i1, *i2;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* the original we've stolen */
|
|
Packit |
ee6627 |
i1 = l->data;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* the munged replacement */
|
|
Packit |
ee6627 |
i2 = g_new0(struct mwEncryptItem, 1);
|
|
Packit |
ee6627 |
i2->id = i1->id;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
switch(i1->id) {
|
|
Packit |
ee6627 |
case mwCipher_RC2_128:
|
|
Packit |
ee6627 |
printf("munging an offered RC2/128\n");
|
|
Packit |
ee6627 |
mwOpaque_clone(&i2->info, &public_key);
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
case mwCipher_RC2_40:
|
|
Packit |
ee6627 |
printf("munging an offered RC2/40\n");
|
|
Packit |
ee6627 |
default:
|
|
Packit |
ee6627 |
;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
msg->encrypt.items = g_list_append(msg->encrypt.items, i2);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
put_msg(MW_MESSAGE(msg), &o);
|
|
Packit |
ee6627 |
side->forward(o.data, o.len);
|
|
Packit |
ee6627 |
mwOpaque_clear(&o);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* find an enc item by id in a list of items */
|
|
Packit |
ee6627 |
struct mwEncryptItem *find_item(GList *items, guint16 id) {
|
|
Packit |
ee6627 |
GList *ltmp;
|
|
Packit |
ee6627 |
for(ltmp = items; ltmp; ltmp = ltmp->next) {
|
|
Packit |
ee6627 |
struct mwEncryptItem *i = ltmp->data;
|
|
Packit |
ee6627 |
if(i->id == id) return i;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
return NULL;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* handle acceptance of a channel */
|
|
Packit |
ee6627 |
static void munge_accept(struct proxy_side *side,
|
|
Packit |
ee6627 |
struct mwMsgChannelAccept *msg) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
struct mwOpaque o = {0,0};
|
|
Packit |
ee6627 |
struct channel *chan;
|
|
Packit |
ee6627 |
struct mwEncryptItem *item;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
chan = GET_CHANNEL(msg->head.channel);
|
|
Packit |
ee6627 |
item = msg->encrypt.item;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(! item) {
|
|
Packit |
ee6627 |
/* cut to the chase */
|
|
Packit |
ee6627 |
put_msg(MW_MESSAGE(msg), &o);
|
|
Packit |
ee6627 |
side->forward(o.data, o.len);
|
|
Packit |
ee6627 |
mwOpaque_clear(&o);
|
|
Packit |
ee6627 |
return;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* init right-side encryption with our enc and accepted enc */
|
|
Packit |
ee6627 |
switch(item->id) {
|
|
Packit |
ee6627 |
case mwCipher_RC2_128: {
|
|
Packit |
ee6627 |
struct mwMpi *remote, *shared;
|
|
Packit |
ee6627 |
struct mwOpaque k;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
remote = mwMpi_new();
|
|
Packit |
ee6627 |
shared = mwMpi_new();
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
printf("right side accepted RC2/128\n");
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwMpi_import(remote, &item->info);
|
|
Packit |
ee6627 |
mwMpi_calculateDHShared(shared, remote, private_key);
|
|
Packit |
ee6627 |
mwMpi_export(shared, &k);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
chan->enc_mode = enc_hard;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwIV_init(chan->right_enc.hard.outgoing_iv);
|
|
Packit |
ee6627 |
mwIV_init(chan->right_enc.hard.incoming_iv);
|
|
Packit |
ee6627 |
mwKeyExpand(chan->right_enc.hard.shared_key, k.data+(k.len-16), 16);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwMpi_free(remote);
|
|
Packit |
ee6627 |
mwMpi_free(shared);
|
|
Packit |
ee6627 |
mwOpaque_clear(&k);
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
case mwCipher_RC2_40: {
|
|
Packit |
ee6627 |
char *who;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
printf("right side accepted RC2/40\n");
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
chan->enc_mode = enc_easy;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwIV_init(chan->right_enc.easy.outgoing_iv);
|
|
Packit |
ee6627 |
mwIV_init(chan->right_enc.easy.incoming_iv);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(msg->acceptor_flag) {
|
|
Packit |
ee6627 |
who = msg->acceptor.login_id;
|
|
Packit |
ee6627 |
printf("right side is the server\n");
|
|
Packit |
ee6627 |
printf("server is %s\n", who);
|
|
Packit |
ee6627 |
mwKeyExpand(chan->right_enc.easy.incoming_key, (guchar *) who, 5);
|
|
Packit |
ee6627 |
key_copy(chan->right_enc.easy.outgoing_key, session_key);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
who = chan->creator;
|
|
Packit |
ee6627 |
printf("right side is the client\n");
|
|
Packit |
ee6627 |
printf("server is %s\n", who);
|
|
Packit |
ee6627 |
key_copy(chan->right_enc.easy.incoming_key, session_key);
|
|
Packit |
ee6627 |
mwKeyExpand(chan->right_enc.easy.outgoing_key, (guchar *) who, 5);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
default:
|
|
Packit |
ee6627 |
chan->enc_mode = enc_none;
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* init left-side encryption with offered enc and our enc, munge accept */
|
|
Packit |
ee6627 |
switch(item->id) {
|
|
Packit |
ee6627 |
case mwCipher_RC2_128: {
|
|
Packit |
ee6627 |
struct mwMpi *remote, *shared;
|
|
Packit |
ee6627 |
struct mwOpaque k;
|
|
Packit |
ee6627 |
struct mwEncryptItem *offered;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
remote = mwMpi_new();
|
|
Packit |
ee6627 |
shared = mwMpi_new();
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
printf("accepting left side with RC2/128\n");
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
offered = find_item(chan->offer.items, mwCipher_RC2_128);
|
|
Packit |
ee6627 |
mwMpi_import(remote, &offered->info);
|
|
Packit |
ee6627 |
mwMpi_calculateDHShared(shared, remote, private_key);
|
|
Packit |
ee6627 |
mwMpi_export(shared, &k);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwIV_init(chan->left_enc.hard.outgoing_iv);
|
|
Packit |
ee6627 |
mwIV_init(chan->left_enc.hard.incoming_iv);
|
|
Packit |
ee6627 |
mwKeyExpand(chan->left_enc.hard.shared_key, k.data+(k.len-16), 16);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwMpi_free(remote);
|
|
Packit |
ee6627 |
mwMpi_free(shared);
|
|
Packit |
ee6627 |
mwOpaque_clear(&k);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* munge accept with out public key */
|
|
Packit |
ee6627 |
mwOpaque_clear(&item->info);
|
|
Packit |
ee6627 |
mwOpaque_clone(&item->info, &public_key);
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
case mwCipher_RC2_40:
|
|
Packit |
ee6627 |
printf("accepting left side with RC2/40\n");
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwIV_init(chan->left_enc.easy.outgoing_iv);
|
|
Packit |
ee6627 |
mwIV_init(chan->left_enc.easy.incoming_iv);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
key_copy(chan->left_enc.easy.outgoing_key,
|
|
Packit |
ee6627 |
chan->right_enc.easy.incoming_key);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
key_copy(chan->left_enc.easy.incoming_key,
|
|
Packit |
ee6627 |
chan->right_enc.easy.outgoing_key);
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
default:
|
|
Packit |
ee6627 |
;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
put_msg(MW_MESSAGE(msg), &o);
|
|
Packit |
ee6627 |
side->forward(o.data, o.len);
|
|
Packit |
ee6627 |
mwOpaque_clear(&o);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static void dec(struct channel *chan, struct proxy_side *side,
|
|
Packit |
ee6627 |
struct mwOpaque *to, struct mwOpaque *from) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
switch(chan->enc_mode) {
|
|
Packit |
ee6627 |
case enc_easy: {
|
|
Packit |
ee6627 |
if(chan->left == side) {
|
|
Packit |
ee6627 |
/* left side decrypt */
|
|
Packit |
ee6627 |
mwDecryptExpanded(chan->left_enc.easy.incoming_key,
|
|
Packit |
ee6627 |
chan->left_enc.easy.incoming_iv,
|
|
Packit |
ee6627 |
from, to);
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
/* right side decrypt */
|
|
Packit |
ee6627 |
mwDecryptExpanded(chan->right_enc.easy.incoming_key,
|
|
Packit |
ee6627 |
chan->right_enc.easy.incoming_iv,
|
|
Packit |
ee6627 |
from, to);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
case enc_hard: {
|
|
Packit |
ee6627 |
if(chan->left == side) {
|
|
Packit |
ee6627 |
/* left side decrypt */
|
|
Packit |
ee6627 |
mwDecryptExpanded(chan->left_enc.hard.shared_key,
|
|
Packit |
ee6627 |
chan->left_enc.hard.incoming_iv,
|
|
Packit |
ee6627 |
from, to);
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
/* right side decrypt */
|
|
Packit |
ee6627 |
mwDecryptExpanded(chan->right_enc.hard.shared_key,
|
|
Packit |
ee6627 |
chan->right_enc.hard.incoming_iv,
|
|
Packit |
ee6627 |
from, to);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static void enc(struct channel *chan, struct proxy_side *side,
|
|
Packit |
ee6627 |
struct mwOpaque *to, struct mwOpaque *from) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
switch(chan->enc_mode) {
|
|
Packit |
ee6627 |
case enc_easy: {
|
|
Packit |
ee6627 |
if(chan->left == side) {
|
|
Packit |
ee6627 |
/* left side encrypt */
|
|
Packit |
ee6627 |
mwEncryptExpanded(chan->left_enc.easy.outgoing_key,
|
|
Packit |
ee6627 |
chan->left_enc.easy.outgoing_iv,
|
|
Packit |
ee6627 |
from, to);
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
/* right side encrypt */
|
|
Packit |
ee6627 |
mwEncryptExpanded(chan->right_enc.easy.outgoing_key,
|
|
Packit |
ee6627 |
chan->right_enc.easy.outgoing_iv,
|
|
Packit |
ee6627 |
from, to);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
case enc_hard: {
|
|
Packit |
ee6627 |
if(chan->left == side) {
|
|
Packit |
ee6627 |
/* left side encrypt */
|
|
Packit |
ee6627 |
mwEncryptExpanded(chan->left_enc.hard.shared_key,
|
|
Packit |
ee6627 |
chan->left_enc.hard.outgoing_iv,
|
|
Packit |
ee6627 |
from, to);
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
/* right side encrypt */
|
|
Packit |
ee6627 |
mwEncryptExpanded(chan->right_enc.hard.shared_key,
|
|
Packit |
ee6627 |
chan->right_enc.hard.outgoing_iv,
|
|
Packit |
ee6627 |
from, to);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static void munge_channel(struct proxy_side *side,
|
|
Packit |
ee6627 |
struct mwMsgChannelSend *msg) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
struct mwOpaque o = {0,0};
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(msg->head.options & mwMessageOption_ENCRYPT) {
|
|
Packit |
ee6627 |
struct mwOpaque d = {0,0};
|
|
Packit |
ee6627 |
struct channel *chan;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
chan = GET_CHANNEL(msg->head.channel);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* decrypt from side */
|
|
Packit |
ee6627 |
dec(chan, side, &d, &msg->data);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* display */
|
|
Packit |
ee6627 |
hexdump_printf(d.data, d.len, "decrypted channel message data:",
|
|
Packit |
ee6627 |
msg->type);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* encrypt to other side */
|
|
Packit |
ee6627 |
mwOpaque_clear(&msg->data);
|
|
Packit |
ee6627 |
enc(chan, OTHER_SIDE(side), &msg->data, &d);
|
|
Packit |
ee6627 |
mwOpaque_clear(&d);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* send to other side */
|
|
Packit |
ee6627 |
put_msg(MW_MESSAGE(msg), &o);
|
|
Packit |
ee6627 |
side->forward(o.data, o.len);
|
|
Packit |
ee6627 |
mwOpaque_clear(&o);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* handle destruction of a channel */
|
|
Packit |
ee6627 |
static void handle_destroy(struct proxy_side *side,
|
|
Packit |
ee6627 |
struct mwMsgChannelDestroy *msg) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
struct channel *chan;
|
|
Packit |
ee6627 |
GList *l;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
chan = GET_CHANNEL(msg->head.channel);
|
|
Packit |
ee6627 |
REMOVE_CHANNEL(msg->head.channel);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(! chan) return;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
for(l = chan->offer.items; l; l = l->next) {
|
|
Packit |
ee6627 |
mwEncryptItem_free(l->data);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
g_list_free(chan->offer.items);
|
|
Packit |
ee6627 |
chan->offer.items = NULL;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
g_free(chan->creator);
|
|
Packit |
ee6627 |
chan->creator = NULL;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
g_free(chan);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static void forward(struct proxy_side *to,
|
|
Packit |
ee6627 |
struct mwOpaque *data) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
struct mwPutBuffer *pb = mwPutBuffer_new();
|
|
Packit |
ee6627 |
struct mwOpaque po = { 0, 0 };
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwOpaque_put(pb, data);
|
|
Packit |
ee6627 |
mwPutBuffer_finalize(&po, pb);
|
|
Packit |
ee6627 |
to->forward(po.data, po.len);
|
|
Packit |
ee6627 |
mwOpaque_clear(&po);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* handle messages from either side */
|
|
Packit |
ee6627 |
static void side_process(struct proxy_side *s, const guchar *buf, gsize len) {
|
|
Packit |
ee6627 |
struct mwOpaque o = { .len = len, .data = (guchar *) buf };
|
|
Packit |
ee6627 |
struct mwGetBuffer *b;
|
|
Packit |
ee6627 |
guint16 type;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(! len) return;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(s == &server) {
|
|
Packit |
ee6627 |
hexdump_printf(buf, len, "server -> client");
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
hexdump_printf(buf, len, "client -> server");
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
b = mwGetBuffer_wrap(&o);
|
|
Packit |
ee6627 |
type = guint16_peek(b);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
switch(type) {
|
|
Packit |
ee6627 |
case mwMessage_LOGIN_ACK: {
|
|
Packit |
ee6627 |
struct mwMsgLoginAck *msg = (struct mwMsgLoginAck *) mwMessage_get(b);
|
|
Packit |
ee6627 |
printf("client is %s\n", msg->login.login_id);
|
|
Packit |
ee6627 |
mwKeyExpand(session_key, (guchar *) msg->login.login_id, 5);
|
|
Packit |
ee6627 |
mwMessage_free(MW_MESSAGE(msg));
|
|
Packit |
ee6627 |
forward(s, &o);
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
case mwMessage_LOGIN_REDIRECT: {
|
|
Packit |
ee6627 |
munge_redir();
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
case mwMessage_CHANNEL_CREATE: {
|
|
Packit |
ee6627 |
struct mwMessage *msg = mwMessage_get(b);
|
|
Packit |
ee6627 |
munge_create(s, (struct mwMsgChannelCreate *) msg);
|
|
Packit |
ee6627 |
mwMessage_free(msg);
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
case mwMessage_CHANNEL_ACCEPT: {
|
|
Packit |
ee6627 |
struct mwMessage *msg = mwMessage_get(b);
|
|
Packit |
ee6627 |
munge_accept(s, (struct mwMsgChannelAccept *) msg);
|
|
Packit |
ee6627 |
mwMessage_free(msg);
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
case mwMessage_CHANNEL_DESTROY: {
|
|
Packit |
ee6627 |
struct mwMessage *msg = mwMessage_get(b);
|
|
Packit |
ee6627 |
handle_destroy(s, (struct mwMsgChannelDestroy *) msg);
|
|
Packit |
ee6627 |
mwMessage_free(msg);
|
|
Packit |
ee6627 |
forward(s, &o);
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
case mwMessage_CHANNEL_SEND: {
|
|
Packit |
ee6627 |
struct mwMessage *msg = mwMessage_get(b);
|
|
Packit |
ee6627 |
munge_channel(s, (struct mwMsgChannelSend *) msg);
|
|
Packit |
ee6627 |
mwMessage_free(msg);
|
|
Packit |
ee6627 |
break;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
default:
|
|
Packit |
ee6627 |
forward(s, &o);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwGetBuffer_free(b);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** clean up a proxy side's inner buffer */
|
|
Packit |
ee6627 |
static void side_buf_free(struct proxy_side *s) {
|
|
Packit |
ee6627 |
g_free(s->buf);
|
|
Packit |
ee6627 |
s->buf = NULL;
|
|
Packit |
ee6627 |
s->buf_size = 0;
|
|
Packit |
ee6627 |
s->buf_recv = 0;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
#define ADVANCE(b, n, count) { b += count; n -= count; }
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** handle input to complete an existing buffer */
|
|
Packit |
ee6627 |
static gsize side_recv_cont(struct proxy_side *s, const guchar *b, gsize n) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
gsize x = s->buf_size - s->buf_recv;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(n < x) {
|
|
Packit |
ee6627 |
memcpy(s->buf+s->buf_recv, b, n);
|
|
Packit |
ee6627 |
s->buf_recv += n;
|
|
Packit |
ee6627 |
return 0;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
memcpy(s->buf+s->buf_recv, b, x);
|
|
Packit |
ee6627 |
ADVANCE(b, n, x);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(s->buf_size == 4) {
|
|
Packit |
ee6627 |
struct mwOpaque o = { .len = 4, .data = s->buf };
|
|
Packit |
ee6627 |
struct mwGetBuffer *gb = mwGetBuffer_wrap(&o);
|
|
Packit |
ee6627 |
x = guint32_peek(gb);
|
|
Packit |
ee6627 |
mwGetBuffer_free(gb);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(n < x) {
|
|
Packit |
ee6627 |
guchar *t;
|
|
Packit |
ee6627 |
x += 4;
|
|
Packit |
ee6627 |
t = (guchar *) g_malloc(x);
|
|
Packit |
ee6627 |
memcpy(t, s->buf, 4);
|
|
Packit |
ee6627 |
memcpy(t+4, b, n);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
side_buf_free(s);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
s->buf = t;
|
|
Packit |
ee6627 |
s->buf_size = x;
|
|
Packit |
ee6627 |
s->buf_recv = n + 4;
|
|
Packit |
ee6627 |
return 0;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
side_buf_free(s);
|
|
Packit |
ee6627 |
side_process(s, b, x);
|
|
Packit |
ee6627 |
ADVANCE(b, n, x);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
side_process(s, s->buf+4, s->buf_size-4);
|
|
Packit |
ee6627 |
side_buf_free(s);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
return n;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** handle input when there's nothing previously buffered */
|
|
Packit |
ee6627 |
static gsize side_recv_empty(struct proxy_side *s, const guchar *b, gsize n) {
|
|
Packit |
ee6627 |
struct mwOpaque o = { .len = n, .data = (guchar *) b };
|
|
Packit |
ee6627 |
struct mwGetBuffer *gb;
|
|
Packit |
ee6627 |
gsize x;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(n < 4) {
|
|
Packit |
ee6627 |
s->buf = (guchar *) g_malloc0(4);
|
|
Packit |
ee6627 |
memcpy(s->buf, b, n);
|
|
Packit |
ee6627 |
s->buf_size = 4;
|
|
Packit |
ee6627 |
s->buf_recv = n;
|
|
Packit |
ee6627 |
return 0;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
gb = mwGetBuffer_wrap(&o);
|
|
Packit |
ee6627 |
x = guint32_peek(gb);
|
|
Packit |
ee6627 |
mwGetBuffer_free(gb);
|
|
Packit |
ee6627 |
if(! x) return n - 4;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(n < (x + 4)) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
x += 4;
|
|
Packit |
ee6627 |
s->buf = (guchar *) g_malloc(x);
|
|
Packit |
ee6627 |
memcpy(s->buf, b, n);
|
|
Packit |
ee6627 |
s->buf_size = x;
|
|
Packit |
ee6627 |
s->buf_recv = n;
|
|
Packit |
ee6627 |
return 0;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
ADVANCE(b, n, 4);
|
|
Packit |
ee6627 |
side_process(s, b, x);
|
|
Packit |
ee6627 |
ADVANCE(b, n, x);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
return n;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** handle input in chunks */
|
|
Packit |
ee6627 |
static gsize side_recv(struct proxy_side *s, const guchar *b, gsize n) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(n && (s->buf_size == 0) && (*b & 0x80)) {
|
|
Packit |
ee6627 |
ADVANCE(b, n, 1);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(n == 0) {
|
|
Packit |
ee6627 |
return 0;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
} else if(s->buf_size > 0) {
|
|
Packit |
ee6627 |
return side_recv_cont(s, b, n);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
return side_recv_empty(s, b, n);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** handle input */
|
|
Packit |
ee6627 |
static void feed_buf(struct proxy_side *side, const guchar *buf, gsize n) {
|
|
Packit |
ee6627 |
guchar *b = (guchar *) buf;
|
|
Packit |
ee6627 |
gsize remain = 0;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
g_return_if_fail(side != NULL);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
while(n > 0) {
|
|
Packit |
ee6627 |
remain = side_recv(side, b, n);
|
|
Packit |
ee6627 |
b += (n - remain);
|
|
Packit |
ee6627 |
n = remain;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static int read_recv(struct proxy_side *side) {
|
|
Packit |
ee6627 |
guchar buf[2048];
|
|
Packit |
ee6627 |
int len;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
len = read(side->sock, buf, 2048);
|
|
Packit |
ee6627 |
if(len > 0) feed_buf(side, buf, (gsize) len);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
return len;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static void init_listen();
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static void side_done(struct proxy_side *side) {
|
|
Packit |
ee6627 |
if(side->sock) {
|
|
Packit |
ee6627 |
g_source_remove(side->chan_io);
|
|
Packit |
ee6627 |
close(side->sock);
|
|
Packit |
ee6627 |
side->sock = 0;
|
|
Packit |
ee6627 |
side->chan = NULL;
|
|
Packit |
ee6627 |
side->chan_io = 0;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static void done() {
|
|
Packit |
ee6627 |
printf("closing connection\n");
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
side_done(&client);
|
|
Packit |
ee6627 |
side_done(&server);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(counter--) {
|
|
Packit |
ee6627 |
init_listen();
|
|
Packit |
ee6627 |
} else {
|
|
Packit |
ee6627 |
exit(0);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static gboolean read_cb(GIOChannel *chan,
|
|
Packit |
ee6627 |
GIOCondition cond,
|
|
Packit |
ee6627 |
gpointer data) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
struct proxy_side *side = data;
|
|
Packit |
ee6627 |
int ret = 0;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(cond & G_IO_IN) {
|
|
Packit |
ee6627 |
ret = read_recv(side);
|
|
Packit |
ee6627 |
if(ret > 0) return TRUE;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
done();
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
return FALSE;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static void client_cb(const guchar *buf, gsize len) {
|
|
Packit |
ee6627 |
if(server.sock) write(server.sock, buf, len);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** setup the client */
|
|
Packit |
ee6627 |
static void init_client(int sock) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
client.forward = client_cb;
|
|
Packit |
ee6627 |
client.sock = sock;
|
|
Packit |
ee6627 |
client.chan = g_io_channel_unix_new(sock);
|
|
Packit |
ee6627 |
client.chan_io = g_io_add_watch(client.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
|
|
Packit |
ee6627 |
read_cb, &client);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static void server_cb(const guchar *buf, gsize len) {
|
|
Packit |
ee6627 |
if(client.sock) write(client.sock, buf, len);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** generate a private/public DH keypair for internal (re)use */
|
|
Packit |
ee6627 |
static void init_rc2_128() {
|
|
Packit |
ee6627 |
struct mwMpi *public;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
private_key = mwMpi_new();
|
|
Packit |
ee6627 |
public = mwMpi_new();
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwMpi_randDHKeypair(private_key, public);
|
|
Packit |
ee6627 |
mwMpi_export(public, &public_key);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
mwMpi_free(public);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** address lookup used by init_sock */
|
|
Packit |
ee6627 |
static void init_sockaddr(struct sockaddr_in *addr,
|
|
Packit |
ee6627 |
const char *host, int port) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
struct hostent *hostinfo;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
addr->sin_family = AF_INET;
|
|
Packit |
ee6627 |
addr->sin_port = htons (port);
|
|
Packit |
ee6627 |
hostinfo = gethostbyname(host);
|
|
Packit |
ee6627 |
if(hostinfo == NULL) {
|
|
Packit |
ee6627 |
fprintf(stderr, "Unknown host %s.\n", host);
|
|
Packit |
ee6627 |
exit(1);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
addr->sin_addr = *(struct in_addr *) hostinfo->h_addr;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/** connect to server on host:port */
|
|
Packit |
ee6627 |
static void init_server() {
|
|
Packit |
ee6627 |
struct sockaddr_in srvrname;
|
|
Packit |
ee6627 |
int sock;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
printf("connecting to %s:%i\n", host, server_port);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
sock = socket(PF_INET, SOCK_STREAM, 0);
|
|
Packit |
ee6627 |
if(sock < 0) {
|
|
Packit |
ee6627 |
fprintf(stderr, "socket failure");
|
|
Packit |
ee6627 |
exit(1);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
init_sockaddr(&srvrname, host, server_port);
|
|
Packit |
ee6627 |
connect(sock, (struct sockaddr *)&srvrname, sizeof(srvrname));
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
server.forward = server_cb;
|
|
Packit |
ee6627 |
server.sock = sock;
|
|
Packit |
ee6627 |
server.chan = g_io_channel_unix_new(sock);
|
|
Packit |
ee6627 |
server.chan_io = g_io_add_watch(server.chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
|
|
Packit |
ee6627 |
read_cb, &server);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
printf("connected to %s:%i\n", host, server_port);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static gboolean listen_cb(GIOChannel *chan,
|
|
Packit |
ee6627 |
GIOCondition cond,
|
|
Packit |
ee6627 |
gpointer data) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
struct sockaddr_in rem;
|
|
Packit |
ee6627 |
guint len = sizeof(rem);
|
|
Packit |
ee6627 |
int sock;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
printf("got connection\n");
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
sock = accept(listen_sock, (struct sockaddr *) &rem, &len;;
|
|
Packit |
ee6627 |
/* g_assert(sock > 0); */
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
init_server();
|
|
Packit |
ee6627 |
init_client(sock);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
listen_io = 0;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
return FALSE;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
static void init_listen() {
|
|
Packit |
ee6627 |
if(! listen_sock) {
|
|
Packit |
ee6627 |
struct sockaddr_in sin;
|
|
Packit |
ee6627 |
int sock;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
sock = socket(PF_INET, SOCK_STREAM, 0);
|
|
Packit |
ee6627 |
g_assert(sock >= 0);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
memset(&sin, 0, sizeof(struct sockaddr_in));
|
|
Packit |
ee6627 |
sin.sin_family = PF_INET;
|
|
Packit |
ee6627 |
sin.sin_port = htons(client_port);
|
|
Packit |
ee6627 |
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
|
|
Packit |
ee6627 |
g_assert_not_reached();
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(listen(sock, 1) < 0)
|
|
Packit |
ee6627 |
g_assert_not_reached();
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
listen_sock = sock;
|
|
Packit |
ee6627 |
listen_chan = g_io_channel_unix_new(sock);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(! listen_io) {
|
|
Packit |
ee6627 |
listen_io = g_io_add_watch(listen_chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
|
|
Packit |
ee6627 |
listen_cb, NULL);
|
|
Packit |
ee6627 |
printf("listening on port %i\n", client_port);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
int main(int argc, char *argv[]) {
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
memset(&client, 0, sizeof(struct proxy_side));
|
|
Packit |
ee6627 |
memset(&server, 0, sizeof(struct proxy_side));
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(argc > 1) {
|
|
Packit |
ee6627 |
char *z;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
host = argv[1];
|
|
Packit |
ee6627 |
z = host;
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
host = strchr(z, ':');
|
|
Packit |
ee6627 |
if(host) *host++ = '\0';
|
|
Packit |
ee6627 |
client_port = atoi(z);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
z = strchr(host, ':');
|
|
Packit |
ee6627 |
if(z) *z++ = '\0';
|
|
Packit |
ee6627 |
server_port = atoi(z);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(argc > 2) {
|
|
Packit |
ee6627 |
counter = atoi(argv[2]);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
if(!host || !*host || !client_port || !server_port) {
|
|
Packit |
ee6627 |
fprintf(stderr,
|
|
Packit |
ee6627 |
( " Usage: %s local_port:remote_host:remote_port [n]\n"
|
|
Packit |
ee6627 |
" Creates a locally-running sametime proxy which enforces"
|
|
Packit |
ee6627 |
" unencrypted channels. Will drop the first n connections\n" ),
|
|
Packit |
ee6627 |
argv[0]);
|
|
Packit |
ee6627 |
exit(1);
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
/* @todo create signal handlers to cleanup sockets */
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
channels = g_hash_table_new(g_direct_hash, g_direct_equal);
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
init_rc2_128();
|
|
Packit |
ee6627 |
init_listen();
|
|
Packit |
ee6627 |
|
|
Packit |
ee6627 |
g_main_loop_run(g_main_loop_new(NULL, FALSE));
|
|
Packit |
ee6627 |
return 0;
|
|
Packit |
ee6627 |
}
|
|
Packit |
ee6627 |
|