  /*

  knetfilter v 1.1.3

  Copyright (C) 2000 Luigi Genoni
  		     venom@DarkStar.sns.it
  */
  

#include <qlayout.h>
#include <qmultilinedit.h>
#include <qkeycode.h>
#include <qbuttongroup.h>
#include <qlabel.h>
#include <qstring.h>
#include <qstrlist.h>
#include <strings.h>

#include <kmsgbox.h>
#include <kiconloader.h>
#include <klocale.h>

#include "knat.h"


// interlaced facilities
void knetfilter::startpolRules() {

    polrules.clearArguments();
    
    polrules << "iptables" << "-P" << polchainChoice << chainpolicyChoice;
    printf("%s %s\n",polchainChoice,chainpolicyChoice);
    bool success=polrules.start(KProcess::NotifyOnExit,
				KProcess::AllOutput);
    if (success)     
      {
	statusbar->message(i18n("Running..."), 2000);
	QString msg; 
	msg.sprintf("Setting policy for chain %s to %s\n",polchainChoice,chainpolicyChoice);
      }
    else
      {
	statusbar->message(i18n("Couldn't start iptables"), 2000);
      }
};


void knetfilter::startlistRules() {

    rules.clearArguments();

    rules << "iptables" << "-L" << "--line-numbers";

    bool success=rules.start(KProcess::NotifyOnExit,
			     KProcess::AllOutput);
    if (success)
      statusbar->message(i18n("Running..."), 2000);
    else
      statusbar->message(i18n("Couldn't start iptables"), 2000);

};

void knetfilter::startmasqEntries() {

  entries.clearArguments();

  entries << "iptables" <<"-t" <<"nat" << "-L" << "--line-numbers";

  bool success=entries.start(KProcess::NotifyOnExit,
  			   KProcess::AllOutput);
  if (success)
    statusbar->message(i18n("Running..."), 2000);
  else
    statusbar->message(i18n("Couldn't start iptables"), 2000);

};

void knetfilter::startmangleEntries() {

  entries.clearArguments();

  entries << "iptables" <<"-t" <<"mangle" << "-L" << "--line-numbers";

  bool success=entries.start(KProcess::NotifyOnExit,
  			   KProcess::AllOutput);
  if (success)
    statusbar->message(i18n("Running..."), 2000);
  else
    statusbar->message(i18n("Couldn't start iptables"), 2000);

};



void knetfilter::starttcpDump() {

      tcpdump.clearArguments();
   char interfaceChoice2[5]; 
   strcpy( interfaceChoice2, interfaceChoice );	
    
    interfaceChoicedmp = strcat ( interfaceChoice2, interfacenrChoicedmp);
    
    //tcpdump << "tcpdump" <<"-c 1000" << "-i" << "eth0" ; 
    tcpdump << "tcpdump" <<"-c 1000" << "-i" << interfaceChoicedmp ; 


    bool success=tcpdump.start(KProcess::NotifyOnExit,
			       KProcess::AllOutput);
            if (success)
          statusbar->message(i18n("Running..."), 2000);
       else
          statusbar->message(i18n("Couldn't start tcpdump"), 2000);

};


void knetfilter::polRules() {
  if ( polList == NULL )
    {
      setupConnect();    

      polList = new KNFWidget();
      polList->resize(350,120);
      polList->setCaption("Set Chains policy");

      QBoxLayout *top = new QBoxLayout(polList, QBoxLayout::LeftToRight, 5);
      QGridLayout *grid = new QGridLayout(7,5);
      top->addLayout(grid,5);
      
      QLabel *labelChainpol = new QLabel(polList);
      labelChainpol->setText("Chain :");
      grid->addMultiCellWidget(labelChainpol,0,0,0,2);

      polchain = new QComboBox( FALSE, polList, "Chain"); 
      polchain->insertItem("INPUT");
      polchain->insertItem("OUTPUT");
      polchain->insertItem("FORWARD");
      polchain->setFixedHeight(polchain->sizeHint().height());
      connect(polchain,SIGNAL(activated(int)), SLOT(polchainActivated(int)));

      grid->addMultiCellWidget(polchain,0,0,2,3);

      QLabel *labelChaindef = new QLabel(polList);
      labelChaindef->setText("Policy :");
      grid->addMultiCellWidget(labelChaindef,1,1,0,2);

      polchainpolicy = new QComboBox( FALSE, polList, "Policy");
      polchainpolicy->insertItem("ACCEPT");
      polchainpolicy->insertItem("DROP");
      polchainpolicy->setFixedHeight(polchainpolicy->sizeHint().height());
      connect(polchainpolicy,SIGNAL(activated(int)), SLOT(chainpolicyActivated(int))); 

      grid->addMultiCellWidget(polchainpolicy,1,1,2,3);

      polBox = new QListBox(polList);
      grid->addMultiCellWidget(polBox,3,4,0,4);

      QPushButton *btnRules = new QPushButton(polList);
      btnRules->setText("Commit");
      btnRules->setFixedHeight(btnRules->sizeHint().height());
      connect(btnRules,SIGNAL(clicked()), this, SLOT(startpolRules()));
      grid->addWidget(btnRules,6,0);

      QPushButton *btnClose = new QPushButton(polList);
      btnClose->setText("Close");
      btnClose->setFixedHeight(btnClose->sizeHint().height());
      connect(btnClose,SIGNAL(clicked()), this, SLOT(closepolRules()));
      grid->addWidget(btnClose,6,2);
      
      polList->show();
      setView(polList);
    }
  else
    {
      if ( !polList->isVisible() )
	{
	  polList->show();
	}
      else
	{
	  QMessageBox::critical(0,"Warning", "Already Running\n");
	}
    }  
};


