/***************************************************************************
 *
 * 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: pyipchains.c,v 1.1.4.3 2001/09/19 19:22:17 bazsi Exp $
 *
 ***************************************************************************/

#include <zorp/zorp.h>

#if ENABLE_IPCHAINS

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

PyTypeObject z_py_zorp_ipchains_type;

typedef struct _ZorpIPChains
{
  PyObject_HEAD
  ZIPChains *ipc;
} ZorpIPChains;

static PyObject *
z_py_zorp_ipchains_add_rule(ZorpIPChains *o, PyObject *args);

static PyObject *
z_py_zorp_ipchains_del_rule(ZorpIPChains *o, PyObject *args);

static PyMethodDef py_zorp_ipchains_methods[] =
{
  { "addRule",     (PyCFunction) z_py_zorp_ipchains_add_rule },
  { "delRule",     (PyCFunction) z_py_zorp_ipchains_del_rule },
  { NULL,          NULL }   /* sentinel*/
};

static PyObject *
z_py_zorp_ipchains_new_instance(PyObject *s, PyObject *args)
{
  ZorpIPChains *self;
  
  if (!PyArg_Parse(args, "()"))
    return NULL;

  self = PyObject_NEW(ZorpIPChains, &z_py_zorp_ipchains_type);
  
  self->ipc = z_ipchains_new();
  if (!self->ipc)
    {
      PyErr_SetString(PyExc_IOError, "Error create ipchains handler instance");
      return NULL;
    }
  return (PyObject *) self;
}

static gboolean
z_py_zorp_ipchains_parse_rule(PyObject *pyrule, struct ip_fwuser *rule)
{
  gulong src, smask, dst, dmask, mark, proto, flags, inv_flags, sports[2], dports[2], redirport, tosand, tosxor;
  gchar *target, *iface;

  if (!PyArg_Parse(pyrule, "(s(ii)(ii)iiii(ii)(ii)isii)",
                   &target, 
                   &src, &smask, &dst, &dmask,
                   &mark, &proto, &flags, &inv_flags, 
                   &sports[0], &sports[1], &dports[0], &dports[1],
                   &redirport, &iface, &tosand, &tosxor))
    return FALSE;
    
  memset(rule, 0, sizeof(struct ip_fwuser));
  rule->ipfw.fw_src.s_addr = src;
  rule->ipfw.fw_smsk.s_addr = smask;
  rule->ipfw.fw_dst.s_addr = dst;
  rule->ipfw.fw_dmsk.s_addr = dmask;
  rule->ipfw.fw_mark = mark;
  rule->ipfw.fw_proto = proto;
  rule->ipfw.fw_flg = flags;
  rule->ipfw.fw_invflg = inv_flags;
  rule->ipfw.fw_spts[0] = sports[0];
  rule->ipfw.fw_spts[1] = sports[1];
  rule->ipfw.fw_dpts[0] = dports[0];
  rule->ipfw.fw_dpts[1] = dports[1];
  rule->ipfw.fw_redirpt = redirport;
  rule->ipfw.fw_tosand = tosand;
  rule->ipfw.fw_tosxor = tosxor;
  strncpy(rule->ipfw.fw_vianame, iface, sizeof(rule->ipfw.fw_vianame) - 1);
  strncpy(rule->label, target, sizeof(rule->label) - 1);
  
  return TRUE;
}

static PyObject *
z_py_zorp_ipchains_add_rule(ZorpIPChains *self, PyObject *args)
{
  struct ip_fwuser rule;
  PyObject *pyrule;
  gchar *chain;
  
  if (!PyArg_Parse(args, "(sO)", &chain, &pyrule) ||
      !z_py_zorp_ipchains_parse_rule(pyrule, &rule))
    return NULL;
  
  
  if (!z_ipchains_add(self->ipc, chain, &rule))
    {
      PyErr_SetString(PyExc_IOError, "Error adding firewall rule.");
      return NULL;
    }
    
  Py_XINCREF(Py_None);
  return Py_None;
}

static PyObject *
z_py_zorp_ipchains_del_rule(ZorpIPChains *self, PyObject *args)
{
  struct ip_fwuser rule;
  PyObject *pyrule;
  gchar *chain;
  
  if (!PyArg_Parse(args, "(sO)", &chain, &pyrule) ||
      !z_py_zorp_ipchains_parse_rule(pyrule, &rule))
    return NULL;
  
  if (!z_ipchains_del(self->ipc, chain, &rule))
    {
      PyErr_SetString(PyExc_IOError, "Error deleting firewall rule.");
      return NULL;
    }
    
  Py_XINCREF(Py_None);
  return Py_None;
}

