/*
 *	"appe" match extension for iptables
 *	Eicke Friedrich/Klaus Degner <ipp2p@ipp2p.org>, 2005 - 2006
 *	Jan Engelhardt <jengelh [at] medozas de>, 2008 - 2009
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License; either
 *	version 2 of the License, or any later version, as published by the
 *	Free Software Foundation.
 */
#include <stdbool.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>
#include "../include/linux/netfilter/xt_appe.h"
#include <xtables.h>

static void ipp2p_mt_help(void)
{
	printf(
	"ipp2p v%s match options:\n"
	"  --ruleidx\n"
	"  --syslog\n"
	"  --msn\n"
	"  --msnmsg\n"
	"  --msnft\n"
	"  --msngame\n"
	"  --msnconf\n"
	"  --msnother\n"
	"  --ym\n"
	"  --ymmsg\n"
	"  --ymfile\n"
	"  --ymgame\n"
	"  --ymconf\n"
	"  --ymother\n"
	"  --aim\n"
	"  --aimmsg\n"
	"  --aimfile\n"
	"  --aimgame\n"
	"  --aimconf\n"
	"  --aimother\n"
	"  --icq\n"
	"  --icqmsg\n"
	"  --icqfile\n"
	"  --icqgame\n"
	"  --icqconf\n"
	"  --icqother\n"
	"  --wim\n"
	"  --aim67\n"
	"  --qq\n"
	"  --ichat\n"
	"  --gt\n"
	"  --gc\n"
	"  --xfire\n"
	"  --gadugadu\n"
	"  --paltalk\n"
	"  --qnext\n"
	"  --pocomsg\n"
	"  --areschat\n"
	"  --aliww\n"
	"  --kc\n"
	"  --lavalava\n"
	"  --icu2\n"
	"  --ispq\n"
	"  --uc\n"
	"  --mobilemsn\n"
	"  --baiduhi\n"
	"  --fetion\n"
	"  --skype\n"
	"  --kubao\n"
	"  --gizmo\n"
	"  --siprtp\n"
	"  --teltel\n"
	"  --teamspeak\n"
	"  --ss\n"
	"  --edk\n"
	"  --ft\n"
	"  --openft\n"
	"  --gnu\n"
	"  --opennap\n"
	"  --bt\n"
	"  --xunlei\n"
	"  --vagaa\n"
	"  --pp365\n"
	"  --poco\n"
	"  --clubbox\n"
	"  --ares\n"
	"  --ezpeer\n"
	"  --pando\n"
	"  --huntmine\n"
	"  --kuwo\n"
	"  --dns\n"
	"  --ftp\n"
	"  --http\n"
	"  --imap\n"
	"  --irc\n"
	"  --nntp\n"
	"  --pop3\n"
	"  --smb\n"
	"  --smtp\n"
	"  --snmp\n"
	"  --ssh\n"
	"  --ssltls\n"
	"  --telnet\n"
	"  --mssql\n"
	"  --mysql\n"
	"  --oracle\n"
	"  --postgresql\n"
	"  --sybase\n"
	"  --db2\n"
	"  --informix\n"
	"  --socks\n"
	"  --pgpnet\n"
	"  --httpproxy\n"
	"  --tor\n"
	"  --vnn\n"
	"  --softether\n"
	"  --msteredo\n"
	"  --ultrasurf\n"
	"  --hamachi\n"
	"  --httptunnel\n"
	"  --pingtunnel\n"
	"  --tinyvpn\n"
	"  --realtunnel\n"
	"  --dynapass\n"
	"  --ultravpn\n"
	"  --freeu\n"
	"  --skyfire\n"
	"  --mms\n"
	"  --rtsp\n"
	"  --tvants\n"
	"  --ppstream\n"
	"  --pptv\n"
	"  --uusee\n"
	"  --nsplayer\n"
	"  --pcast\n"
	"  --tvkoo\n"
	"  --sopcast\n"
	"  --udlivex\n"
	"  --tvuplayer\n"
	"  --mysee\n"
	"  --joost\n"
	"  --flashvideo\n"
	"  --silverlight\n"
	"  --slingbox\n"
	"  --qvod\n"
	"  --qqlive\n"
	"  --china\n"
	"  --shanghai\n"
	"  --lianzhong\n"
	"  --bianfeng\n"
	"  --vnc\n"
	"  --radmin\n"
	"  --tvants\n"
	"  --spyanywhere\n"
	"  --showmypc\n"
	"  --logmein\n"
	"  --teamviewer\n"
	"  --gogrok\n"
	"  --remotecontrolpro\n"
	"  --crossloop\n"
	"  --windowsrdp\n"
	"  --pcanywhere\n"
	"  --windowslivesync\n"
	"  --sharedview\n"
	"  --httpupload\n"
	"  --hinetsafebox\n"
	"  --msskydrive\n"
	"  --gdocuploader\n"
	"  --adrive\n"
	"  --myotherdrive\n"
	"  --mozy\n"
	"  --boxnet\n"
	"  --officelive\n"
	"  --readdlestorage\n"
	"  --dropbox\n"
	, APPE_VERSION);
}