// Print in a window iptables rules or masquerading entries.
// If masquerading is not compiled in the kernel maybe it will fail, but
// it should disable masList function and go on.
void knetfilter::iptablesRules() {
  if ( masqList == NULL )
    {

      masqList = new KNFWidget();
      masqList->resize(680,420);
      masqList->setCaption("current iptables rules, masqurading and mangle  entries");

      QBoxLayout *top = new QBoxLayout(masqList, QBoxLayout::LeftToRight, 7);
      QGridLayout *grid = new QGridLayout(7,5);
      top->addLayout(grid,5);
      
      masqBox = new QListBox(masqList);
      grid->addMultiCellWidget(masqBox,0,5,0,4);

      QPushButton *btnRules = new QPushButton(masqList);
      btnRules->setText("Rules");
      btnRules->setFixedHeight(btnRules->sizeHint().height());
      connect(btnRules,SIGNAL(clicked()), this, SLOT(startlistRules()));
      grid->addWidget(btnRules,6,0);

      checkMasquerade();
      if(ip_masquerade==NULL){
	QMessageBox::critical(0, "Notice",
			      "You haven't support for IP masquerade\n"
			      "in your kernel, so Listing Masquerading Entries is disabled.\n");
      }
      else {
	QPushButton *btnTraff = new QPushButton(masqList);
	btnTraff->setText("Masq Entries");
	btnTraff->setFixedHeight(btnTraff->sizeHint().height());
	connect(btnTraff,SIGNAL(clicked()), this, SLOT(startmasqEntries()));
	grid->addWidget(btnTraff,6,1);
      }

      QPushButton *btnMangle = new QPushButton(masqList);
      btnMangle->setText("Mangle Entries");
      btnMangle->setFixedHeight(btnMangle->sizeHint().height());
      connect(btnMangle,SIGNAL(clicked()), this, SLOT(startmangleEntries()));
      grid->addWidget(btnMangle,6,2);
  
      QPushButton *btnClose = new QPushButton(masqList);
      btnClose->setText("Close");
      btnClose->setFixedHeight(btnClose->sizeHint().height());
      connect(btnClose,SIGNAL(clicked()), this, SLOT(closeiptablesRules()));
      grid->addWidget(btnClose,6,4);

      masqList->show();
      setView(masqList);
    }
  else
    {
      if ( !masqList->isVisible() )
	{
	  masqList->show();
	}
      else
	{
	  QMessageBox::critical(0,"Warning", "Already Running\n");
	}
    }  
};

void knetfilter::closepolRules() {

  polList->close();

};

void knetfilter::closeiptablesRules() {

  masqList->close();

};

void knetfilter::closetcpDump() {

  dumpList->close();

};

void knetfilter::polRulesDone() {
  if (polrules.normalExit() && (polrules.exitStatus()==0))
    statusbar->message(i18n("Setting Chain Policy..."), 2000);
  else
    statusbar->message(i18n("Couldn't set Chain Policy"), 2000);

};

void knetfilter::listRulesDone() {

  if (rules.normalExit() && (rules.exitStatus()==0)) 
    statusbar->message(i18n("Listing all rules..."), 2000);
  else 
    statusbar->message(i18n("Couldn't list all rules"), 2000);

};

