/* Copyright (C) 2000-1 drscholl@users.sourceforge.net
   This is free software distributed under the terms of the
   GNU Public License.  See the file COPYING for details.

   $Id: proxy-client.c,v 1.1.1.1 2002/06/01 14:07:05 the_turner Exp $ */

/* a simple proxy server to spy on the traffic between clients.  this
   is a lot easier than using tcpdump.  */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <errno.h>

unsigned char buf[2048];

int
pass_message (const char *id, int s, int d)
{
    int     len;
    int     i;

    len = read (s, buf, sizeof (buf));
    if (len <= 0)
    {
	if (len == -1)
	    printf ("%s: %s\n", id, STRERROR (errno));
	else
	    printf ("%s: EOF\n", id);
	return -1;
    }
    buf[len] = 0;

    for (i = 0; i < len; i++)
	if (buf[i] == '\r')
	    buf[i] = 'M';

    printf ("%s: len=%d, data=%s\n", id, len, buf);

    write (d, buf, len);

    return 0;
}

static void
usage (void)
{
    puts ("usage: spyserv [ -s client ] [ -p clientport ] [ -l localport ]");
    exit (0);
}

int
main (int argc, char **argv)
{
    int     s;
    int     c;
    int     r;
    int     localport = 6699;
    size_t  sinsize;
    struct sockaddr_in sin;
    fd_set  fds;
    char   *host = "192.168.0.101";
    int     port = 6699;

    while ((r = getopt (argc, argv, "hs:p:l:")) != EOF)
    {
	switch (r)
	{
	case 'l':
	    localport = atoi (optarg);
	    break;
	case 's':
	    host = optarg;
	    break;
	case 'p':
	    port = atoi (optarg);
	    break;
	default:
	    usage ();
	}
    }

    /* accept connection from client */
    s = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (s < 0)
    {
	perror ("socket");
	exit (1);
    }
    c = 1;
    if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &c, sizeof (c)) != 0)
    {
	perror ("setsockopt");
	exit (1);
    }
    memset (&sin, 0, sizeof (sin));
    sin.sin_port = htons (localport);
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    if (bind (s, &sin, sizeof (sin)) < 0)
    {
	perror ("bind");
	exit (1);
    }
    if (listen (s, 1) < 0)
    {
	perror ("listen");
	exit (1);
    }

    for (;;)
    {
	puts ("waiting for connection");
	sinsize = sizeof (sin);
	c = accept (s, &sin, &sinsize);
	if (c < 0)
	{
	    perror ("accept");
	    exit (1);
	}
	puts ("got incoming connection");

	/* make connection to server */
	printf ("connecting to client...");
	fflush (stdout);
	r = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (r < 0)
	{
	    perror ("socket");
	    exit (1);
	}
	memset (&sin, 0, sizeof (sin));
	sin.sin_port = htons (port);
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = inet_addr (host);
	if (connect (r, &sin, sizeof (sin)) < 0)
	{
	    perror ("connect");
	    exit (1);
	}
	puts ("connected");

	for (;;)
	{
	    FD_ZERO (&fds);
	    FD_SET (r, &fds);
	    FD_SET (c, &fds);
	    puts ("Waiting for input");
	    if (select (((r > c) ? r : c) + 1, &fds, 0, 0, 0) < 0)
	    {
		perror ("select");
		break;
	    }
	    if (FD_ISSET (c, &fds))
	    {
		if (pass_message ("remote", c, r) != 0)
		    break;
	    }
	    if (FD_ISSET (r, &fds))
	    {
		if (pass_message ("local", r, c) != 0)
		    break;
	    }
	}

	close (r);
	close (c);
    }
    close (s);

    exit (0);
}