#if 0
int
z_py_zorp_rule_convert(PyObject *o, ZPFInetDomain **res)
{
  PyObject *tmp;
  guint ip, mask;

  if (!PyInstance_Check(o))
    {
      PyErr_SetString(PyExc_TypeError, "Domain must be an instance");
      return 0;
    }
  tmp = PyObject_GetAttrString(o, "family");
  if (!tmp)
    {
      return 0;
    }
  if (PyInt_AsLong(tmp) != AF_INET)
    {
      PyErr_SetString(PyExc_TypeError, "Only InetDomains are supported");
      return 0;
    }
  Py_XDECREF(tmp);

  *res = g_new0(ZPFInetDomain, 1);
  (*res)->family = AF_INET;
  (*res)->size = sizeof(ZPFInetDomain);

  tmp = PyObject_GetAttrString(o, "ip");
  if (!PyInt_Check(tmp))
    {
      PyErr_SetString(PyExc_TypeError, "Domain.ip must be an Int");
      return 0;
    }
  ip = PyInt_AsLong(tmp);
  Py_XDECREF(tmp);

  tmp = PyObject_GetAttrString(o, "mask");
  if (!PyInt_Check(tmp))
    {
      PyErr_SetString(PyExc_TypeError, "Domain.mask must be an Int");
      return 0;
    }
  mask = PyInt_AsLong(tmp);
  Py_XDECREF(tmp);

  (*res)->ip.s_addr = ip;
  (*res)->mask.s_addr = mask;
  return 1;
}

static PyObject *
z_py_zorp_packet_filter_redirect(PyObject *o, PyObject *args)
{
  ZorpPacketFilter *self = (ZorpPacketFilter *) o;
  ZPFDomain *sdom, *ddom;
  guint sports[2], dports[2], redirport, proto;

  if (!PyArg_ParseTuple(args, "iO&(ii)O&(ii)i", 
			&proto,
			z_py_zorp_domain_convert, &sdom, 
			&sports[0], &sports[1], 
			z_py_zorp_domain_convert, &ddom, 
			&dports[0], &dports[1], 
			&redirport))
    {
      return NULL;
    }

  z_pf_redirect(self->pf, proto, sdom, sports, ddom, dports, redirport);
  g_free(sdom);
  g_free(ddom);
  Py_XINCREF(Py_None);
  return Py_None;
}
#endif

static PyObject *
z_py_zorp_ipchains_getattr(PyObject *o, char *name)
{
  return Py_FindMethod(py_zorp_ipchains_methods, o, name);
}

static void
z_py_zorp_ipchains_free(ZorpIPChains *self)
{
  if (self->ipc)  
    z_ipchains_destroy(self->ipc);
  PyMem_DEL(self);
}

PyTypeObject z_py_zorp_ipchains_type =
{
  PyObject_HEAD_INIT(&PyType_Type)
  0,                                        /*ob_size*/
  "ZorpIPChains",                           /*tp_name*/
  sizeof(ZorpIPChains),                     /*tp_basicsize*/
  0,                                        /*tp_itemsize*/
  /* methods */
  (destructor)z_py_zorp_ipchains_free,      /*tp_dealloc*/
  (printfunc)0,                             /*tp_print*/
  (getattrfunc)z_py_zorp_ipchains_getattr,  /*tp_getattr*/
  (setattrfunc)0,                           /*tp_setattr*/
  (cmpfunc)0,                               /*tp_compare*/
  (reprfunc)0,                              /*tp_repr*/
  0,                                        /*tp_as_number*/
  0,                   		            /*tp_as_sequence*/
  0,                   		            /*tp_as_mapping*/
  (hashfunc)0,         		            /*tp_hash*/
  (ternaryfunc)0,      		            /*tp_call*/
  (reprfunc)0,                              /*tp_str*/

  /* Space for future expansion */
  0L,0L,0L,0L,
  "ZorpIPChains class", /* Documentation string */
};

PyMethodDef z_py_zorp_ipchains_funcs[] =
{
  { "IPChains",      z_py_zorp_ipchains_new_instance, METH_VARARGS },
  { NULL,            NULL }   /* sentinel*/
};

void
z_py_zorp_ipchains_init(void)
{
  Py_InitModule("Zorp.Zorp", z_py_zorp_ipchains_funcs);  
}
#else

void
z_py_zorp_ipchains_init(void)
{
}

#endif