void knetfilter::setpolRules(KProcess *, char *data, int len) {
  
  if (len<0)
    return;
  static QString remainder;
  QString list;

  char dst[len+1];
  memmove(dst,data,len);
  dst[len]=0;

  list=remainder+dst;
  QStrList lines;
  int index=0;
  int newindex=0;

  while (1)
  {
    newindex=list.find('\n',index);
    if(newindex==-1) {
      remainder=list.right(list.length()-index);
      break;
    } else {
      lines.append(list.mid(index,newindex-index));
      index=newindex+1;
    };
  };
  
  if(lines.count()>0){
    polBox->insertStrList(&lines);
    polBox->insertItem(remainder.data());
    polBox->setTopItem(polBox->count()-polBox->numItemsVisible()); 
  };
};


void knetfilter::listRules(KProcess *, char *data, int len) {

  if (len<0)
    return;
  static QString remainder;
  QString list;

  char dst[len+1];
  memmove(dst,data,len);
  dst[len]=0;

  list=remainder+dst;
  QStrList lines;
  int index=0;
  int newindex=0;

  while (1)
  {
    newindex=list.find('\n',index);
    if(newindex==-1) {
      remainder=list.right(list.length()-index);
      break;
    } else {
      lines.append(list.mid(index,newindex-index));
      index=newindex+1;
    };
  };

  if(lines.count()>0){
    masqBox->insertStrList(&lines);
    masqBox->insertItem(remainder.data());
    masqBox->setTopItem(masqBox->count()-masqBox->numItemsVisible());
  };
};

void knetfilter::tcpDump() {
  if ( dumpList == NULL )
    { 

      dumpList = new KNFWidget();
      dumpList->resize(550,420);
      dumpList->setCaption("tcpdump");
      
      QBoxLayout *top = new QBoxLayout(dumpList, QBoxLayout::LeftToRight, 5);
      QGridLayout *grid = new QGridLayout(5,5);
      top->addLayout(grid,5);
  
      dumpBox = new QListBox(dumpList);
      grid->addMultiCellWidget(dumpBox,0,3,0,4);
  
      QPushButton *btnDump = new QPushButton(dumpList);
      btnDump->setText("tcpdump");
      btnDump->setFixedHeight(btnDump->sizeHint().height());
      connect(btnDump,SIGNAL(clicked()), this, SLOT(starttcpDump()));
      grid->addWidget(btnDump,4,0);
        
      QPushButton *btnClose = new QPushButton(dumpList);
      btnClose->setText("Close");
      btnClose->setFixedHeight(btnClose->sizeHint().height());
      connect(btnClose,SIGNAL(clicked()), this, SLOT(closetcpDump()));
      grid->addWidget(btnClose,4,2);
  
      dumpList->show();
      setView(dumpList);
    }
  else
    {
      if ( !dumpList->isVisible() )
	{
	  dumpList->show();
	}
      else
    	{
	  QMessageBox::critical(0,"Warning", "Already Running\n");      
	}
    }  
};


void knetfilter::listDump(KProcess *, char *data, int len) {

  if (len<0)
    return;
  static QString remainder;
  QString list;

  char dst[len+1];
  memmove(dst,data,len);
  dst[len]=0;

  list=remainder+dst;
  QStrList lines;
  int index=0;
  int newindex=0;

  while (1)
  {
    newindex=list.find('\n',index);
    if(newindex==-1) {
      remainder=list.right(list.length()-index);
      break;
    } else {
      lines.append(list.mid(index,newindex-index));
      index=newindex+1;
    };
  };

  if(lines.count()>0) 
    dumpBox->insertStrList(&lines);

 dumpBox->insertItem(remainder.data());
 dumpBox->setTopItem(dumpBox->count()-dumpBox->numItemsVisible());

};