static const struct option ipp2p_mt_opts[] = {
	{.name = "ruleidx",				.has_arg = true,	.val = CMD_RULE_INDEX},
	{.name = "syslog",				.has_arg = false,	.val = CMD_SYSLOG_ENABLE},
	{.name = "pass",				.has_arg = false,	.val = LOG_PASS},
	{.name = "block",				.has_arg = false,	.val = LOG_BLOCK},
	{.name = "msn",					.has_arg = false,	.val = IM_MSN},
	{.name = "msnmsg",				.has_arg = false,	.val = IM_MSN_MSG},
	{.name = "msnfile",				.has_arg = false,	.val = IM_MSN_FILE},
	{.name = "msngame",				.has_arg = false,	.val = IM_MSN_GAME},
	{.name = "msnconf",				.has_arg = false,	.val = IM_MSN_CONF},
	{.name = "msnother",			.has_arg = false,	.val = IM_MSN_OTHER},
	{.name = "ym",					.has_arg = false,	.val = IM_YM},
	{.name = "ymmsg",				.has_arg = false,	.val = IM_YM_MSG},
	{.name = "ymfile",				.has_arg = false,	.val = IM_YM_FILE},
	{.name = "ymgame",				.has_arg = false,	.val = IM_YM_GAME},
	{.name = "ymconf",				.has_arg = false,	.val = IM_YM_CONF},
	{.name = "ymother",				.has_arg = false,	.val = IM_YM_OTHER},
	{.name = "icq",					.has_arg = false,	.val = IM_ICQ},
	{.name = "icqmsg",				.has_arg = false,	.val = IM_ICQ_MSG},
	{.name = "icqfile",				.has_arg = false,	.val = IM_ICQ_FILE},
	{.name = "icqgame",				.has_arg = false,	.val = IM_ICQ_GAME},
	{.name = "icqconf",				.has_arg = false,	.val = IM_ICQ_CONF},
	{.name = "icqother",			.has_arg = false,	.val = IM_ICQ_OTHER},
	{.name = "aim",					.has_arg = false,	.val = IM_AIM},
	{.name = "aimmsg",				.has_arg = false,	.val = IM_AIM_MSG},
	{.name = "aimfile",				.has_arg = false,	.val = IM_AIM_FILE},
	{.name = "aimgame",				.has_arg = false,	.val = IM_AIM_GAME},
	{.name = "aimconf",				.has_arg = false,	.val = IM_AIM_CONF},
	{.name = "aimother",			.has_arg = false,	.val = IM_AIM_OTHER},
	{.name = "wim",					.has_arg = false,	.val = IM_WEB},
	{.name = "aim67",				.has_arg = false,	.val = IM_AIM67},
	{.name = "qq",					.has_arg = false,	.val = IM_QQTM},
	{.name = "ichat",				.has_arg = false,	.val = IM_ICHAT},
	{.name = "gt",					.has_arg = false,	.val = IM_JABBER},
	{.name = "gc",					.has_arg = false,	.val = IM_GOOGLECHAT},
	{.name = "xfire",				.has_arg = false,	.val = IM_XFIRE},
	{.name = "gadugadu",			.has_arg = false,	.val = IM_GADUGADU},
	{.name = "paltalk",				.has_arg = false,	.val = IM_PALTALK},
	{.name = "qnext",				.has_arg = false,	.val = IM_QNEXT},
	{.name = "pocomsg",				.has_arg = false,	.val = IM_POCO},
	{.name = "areachat",			.has_arg = false,	.val = IM_ARES},
	{.name = "aliww",				.has_arg = false,	.val = IM_ALIWW},
	{.name = "kc",					.has_arg = false,	.val = IM_KC},
	{.name = "lavalava",			.has_arg = false,	.val = IM_LAVALAVA},
	{.name = "icu2",				.has_arg = false,	.val = IM_ICU2},
	{.name = "ispq",				.has_arg = false,	.val = IM_ISPQ},
	{.name = "uc",					.has_arg = false,	.val = IM_UC},
	{.name = "mobilemsn",			.has_arg = false,	.val = IM_MOBILEMSN},
	{.name = "baiduhi",				.has_arg = false,	.val = IM_BAIDUHI},
	{.name = "fetion",				.has_arg = false,	.val = IM_FETION},
	{.name = "skype",				.has_arg = false,	.val = VOIP_SKYPE},
	{.name = "kubao",				.has_arg = false,	.val = VOIP_KUBAO},
	{.name = "gizmo",				.has_arg = false,	.val = VOIP_GIZMO},
	{.name = "siprtp",				.has_arg = false,	.val = VOIP_SIPRTP},
	{.name = "teltel",				.has_arg = false,	.val = VOIP_TELTEL},
	{.name = "teamspeak",			.has_arg = false,	.val = VOIP_TEAMSPEAK},
	{.name = "ss",					.has_arg = false,	.val = P2P_SOULSEEK},
	{.name = "edk",					.has_arg = false,	.val = P2P_EDONKEY},
	{.name = "ft",					.has_arg = false,	.val = P2P_FASTTRACK},
	{.name = "openft",				.has_arg = false,	.val = P2P_OPENFT},
	{.name = "gnu",					.has_arg = false,	.val = P2P_GNUTELLA},
	{.name = "opennap",				.has_arg = false,	.val = P2P_OPENNAP},
	{.name = "bt",					.has_arg = false,	.val = P2P_BITTORRENT},
	{.name = "xunlei",				.has_arg = false,	.val = P2P_XUNLEI},
	{.name = "vagaa",				.has_arg = false,	.val = P2P_VAGAA},
	{.name = "pp365",				.has_arg = false,	.val = P2P_PP365},
	{.name = "poco",				.has_arg = false,	.val = P2P_POCO},
	{.name = "clubbox",				.has_arg = false,	.val = P2P_CLUBBOX},
	{.name = "ares",				.has_arg = false,	.val = P2P_ARES},
	{.name = "ezpeer",				.has_arg = false,	.val = P2P_EZPEER},
	{.name = "pando",				.has_arg = false,	.val = P2P_PANDO},
	{.name = "huntmine",			.has_arg = false,	.val = P2P_HUNTMINE},
	{.name = "kuwo",				.has_arg = false,	.val = P2P_KUWO},
	{.name = "dns",					.has_arg = false,	.val = PROT_DNS},
	{.name = "ftp",					.has_arg = false,	.val = PROT_FTP},
	{.name = "http",				.has_arg = false,	.val = PROT_HTTP},
	{.name = "imap",				.has_arg = false,	.val = PROT_IMAP},
	{.name = "irc",					.has_arg = false,	.val = PROT_IRC},
	{.name = "nntp",				.has_arg = false,	.val = PROT_NNTP},
	{.name = "pop3",				.has_arg = false,	.val = PROT_POP3},
	{.name = "smb",					.has_arg = false,	.val = PROT_SMB},
	{.name = "smtp",				.has_arg = false,	.val = PROT_SMTP},
	{.name = "snmp",				.has_arg = false,	.val = PROT_SNMP},
	{.name = "ssh",					.has_arg = false,	.val = PROT_SSH},
	{.name = "ssltls",				.has_arg = false,	.val = PROT_SSLTLS},
	{.name = "telnet",				.has_arg = false,	.val = PROT_TELNET},
	{.name = "mssql",				.has_arg = false,	.val = PROT_MSSQL},
	{.name = "mysql",				.has_arg = false,	.val = PROT_MYSQL},
	{.name = "oracle",				.has_arg = false,	.val = PROT_ORACLE},
	{.name = "postgresql",			.has_arg = false,	.val = PROT_POSTGRESQL},
	{.name = "sybase",				.has_arg = false,	.val = PROT_SYBASE},
	{.name = "db2",					.has_arg = false,	.val = PROT_DB2},
	{.name = "informix",			.has_arg = false,	.val = PROT_INFORMIX},
	{.name = "socks",				.has_arg = false,	.val = TUNL_SOCKS},
	{.name = "pgpnet",				.has_arg = false,	.val = TUNL_PGPNET},
	{.name = "httpproxy",			.has_arg = false,	.val = TUNL_HTTPPROXY},
	{.name = "tor",					.has_arg = false,	.val = TUNL_TOR},
	{.name = "vnn",					.has_arg = false,	.val = TUNL_VNN},
	{.name = "softether",			.has_arg = false,	.val = TUNL_SOFTETHER},
	{.name = "msteredo",			.has_arg = false,	.val = TUNL_MSTEREDO},
	{.name = "ultrasurf",			.has_arg = false,	.val = TUNL_ULTRASURF},
	{.name = "hamachi",				.has_arg = false,	.val = TUNL_HAMACHI},
	{.name = "httptunnel",			.has_arg = false,	.val = TUNL_HTTPTUNNEL},
	{.name = "pingtunnel",			.has_arg = false,	.val = TUNL_PINGTUNNEL},
	{.name = "tinyvpn",				.has_arg = false,	.val = TUNL_TINYVPN},
	{.name = "realtunnel",			.has_arg = false,	.val = TUNL_REALTUNNEL},
	{.name = "dynapass",			.has_arg = false,	.val = TUNL_DYNAPASS},
	{.name = "ultravpn",			.has_arg = false,	.val = TUNL_ULTRAVPN},
	{.name = "freeu",				.has_arg = false,	.val = TUNL_FREEU},
	{.name = "skyfire",				.has_arg = false,	.val = TUNL_SKYFIRE},
	{.name = "mms",					.has_arg = false,	.val = STRM_MMS},
	{.name = "rtsp",				.has_arg = false,	.val = STRM_RTSP},
	{.name = "tvants",				.has_arg = false,	.val = STRM_TVANTS},
	{.name = "ppstream",			.has_arg = false,	.val = STRM_PPSTREAM},
	{.name = "pptv",				.has_arg = false,	.val = STRM_PPLIVE},
	{.name = "uusee",				.has_arg = false,	.val = STRM_UUSEE},
	{.name = "nsplayer",			.has_arg = false,	.val = STRM_NSPLAYER},
	{.name = "pcast",				.has_arg = false,	.val = STRM_PCAST},
	{.name = "tvkoo",				.has_arg = false,	.val = STRM_TVKOO},
	{.name = "sopcast",				.has_arg = false,	.val = STRM_SOPCAST},
	{.name = "udlivex",				.has_arg = false,	.val = STRM_UDLIVEX},
	{.name = "tvuplayer",			.has_arg = false,	.val = STRM_TVUPLAYER},
	{.name = "mysee",				.has_arg = false,	.val = STRM_MYSEE},
	{.name = "joost",				.has_arg = false,	.val = STRM_JOOST},
	{.name = "flashvideo",			.has_arg = false,	.val = STRM_FLASHVIDEO},
	{.name = "silverlight",			.has_arg = false,	.val = STRM_SILVERLIGHT},
	{.name = "slingbox",			.has_arg = false,	.val = STRM_SLINGBOX},
	{.name = "qvod",				.has_arg = false,	.val = STRM_QVOD},
	{.name = "qqlive",				.has_arg = false,	.val = STRM_QQLIVE},
	{.name = "china",				.has_arg = false,	.val = GAME_CNGAMES},
	{.name = "shanghai",			.has_arg = false,	.val = GAME_SHGAMES},
	{.name = "lianzhong",			.has_arg = false,	.val = GAME_LZGAMES},
	{.name = "bianfeng",			.has_arg = false,	.val = GAME_BFGAMES},
	{.name = "vnc",					.has_arg = false,	.val = RCTL_VNC},
	{.name = "radmin",				.has_arg = false,	.val = RCTL_RADMIN},
	{.name = "spyanywhere",			.has_arg = false,	.val = RCTL_SPYANYWHERE},
	{.name = "showmypc",			.has_arg = false,	.val = RCTL_SHOWMYPC},
	{.name = "logmein",				.has_arg = false,	.val = RCTL_LOGMEIN},
	{.name = "teamviewer",			.has_arg = false,	.val = RCTL_TEAMVIEWER},
	{.name = "gogrok",				.has_arg = false,	.val = RCTL_GOGROK},
	{.name = "remotecontrolpro",	.has_arg = false,	.val = RCTL_RCONTROLPRO},
	{.name = "crossloop",			.has_arg = false,	.val = RCTL_CROSSLOOP},
	{.name = "windowsrdp",			.has_arg = false,	.val = RCTL_WINDOWSRDP},
	{.name = "pcanywhere",			.has_arg = false,	.val = RCTL_PCANYWHERE},
	{.name = "timbuktu",			.has_arg = false,	.val = RCTL_TIMBUKTU},
	{.name = "windowslivesync",		.has_arg = false,	.val = RCTL_WINLIVESYNC},
	{.name = "sharedview",			.has_arg = false,	.val = RCTL_SHAREDVIEW},
	{.name = "httpupload",			.has_arg = false,	.val = WHD_HTTPUPLOAD},
	{.name = "hinetsafebox",		.has_arg = false,	.val = WHD_HINETSAFEBOX},
	{.name = "msskydrive",			.has_arg = false,	.val = WHD_MSSKYDRIVE},
	{.name = "gdocuploader",		.has_arg = false,	.val = WHD_GDOCUPLOADER},
	{.name = "adrive",				.has_arg = false,	.val = WHD_ADRIVE},
	{.name = "myotherdrive",		.has_arg = false,	.val = WHD_MYOTHERDRIVE},
	{.name = "mozy",				.has_arg = false,	.val = WHD_MOZY},
	{.name = "boxnet",				.has_arg = false,	.val = WHD_BOXNET},
	{.name = "officelive",			.has_arg = false,	.val = WHD_OFFICELIVE},
	{.name = "readdlestorage",		.has_arg = false,	.val = WHD_READDLESTORAGE},
	{.name = "dropbox",				.has_arg = false,	.val = WHD_DROPBOX},
	{NULL},
};

