<commit_before>#include "Python.h" 
/* user headers common */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h> 
#include <syslog.h>
/* kernel header common */
#include <netinet/in.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <linux/types.h>
#include <linux/icmp.h>
/* netfilter */
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/nf_conntrack_tuple_common.h>
#include <linux/netfilter/xt_pkttype.h>
#include <linux/netfilter/xt_conntrack.h>
#include <linux/netfilter/nf_conntrack_common.h>
#include <linux/netfilter/xt_limit.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_LOG.h>
#include <linux/netfilter_ipv4/ipt_REJECT.h>

#define XTABLES_VERSION "9" 

#define HOOK_PRE_ROUTING	NF_IP_PRE_ROUTING
#define HOOK_LOCAL_IN		NF_IP_LOCAL_IN
#define HOOK_FORWARD		NF_IP_FORWARD
#define HOOK_LOCAL_OUT		NF_IP_LOCAL_OUT
#define HOOK_POST_ROUTING	NF_IP_POST_ROUTING 


struct replace_context {
	struct ipt_replace *replace;
	struct ipt_getinfo *info;
	unsigned int current_offset;
	unsigned int memory_size;
	void *memory;
	unsigned int last_chain_end;
};

static const char *hooknames[] = {
	[HOOK_PRE_ROUTING]	= "PREROUTING",
	[HOOK_LOCAL_IN]		= "INPUT",
	[HOOK_FORWARD]		= "FORWARD",
	[HOOK_LOCAL_OUT]	= "OUTPUT",
	[HOOK_POST_ROUTING]	= "POSTROUTING",
};


static struct ipt_entry *
offset_get_entry(struct ipt_get_entries *entries, unsigned int offset)
{
	return (struct ipt_entry *)((char*)entries->entrytable + offset);
}

static unsigned long 
entry_get_offset(struct ipt_get_entries *entries, struct ipt_entry *e)
{
	return (void *)e - (void *)entries->entrytable;
}
/*
 * maybe a predefined chain, aka hook.
 */
static unsigned int 
entry_is_hook_entry(struct ipt_entry *e, struct ipt_getinfo *info,
		struct ipt_get_entries *entries)
{
	unsigned int i;
	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
		if ((info->valid_hooks & (1 << i))
			&& offset_get_entry(entries,
				info->hook_entry[i]) == e) { 
			return i+1;
		}
	}
	return 0;
}


static int 
add_matches(struct xt_entry_match *m, PyObject *matches_dict)
{ 
    PyObject *match_dict = NULL; 
        match_dict = PyDict_New();  
	PyDict_SetItemString(match_dict, "size",
			PyInt_FromLong(m->u.user.match_size));
    if (strcmp(m->u.user.name, "pkttype") == 0) {
        struct xt_pkttype_info *info  = (struct xt_pkttype_info *)m->data; 
        PyDict_SetItemString(match_dict, "type",
                PyInt_FromLong(info->pkttype));
        PyDict_SetItemString(match_dict, "invert",
                PyInt_FromLong(info->invert));
    } else if (strcmp(m->u.user.name, "tcp") == 0) { 
        struct xt_tcp *tcpinfo = (struct xt_tcp *)m->data;        
        PyDict_SetItemString(match_dict, "spts",
                PyTuple_Pack(2, PyInt_FromLong(tcpinfo->spts[0]),
                    PyInt_FromLong(tcpinfo->spts[1])));
        PyDict_SetItemString(match_dict, "dpts",
                PyTuple_Pack(2, PyInt_FromLong(tcpinfo->dpts[0]),
                    PyInt_FromLong(tcpinfo->dpts[1])));
        PyDict_SetItemString(match_dict, "options",
                PyInt_FromLong(tcpinfo->option));
        PyDict_SetItemString(match_dict, "flag_mask",
                PyInt_FromLong(tcpinfo->flg_mask)); 
        PyDict_SetItemString(match_dict, "flag_cmp",
                PyInt_FromLong(tcpinfo->flg_cmp));
        PyDict_SetItemString(match_dict, "invflags",
                PyInt_FromLong(tcpinfo->invflags)); 
    } else if (strcmp(m->u.user.name, "conntrack") == 0) {
	    if (m->u.user.revision == 3) {
		struct xt_conntrack_mtinfo3 *info = (void *)m->data; 
		
		if (info->match_flags & XT_CONNTRACK_STATE) { 
		    PyDict_SetItemString(match_dict, "state",
			    PyInt_FromLong(info->state_mask));
		}
		if (info->match_flags & XT_CONNTRACK_STATUS) {
		    PyDict_SetItemString(match_dict, "status",
			    PyInt_FromLong(info->status_mask));
		}
		if (info->match_flags & XT_CONNTRACK_EXPIRES) {
		    PyDict_SetItemString(match_dict, "expires_min", 
			    PyInt_FromLong(info->expires_min));
		    PyDict_SetItemString(match_dict, "expires_max",
			    PyInt_FromLong(info->expires_max));
		} 
		if (info->match_flags & XT_CONNTRACK_ORIGSRC) {
			PyDict_SetItemString(match_dict, "origsrc_ip",
					PyString_FromStringAndSize(
						(void *)&((struct in_addr *)&info->origsrc_addr.in)->s_addr, 4));
			PyDict_SetItemString(match_dict, "origsrc_mask",
					PyString_FromStringAndSize(
						(void *)&(((struct in_addr *)&info->origsrc_mask.in)->s_addr), 4)); 
		} 
		if (info->match_flags & XT_CONNTRACK_ORIGDST) {
			PyDict_SetItemString(match_dict, "origdst_ip",
					PyString_FromStringAndSize(
						(void *)&((struct in_addr *)&info->origdst_addr.in)->s_addr, 4));
			PyDict_SetItemString(match_dict, "origdst_mask",
					PyString_FromStringAndSize(
						(void *)&(((struct in_addr *)&info->origdst_mask.in)->s_addr), 4));
		} 
		if (info->match_flags & XT_CONNTRACK_REPLSRC) {
			PyDict_SetItemString(match_dict, "replsrc_ip",
					PyString_FromStringAndSize(
						(void *)&((struct in_addr *)&info->replsrc_addr.in)->s_addr, 4));
			PyDict_SetItemString(match_dict, "replsrc_mask",
					PyString_FromStringAndSize(
						(void *)&(((struct in_addr *)&info->replsrc_mask.in)->s_addr), 4)); 
		} 

		if (info->match_flags & XT_CONNTRACK_REPLDST) {
			PyDict_SetItemString(match_dict, "repldst_ip",
					PyString_FromStringAndSize(
						(void *)&((struct in_addr *)&info->repldst_addr.in)->s_addr, 4));
			PyDict_SetItemString(match_dict, "repldst_mask",
					PyString_FromStringAndSize(
						(void *)&(((struct in_addr *)&info->repldst_mask.in)->s_addr), 4)); 
		} 
		PyDict_SetItemString(match_dict, "invflags",
			PyInt_FromLong(info->invert_flags)); 
	}	
    } else if (strcmp(m->u.user.name, "limit") == 0) {
        struct xt_rateinfo *r =(struct xt_rateinfo *)m->data; 
        PyDict_SetItemString(match_dict, "avg",
                PyInt_FromLong(r->avg));
        PyDict_SetItemString(match_dict, "burst",
                PyInt_FromLong(r->burst));
    } else if (strcmp(m->u.user.name, "icmp") == 0) {
        struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data; 
        PyDict_SetItemString(match_dict, "type",
                PyInt_FromLong(icmpinfo->type));
        PyDict_SetItemString(match_dict, "min",
                PyInt_FromLong(icmpinfo->code[0]));
        PyDict_SetItemString(match_dict, "max",
                PyInt_FromLong(icmpinfo->code[1]));
        PyDict_SetItemString(match_dict, "invflags",
                PyInt_FromLong(icmpinfo->invflags));
    } 


	PyDict_SetItemString(matches_dict, m->u.user.name,
                    match_dict); 

    return 0;
}

