/* Shared library add-on to iptables for web category
 *
 * (C) 2010 by Eric Hsiao <erichs0608@gmail.com>
 *
 * This program is distributed under the terms of GNU GPL v2, 1991
 *
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#include <xtables.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_set.h>
#include <linux/netfilter_ipv4/ipt_set.h>
//#include <linux/netfilter/xt_WEBCATEGORY.h>
#include "libipt_set.h"

struct xt_WEBCATEGORY_info {
	struct ipt_set_info match_set;
	unsigned int flag;
};

/* Initialize the target. */
static void WEBCATEGORY_init(struct xt_entry_target *target)
{
	struct xt_WEBCATEGORY_info *info = (struct xt_WEBCATEGORY_info *)target->data;

	memset(info, 0, sizeof(struct xt_WEBCATEGORY_info));
	info->match_set.index = IP_SET_INVALID_ID;

}

static void WEBCATEGORY_help(void)
{
	printf(
"WEBCATEGORY target options\n"
"  --set name\n"
"  --log\n"	
"  --drop\n"	
);
}

static const struct option WEBCATEGORY_opts[] = {
	{ "set", 1, NULL, '1' },
	{ "log", 0, NULL, '2'},	
	{ "drop", 0, NULL, '3'},	
	{ }
};

static int
WEBCATEGORY_parse(int c, char **argv, int invert, unsigned int *flags,
              const void *entry, struct xt_entry_target **target)
{
	struct xt_WEBCATEGORY_info *info = (struct xt_WEBCATEGORY_info *)(*target)->data;

	if (*flags & (1 << c))
		exit_error(PARAMETER_PROBLEM,
			           "Cannot specify --%s twice", WEBCATEGORY_opts[c].name);
	if (invert)
			exit_error(PARAMETER_PROBLEM,
			           "Unexpected \"!\" with --%s", WEBCATEGORY_opts[c].name);
	*flags |= (1 << c);

	switch (c) {
	case '1':		/* --set name */
		get_set_byname(argv[optind-1], &info->match_set);
		break;
	case '2':
		info->flag |= IPSET_MATCH_LOG;
		break;
	case '3':
		info->flag |= IPSET_MATCH_DRP;
		break;
	default:
		return 0;
	}

	return 1;
}

/* Prints out the targinfo. */
static void WEBCATEGORY_print(const void *ip,
                          const struct xt_entry_target *target, int numeric)
{
	const struct xt_WEBCATEGORY_info *info = (const struct xt_WEBCATEGORY_info *)target->data;
	char setname[IP_SET_MAXNAMELEN];
	
	if (info->match_set.index == IP_SET_INVALID_ID)
		return;
	get_set_byid(setname, info->match_set.index);
	printf("set %s ", setname);
}

/* Saves the union ipt_targinfo in parsable form to stdout. */
static void WEBCATEGORY_save(const void *ip, const struct xt_entry_target *target)
{
	const struct xt_WEBCATEGORY_info *info = (const struct xt_WEBCATEGORY_info *)target->data;
	char setname[IP_SET_MAXNAMELEN];
	
	if (info->match_set.index == IP_SET_INVALID_ID)
		return;
	get_set_byid(setname, info->match_set.index);
	printf("--set %s ", setname);
}

static struct xtables_target webcategory_target = {
	.family		= AF_INET,
	.name		= "WEBCATEGORY",
	.version	= IPTABLES_VERSION,
	.size		= XT_ALIGN(sizeof(struct xt_WEBCATEGORY_info)),
	.userspacesize	= XT_ALIGN(sizeof(struct xt_WEBCATEGORY_info)),
	.help		= WEBCATEGORY_help,
	.parse		= WEBCATEGORY_parse,
	.print		= WEBCATEGORY_print,
	.save		= WEBCATEGORY_save,
	.init		= WEBCATEGORY_init,
	.extra_opts	= WEBCATEGORY_opts
};

static struct xtables_target webcategory_target6 = {
	.family		= AF_INET6,
	.name		= "WEBCATEGORY",
	.version	= IPTABLES_VERSION,
	.size		= XT_ALIGN(sizeof(struct xt_WEBCATEGORY_info)),
	.userspacesize	= XT_ALIGN(sizeof(struct xt_WEBCATEGORY_info)),
	.help		= WEBCATEGORY_help,
	.parse		= WEBCATEGORY_parse,
	.print		= WEBCATEGORY_print,
	.save		= WEBCATEGORY_save,
	.init		= WEBCATEGORY_init,
	.extra_opts	= WEBCATEGORY_opts,
};

void _init(void)
{
	xtables_register_target(&webcategory_target);
	xtables_register_target(&webcategory_target6);
}