static const char *const op_cmds[] = {
	"--ruleidx",
	"--syslog",
};

static const char *const im_adv_cmds[] = {
	"--msn",
	"--msnmsg",
	"--msnfile",
	"--msngame",
	"--msnconf",
	"--msnother",
	"--ym",
	"--ymmsg",
	"--ymfile",
	"--ymgame",
	"--ymconf",
	"--ymother",
	"--aim",
	"--aimmsg",
	"--aimfile",
	"--aimgame",
	"--aimconf",
	"--aimother",
	"--icq",
	"--icqmsg",
	"--icqfile",
	"--icqgame",
	"--icqconf",
	"--icqother",
};

static const char *const im_cmds[] = {
	"--wim",
	"--aim67",
	"--qq",
	"--ichat",
	"--gt",
	"--gc",
	"--xfire",
	"--gadugadu",
	"--paltalk",
	"--qnext",
	"--pocomsg",
	"--areschat",
	"--aliww",
	"--kc",
	"--lavalava",
	"--icu2",
	"--ispq",
	"--uc",
	"--mobilemsn",
	"--baiduhi",
	"--fetion",
};

static const char *const voip_cmds[] = {
	"--skype",
	"--kubao",
	"--gizmo",
	"--siprtp",
	"--teltel",
	"--teamspeak",
};