static int 
add_entry(struct ipt_entry *e, PyObject *chains_dict,
		PyObject **current_chain_ptr,
		struct ipt_getinfo *info,
		struct ipt_get_entries *entries)
{
	size_t i;	
	unsigned int builtin;
	struct xt_entry_target *t; 
	char iniface_buffer[IFNAMSIZ+1];
	char outiface_buffer[IFNAMSIZ+1];
	PyObject *rule_dict;
	PyObject *matches_dict; 

	memset(iniface_buffer, 0, IFNAMSIZ+1);
	memset(outiface_buffer, 0, IFNAMSIZ+1);
	if ((unsigned long)((void *)e - (void *)entries->entrytable)
			+ e->next_offset == entries->size) {
		/* last one, policy rule do nothing*/	
		return 0;
	}
	/* rule data */
	rule_dict = PyDict_New();
	/* for jump target */
	PyDict_SetItemString(rule_dict, "offset", 
			PyInt_FromLong(entry_get_offset(entries, e)));
	PyDict_SetItemString(rule_dict, "srcip",
			PyInt_FromLong(e->ip.src.s_addr));
	PyDict_SetItemString(rule_dict, "srcip_mask",
			PyInt_FromLong(e->ip.smsk.s_addr));
	PyDict_SetItemString(rule_dict, "dstip",
			PyInt_FromLong(e->ip.dst.s_addr));
	PyDict_SetItemString(rule_dict, "dstip_mask",
			PyInt_FromLong(e->ip.dmsk.s_addr));
	for (i = 0; i < IFNAMSIZ; i++) {
		*(iniface_buffer+i) = e->ip.iniface_mask[i];
		*(outiface_buffer) = e->ip.outiface_mask[i];
	} 
	PyDict_SetItemString(rule_dict, "iniface",
			PyString_FromString(e->ip.iniface));
	PyDict_SetItemString(rule_dict, "iniface_mask",
			PyByteArray_FromStringAndSize(iniface_buffer, IFNAMSIZ));
	PyDict_SetItemString(rule_dict, "outiface",
			PyString_FromString(e->ip.outiface));
	PyDict_SetItemString(rule_dict, "outiface_mask",
			PyByteArray_FromStringAndSize(outiface_buffer, IFNAMSIZ));
	PyDict_SetItemString(rule_dict, "protocol",
			PyInt_FromLong(e->ip.proto));
	PyDict_SetItemString(rule_dict, "flags",
			PyInt_FromLong(e->ip.flags));
	PyDict_SetItemString(rule_dict, "invflags",
			PyInt_FromLong(e->ip.invflags));
	PyDict_SetItemString(rule_dict, "packets",
			PyInt_FromLong(
				(unsigned long long)e->counters.pcnt));
	PyDict_SetItemString(rule_dict, "bytes",
			PyInt_FromLong(
				(unsigned long long)e->counters.bcnt));
	PyDict_SetItemString(rule_dict, "cache",
			PyInt_FromLong(e->nfcache));
	/* matches */
	matches_dict = PyDict_New(); 
	XT_MATCH_ITERATE(struct ipt_entry, e, add_matches, matches_dict); 
	PyDict_SetItemString(rule_dict, "matches", matches_dict); 
	/* target */
	t = (void *)e + e->target_offset;
	PyDict_SetItemString(rule_dict, "target",
			PyString_FromString(t->u.user.name));
	/* new chain */ 
	if (strcmp(t->u.user.name, XT_ERROR_TARGET) == 0) {
		/* new user defined chain */
		*current_chain_ptr = PyList_New(0);
		PyDict_SetItemString(chains_dict, (char *)t->data,
				*current_chain_ptr); 
		Py_XDECREF(rule_dict);	
		return 0;
	} else if ((builtin = entry_is_hook_entry(e, info, entries)) != 0) {
		*current_chain_ptr = PyList_New(0); 
		PyDict_SetItemString(chains_dict,
				(char *)hooknames[builtin-1],
				*current_chain_ptr); 
	} 
	/* target */
	struct xt_standard_target *xt = (void *)t; 
	if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0) { 
		if (xt->verdict < 0) {
			PyDict_SetItemString(rule_dict, "target_type",
					PyString_FromString("standard"));
			PyDict_SetItemString(rule_dict, "verb",
				PyString_FromString(
					xt->verdict == -NF_ACCEPT-1 ? "ACCEPT"
					: xt->verdict == -NF_DROP-1 ? "DROP"
					: xt->verdict == -NF_QUEUE-1 ?"QUEUE"
					: xt->verdict == XT_RETURN ? "RETURN"
					: "UNKNOWN"));
		}
		else if (xt->verdict == entry_get_offset(entries, e) + e->next_offset) {
			PyDict_SetItemString(rule_dict, "target_type",
					PyString_FromString("fallthrough"));
			PyDict_SetItemString(rule_dict, "verb",
					PyInt_FromLong(xt->verdict));
		} else {
			PyDict_SetItemString(rule_dict, "target_type",
					PyString_FromString("jump"));
			PyDict_SetItemString(rule_dict, "verb",
					PyInt_FromLong(xt->verdict));
		}
	}  else {
		/* target extension */
		PyObject *target_dict;
		target_dict = PyDict_New();
		if (strcmp(t->u.user.name, "LOG") == 0) { 
			struct ipt_log_info *loginfo = (void *)t->data;
			PyDict_SetItemString(target_dict, "level",	
					PyInt_FromLong((long)loginfo->level));
			PyDict_SetItemString(target_dict, "logflags",
					PyInt_FromLong((long)loginfo->logflags));
			PyDict_SetItemString(target_dict, "prefix",
					PyString_FromString(loginfo->prefix));
			PyDict_SetItemString(rule_dict, "target_dict",
					target_dict);
		} 
		if (strcmp(t->u.user.name, "REJECT") == 0) {
			struct ipt_reject_info *rjinfo = (void *)t->data;
			PyDict_SetItemString(target_dict, "with",
					PyInt_FromLong(rjinfo->with));
			PyDict_SetItemString(rule_dict, "target_dict",
					target_dict);
		}
		PyDict_SetItemString(rule_dict, "target_type",
				PyString_FromString("module"));
		PyDict_SetItemString(rule_dict, "verb",
				PyInt_FromLong(xt->verdict)); 
	}
	/* add rule to current_chain */
	if (*current_chain_ptr) 
		return PyList_Append(*current_chain_ptr, rule_dict) ? 1 : 0; 
	else
		return 1;

}

