/* Copyright (c) 1995-1999 NEC USA, Inc.  All rights reserved.               */
/*                                                                           */
/* The redistribution, use and modification in source or binary forms of     */
/* this software is subject to the conditions set forth in the copyright     */
/* document ("Copyright") included with this distribution.                   */

/*
 * $Id: packet.c,v 1.11.4.4 1999/05/27 16:48:22 steve Exp $
 */

#include "socks5p.h"
#include "threads.h"
#include "daemon.h"
#include "packet.h"
#include "log.h"

static const char *Addr2Ascii(const S5NetAddr *na) {
    switch (na->sa.sa_family) {
	case AF_S5NAME:
	    return na->sn.sn_name;
	case AF_INET:
	    return inet_ntoa(na->sin.sin_addr);
	default:
	    return "";
    }
}

static u_short Addr2Port(const S5NetAddr *na) {
    switch (na->sa.sa_family) {
	case AF_S5NAME:
	    return na->sn.sn_port;
	case AF_INET:
	    return na->sin.sin_port;
	default:
	    return (u_short)0;
    }
}

#define AddrAndPort(x)     Addr2Ascii((x)), ntohs(Addr2Port((x)))

static int PacketPrintFilter(S5Packet *inPacket, S5Packet *outPacket, S5LinkInfo *pri, void *option, int *dir, int *action) {
    register u_int i,j;
    register char *sp;
    char buf[1024];

    /* Since we are only worried about what comes in, if this wasn't the     */
    /* result of a read, return -1, indicating we did nothing...             */
    if (*action != S5_ACTION_READ || !option) {
	return -1;
    }

    /* Ok the output of this packet, but print it first...                   */
    *outPacket = *inPacket;
    *action    = S5_ACTION_WRITE;

    /* Print out a header showing who sent what...                           */
    S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, 0, "PacketPrint: Sender: %s:%d", AddrAndPort((*dir == S5_DIRECTION_OUT)?&pri->srcAddr:&pri->dstAddr));
    S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, 0, "PacketPrint: Recver: %s:%d", AddrAndPort((*dir == S5_DIRECTION_OUT)?&pri->dstAddr:&pri->srcAddr));
    S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, 0, "PacketPrint: Packet contents (%d chars):", inPacket->off);
    sprintf(buf, "PacketPrint:     ");
    j = strlen("PacketPrint:     ");

    /* Print out the data contained in the packet...                         */
    for (i = 0, sp = inPacket->data; i < inPacket->off; i++, sp++) {
	if (isprint((unsigned char)*sp) && *sp != '\n') {
	    sprintf(buf+j, "%c", *sp);
	    j++;
	} else if (j + 3 > 80) {
	    i--; sp--;
	    j += 3;
	} else {
	    sprintf(buf+j, "\\%02x", (u_char)*sp);
	    j += 3;
	}

	/* Try to break around 80 characters or when there was a newline in  */
	/* the string itself...                                              */
	if (j > 80 || *sp == '\n') {
	    S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, 0, "%s", buf);
	    sprintf(buf, "PacketPrint:     ");
	    j = strlen("PacketPrint:     ");
	}
    }

    return 0;
}

int PacketPrintSetup(S5LinkInfo *li, S5FilterInfo *finfo) {
    MUTEX_LOCK(env_mutex);
    finfo->option = getenv("SOCKS5_PRINTPACKET")?(void *)-1:0;
    MUTEX_UNLOCK(env_mutex);

    if (!finfo->option) {
	finfo->filter = NULL;
	finfo->clean  = NULL;
	return -1;
    } else {
	finfo->filter = PacketPrintFilter;
	finfo->clean  = NULL;
	return 0;
    }
}