static const char *const p2p_cmds[] = {
	"--ss",
	"--edk",
	"--ft",
	"--openft",
	"--gnu",
	"--opennap",
	"--bt",
	"--xunlei",
	"--vagaa",
	"--pp365",
	"--poco",
	"--clubbox",
	"--ares",
	"--ezpeer",
	"--pando",
	"--huntmine",
	"--kuwo",
};

static const char *const prot_cmds[] = {
	"--dns",
	"--ftp",
	"--http",
	"--imap",
	"--irc",
	"--nntp",
	"--pop3",
	"--smb",
	"--smtp",
	"--snmp",
	"--ssh",
	"--ssltls",
	"--telnet",
	"--mssql",
	"--mysql",
	"--oracle",
	"--postgresql",
	"--sybase",
	"--db2",
	"--informix",
};

static const char *const tunl_cmds[] = {
	"--socks",
	"--pgpnet",
	"--httpproxy",
	"--tor",
	"--vnn",
	"--softether",
	"--msteredo",
	"--ultrasurf",
	"--hamachi",
	"--httptunnel",
	"--pingtunnel",
	"--tinyvpn",
	"--realtunnel",
	"--dynapass",
	"--ultravpn",
	"--freeu",
	"--skyfire",
};

static const char *const strm_cmds[] = {
	"--mms",
	"--rtsp",
	"--tvants",
	"--ppstream",
	"--pptv",
	"--uusee",
	"--nsplayer",
	"--pcast",
	"--tvkoo",
	"--sopcast",
	"--udlivex",
	"--tvuplayer",
	"--mysee",
	"--joost",
	"--flashvideo",
	"--silverlight",
	"--slingbox",
	"--qvod",
	"--qqlive",
};

