/*
 * fwent() add or delete firewall entries
 */
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <netdb.h>
#include <netinet/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/if.h>
#include <linux/ip_fw.h>
#include <sys/param.h>

#include "parser.h"
#include "policies.h"

static int sockop[3][4] = {
	{ IP_FW_DELETE_IN, IP_FW_DELETE_OUT, IP_FW_DELETE_FWD, IP_ACCT_DELETE },
	{ IP_FW_INSERT_IN, IP_FW_INSERT_OUT, IP_FW_INSERT_FWD, IP_ACCT_INSERT },
	{ IP_FW_APPEND_IN, IP_FW_APPEND_OUT, IP_FW_APPEND_FWD, IP_ACCT_APPEND },
} ;

extern int vflag;

struct ip_fw *
chain2fw(struct chainv4 *fwc) {
    static struct ip_fw fw;
    int i;

    memset(&fw, 0, sizeof fw);
    fw.fw_src  = *( (struct in_addr*) &fwc->srcaddr );
    fw.fw_smsk = *( (struct in_addr*) &fwc->srcmask );
    fw.fw_dst  = *( (struct in_addr*) &fwc->dstaddr );
    fw.fw_dmsk = *( (struct in_addr*) &fwc->dstmask );

    if (fwc->nrports) {
	fw.fw_ndp = fwc->nrports;
	for (i=0; i < fwc->nrports; i++)
	    fw.fw_pts[i] = ntohs(fwc->port[i]);
    }
    fw.fw_flg = (fwc->flag & ~(IP_FW_F_KIND|IP_FW_F_ACCEPT));

    if (fwc->action == ALLOW)
	fw.fw_flg |= IP_FW_F_ACCEPT;

    switch (fwc->proto) {
    case TCP:	fw.fw_flg |= IP_FW_F_TCP;	break;
    case UDP:	fw.fw_flg |= IP_FW_F_UDP;	break;
    case ICMP:	fw.fw_flg |= IP_FW_F_ICMP;	break;
    }
    return &fw;
} /* chain2fw */


/*
 * fwent() add or delete entries
 */
int
fwent(int action, struct chainv4 *chain)
{
    int sock;
    struct chainv4 *p;
    struct ip_fw *cmd;

    if (chain == 0)
	return 1;

    if ( (sock = fwopen(0)) != EOF) {
	p = chain;
	do {
	    if (vflag > 1)
		print(stderr, "process ", p);
	    cmd = chain2fw(p);
	    if (vflag > 2)
		fprintf(stderr, "cmd->fw_flg = 0x%08x\n", cmd->fw_flg);
	    fwcmd(sock, sockop[action][p->direction-IN], cmd, sizeof *cmd);
	    p = p->next;
	} while (p != chain);
	fwclose(sock);
	return 1;
    }
    return 0;
} /* fwent */