// probe interface action
void knetfilter::startprobeInterface() {

  fetchIp.clearArguments();
  fetchNetmask.clearArguments();

  if(interfaceChoice=="lo") {
    ipAddr->clear();
    netmaskAddr->clear();
    fetchIp << "getip" << "lo"; 
    fetchNetmask << "getloop" << "lo";
  } else if(interfaceChoice=="eth") {
    QString ethdevice;
    ethdevice.sprintf("eth%d", interfacenrChoice);
    ipAddr->clear();
    netmaskAddr->clear();
    fetchIp << "getip" << ethdevice;
    fetchNetmask << "getnetmask" << ethdevice; 
  } else if(interfaceChoice=="tr") {
    QString ethdevice;
    ethdevice.sprintf("tr%d", interfacenrChoice);
    ipAddr->clear();
    netmaskAddr->clear();
    fetchIp << "getip" << ethdevice;
    fetchNetmask << "getnetmask" << ethdevice; 
  } else if(interfaceChoice=="bond") {
    QString ethdevice;
    ethdevice.sprintf("bond%d", interfacenrChoice);
    ipAddr->clear();
    netmaskAddr->clear();
    fetchIp << "getip" << ethdevice;
    fetchNetmask << "getnetmask" << ethdevice; 
  } else if(interfaceChoice=="slip") {
    QString slipdevice;
    slipdevice.sprintf("slip%d", interfacenrChoice);
    ipAddr->clear();
    netmaskAddr->clear();
    fetchIp << "getip" << slipdevice;
    fetchNetmask << "getnetmask" << slipdevice;
  } else if(interfaceChoice=="plip") {
    QString plipdevice;
    plipdevice.sprintf("plip%d", interfacenrChoice);
    ipAddr->clear();
    netmaskAddr->clear();
    fetchIp << "getip" << plipdevice;
    fetchNetmask << "getnetmask" << plipdevice;
  } else if(interfaceChoice=="ppp") { 
    QString pppdevice;
    pppdevice.sprintf("ppp%d", interfaceChoice);
    ipAddr->clear();
    netmaskAddr->clear(); 
    fetchIp << "getip" << pppdevice;
    fetchNetmask << "getnetmask" << pppdevice;
  } else if(interfaceChoice=="ippp") { 
    QString ipppdevice;
    ipppdevice.sprintf("ippp%d", interfaceChoice);
    ipAddr->clear();
    netmaskAddr->clear();
    fetchIp << "getip" << ipppdevice;
    fetchNetmask << "getnetmask" << ipppdevice;
  } else if(interfaceChoice=="tap") {
    QString ethdevice;
    ethdevice.sprintf("tap%d", interfacenrChoice);
    ipAddr->clear();
    netmaskAddr->clear();
    fetchIp << "getip" << ethdevice;
    fetchNetmask << "getnetmask" << ethdevice; 
  } else {
    ipAddr->setText("Couldn't probe");
    netmaskAddr->setText("Couldn't probe");
  }; 

  bool success=fetchIp.start(KProcess::NotifyOnExit,
  			   KProcess::AllOutput);
  bool success2=fetchNetmask.start(KProcess::NotifyOnExit,
  				KProcess::AllOutput);

  if (success && success2)
    statusbar->message(i18n("Running..."), 2000);
  else
    statusbar->message(i18n("Couldn't start probing"), 2000);

};


void knetfilter::probeInterfaceDone() {

  if (fetchIp.normalExit() && (fetchIp.exitStatus()==0) && fetchNetmask.normalExit() && (fetchNetmask.exitStatus()==0)) 
    statusbar->message(i18n("Probe completed successfully"), 2000);
  else {
    statusbar->message(i18n("ifconfig, awk and sed died"), 2000);
  };

};


void knetfilter::probeInterface(KProcess *, char *data, int len) {

  if (len<0) {
    ipAddr->setText("Couldn't get IP");
    return;
  };
  static QString remainder;
  QString ip;

  char ipdst[len+1];
  memmove(ipdst,data,len);
  ipdst[len]=0;

  ip=remainder+ipdst;

  if(ip.length()==0) {
    ipAddr->setMaxLength(17);
    QMessageBox::critical(0, "Couldn't get IP",
    			"knetfilter couldn't get the IP address.\n");
  } else if(ip.length()>17) {
    ipAddr->setMaxLength(17);
    QMessageBox::critical(0, "Couldn't probe",
    			"knetfilter couldn't probe the device.\n");
  } else {
    ipAddr->setMaxLength(ip.length()-1); 
    ipAddr->setText(ip);
  };

};


void knetfilter::probeInterface2(KProcess *, char *data, int len) {

  if (len<0) {
    netmaskAddr->setText("Couldn't get netmask");
    return;
  };
  static QString remainder;
  QString netmask;

  char netmaskdst[len+1];
  memmove(netmaskdst,data,len);
  netmaskdst[len]=0;

  netmask=remainder+netmaskdst;

  if(netmask.length()==0) {
    netmaskAddr->setMaxLength(17);
  } else if(netmask.length()>17) {
    netmaskAddr->setMaxLength(17);
  } else {
    netmaskAddr->setMaxLength(netmask.length()-1); 
    netmaskAddr->setText(netmask);
  };

};