static const char *const game_cmds[] = {
	"--china",
	"--shanghai",
	"--lianzhong",
	"--bianfeng",
};

static const char *const rctl_cmds[] = {
	"--vnc",
	"--radmin",
	"--tvants",
	"--spyanywhere",
	"--showmypc",
	"--logmein",
	"--teamviewer",
	"--gogrok",
	"--remotecontrolpro",
	"--crossloop",
	"--windowsrdp",
	"--pcanywhere",
	"--windowslivesync",
	"--sharedview",
};

static const char *const whd_cmds[] = {
	"--httpupload",
	"--hinetsafebox",
	"--msskydrive",
	"--gdocuploader",
	"--adrive",
	"--myotherdrive",
	"--mozy",
	"--boxnet",
	"--officelive",
	"--readdlestorage",
	"--dropbox",
};

static int ipp2p_mt_parse(int c, char **argv, int invert, unsigned int *flags,
                          const void *entry, struct xt_entry_match **match)
{
	struct ipt_appe_info *info = (struct ipt_appe_info *)(*match)->data;
	int ap_type = GET_AP_TYPE(c);
	int ap_subgroup = GET_AP_SUBGROUP(c);
	int ap_enable = GET_AP_ENABLE(c);

	// operation command
	if ((c == CMD_RULE_INDEX) && (argv[optind - 1] != NULL)) {
		*flags |= CMD_RULE_INDEX;
		info->rule_idx = atoi(argv[optind - 1]);
		return 1;
	}

	if (c == CMD_SYSLOG_ENABLE) {
		*flags |= CMD_SYSLOG_ENABLE;
		info->syslog_enable = 1;
		return 1;
	}

    if (c == LOG_PASS){
        *flags |= LOG_PASS;
        info->block=0;
        return 1;
    }

    if (c == LOG_BLOCK){
        *flags |= LOG_BLOCK;
        info->block=1;
        return 1;
    }	

	// apid config
	switch (ap_type) {
		case APPE_TYPE_IM_ADV:
			*flags |= ap_enable;
			info->im_adv_cfg[ap_subgroup] |= ap_enable;
			break;
		case APPE_TYPE_IM:
			*flags |= ap_enable;
			info->im_cfg[ap_subgroup] |= ap_enable;
			break;
		case APPE_TYPE_VOIP:
			*flags |= ap_enable;
			info->voip_cfg[ap_subgroup] |= ap_enable;
			break;
		case APPE_TYPE_P2P:
			*flags |= ap_enable;
			info->p2p_cfg[ap_subgroup] |= ap_enable;
			break;
		case APPE_TYPE_PROT:
			*flags |= ap_enable;
			info->prot_cfg[ap_subgroup] |= ap_enable;
			break;
		case APPE_TYPE_TUNL:
			*flags |= ap_enable;
			info->tunl_cfg[ap_subgroup] |= ap_enable;
			break;
		case APPE_TYPE_STRM:
			*flags |= ap_enable;
			info->strm_cfg[ap_subgroup] |= ap_enable;
			break;
		case APPE_TYPE_GAME:
			*flags |= ap_enable;
			info->game_cfg[ap_subgroup] |= ap_enable;
			break;
		case APPE_TYPE_RCTL:
			*flags |= ap_enable;
			info->rctl_cfg[ap_subgroup] |= ap_enable;
			break;
		case APPE_TYPE_WHD:
			*flags |= ap_enable;
			info->whd_cfg[ap_subgroup] |= ap_enable;
			break;
		default:
			return 0;
	}
	
	return 1;
}

