/*

                                   _JNJ`                        
                               .JNMH`                           
                              JMMF`       `;.                   
                            .NMM)          `MN.                 
                            MMM)            (MML                
                           (MMM`             MMML               
                     M  I  D  N  I  G  H  T    C  o  D  E       
                           (NMMF             MHNH               
                            NMML            .MMM                
                             NMML          .NMH                 
                              4MMNL       .#F                   
                               `4HNNL_   `                      
                                   `"""`                        

                          Copyright (C) 2004-2007
       "Ian (Larry) Latter" <ian dot latter at midnightcode dot org>

    Midnight Code is a registered trademark of Ian Latter.

    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, and mirrored at the Midnight Code web
    site; as at version 2 of the License only.
  
    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
    (version 2) along with this program; if not, write to the Free
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA, or see http://midnightcode.org/gplv2.txt

*/

/* midnightcode-filter.c :: Midnight Code packet filter library		*/


#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "preferences.h"
#include "midnightcode-list.h"
#include "midnightcode-process.h"
#include "midnightcode-filter.h"



int
midnightcode_filter_bycommand(struct midnightcode_filter_command_t * commands,
                              char * executable) {
  int options;
  int terminal;
  int ret_i;
  int cmdn;
  char execute[4096];
  struct midnightcode_filter_command_t * cmd;


  options = 0;
  options |= MIDNIGHTCODE_PROCESS_OPTION_WAITTERM;
  options |= MIDNIGHTCODE_PROCESS_OPTION_NULLIO;
  options |= MIDNIGHTCODE_PROCESS_OPTION_EXITCODE;
  terminal = MIDNIGHTCODE_TERMINAL_VIRTUAL_NULL;

  if(strlen(executable) <= 0)
    return -1;

  
  ret_i = 0;
  for(cmd = commands, cmdn = 0; cmd[cmdn].exec != NULL; cmdn++) {
    memset(execute, 0, sizeof(execute));
    ret_i = snprintf(execute,  sizeof(execute) - 1, "%s %s",
                     executable, cmd[cmdn].exec);
    if(ret_i >= (int)sizeof(execute)) {
      ret_i = 0 - cmdn;
      break;
    }
    ret_i = midnightcode_process(execute, options, terminal);
    if(ret_i != 0) {
      ret_i = 0 - cmdn;
      break;
    }
  }
  if(ret_i == 0)
    ret_i = cmdn;


  return ret_i;
}


int
midnightcode_filter(int action, char * chain, int position,
                    struct midnightcode_filter_rule_head_t * rule_elements,
                    struct midnightcode_filter_chain_head_t * chain_elements) {
  int ret_i;
  struct midnightcode_filter_rule_element_t * rule_element;
  struct midnightcode_filter_chain_element_t * chain_element;
  /* char executable[256] = "/sbin/iptables"; */
  char executable[256] = "/bin/echo";

  struct midnightcode_filter_command_t set_shutdown[] = {
    { "-P INPUT ALLOW" },
    { "-P OUTPUT ALLOW" },
    { "-P FORWARD ALLOW" },
    { "-F -t filter" },
    { "-F -t nat" },
    { "-F -t mangle" },
    { 0 }
  };

  struct midnightcode_filter_command_t set_initialise[] = {
    { "-P INPUT DROP" },
    { "-P OUTPUT DROP" },
    { "-P FORWARD DROP" },
    { "-A INPUT -i lo -j ACCEPT" },
    { "-A OUTPUT -o lo -j ACCEPT" },
    { "-N MIDNIGHTCODE_CLEAN" },
    { "-A MIDNIGHTCODE_CLEAN -m state --state INVALID -j DROP" },
    { "-A MIDNIGHTCODE_CLEAN -m state --state NEW -p tcp ! "
      "--tcp-flags SYN,RST,ACK SYN -j DROP" },
    { "-A MIDNIGHTCODE_CLEAN -p tcp --tcp-flags ALL ALL -j DROP" },
    { "-A MIDNIGHTCODE_CLEAN -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG "
      "-j DROP" },
    { "-A MIDNIGHTCODE_CLEAN -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP" },
    { "-A MIDNIGHTCODE_CLEAN -p tcp --tcp-flags ALL NONE -j DROP" },
    { "-A MIDNIGHTCODE_CLEAN -p tcp --tcp-flags SYN,RST SYN,RST -j DROP" },
    { "-A MIDNIGHTCODE_CLEAN -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP" },
    { "-A MIDNIGHTCODE_CLEAN -j RETURN" },
    { "-A INPUT -j MIDNIGHTCODE_CLEAN" },
    { "-A OUTPUT -j MIDNIGHTCODE_CLEAN" },
    { "-A FORWARD -j MIDNIGHTCODE_CLEAN" },
    { "-A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS "
      "--clamp-mss-to-pmtu" },
    { "-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT" },
    { "-A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT" },
    { "-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT" },
    { "-A INPUT -p icmp --icmp-type fragmentation-needed -j ACCEPT" },
    { "-A OUTPUT -p icmp --icmp-type fragmentation-needed -j ACCEPT" },
    { "-A FORWARD -p icmp --icmp-type fragmentation-needed -j ACCEPT" },
    { 0 }
  };

  struct midnightcode_filter_command_t set_log[] = {
    { "-A INPUT -j LOG --log-level info --log-prefix \"Firewal   (input):\"" },
    { "-A OUTPUT -j LOG --log-level info --log-prefix \"Firewal  (output):\"" },
    { "-A FORWARD -j LOG --log-level info --log-prefix "
      "\"Firewal (forward):\"" },
    { 0 }
  };

  ret_i = MIDNIGHTCODE_FILTER_ERROR_NONE;

  switch(action) {
    case MIDNIGHTCODE_FILTER_ACTION_INITIALISE:
      if(midnightcode_filter_bycommand(set_shutdown, executable) < 0)
        ret_i = MIDNIGHTCODE_FILTER_ERROR_INITIALISE;
      if(midnightcode_filter_bycommand(set_initialise, executable) < 0)
        ret_i = MIDNIGHTCODE_FILTER_ERROR_INITIALISE;
      if(midnightcode_filter_bycommand(set_log, executable) < 0)
        ret_i = MIDNIGHTCODE_FILTER_ERROR_INITIALISE;
      break;

    case MIDNIGHTCODE_FILTER_ACTION_FIND:
      /* TODO: implement filters */
      // for each chain
      //  for each rule
      //    add rule 
      break;

    case MIDNIGHTCODE_FILTER_ACTION_INSERT:
      break;

    case MIDNIGHTCODE_FILTER_ACTION_ADD:
      break;

    case MIDNIGHTCODE_FILTER_ACTION_DELETE:
      break;

    case MIDNIGHTCODE_FILTER_ACTION_APPLY:
      break;

    case MIDNIGHTCODE_FILTER_ACTION_SHUTDOWN:
      if(midnightcode_filter_bycommand(set_shutdown, executable) < 0)
        ret_i = MIDNIGHTCODE_FILTER_ERROR_SHUTDOWN;
      break;

    default:
      ret_i = MIDNIGHTCODE_FILTER_ERROR_ACTION;
      break;

  }

  return ret_i;
}