// menu widget choice interface
void knetfilter::interfaceActivated(int index) {

  ipAddr->clear();
  netmaskAddr->clear();

  ipAddr->setMaxLength(17);
  netmaskAddr->setMaxLength(17);

  switch(index) {
  default:
    interfaceChoice = "eth";
  case 0:
    interfaceChoice = "eth";
    break;
  case 1:
    interfaceChoice = "eth";
    break;
  case 2:
    interfaceChoice = "tr";
    break;
  case 3:
    interfaceChoice = "bond";
    break;
  case 4:
    interfaceChoice = "lo";
    break;
  case 5:
    interfaceChoice = "slip";
    break;
  case 6:
    interfaceChoice = "plip";
    break;
  case 7:
    interfaceChoice = "ppp";
    break;
  case 8:
    interfaceChoice = "ippp";
    break;
  case 9:
    interfaceChoice = "tap";
    break;
  };

};


void knetfilter::interfacenrActivated(int index) {

  ipAddr->clear();
  netmaskAddr->clear();

  ipAddr->setMaxLength(17);
  netmaskAddr->setMaxLength(17);

  switch(index) {
  default:
    interfacenrChoice = 0;
  case 0:
    interfacenrChoice = 0;
    interfacenrChoicedmp = "0";
    break;
  case 1:
    interfacenrChoice = 1;
    interfacenrChoicedmp = "1";
    break;
  case 2:
    interfacenrChoice = 2;
    interfacenrChoicedmp = "2";
    break;
  case 3:
    interfacenrChoice = 3;
    interfacenrChoicedmp = "3";
    break;
  case 4:
    interfacenrChoice = 4;
    interfacenrChoicedmp = "4";
    break;
  case 5:
    interfacenrChoice = 5;
    interfacenrChoicedmp = "5";
    break;
  };

};


void knetfilter::chainActivated(int index) {
  switch(index) {
  default:
    chainChoice = "INPUT";
  case 0:
    chainChoice = "INPUT";
    break;
  case 1:
    chainChoice = "OUTPUT";
    break;
  case 2:
    chainChoice = "FORWARD";
    break;
  };
};


void knetfilter::policyActivated(int index) {
  switch(index) {
  default:
    policyChoice = "DROP";
  case 0:
    policyChoice = "DROP";
    break;
  case 1:
    policyChoice = "REJECT";
    break;
  case 2:
    policyChoice = "ACCEPT";
    break;
  case 3:
    policyChoice = "RETURN";
    break;
  case 4:
    policyChoice = "QUEUE";
    break;
  case 5:
    policyChoice = "MIRROR";
    break;
  };
};


void knetfilter::flagsActivated(int index) {
  switch(index) {
  default: 
    flagChoice = "-v";
  case 0:
    flagChoice = "-v";
    break;
  case 1:
    flagChoice = "--syn";
      break;
  };
};

void knetfilter::polchainActivated(int index) {
  switch(index) {
  default:
    polchainChoice = "INPUT";
  case 0:
    polchainChoice = "INPUT";
    break;
  case 1:
    polchainChoice = "OUTPUT";
    break;
  case 2:
    polchainChoice = "FORWARD";
    break;
  };
};


void knetfilter::chainpolicyActivated(int index) {
  switch(index) {
  default:
    chainpolicyChoice = "ACCEPT";
  case 0:
     chainpolicyChoice = "ACCEPT";
    break;
  case 1:
     chainpolicyChoice = "DROP";
    break;
  };
};


// I was forgeting ...
void knetfilter::userEntries(KProcess *, char *data, int len) {

  if (len<0)
    return;
  static QString remainder;
  QString list;

  char dst[len+1];
  memmove(dst,data,len);
  dst[len]=0;

  list=remainder+dst;
  QStrList lines;
  int index=0;
  int newindex=0;

  while (1)
  {
    newindex=list.find('\n',index);
    if(newindex==-1) {
      remainder=list.right(list.length()-index);
      break;
    } else {
      lines.append(list.mid(index,newindex-index));
      index=newindex+1;
    };
  };

  if(lines.count()>0){ 
    masqBox->insertStrList(&lines);
    masqBox->insertItem(remainder.data());
    masqBox->setTopItem(masqBox->count()-masqBox->numItemsVisible());
  };
};


void knetfilter::userEntriesDone() {

  if (entries.normalExit() && (entries.exitStatus()==0)) 
    statusbar->message(i18n("Listing all entries..."), 2000);
  else 
    statusbar->message(i18n("Couldn't list all entries"), 2000);

};