static PyObject *
parse_entries(struct ipt_getinfo *info, struct ipt_get_entries *entries)
{
	PyObject *table_dict; 
	PyObject *chains_dict;
	PyObject *current_chain = NULL;

	table_dict = PyDict_New();
	PyDict_SetItemString(table_dict, "iptver",
			PyString_FromString(XTABLES_VERSION));		
	PyDict_SetItemString(table_dict, "blobsize",
			PyInt_FromLong(entries->size));
	PyDict_SetItemString(table_dict, "name",
			PyString_FromString(info->name)); 

	chains_dict = PyDict_New();
	
	unsigned int i, ret; 
	struct ipt_entry *entry;

	for (i = 0;i < entries->size;
			i += entry->next_offset) {
		entry = (void *)(entries->entrytable) + i; 
		ret = add_entry(entry, chains_dict,
				&current_chain, info, entries); 
		if (ret != 0)
			break;
	}

	PyDict_SetItemString(table_dict, "chains", chains_dict);
	return table_dict;

} 

PyDoc_STRVAR(iptables_get_table_doc, "get entries of a table");

static PyObject *
iptables_get_table(PyObject *object, PyObject *args)
{ 
	struct ipt_getinfo *info;
	struct ipt_get_entries *entries;
	char *tablename; 
	socklen_t s;
	int sockfd; 
	unsigned int tmp; 

	if (!PyArg_ParseTuple(args, "s:get_entries", &tablename)) {
		return NULL;
	} 
	if (strlen(tablename) >= XT_TABLE_MAXNAMELEN) { 
		return NULL;
	}
	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
	if (sockfd < 0) {
		PyErr_SetFromErrno(PyExc_OSError);
		return NULL;
	}
	if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
		PyErr_SetFromErrno(PyExc_OSError);
		return NULL;
	}
	info = PyMem_Malloc(sizeof(struct ipt_getinfo)); 
	if (!info)
		goto ERROR; 
	s = sizeof(struct ipt_getinfo);
	memset(info, 0, s);
	strcpy(info->name, tablename);
	if (getsockopt(sockfd, IPPROTO_IP,
				IPT_SO_GET_INFO, info, &s) < 0) {
		PyErr_SetFromErrno(PyExc_OSError);
		PyMem_Free(info);
		goto ERROR; 
	} 
	entries = PyMem_Malloc(sizeof(struct ipt_get_entries) + info->size);
	if (!entries) {
		PyMem_Free(info);
		goto ERROR;
	}
	entries->size = info->size; 
	strcpy(entries->name, info->name);
	tmp = sizeof(struct ipt_get_entries) + info->size;
	if (getsockopt(sockfd, IPPROTO_IP,
				IPT_SO_GET_ENTRIES, entries, &tmp) < 0) {
		PyErr_SetFromErrno(PyExc_OSError);	
		PyMem_Free(info);
		PyMem_Free(entries);
		goto ERROR;
	}
	close(sockfd); 
	return parse_entries(info, entries); 
ERROR:	
	close(sockfd); 
	return NULL;
}


static int 
compile_match(void *base, PyObject *this_match,unsigned int *match_offset) 
{
	/*supress gcc warning*/
	struct xt_entry_match *match_entry_base = base;
	const char *keystr = NULL;
	PyObject *key = PyTuple_GetItem(this_match, 0);
	PyObject *value = PyTuple_GetItem(this_match, 1);
	if (key == NULL | value == NULL) {
		return 0;
	}
	keystr = PyString_AsString(key);
	if (strcmp(keystr, "tcp") == 0) {
		/* tcp match plugin */	
	}
	return 1;
}

