/***************************************************************************
 *
 * 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: ipchains.c,v 1.1.4.2 2001/09/19 19:22:16 bazsi Exp $
 *
 ***************************************************************************/

#include <zorp/ipchains.h>
#include <zorp/log.h>
#include <zorp/cap.h>

#if ENABLE_IPCHAINS

#include <string.h>
#include <unistd.h>

#define CORE_ERROR "core.error"

/* ipchains specific */

struct _ZIPChains 
{
  gint fd;
};

ZIPChains *
z_ipchains_new(void)
{
  ZIPChains *self = g_new0(ZIPChains, 1);
  cap_t oldcaps;
  
  oldcaps = cap_save();

  cap_enable(CAP_NET_ADMIN);
  /* cap_enable(CAP_NET_RAW); */
  self->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  cap_restore(oldcaps);
  if (self->fd == -1)
    {
      /*LOG
        This message indicates that the ipchains support layer could not
        create a raw socket, needed for manipulating ipchains rules.
       */
      z_log(NULL, CORE_ERROR, 0, "Error creating RAW socket for ipchains manipulation; error='%m'");
      g_free(self);
      return NULL;
    }
  return self;
}

gboolean
z_ipchains_add(ZIPChains *self, gchar *chain, struct ip_fwuser *r)
{
  struct ip_fwnew new;
  cap_t oldcaps;

  new.fwn_rulenum = 1;
  memcpy(&new.fwn_rule, r, sizeof(struct ip_fwuser));  
  strncpy(new.fwn_label, chain, sizeof(new.fwn_label) - 1);
  new.fwn_label[sizeof(new.fwn_label) - 1] = 0;
  oldcaps = cap_save();
  cap_enable(CAP_NET_ADMIN);
  if (setsockopt(self->fd, IPPROTO_IP, IP_FW_INSERT, &new, sizeof(new)) == -1)
    {
      cap_restore(oldcaps);
      /*LOG
        This message indicates that adding a firewall rule failed.
       */
      z_log(NULL, CORE_ERROR, 0, "Error adding firewall rule, setsockopt(IPPOROT_IP, IP_FW_INSERT) failed; error='%m'");
      return FALSE;
    }
  cap_restore(oldcaps);
  return TRUE;
}

gboolean
z_ipchains_del(ZIPChains *self, gchar *chain, struct ip_fwuser *r)
{
  struct ip_fwchange change;
  cap_t oldcaps;

  memcpy(&change.fwc_rule, r, sizeof(struct ip_fwuser));
  strncpy(change.fwc_label, chain, sizeof(change.fwc_label) - 1);
  change.fwc_label[sizeof(change.fwc_label) - 1] = 0;
  oldcaps = cap_save();
  cap_enable(CAP_NET_ADMIN);
  if (setsockopt(self->fd, IPPROTO_IP, IP_FW_DELETE, &change, sizeof(change)) == -1)
    {
      cap_restore(oldcaps);
      /*LOG
        This message indicates that removing a firewall rule failed.
       */
      z_log(NULL, CORE_ERROR, 0, "Error removing firewall rule, setsockopt(IPPROTO_IP, IP_FW_DELETE) failed; error='%m'");
      return FALSE;
    }
  cap_restore(oldcaps);
  return TRUE;
}

void
z_ipchains_destroy(ZIPChains *self)
{
  close(self->fd);
  g_free(self);
}

#endif
