/***************************************************************************
 *
 * Copyright (c) 2000, 2001 BalaBit IT Ltd, Budapest, Hungary
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: packsock.c,v 1.7.2.1.2.3 2001/09/19 19:22:16 bazsi Exp $
 *
 * Author  : Bazsi
 * Auditor : kisza
 * Last version: 1.4
 * Notes:
 *    - messages: no process identifier !
 *
 ***************************************************************************/

#define MAX_UDP_PACKET 16384
#define MAX_TIMEOUT 15

#include <time.h>

#include <zorp/packsock.h>
#include <zorp/sockaddr.h>
#include <zorp/zorp.h>
#include <zorp/io.h>
#include <zorp/log.h>
#include <zorp/ctrack.h>
#include <zorp/stream.h>
#include <zorp/cap.h>

#if ENABLE_CONNTRACK

#define CORE_DEBUG "core.debug"
#define CORE_ERROR "core.error"

gboolean
z_packsock_receive(int fd, ZPacket *packet)
{
  struct sockaddr_in from;
  struct sockaddr_in *to_p = (struct sockaddr_in *) &(from.sin_zero);
  int from_len = sizeof(struct sockaddr_in);

  z_enter();
  z_trace(NULL, "fd=%d, packet available", fd);

  packet->data = g_new(char, MAX_UDP_PACKET);

  /* IP: transparent proxy must be compiled into kernel */

  packet->length = recvfrom(fd, packet->data,
			   MAX_UDP_PACKET, MSG_PROXY, &from, &from_len);
  if (packet->length == -1)
    {
      z_leave();
      return TRUE;
    }
  packet->data = g_renew(char, packet->data, packet->length);

#if ENABLE_PACKET_TRACE
  z_data_dump("Haliho", packet->data, packet->length);
#endif

  memcpy(&(packet->packheader.from), &from, sizeof(struct sockaddr_in));
  memcpy(&(packet->packheader.to), to_p, sizeof(struct sockaddr_in));
  
  z_leave();
  return TRUE;
}

int
z_packsock_send(ZPacket *packet, guint socket, struct sockaddr_in *xfrom,
                                 struct sockaddr_in *xto)
{
  struct sockaddr_in to;
  struct sockaddr_in *from = (struct sockaddr_in *) &(to.sin_zero);
  int ret;
  cap_t oldcaps;

  z_enter();
  
  to.sin_family = AF_INET;
  to.sin_port = xto->sin_port;
  to.sin_addr.s_addr = xto->sin_addr.s_addr;
        
  from->sin_family = AF_INET;
  from->sin_port = xfrom->sin_port;
  from->sin_addr.s_addr = xfrom->sin_addr.s_addr;
 
  /* This is some deep kernel-level magic. Requires IP: transparent
     proxy to be compiled into kernel to work. */

  oldcaps = cap_save();
  cap_enable(CAP_NET_ADMIN);

  ret=sendto(socket, packet->data, packet->length,
                     MSG_PROXY, &to, sizeof(struct sockaddr_in));
  
  cap_restore(oldcaps);
  
  free(packet->data);
  z_leave();
  return ret;
}

#endif