static int
compile_rule(PyObject *rule_dict, struct ipt_entry *this_entry, unsigned int *current_offset)
{ 
	struct xt_entry_match *match_entry_base = NULL;
	/*convert entry, match, target plugins */
	this_entry->ip.src.s_addr = PyInt_AsLong(PyDict_GetItemString(rule_dict, "srcip"));
	this_entry->ip.dst.s_addr = PyInt_AsLong(PyDict_GetItemString(rule_dict, "dstip"));
	this_entry->ip.smsk.s_addr = PyInt_AsLong(PyDict_GetItemString(rule_dict, "srcip_mask"));
	this_entry->ip.dmsk.s_addr = PyInt_AsLong(PyDict_GetItemString(rule_dict, "dstip_mask"));
	/*bug char * , unsgined char */
	strcpy(this_entry->ip.iniface, PyString_AsString(PyDict_GetItemString(rule_dict, "iniface")));
	strcpy(this_entry->ip.outiface,  PyString_AsString(PyDict_GetItemString(rule_dict, "outiface")));
	PyObject *iniface_mask = PyDict_GetItemString(rule_dict, "iniface_mask");
	memcpy(this_entry->ip.iniface_mask, PyByteArray_AsString(iniface_mask), PyByteArray_Size(iniface_mask));
	PyObject *outiface_mask = PyDict_GetItemString(rule_dict, "outiface_mask");
	memcpy(this_entry->ip.outiface_mask,  PyByteArray_AsString(outiface_mask), PyByteArray_Size(outiface_mask)); 
	this_entry->ip.proto = PyInt_AsLong(PyDict_GetItemString(rule_dict, "protocol"));	
	this_entry->ip.flags = PyInt_AsLong(PyDict_GetItemString(rule_dict, "flags"));
	this_entry->ip.invflags = PyInt_AsLong(PyDict_GetItemString(rule_dict, "invflags"));
	this_entry->counters.pcnt = PyInt_AsLong(PyDict_GetItemString(rule_dict, "packets"));
	this_entry->counters.bcnt = PyInt_AsLong(PyDict_GetItemString(rule_dict, "bytes"));
	this_entry->nfcache = PyInt_AsLong(PyDict_GetItemString(rule_dict, "bytes"));	
	/*iter over matches */
	match_entry_base = (void *)this_entry + sizeof(struct ipt_entry);
	PyObject *matches_dict = PyDict_GetItemString(rule_dict, "matches");
	PyObject *matches_dict_iter = PyObject_GetIter(PyDict_Items(matches_dict));
	unsigned int match_offset;
	int ret;
	PyObject *matches_dict_next = PyIter_Next(matches_dict_iter);
	while (matches_dict_next) {
		ret = compile_match(match_entry_base, matches_dict_next, &match_offset);
		Py_XDECREF(matches_dict_next);
		if (!ret) {
			Py_XDECREF(matches_dict_iter);	
			goto CLEAR;
		}
		matches_dict_next = PyIter_Next(matches_dict_iter); 
	}
	return 1;
CLEAR:
	return 0; 
}