static void ipp2p_mt_check(unsigned int flags)
{
	if (!flags)
		exit_error(PARAMETER_PROBLEM,
			"\nipp2p-parameter problem: for ipp2p usage type: iptables -m ipp2p --help\n");
}

static void ipp2p_mt_print_cmd(int *cfg, const char **const cmds, int from, int to)
{
	unsigned int i;

	for (i = from; i <= to; ++i)
		if (cfg[GET_AP_SUBGROUP(i)] & GET_AP_ENABLE(i))
			printf("%s ", cmds[GET_AP_INDEX(i)]);
}

static void ipp2p_mt_print_detail(const void *entry, const struct xt_entry_match *match, int numeric)
{
	const struct ipt_appe_info *info = (const void *)match->data;
	unsigned int i;
	int ap_subgroup;
	int ap_enable;

	printf("%s %d ", op_cmds[GET_AP_INDEX(CMD_RULE_INDEX)], info->rule_idx);
	if (info->syslog_enable) printf("%s ", op_cmds[GET_AP_INDEX(CMD_SYSLOG_ENABLE)]);
    printf("%s ", (info->block)?"--block ":" --pass ");
	ipp2p_mt_print_cmd(info->im_adv_cfg, im_adv_cmds, IM_MSN, IM_ICQ_OTHER);
	ipp2p_mt_print_cmd(info->im_cfg, im_cmds, IM_WEB, IM_FETION);
	ipp2p_mt_print_cmd(info->voip_cfg, voip_cmds, VOIP_SKYPE, VOIP_TEAMSPEAK);
	ipp2p_mt_print_cmd(info->p2p_cfg, p2p_cmds, P2P_SOULSEEK, P2P_KUWO);
	ipp2p_mt_print_cmd(info->prot_cfg, prot_cmds, PROT_DNS, PROT_INFORMIX);
	ipp2p_mt_print_cmd(info->tunl_cfg, tunl_cmds, TUNL_SOCKS, TUNL_SKYFIRE);
	ipp2p_mt_print_cmd(info->strm_cfg, strm_cmds, STRM_MMS, STRM_QQLIVE);
	ipp2p_mt_print_cmd(info->game_cfg, game_cmds, GAME_CNGAMES, GAME_BFGAMES);
	ipp2p_mt_print_cmd(info->rctl_cfg, rctl_cmds, RCTL_VNC, RCTL_SHAREDVIEW);
	ipp2p_mt_print_cmd(info->whd_cfg, whd_cmds, WHD_HTTPUPLOAD, WHD_DROPBOX);
}

static void ipp2p_mt_print(const void *entry,
    const struct xt_entry_match *match, int numeric)
{
	printf("ipp2p ");
	ipp2p_mt_print_detail(entry, match, true);
}

static void ipp2p_mt_save(const void *entry, const struct xt_entry_match *match)
{
	ipp2p_mt_print_detail(entry, match, true);
}

static struct xtables_match ipp2p_mt_reg = {
	.version       = IPTABLES_VERSION,
	.name          = "ipp2p",
	.revision      = 1,
	.family        = AF_INET,
	.size          = XT_ALIGN(sizeof(struct ipt_appe_info)),
	.userspacesize = XT_ALIGN(sizeof(struct ipt_appe_info)),
	.help          = ipp2p_mt_help,
	.parse         = ipp2p_mt_parse,
	.final_check   = ipp2p_mt_check,
	.print         = ipp2p_mt_print,
	.save          = ipp2p_mt_save,
	.extra_opts    = ipp2p_mt_opts,
};

static __attribute__((constructor)) void ipp2p_mt_ldr(void)
{
	xtables_register_match(&ipp2p_mt_reg);
}