static int 
compile_chain(struct replace_context *context, PyObject *chain_name,  PyObject *rule_list)
{<commit_msg>update match plugins<commit_after>#include "Python.h" 
/* user headers common */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h> 
#include <syslog.h>
/* kernel header common */
#include <netinet/in.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <linux/types.h>
#include <linux/icmp.h>
/* netfilter */
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/nf_conntrack_tuple_common.h>
#include <linux/netfilter/xt_pkttype.h>
#include <linux/netfilter/xt_conntrack.h>
#include <linux/netfilter/nf_conntrack_common.h>
#include <linux/netfilter/xt_limit.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_LOG.h>
#include <linux/netfilter_ipv4/ipt_REJECT.h>

#define XTABLES_VERSION "9" 

#define HOOK_PRE_ROUTING	NF_IP_PRE_ROUTING
#define HOOK_LOCAL_IN		NF_IP_LOCAL_IN
#define HOOK_FORWARD		NF_IP_FORWARD
#define HOOK_LOCAL_OUT		NF_IP_LOCAL_OUT
#define HOOK_POST_ROUTING	NF_IP_POST_ROUTING 


struct replace_context {
	struct ipt_replace *replace;
	struct ipt_getinfo *info;
	unsigned int current_offset;
	unsigned int memory_size;
	void *memory;
	unsigned int last_chain_end;
};

static const char *hooknames[] = {
	[HOOK_PRE_ROUTING]	= "PREROUTING",
	[HOOK_LOCAL_IN]		= "INPUT",
	[HOOK_FORWARD]		= "FORWARD",
	[HOOK_LOCAL_OUT]	= "OUTPUT",
	[HOOK_POST_ROUTING]	= "POSTROUTING",
};


static struct ipt_entry *
offset_get_entry(struct ipt_get_entries *entries, unsigned int offset)
{
	return (struct ipt_entry *)((char*)entries->entrytable + offset);
}

static unsigned long 
entry_get_offset(struct ipt_get_entries *entries, struct ipt_entry *e)
{
	return (void *)e - (void *)entries->entrytable;
}
/*
 * maybe a predefined chain, aka hook.
 */
static unsigned int 
entry_is_hook_entry(struct ipt_entry *e, struct ipt_getinfo *info,
		struct ipt_get_entries *entries)
{
	unsigned int i;
	for (i = 0; i < NF_IP_NUMHOOKS; i++) {
		if ((info->valid_hooks & (1 << i))
			&& offset_get_entry(entries,
				info->hook_entry[i]) == e) { 
			return i+1;
		}
	}
	return 0;
}


static int 
add_matches(struct xt_entry_match *m, PyObject *matches_dict)
{ 
    PyObject *match_dict = NULL; 
        match_dict = PyDict_New();  
	PyDict_SetItemString(match_dict, "size",
			PyInt_FromLong(m->u.user.match_size));
    if (strcmp(m->u.user.name, "pkttype") == 0) {
        struct xt_pkttype_info *info  = (struct xt_pkttype_info *)m->data; 
        PyDict_SetItemString(match_dict, "type",
                PyInt_FromLong(info->pkttype));
        PyDict_SetItemString(match_dict, "invert",
                PyInt_FromLong(info->invert));
    } else if (strcmp(m->u.user.name, "tcp") == 0) { 
        struct xt_tcp *tcpinfo = (struct xt_tcp *)m->data;        
        PyDict_SetItemString(match_dict, "spts",
                PyTuple_Pack(2, PyInt_FromLong(tcpinfo->spts[0]),
                    PyInt_FromLong(tcpinfo->spts[1])));
        PyDict_SetItemString(match_dict, "dpts",
                PyTuple_Pack(2, PyInt_FromLong(tcpinfo->dpts[0]),
                    PyInt_FromLong(tcpinfo->dpts[1])));
        PyDict_SetItemString(match_dict, "options",
                PyInt_FromLong(tcpinfo->option));
        PyDict_SetItemString(match_dict, "flag_mask",
                PyInt_FromLong(tcpinfo->flg_mask)); 
        PyDict_SetItemString(match_dict, "flag_cmp",
                PyInt_FromLong(tcpinfo->flg_cmp));
        PyDict_SetItemString(match_dict, "invflags",
                PyInt_FromLong(tcpinfo->invflags)); 
    } else if (strcmp(m->u.user.name, "conntrack") == 0) {
	    if (m->u.user.revision == 3) {
		struct xt_conntrack_mtinfo3 *info = (void *)m->data; 
		
		if (info->match_flags & XT_CONNTRACK_STATE) { 
		    PyDict_SetItemString(match_dict, "state",
			    PyInt_FromLong(info->state_mask));
		}
		if (info->match_flags & XT_CONNTRACK_STATUS) {
		    PyDict_SetItemString(match_dict, "status",
			    PyInt_FromLong(info->status_mask));
		}
		if (info->match_flags & XT_CONNTRACK_EXPIRES) {
		    PyDict_SetItemString(match_dict, "expires_min", 
			    PyInt_FromLong(info->expires_min));
		    PyDict_SetItemString(match_dict, "expires_max",
			    PyInt_FromLong(info->expires_max));
		} 
		if (info->match_flags & XT_CONNTRACK_ORIGSRC) {
			PyDict_SetItemString(match_dict, "origsrc_ip",
					PyString_FromStringAndSize(
						(void *)&((struct in_addr *)&info->origsrc_addr.in)->s_addr, 4));
			PyDict_SetItemString(match_dict, "origsrc_mask",
					PyString_FromStringAndSize(
						(void *)&(((struct in_addr *)&info->origsrc_mask.in)->s_addr), 4)); 
		} 
		if (info->match_flags & XT_CONNTRACK_ORIGDST) {
			PyDict_SetItemString(match_dict, "origdst_ip",
					PyString_FromStringAndSize(
						(void *)&((struct in_addr *)&info->origdst_addr.in)->s_addr, 4));
			PyDict_SetItemString(match_dict, "origdst_mask",
					PyString_FromStringAndSize(
						(void *)&(((struct in_addr *)&info->origdst_mask.in)->s_addr), 4));
		} 
		if (info->match_flags & XT_CONNTRACK_REPLSRC) {
			PyDict_SetItemString(match_dict, "replsrc_ip",
					PyString_FromStringAndSize(
						(void *)&((struct in_addr *)&info->replsrc_addr.in)->s_addr, 4));
			PyDict_SetItemString(match_dict, "replsrc_mask",
					PyString_FromStringAndSize(
						(void *)&(((struct in_addr *)&info->replsrc_mask.in)->s_addr), 4)); 
		} 

		if (info->match_flags & XT_CONNTRACK_REPLDST) {
			PyDict_SetItemString(match_dict, "repldst_ip",
					PyString_FromStringAndSize(
						(void *)&((struct in_addr *)&info->repldst_addr.in)->s_addr, 4));
			PyDict_SetItemString(match_dict, "repldst_mask",
					PyString_FromStringAndSize(
						(void *)&(((struct in_addr *)&info->repldst_mask.in)->s_addr), 4)); 
		} 
		PyDict_SetItemString(match_dict, "invflags",
			PyInt_FromLong(info->invert_flags)); 
	}	
    } else if (strcmp(m->u.user.name, "limit") == 0) {
        struct xt_rateinfo *r =(struct xt_rateinfo *)m->data; 
        PyDict_SetItemString(match_dict, "avg",
                PyInt_FromLong(r->avg));
        PyDict_SetItemString(match_dict, "burst",
                PyInt_FromLong(r->burst));
    } else if (strcmp(m->u.user.name, "icmp") == 0) {
        struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data; 
        PyDict_SetItemString(match_dict, "type",
                PyInt_FromLong(icmpinfo->type));
        PyDict_SetItemString(match_dict, "min",
                PyInt_FromLong(icmpinfo->code[0]));
        PyDict_SetItemString(match_dict, "max",
                PyInt_FromLong(icmpinfo->code[1]));
        PyDict_SetItemString(match_dict, "invflags",
                PyInt_FromLong(icmpinfo->invflags));
    } 


	PyDict_SetItemString(matches_dict, m->u.user.name,
                    match_dict); 

    return 0;
}

static int 
add_entry(struct ipt_entry *e, PyObject *chains_dict,
		PyObject **current_chain_ptr,
		struct ipt_getinfo *info,
		struct ipt_get_entries *entries)
{
	size_t i;	
	unsigned int builtin;
	struct xt_entry_target *t; 
	char iniface_buffer[IFNAMSIZ+1];
	char outiface_buffer[IFNAMSIZ+1];
	PyObject *rule_dict;
	PyObject *matches_dict; 

	memset(iniface_buffer, 0, IFNAMSIZ+1);
	memset(outiface_buffer, 0, IFNAMSIZ+1);
	if ((unsigned long)((void *)e - (void *)entries->entrytable)
			+ e->next_offset == entries->size) {
		/* last one, policy rule do nothing*/	
		return 0;
	}
	/* rule data */
	rule_dict = PyDict_New();
	/* for jump target */
	PyDict_SetItemString(rule_dict, "offset", 
			PyInt_FromLong(entry_get_offset(entries, e)));
	PyDict_SetItemString(rule_dict, "srcip",
			PyInt_FromLong(e->ip.src.s_addr));
	PyDict_SetItemString(rule_dict, "srcip_mask",
			PyInt_FromLong(e->ip.smsk.s_addr));
	PyDict_SetItemString(rule_dict, "dstip",
			PyInt_FromLong(e->ip.dst.s_addr));
	PyDict_SetItemString(rule_dict, "dstip_mask",
			PyInt_FromLong(e->ip.dmsk.s_addr));
	for (i = 0; i < IFNAMSIZ; i++) {
		*(iniface_buffer+i) = e->ip.iniface_mask[i];
		*(outiface_buffer) = e->ip.outiface_mask[i];
	} 
	PyDict_SetItemString(rule_dict, "iniface",
			PyString_FromString(e->ip.iniface));
	PyDict_SetItemString(rule_dict, "iniface_mask",
			PyByteArray_FromStringAndSize(iniface_buffer, IFNAMSIZ));
	PyDict_SetItemString(rule_dict, "outiface",
			PyString_FromString(e->ip.outiface));
	PyDict_SetItemString(rule_dict, "outiface_mask",
			PyByteArray_FromStringAndSize(outiface_buffer, IFNAMSIZ));
	PyDict_SetItemString(rule_dict, "protocol",
			PyInt_FromLong(e->ip.proto));
	PyDict_SetItemString(rule_dict, "flags",
			PyInt_FromLong(e->ip.flags));
	PyDict_SetItemString(rule_dict, "invflags",
			PyInt_FromLong(e->ip.invflags));
	PyDict_SetItemString(rule_dict, "packets",
			PyInt_FromLong(
				(unsigned long long)e->counters.pcnt));
	PyDict_SetItemString(rule_dict, "bytes",
			PyInt_FromLong(
				(unsigned long long)e->counters.bcnt));
	PyDict_SetItemString(rule_dict, "cache",
			PyInt_FromLong(e->nfcache));
	/* matches */
	matches_dict = PyDict_New(); 
	XT_MATCH_ITERATE(struct ipt_entry, e, add_matches, matches_dict); 
	PyDict_SetItemString(rule_dict, "matches", matches_dict); 
	/* target */
	t = (void *)e + e->target_offset;
	PyDict_SetItemString(rule_dict, "target",
			PyString_FromString(t->u.user.name));
	/* new chain */ 
	if (strcmp(t->u.user.name, XT_ERROR_TARGET) == 0) {
		/* new user defined chain */
		*current_chain_ptr = PyList_New(0);
		PyDict_SetItemString(chains_dict, (char *)t->data,
				*current_chain_ptr); 
		Py_XDECREF(rule_dict);	
		return 0;
	} else if ((builtin = entry_is_hook_entry(e, info, entries)) != 0) {
		*current_chain_ptr = PyList_New(0); 
		PyDict_SetItemString(chains_dict,
				(char *)hooknames[builtin-1],
				*current_chain_ptr); 
	} 
	/* target */
	struct xt_standard_target *xt = (void *)t; 
	if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0) { 
		if (xt->verdict < 0) {
			PyDict_SetItemString(rule_dict, "target_type",
					PyString_FromString("standard"));
			PyDict_SetItemString(rule_dict, "verb",
				PyString_FromString(
					xt->verdict == -NF_ACCEPT-1 ? "ACCEPT"
					: xt->verdict == -NF_DROP-1 ? "DROP"
					: xt->verdict == -NF_QUEUE-1 ?"QUEUE"
					: xt->verdict == XT_RETURN ? "RETURN"
					: "UNKNOWN"));
		}
		else if (xt->verdict == entry_get_offset(entries, e) + e->next_offset) {
			PyDict_SetItemString(rule_dict, "target_type",
					PyString_FromString("fallthrough"));
			PyDict_SetItemString(rule_dict, "verb",
					PyInt_FromLong(xt->verdict));
		} else {
			PyDict_SetItemString(rule_dict, "target_type",
					PyString_FromString("jump"));
			PyDict_SetItemString(rule_dict, "verb",
					PyInt_FromLong(xt->verdict));
		}
	}  else {
		/* target extension */
		PyObject *target_dict;
		target_dict = PyDict_New();
		if (strcmp(t->u.user.name, "LOG") == 0) { 
			struct ipt_log_info *loginfo = (void *)t->data;
			PyDict_SetItemString(target_dict, "level",	
					PyInt_FromLong((long)loginfo->level));
			PyDict_SetItemString(target_dict, "logflags",
					PyInt_FromLong((long)loginfo->logflags));
			PyDict_SetItemString(target_dict, "prefix",
					PyString_FromString(loginfo->prefix));
			PyDict_SetItemString(rule_dict, "target_dict",
					target_dict);
		} 
		if (strcmp(t->u.user.name, "REJECT") == 0) {
			struct ipt_reject_info *rjinfo = (void *)t->data;
			PyDict_SetItemString(target_dict, "with",
					PyInt_FromLong(rjinfo->with));
			PyDict_SetItemString(rule_dict, "target_dict",
					target_dict);
		}
		PyDict_SetItemString(rule_dict, "target_type",
				PyString_FromString("module"));
		PyDict_SetItemString(rule_dict, "verb",
				PyInt_FromLong(xt->verdict)); 
	}
	/* add rule to current_chain */
	if (*current_chain_ptr) 
		return PyList_Append(*current_chain_ptr, rule_dict) ? 1 : 0; 
	else
		return 1;

}

static PyObject *
parse_entries(struct ipt_getinfo *info, struct ipt_get_entries *entries)
{
	PyObject *table_dict; 
	PyObject *chains_dict;
	PyObject *current_chain = NULL;

	table_dict = PyDict_New();
	PyDict_SetItemString(table_dict, "iptver",
			PyString_FromString(XTABLES_VERSION));		
	PyDict_SetItemString(table_dict, "blobsize",
			PyInt_FromLong(entries->size));
	PyDict_SetItemString(table_dict, "name",
			PyString_FromString(info->name)); 

	chains_dict = PyDict_New();
	
	unsigned int i, ret; 
	struct ipt_entry *entry;

	for (i = 0;i < entries->size;
			i += entry->next_offset) {
		entry = (void *)(entries->entrytable) + i; 
		ret = add_entry(entry, chains_dict,
				&current_chain, info, entries); 
		if (ret != 0)
			break;
	}

	PyDict_SetItemString(table_dict, "chains", chains_dict);
	return table_dict;

} 

PyDoc_STRVAR(iptables_get_table_doc, "get entries of a table");

static PyObject *
iptables_get_table(PyObject *object, PyObject *args)
{ 
	struct ipt_getinfo *info;
	struct ipt_get_entries *entries;
	char *tablename; 
	socklen_t s;
	int sockfd; 
	unsigned int tmp; 

	if (!PyArg_ParseTuple(args, "s:get_entries", &tablename)) {
		return NULL;
	} 
	if (strlen(tablename) >= XT_TABLE_MAXNAMELEN) { 
		return NULL;
	}
	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
	if (sockfd < 0) {
		PyErr_SetFromErrno(PyExc_OSError);
		return NULL;
	}
	if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
		PyErr_SetFromErrno(PyExc_OSError);
		return NULL;
	}
	info = PyMem_Malloc(sizeof(struct ipt_getinfo)); 
	if (!info)
		goto ERROR; 
	s = sizeof(struct ipt_getinfo);
	memset(info, 0, s);
	strcpy(info->name, tablename);
	if (getsockopt(sockfd, IPPROTO_IP,
				IPT_SO_GET_INFO, info, &s) < 0) {
		PyErr_SetFromErrno(PyExc_OSError);
		PyMem_Free(info);
		goto ERROR; 
	} 
	entries = PyMem_Malloc(sizeof(struct ipt_get_entries) + info->size);
	if (!entries) {
		PyMem_Free(info);
		goto ERROR;
	}
	entries->size = info->size; 
	strcpy(entries->name, info->name);
	tmp = sizeof(struct ipt_get_entries) + info->size;
	if (getsockopt(sockfd, IPPROTO_IP,
				IPT_SO_GET_ENTRIES, entries, &tmp) < 0) {
		PyErr_SetFromErrno(PyExc_OSError);	
		PyMem_Free(info);
		PyMem_Free(entries);
		goto ERROR;
	}
	close(sockfd); 
	return parse_entries(info, entries); 
ERROR:	
	close(sockfd); 
	return NULL;
}


static int 
compile_match(void *base, PyObject *this_match) 
{
	/*supress gcc warning*/
	struct xt_entry_match *match_entry = base;
	const char *keystr = NULL;
	PyObject *plugin_name = PyTuple_GetItem(this_match, 0);
	PyObject *plugin_dict = PyTuple_GetItem(this_match, 1);

	if (plugin_name == NULL | plugin_dict == NULL) {
		return 0;
	}
	base += sizeof(struct xt_entry_match);
	match_entry->u.user.revision = 3;

	keystr = PyString_AsString(plugin_name);
	if (strcmp(keystr, "tcp") == 0) { 
		/* tcp match plugin */	
		struct xt_tcp *tcpinfo = base;
		PyObject *spts_tuple = PyDict_GetItemString(plugin_dict, "spts"); 
		tcpinfo->spts[0] = PyInt_AsLong(PyTuple_GetItem(spts_tuple, 0));
		tcpinfo->spts[1] = PyInt_AsLong(PyTuple_GetItem(spts_tuple, 1));
		PyObject *dpts_tuple = PyDict_GetItemString(plugin_dict, "dpts");
		tcpinfo->dpts[0] = PyInt_AsLong(PyTuple_GetItem(dpts_tuple, 0));
		tcpinfo->dpts[1] = PyInt_AsLong(PyTuple_GetItem(dpts_tuple, 1));
		tcpinfo->option = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "options"));
		tcpinfo->flg_mask = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "flag_mask"));
		tcpinfo->flg_cmp = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "flag_cmp"));
		tcpinfo->invflags = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "invflags"));
		strcpy(match_entry->u.user.name, keystr);
		match_entry->u.match_size = sizeof(struct xt_tcp);
		base += sizeof(struct xt_tcp);
	} else if (strcmp(keystr, "pkttype")) {
		/* packet type plugin */
		struct xt_pkttype_info *info = base;
		info->pkttype = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "type"));
		info->invert = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "invert"));

		strcpy(match_entry->u.user.name, keystr);
		match_entry->u.match_size = sizeof(struct xt_pkttype_info);
		base += sizeof(struct xt_pkttype_info);
	}  else if (strcmp(keystr, "conntrack")) {
		/* conntrack plugin */
		struct xt_conntrack_mtinfo3 *info = base;
		unsigned int match_flags = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "match_flags"));
		if (match_flags & XT_CONNTRACK_STATE) {
			info->state_mask = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "state"));
		}
		if (match_flags & XT_CONNTRACK_STATUS) {
			info->status_mask = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "status"));
		}
		if (match_flags & XT_CONNTRACK_EXPIRES) {
			info->expires_min = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "expires_min")); 
			info->expires_max = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "expires_max"));
		}
		if (match_flags & XT_CONNTRACK_ORIGSRC) {
			info->origsrc_addr.in.s_addr = *(unsigned int *)PyString_AsString(PyDict_GetItemString(plugin_dict, "origsrc_ip"));
			info->origsrc_mask.in.s_addr = *(unsigned int *)PyString_AsString(PyDict_GetItemString(plugin_dict, "origsrc_mask"));
		}
		if (match_flags & XT_CONNTRACK_ORIGDST) {
			info->origdst_addr.in.s_addr = *(unsigned int *)PyString_AsString(PyDict_GetItemString(plugin_dict, "origdst_ip"));
			info->origdst_mask.in.s_addr = *(unsigned int *)PyString_AsString(PyDict_GetItemString(plugin_dict, "origdst_mask"));	
		}
		if (match_flags & XT_CONNTRACK_REPLSRC) {
			info->replsrc_addr.in.s_addr = *(unsigned int *)PyString_AsString(PyDict_GetItemString(plugin_dict, "replsrc_ip"));
			info->replsrc_mask.in.s_addr = *(unsigned int *)PyString_AsString(PyDict_GetItemString(plugin_dict, "replsrc_mask"));
		}
		if (match_flags & XT_CONNTRACK_REPLDST) {
			info->repldst_addr.in.s_addr = *(unsigned int *)PyString_AsString(PyDict_GetItemString(plugin_dict, "repldst_ip"));
			info->repldst_addr.in.s_addr = *(unsigned int *)PyString_AsString(PyDict_GetItemString(plugin_dict, "repldst_mask")); 
		}
		info->invert_flags = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "invflags"));
		strcpy(match_entry->u.user.name, keystr);
		match_entry->u.match_size = sizeof(struct xt_conntrack_mtinfo3);
		base += sizeof(struct xt_conntrack_mtinfo3);
	} else if (strcmp(keystr, "limit")) {
		/* limit plugin */
		struct xt_rateinfo *r = base;
		r->avg = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "avg"));
		r->burst = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "burst"));
		strcpy(match_entry->u.user.name, keystr);
		match_entry->u.match_size = sizeof(struct xt_rateinfo);
		base += sizeof(struct xt_rateinfo);
	} else if (strcmp(keystr, "icmp")) {
		/* icmp plugin */
		struct ipt_icmp *icmpinfo = base;
		icmpinfo->type = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "type"));
		icmpinfo->code[0] = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "min"));
		icmpinfo->code[1] = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "max"));
		icmpinfo->invflags = PyInt_AsLong(PyDict_GetItemString(plugin_dict, "invflags"));
		strcpy(match_entry->u.user.name, keystr);
		match_entry->u.match_size = sizeof(struct ipt_icmp);
		base += sizeof(struct ipt_icmp);
	}
	return 1;
}

static int
compile_rule(PyObject *rule_dict, struct ipt_entry *this_entry, unsigned int *current_offset)
{ 
	struct xt_entry_match *match_entry_base = NULL;
	/*convert entry, match, target plugins */
	this_entry->ip.src.s_addr = PyInt_AsLong(PyDict_GetItemString(rule_dict, "srcip"));
	this_entry->ip.dst.s_addr = PyInt_AsLong(PyDict_GetItemString(rule_dict, "dstip"));
	this_entry->ip.smsk.s_addr = PyInt_AsLong(PyDict_GetItemString(rule_dict, "srcip_mask"));
	this_entry->ip.dmsk.s_addr = PyInt_AsLong(PyDict_GetItemString(rule_dict, "dstip_mask"));
	/*bug char * , unsgined char */
	strcpy(this_entry->ip.iniface, PyString_AsString(PyDict_GetItemString(rule_dict, "iniface")));
	strcpy(this_entry->ip.outiface,  PyString_AsString(PyDict_GetItemString(rule_dict, "outiface")));
	PyObject *iniface_mask = PyDict_GetItemString(rule_dict, "iniface_mask");
	memcpy(this_entry->ip.iniface_mask, PyByteArray_AsString(iniface_mask), PyByteArray_Size(iniface_mask));
	PyObject *outiface_mask = PyDict_GetItemString(rule_dict, "outiface_mask");
	memcpy(this_entry->ip.outiface_mask,  PyByteArray_AsString(outiface_mask), PyByteArray_Size(outiface_mask)); 
	this_entry->ip.proto = PyInt_AsLong(PyDict_GetItemString(rule_dict, "protocol"));	
	this_entry->ip.flags = PyInt_AsLong(PyDict_GetItemString(rule_dict, "flags"));
	this_entry->ip.invflags = PyInt_AsLong(PyDict_GetItemString(rule_dict, "invflags"));
	this_entry->counters.pcnt = PyInt_AsLong(PyDict_GetItemString(rule_dict, "packets"));
	this_entry->counters.bcnt = PyInt_AsLong(PyDict_GetItemString(rule_dict, "bytes"));
	this_entry->nfcache = PyInt_AsLong(PyDict_GetItemString(rule_dict, "bytes"));	
	/*iter over matches */
	match_entry_base = (void *)this_entry + sizeof(struct ipt_entry);
	PyObject *matches_dict = PyDict_GetItemString(rule_dict, "matches");
	PyObject *matches_dict_iter = PyObject_GetIter(PyDict_Items(matches_dict));

	int ret;
	PyObject *matches_dict_next = PyIter_Next(matches_dict_iter);
	while (matches_dict_next) {
		ret = compile_match(match_entry_base, matches_dict_next);
		Py_XDECREF(matches_dict_next);
		if (!ret) {
			Py_XDECREF(matches_dict_iter);	
			goto CLEAR;
		}
		matches_dict_next = PyIter_Next(matches_dict_iter); 
	}
	return 1;
CLEAR:
	return 0; 
}

static int 
compile_chain(struct replace_context *context, PyObject *chain_name,  PyObject *rule_list)
{
{'fraction_non_alphanumeric': 0.13730590368093323, 'fraction_numerical': 0.004046136465148052, 'mean_word_length': 4.921281891723709, 'pattern_counts': {'":': 0, '<': 69, '<?xml version=': 0, '>': 347, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7501015', 'n_tokens_mistral': 15587, 'n_tokens_neox': 14537, 'n_words': 2289}