diff mbox

[04/05] IPtablestng/UserSpace - patch user commands

Message ID 20081027052708.48E96C64095@host1.ystp.ac.ir
State Rejected, archived
Headers show

Commit Message

hamid jafarian Oct. 27, 2008, 5:27 a.m. UTC
patching iptables.c/iptables-save.c/iptables-restore.c/iptables.8.in to care of classifier

this patch add the '-C' command to change the classifier of the chains and also he changes the manner that iptables.c defines 'chains' as targets. he uses from a new target named 'chain' to send the name of the chain that is used as a target. by this all of the chains can be used as target.
Output format of the 'iptables-save' cammand is changed to display the chain classifier. he like this:
*filter
:INPUT ACCEPT tuple [0:0]
:FORWARD ACCEPT linear [0:0]
:OUTPUT ACCEPT linear [0:0]
the last name is the name of the classifier. also aome changes in iptables-restore to be aware about the name of the classifier.
also by this patch users can use "CONTINUE & RETURN" as target.


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/iptables.c b/iptables.c
index cff8cf4..d2df3a9 100644
--- a/iptables.c
+++ b/iptables.c
@@ -76,9 +76,10 @@ 
 #define CMD_SET_POLICY		0x0400U
 #define CMD_RENAME_CHAIN	0x0800U
 #define CMD_LIST_RULES		0x1000U
-#define NUMBER_OF_CMD	14
+#define CMD_CHG_CLASSIFIER	0x2000U
+#define NUMBER_OF_CMD	15
 static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z',
-				 'N', 'X', 'P', 'E', 'S' };
+				 'N', 'X', 'P', 'E', 'S', 'C' };
 
 #define OPTION_OFFSET 256
 
@@ -112,6 +113,7 @@  static struct option original_opts[] = {
 	{.name = "delete-chain",  .has_arg = 2, .val = 'X'},
 	{.name = "rename-chain",  .has_arg = 1, .val = 'E'},
 	{.name = "policy",        .has_arg = 1, .val = 'P'},
+	{.name = "classifier",	  .has_arg = 1, .val = 'C'},
 	{.name = "source",        .has_arg = 1, .val = 's'},
 	{.name = "destination",   .has_arg = 1, .val = 'd'},
 	{.name = "src",           .has_arg = 1, .val = 's'}, /* synonym */
@@ -169,7 +171,8 @@  static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
 /*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
 /*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x','x',' '},
 /*RENAME*/    {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'}
+/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
+/*CLASSIFIER*/{'x','x','x','x','x',' ','x','x','x','x','x','x'}
 };
 
 static int inverse_for_options[NUMBER_OF_OPT] =
@@ -317,6 +320,9 @@  exit_printhelp(struct iptables_rule_match *matches)
 "            -X [chain]		Delete a user-defined chain\n"
 "  --policy  -P chain target\n"
 "				Change policy on chain to target\n"
+"  --classifier \n"
+"	     -C chain classifier\n"
+"				Change chain classifeir\n"
 "  --rename-chain\n"
 "            -E old-chain new-chain\n"
 "				Change chain name, (moving any references)\n"
@@ -650,24 +656,28 @@  print_header(unsigned int format, const char *chain, iptc_handle_t *handle)
 {
 	struct ipt_counters counters;
 	const char *pol = iptc_get_policy(chain, &counters, handle);
+	unsigned int refs;
+	char *classifier;
 	printf("Chain %s", chain);
-	if (pol) {
-		printf(" (policy %s", pol);
-		if (!(format & FMT_NOCOUNTS)) {
-			fputc(' ', stdout);
-			print_num(counters.pcnt, (format|FMT_NOTABLE));
-			fputs("packets, ", stdout);
-			print_num(counters.bcnt, (format|FMT_NOTABLE));
-			fputs("bytes", stdout);
-		}
-		printf(")\n");
-	} else {
-		unsigned int refs;
-		if (!iptc_get_references(&refs, chain, handle))
-			printf(" (ERROR obtaining refs)\n");
-		else
-			printf(" (%u references)\n", refs);
+		
+	printf(" (policy %s", pol);
+	if (!(format & FMT_NOCOUNTS)) {
+		fputc(' ', stdout);
+		print_num(counters.pcnt, (format|FMT_NOTABLE));
+		fputs("packets, ", stdout);
+		print_num(counters.bcnt, (format|FMT_NOTABLE));
+		fputs("bytes", stdout);
 	}
+	printf(")\n");
+		
+	if (!iptc_get_references(&refs, chain, handle))
+		printf(" (ERROR obtaining refs)\n");
+	else
+		printf(" (%u references)\n", refs);
+
+	classifier = iptc_get_classifier(chain, handle);
+	if(classifier) printf(" (classifier %s)\n", classifier);
+	else printf(" (can't optain classifier) \n");
 
 	if (format & FMT_LINENUMBERS)
 		printf(FMT("%-4s ", "%s "), "num");
@@ -717,7 +727,7 @@  print_match(const struct ipt_entry_match *m,
 
 /* e is called `fw' here for historical reasons */
 static void
-print_firewall(const struct ipt_entry *fw,
+print_firewall(const struct pktt_entry *fw,
 	       const char *targname,
 	       unsigned int num,
 	       unsigned int format,
@@ -731,10 +741,10 @@  print_firewall(const struct ipt_entry *fw,
 	if (!iptc_is_chain(targname, handle))
 		target = find_target(targname, TRY_LOAD);
 	else
-		target = find_target(IPT_STANDARD_TARGET, LOAD_MUST_SUCCEED);
+		target = find_target("chain", LOAD_MUST_SUCCEED);
 
 	t = ipt_get_target((struct ipt_entry *)fw);
-	flags = fw->ip.flags;
+	flags = fw->pkt_header.ip4.flags;
 
 	if (format & FMT_LINENUMBERS)
 		printf(FMT("%-4u ", "%u "), num+1);
@@ -747,19 +757,19 @@  print_firewall(const struct ipt_entry *fw,
 	if (!(format & FMT_NOTARGET))
 		printf(FMT("%-9s ", "%s "), targname);
 
-	fputc(fw->ip.invflags & IPT_INV_PROTO ? '!' : ' ', stdout);
+	fputc(fw->pkt_header.ip4.invflags & IPT_INV_PROTO ? '!' : ' ', stdout);
 	{
-		char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC);
+		char *pname = proto_to_name(fw->pkt_header.ip4.proto, format&FMT_NUMERIC);
 		if (pname)
 			printf(FMT("%-5s", "%s "), pname);
 		else
-			printf(FMT("%-5hu", "%hu "), fw->ip.proto);
+			printf(FMT("%-5hu", "%hu "), fw->pkt_header.ip4.proto);
 	}
 
 	if (format & FMT_OPTIONS) {
 		if (format & FMT_NOTABLE)
 			fputs("opt ", stdout);
-		fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout);
+		fputc(fw->pkt_header.ip4.invflags & IPT_INV_FRAG ? '!' : '-', stdout);
 		fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
 		fputc(' ', stdout);
 	}
@@ -767,54 +777,54 @@  print_firewall(const struct ipt_entry *fw,
 	if (format & FMT_VIA) {
 		char iface[IFNAMSIZ+2];
 
-		if (fw->ip.invflags & IPT_INV_VIA_IN) {
+		if (fw->pkt_header.ip4.invflags & IPT_INV_VIA_IN) {
 			iface[0] = '!';
 			iface[1] = '\0';
 		}
 		else iface[0] = '\0';
 
-		if (fw->ip.iniface[0] != '\0') {
-			strcat(iface, fw->ip.iniface);
+		if (fw->pkt_header.ip4.iniface[0] != '\0') {
+			strcat(iface, fw->pkt_header.ip4.iniface);
 		}
 		else if (format & FMT_NUMERIC) strcat(iface, "*");
 		else strcat(iface, "any");
 		printf(FMT(" %-6s ","in %s "), iface);
 
-		if (fw->ip.invflags & IPT_INV_VIA_OUT) {
+		if (fw->pkt_header.ip4.invflags & IPT_INV_VIA_OUT) {
 			iface[0] = '!';
 			iface[1] = '\0';
 		}
 		else iface[0] = '\0';
 
-		if (fw->ip.outiface[0] != '\0') {
-			strcat(iface, fw->ip.outiface);
+		if (fw->pkt_header.ip4.outiface[0] != '\0') {
+			strcat(iface, fw->pkt_header.ip4.outiface);
 		}
 		else if (format & FMT_NUMERIC) strcat(iface, "*");
 		else strcat(iface, "any");
 		printf(FMT("%-6s ","out %s "), iface);
 	}
 
-	fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
-	if (fw->ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC))
+	fputc(fw->pkt_header.ip4.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
+	if (fw->pkt_header.ip4.smsk.s_addr == 0L && !(format & FMT_NUMERIC))
 		printf(FMT("%-19s ","%s "), "anywhere");
 	else {
 		if (format & FMT_NUMERIC)
-			sprintf(buf, "%s", ipaddr_to_numeric(&fw->ip.src));
+			sprintf(buf, "%s", ipaddr_to_numeric(&fw->pkt_header.ip4.src));
 		else
-			sprintf(buf, "%s", ipaddr_to_anyname(&fw->ip.src));
-		strcat(buf, ipmask_to_numeric(&fw->ip.smsk));
+			sprintf(buf, "%s", ipaddr_to_anyname(&fw->pkt_header.ip4.src));
+		strcat(buf, ipmask_to_numeric(&fw->pkt_header.ip4.smsk));
 		printf(FMT("%-19s ","%s "), buf);
 	}
 
-	fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
-	if (fw->ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC))
+	fputc(fw->pkt_header.ip4.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
+	if (fw->pkt_header.ip4.dmsk.s_addr == 0L && !(format & FMT_NUMERIC))
 		printf(FMT("%-19s ","-> %s"), "anywhere");
 	else {
 		if (format & FMT_NUMERIC)
-			sprintf(buf, "%s", ipaddr_to_numeric(&fw->ip.dst));
+			sprintf(buf, "%s", ipaddr_to_numeric(&fw->pkt_header.ip4.dst));
 		else
-			sprintf(buf, "%s", ipaddr_to_anyname(&fw->ip.dst));
-		strcat(buf, ipmask_to_numeric(&fw->ip.dmsk));
+			sprintf(buf, "%s", ipaddr_to_anyname(&fw->pkt_header.ip4.dst));
+		strcat(buf, ipmask_to_numeric(&fw->pkt_header.ip4.dmsk));
 		printf(FMT("%-19s ","-> %s"), buf);
 	}
 
@@ -822,16 +832,16 @@  print_firewall(const struct ipt_entry *fw,
 		fputs("  ", stdout);
 
 #ifdef IPT_F_GOTO
-	if(fw->ip.flags & IPT_F_GOTO)
+	if(fw->pkt_header.ip4.flags & IPT_F_GOTO)
 		printf("[goto] ");
 #endif
 
-	IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC);
+	IPT_MATCH_ITERATE(fw, print_match, &fw->pkt_header.ip4, format & FMT_NUMERIC);
 
 	if (target) {
 		if (target->print)
 			/* Print the target information. */
-			target->print(&fw->ip, t, format & FMT_NUMERIC);
+			target->print(&fw->pkt_header.ip4, t, format & FMT_NUMERIC);
 	} else if (t->u.target_size != sizeof(*t))
 		printf("[%u bytes of unknown target data] ",
 		       (unsigned int)(t->u.target_size - sizeof(*t)));
@@ -864,9 +874,9 @@  append_entry(const ipt_chainlabel chain,
 	int ret = 1;
 
 	for (i = 0; i < nsaddrs; i++) {
-		fw->ip.src.s_addr = saddrs[i].s_addr;
+		fw->pkt_header.ip4.src.s_addr = saddrs[i].s_addr;
 		for (j = 0; j < ndaddrs; j++) {
-			fw->ip.dst.s_addr = daddrs[j].s_addr;
+			fw->pkt_header.ip4.dst.s_addr = daddrs[j].s_addr;
 			if (verbose)
 				print_firewall_line(fw, *handle);
 			ret &= iptc_append_entry(chain, fw, handle);
@@ -885,8 +895,8 @@  replace_entry(const ipt_chainlabel chain,
 	      int verbose,
 	      iptc_handle_t *handle)
 {
-	fw->ip.src.s_addr = saddr->s_addr;
-	fw->ip.dst.s_addr = daddr->s_addr;
+	fw->pkt_header.ip4.src.s_addr = saddr->s_addr;
+	fw->pkt_header.ip4.dst.s_addr = daddr->s_addr;
 
 	if (verbose)
 		print_firewall_line(fw, *handle);
@@ -908,9 +918,9 @@  insert_entry(const ipt_chainlabel chain,
 	int ret = 1;
 
 	for (i = 0; i < nsaddrs; i++) {
-		fw->ip.src.s_addr = saddrs[i].s_addr;
+		fw->pkt_header.ip4.src.s_addr = saddrs[i].s_addr;
 		for (j = 0; j < ndaddrs; j++) {
-			fw->ip.dst.s_addr = daddrs[j].s_addr;
+			fw->pkt_header.ip4.dst.s_addr = daddrs[j].s_addr;
 			if (verbose)
 				print_firewall_line(fw, *handle);
 			ret &= iptc_insert_entry(chain, fw, rulenum, handle);
@@ -970,9 +980,9 @@  delete_entry(const ipt_chainlabel chain,
 
 	mask = make_delete_mask(fw, matches);
 	for (i = 0; i < nsaddrs; i++) {
-		fw->ip.src.s_addr = saddrs[i].s_addr;
+		fw->pkt_header.ip4.src.s_addr = saddrs[i].s_addr;
 		for (j = 0; j < ndaddrs; j++) {
-			fw->ip.dst.s_addr = daddrs[j].s_addr;
+			fw->pkt_header.ip4.dst.s_addr = daddrs[j].s_addr;
 			if (verbose)
 				print_firewall_line(fw, *handle);
 			ret &= iptc_delete_entry(chain, fw, mask, handle);
@@ -1224,7 +1234,7 @@  static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
 
 /* We want this to be readable, so only print out neccessary fields.
  * Because that's the kind of world I want to live in.  */
-void print_rule(const struct ipt_entry *e,
+void print_rule(const struct pktt_entry *e,
 		iptc_handle_t *h, const char *chain, int counters)
 {
 	struct ipt_entry_target *t;
@@ -1238,27 +1248,27 @@  void print_rule(const struct ipt_entry *e,
 	printf("-A %s ", chain);
 
 	/* Print IP part. */
-	print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
-			e->ip.invflags & IPT_INV_SRCIP);
+	print_ip("-s", e->pkt_header.ip4.src.s_addr,e->pkt_header.ip4.smsk.s_addr,
+			e->pkt_header.ip4.invflags & IPT_INV_SRCIP);
 
-	print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
-			e->ip.invflags & IPT_INV_DSTIP);
+	print_ip("-d", e->pkt_header.ip4.dst.s_addr, e->pkt_header.ip4.dmsk.s_addr,
+			e->pkt_header.ip4.invflags & IPT_INV_DSTIP);
 
-	print_iface('i', e->ip.iniface, e->ip.iniface_mask,
-		    e->ip.invflags & IPT_INV_VIA_IN);
+	print_iface('i', e->pkt_header.ip4.iniface, e->pkt_header.ip4.iniface_mask,
+		    e->pkt_header.ip4.invflags & IPT_INV_VIA_IN);
 
-	print_iface('o', e->ip.outiface, e->ip.outiface_mask,
-		    e->ip.invflags & IPT_INV_VIA_OUT);
+	print_iface('o', e->pkt_header.ip4.outiface, e->pkt_header.ip4.outiface_mask,
+		    e->pkt_header.ip4.invflags & IPT_INV_VIA_OUT);
 
-	print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
+	print_proto(e->pkt_header.ip4.proto, e->pkt_header.ip4.invflags & IPT_INV_PROTO);
 
-	if (e->ip.flags & IPT_F_FRAG)
+	if (e->pkt_header.ip4.flags & IPT_F_FRAG)
 		printf("%s-f ",
-		       e->ip.invflags & IPT_INV_FRAG ? "! " : "");
+		       e->pkt_header.ip4.invflags & IPT_INV_FRAG ? "! " : "");
 
 	/* Print matchinfo part */
 	if (e->target_offset) {
-		IPT_MATCH_ITERATE(e, print_match_save, &e->ip);
+		IPT_MATCH_ITERATE(e, print_match_save, &e->pkt_header.ip4);
 	}
 
 	/* print counters for iptables -R */
@@ -1269,7 +1279,7 @@  void print_rule(const struct ipt_entry *e,
 	target_name = iptc_get_target(e, h);
 	if (target_name && (*target_name != '\0'))
 #ifdef IPT_F_GOTO
-		printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
+		printf("-%c %s ", e->pkt_header.ip4.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
 #else
 		printf("-j %s ", target_name);
 #endif
@@ -1280,6 +1290,9 @@  void print_rule(const struct ipt_entry *e,
 		struct xtables_target *target
 			= find_target(t->u.user.name, TRY_LOAD);
 
+		if(!target && iptc_is_chain(t->u.user.name, *h))
+			target = find_target("chain", LOAD_MUST_SUCCEED);
+
 		if (!target) {
 			fprintf(stderr, "Can't find library for target `%s'\n",
 				t->u.user.name);
@@ -1287,7 +1300,7 @@  void print_rule(const struct ipt_entry *e,
 		}
 
 		if (target->save)
-			target->save(&e->ip, t);
+			target->save(&e->pkt_header.ip4, t);
 		else {
 			/* If the target size is greater than ipt_entry_target
 			 * there is something to be saved, we just don't know
@@ -1372,9 +1385,10 @@  generate_entry(const struct ipt_entry *fw,
 
 	e = fw_malloc(size + target->u.target_size);
 	*e = *fw;
-	e->target_offset = size;
-	e->next_offset = size + target->u.target_size;
-
+	//e->target_offset = size;
+	//e->next_offset = size + target->u.target_size;
+	e->size = size + target->u.target_size;
+	e->target_offset = size - sizeof(struct ipt_entry);
 	size = 0;
 	for (matchp = matches; matchp; matchp = matchp->next) {
 		memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size);
@@ -1439,7 +1453,7 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 	int c, verbose = 0;
 	const char *chain = NULL;
 	const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
-	const char *policy = NULL, *newname = NULL;
+	const char *policy = NULL, *newname = NULL, *classifier = NULL;
 	unsigned int rulenum = 0, options = 0, command = 0;
 	const char *pcnt = NULL, *bcnt = NULL;
 	int ret = 1;
@@ -1474,7 +1488,7 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 	opterr = 0;
 
 	while ((c = getopt_long(argc, argv,
-	   "-A:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
+	   "-A:D:R:I:L::S::M:F::Z::N:X::E:P:C:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
 					   opts, NULL)) != -1) {
 		switch (c) {
 			/*
@@ -1611,7 +1625,18 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 					   "-%c requires a chain and a policy",
 					   cmd2char(CMD_SET_POLICY));
 			break;
-
+		case 'C':
+			add_command(&command, CMD_CHG_CLASSIFIER,
+						CMD_NONE, invert);
+			chain = optarg;
+			if (optind < argc && argv[optind][0] != '-'
+				&& argv[optind][0]!= '!')
+				classifier = argv[optind++];
+			else
+				exit_error(PARAMETER_PROBLEM,
+					"-%c requires a chain and a classifier",
+					cmd2char(CMD_CHG_CLASSIFIER));
+			break;
 		case 'h':
 			if (!optarg)
 				optarg = argv[optind];
@@ -1627,7 +1652,7 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 			 */
 		case 'p':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_PROTOCOL, &fw.ip.invflags,
+			set_option(&options, OPT_PROTOCOL, &fw.pkt_header.ip4.invflags,
 				   invert);
 
 			/* Canonicalize into lower case */
@@ -1635,39 +1660,39 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 				*protocol = tolower(*protocol);
 
 			protocol = argv[optind-1];
-			fw.ip.proto = parse_protocol(protocol);
+			fw.pkt_header.ip4.proto = parse_protocol(protocol);
 
-			if (fw.ip.proto == 0
-			    && (fw.ip.invflags & IPT_INV_PROTO))
+			if (fw.pkt_header.ip4.proto == 0
+			    && (fw.pkt_header.ip4.invflags & IPT_INV_PROTO))
 				exit_error(PARAMETER_PROBLEM,
 					   "rule would never match protocol");
 			break;
 
 		case 's':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_SOURCE, &fw.ip.invflags,
+			set_option(&options, OPT_SOURCE, &fw.pkt_header.ip4.invflags,
 				   invert);
 			shostnetworkmask = argv[optind-1];
 			break;
 
 		case 'd':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_DESTINATION, &fw.ip.invflags,
+			set_option(&options, OPT_DESTINATION, &fw.pkt_header.ip4.invflags,
 				   invert);
 			dhostnetworkmask = argv[optind-1];
 			break;
 
 #ifdef IPT_F_GOTO
 		case 'g':
-			set_option(&options, OPT_JUMP, &fw.ip.invflags,
+			set_option(&options, OPT_JUMP, &fw.pkt_header.ip4.invflags,
 				   invert);
-			fw.ip.flags |= IPT_F_GOTO;
+			fw.pkt_header.ip4.flags |= IPT_F_GOTO;
 			jumpto = parse_target(optarg);
 			break;
 #endif
 
 		case 'j':
-			set_option(&options, OPT_JUMP, &fw.ip.invflags,
+			set_option(&options, OPT_JUMP, &fw.pkt_header.ip4.invflags,
 				   invert);
 			jumpto = parse_target(optarg);
 			/* TRY_LOAD (may be chain name) */
@@ -1698,32 +1723,32 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 
 		case 'i':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_VIANAMEIN, &fw.ip.invflags,
+			set_option(&options, OPT_VIANAMEIN, &fw.pkt_header.ip4.invflags,
 				   invert);
 			parse_interface(argv[optind-1],
-					fw.ip.iniface,
-					fw.ip.iniface_mask);
+					fw.pkt_header.ip4.iniface,
+					fw.pkt_header.ip4.iniface_mask);
 			break;
 
 		case 'o':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_VIANAMEOUT, &fw.ip.invflags,
+			set_option(&options, OPT_VIANAMEOUT, &fw.pkt_header.ip4.invflags,
 				   invert);
 			parse_interface(argv[optind-1],
-					fw.ip.outiface,
-					fw.ip.outiface_mask);
+					fw.pkt_header.ip4.outiface,
+					fw.pkt_header.ip4.outiface_mask);
 			break;
 
 		case 'f':
-			set_option(&options, OPT_FRAGMENT, &fw.ip.invflags,
+			set_option(&options, OPT_FRAGMENT, &fw.pkt_header.ip4.invflags,
 				   invert);
-			fw.ip.flags |= IPT_F_FRAG;
+			fw.pkt_header.ip4.flags |= IPT_F_FRAG;
 			break;
 
 		case 'v':
 			if (!verbose)
 				set_option(&options, OPT_VERBOSE,
-					   &fw.ip.invflags, invert);
+					   &fw.pkt_header.ip4.invflags, invert);
 			verbose++;
 			break;
 
@@ -1756,7 +1781,7 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 		break;
 
 		case 'n':
-			set_option(&options, OPT_NUMERIC, &fw.ip.invflags,
+			set_option(&options, OPT_NUMERIC, &fw.pkt_header.ip4.invflags,
 				   invert);
 			break;
 
@@ -1768,7 +1793,7 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 			break;
 
 		case 'x':
-			set_option(&options, OPT_EXPANDED, &fw.ip.invflags,
+			set_option(&options, OPT_EXPANDED, &fw.pkt_header.ip4.invflags,
 				   invert);
 			break;
 
@@ -1781,7 +1806,7 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 			exit(0);
 
 		case '0':
-			set_option(&options, OPT_LINENUMBERS, &fw.ip.invflags,
+			set_option(&options, OPT_LINENUMBERS, &fw.pkt_header.ip4.invflags,
 				   invert);
 			break;
 
@@ -1791,7 +1816,7 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 
 		case 'c':
 
-			set_option(&options, OPT_COUNTERS, &fw.ip.invflags,
+			set_option(&options, OPT_COUNTERS, &fw.pkt_header.ip4.invflags,
 				   invert);
 			pcnt = optarg;
 			bcnt = strchr(pcnt + 1, ',');
@@ -1945,14 +1970,14 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 
 	if (shostnetworkmask)
 		ipparse_hostnetworkmask(shostnetworkmask, &saddrs,
-					&fw.ip.smsk, &nsaddrs);
+					&fw.pkt_header.ip4.smsk, &nsaddrs);
 
 	if (dhostnetworkmask)
 		ipparse_hostnetworkmask(dhostnetworkmask, &daddrs,
-					&fw.ip.dmsk, &ndaddrs);
+					&fw.pkt_header.ip4.dmsk, &ndaddrs);
 
 	if ((nsaddrs > 1 || ndaddrs > 1) &&
-	    (fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
+	    (fw.pkt_header.ip4.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
 		exit_error(PARAMETER_PROBLEM, "! not allowed with multiple"
 			   " source or destination IP addresses");
 
@@ -2022,8 +2047,16 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 			|| iptc_is_chain(jumpto, *handle))) {
 			size_t size;
 
-			target = find_target(IPT_STANDARD_TARGET,
-					     LOAD_MUST_SUCCEED);
+			//target = find_target(IPT_STANDARD_TARGET,
+			//		     LOAD_MUST_SUCCEED);
+
+			/* chain is an specific target */
+			if(iptc_is_chain(jumpto, *handle))
+				target = find_target("chain",
+					LOAD_MUST_SUCCEED);
+			else
+				target = find_target(IPT_STANDARD_TARGET,
+					LOAD_MUST_SUCCEED);
 
 			size = sizeof(struct ipt_entry_target)
 				+ target->size;
@@ -2043,7 +2076,7 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 			 * existant OR if the user just misspelled a
 			 * chain. */
 #ifdef IPT_F_GOTO
-			if (fw.ip.flags & IPT_F_GOTO)
+			if (fw.pkt_header.ip4.flags & IPT_F_GOTO)
 				exit_error(PARAMETER_PROBLEM,
 					   "goto '%s' is not a chain\n", jumpto);
 #endif
@@ -2068,15 +2101,15 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 				   handle, matches);
 		break;
 	case CMD_DELETE_NUM:
-		ret = iptc_delete_num_entry(chain, rulenum - 1, handle);
+		ret = iptc_delete_num_entry(chain, rulenum /*- 1*/, handle);
 		break;
 	case CMD_REPLACE:
-		ret = replace_entry(chain, e, rulenum - 1,
+		ret = replace_entry(chain, e, rulenum /*- 1*/,
 				    saddrs, daddrs, options&OPT_VERBOSE,
 				    handle);
 		break;
 	case CMD_INSERT:
-		ret = insert_entry(chain, e, rulenum - 1,
+		ret = insert_entry(chain, e, rulenum /*- 1*/,
 				   nsaddrs, saddrs, ndaddrs, daddrs,
 				   options&OPT_VERBOSE,
 				   handle);
@@ -2122,6 +2155,9 @@  int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 	case CMD_SET_POLICY:
 		ret = iptc_set_policy(chain, policy, options&OPT_COUNTERS ? &fw.counters : NULL, handle);
 		break;
+	case CMD_CHG_CLASSIFIER:
+		ret = iptc_chg_classifier(chain, classifier, handle);
+		break;
 	default:
 		/* We should never reach this... */
 		exit_tryhelp(2);
diff --git a/iptables-save.c b/iptables-save.c
index ecccac4..031a583 100644
--- a/iptables-save.c
+++ b/iptables-save.c
@@ -82,16 +82,13 @@  static int do_output(const char *tablename)
 		for (chain = iptc_first_chain(&h);
 		     chain;
 		     chain = iptc_next_chain(&h)) {
+			struct ipt_counters count;
 
 			printf(":%s ", chain);
-			if (iptc_builtin(chain, h)) {
-				struct ipt_counters count;
-				printf("%s ",
-				       iptc_get_policy(chain, &count, &h));
-				printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
-			} else {
-				printf("- [0:0]\n");
-			}
+			printf("%s ",
+			       iptc_get_policy(chain, &count, &h));
+			printf("%s ", iptc_get_classifier(chain, &h));
+			printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt);
 		}
 
 
diff --git a/iptables.8.in b/iptables.8.in
index 0b945cb..0a65aa5 100644
--- a/iptables.8.in
+++ b/iptables.8.in
@@ -41,6 +41,8 @@  iptables \- administration tool for IPv4 packet filtering and NAT
 .br
 .BR "iptables [-t table] -P " "chain target [options]"
 .br
+.BR "iptables [-t table] -C " "chain classifeir "
+.br
 .BR "iptables [-t table] -E " "old-chain-name new-chain-name"
 .SH DESCRIPTION
 .B Iptables
@@ -58,10 +60,11 @@  table.
 A firewall rule specifies criteria for a packet and a target.  If the
 packet does not match, the next rule in the chain is the examined; if
 it does match, then the next rule is specified by the value of the
-target, which can be the name of a user-defined chain or one of the
+target, which can be the name of a chain or one of the
 special values 
 .IR ACCEPT ,
 .IR DROP ,
+.IR CONTINUE ,
 .IR QUEUE ,
 or
 .IR RETURN .
@@ -70,6 +73,8 @@  or
 means to let the packet through.
 .I DROP
 means to drop the packet on the floor.
+.I CONTINUE
+meane going to next rule
 .I QUEUE
 means to pass the packet to userspace.  (How the packet can be received
 by a userspace process differs by the particular queue handler.  2.4.x
@@ -234,8 +239,11 @@  non-builtin chain in the table.
 .TP
 .BI "-P, --policy " "chain target"
 Set the policy for the chain to the given target.  See the section
+.BI "-C, --classifier " "chain classifier"
+chaine the chain classifier
+.TP
 .B TARGETS
-for the legal targets.  Only built-in (non-user-defined) chains can have
+for the legal targets. In this version all of the chains can have
 policies, and neither built-in nor user-defined chains can be policy
 targets.
 .TP
diff --git a/iptables-restore.c b/iptables-restore.c
index 4b199d9..94c5d24 100644
--- a/iptables-restore.c
+++ b/iptables-restore.c
@@ -75,7 +75,7 @@  static iptc_handle_t create_handle(const char *tablename, const char *modprobe)
 	return handle;
 }
 
-static int parse_counters(char *string, struct ipt_counters *ctr)
+static int parse_counters(char *string, struct pktt_counters *ctr)
 {
 	unsigned long long pcnt, bcnt;
 	int ret;
@@ -247,7 +247,8 @@  main(int argc, char *argv[])
 
 		} else if ((buffer[0] == ':') && (in_table)) {
 			/* New chain. */
-			char *policy, *chain;
+			char *policy, *chain, *classifier;
+			struct pktt_counters count;
 
 			chain = strtok(buffer+1, " \t\n");
 			DEBUGP("line %u, chain '%s'\n", line, chain);
@@ -285,35 +286,46 @@  main(int argc, char *argv[])
 				exit(1);
 			}
 
-			if (strcmp(policy, "-") != 0) {
-				struct ipt_counters count;
-
-				if (counters) {
-					char *ctrs;
-					ctrs = strtok(NULL, " \t\n");
-
-					if (!ctrs || !parse_counters(ctrs, &count))
-						exit_error(PARAMETER_PROBLEM,
-							   "invalid policy counters "
-							   "for chain '%s'\n", chain);
-
-				} else {
-					memset(&count, 0,
-					       sizeof(struct ipt_counters));
-				}
+			classifier = strtok(NULL, " \t\n");
+			DEBUGP("line %u, classifier '%s'\n", line, classifier);
+			if(!classifier){
+				exit_error(PARAMETER_PROBLEM,
+					"%s: line %u classifier invalid\n",
+					program_name, line);
+				exit(1);
+			}
 
-				DEBUGP("Setting policy of chain %s to %s\n",
-					chain, policy);
+			if (counters) {
+				char *ctrs;
+				ctrs = strtok(NULL, " \t\n");
 
-				if (!iptc_set_policy(chain, policy, &count,
-						     &handle))
-					exit_error(OTHER_PROBLEM,
-						"Can't set policy `%s'"
-						" on `%s' line %u: %s\n",
-						chain, policy, line,
-						iptc_strerror(errno));
+				if (!ctrs || !parse_counters(ctrs, &count))
+					exit_error(PARAMETER_PROBLEM,
+						   "invalid policy counters "
+						   "for chain '%s'\n", chain);
+			} else {
+				memset(&count, 0,
+				       sizeof(struct ipt_counters));
 			}
 
+			DEBUGP("Setting policy of chain %s to %s\n",
+				chain, policy);
+
+			if (!iptc_set_policy(chain, policy, &count,
+					     &handle))
+				exit_error(OTHER_PROBLEM,
+					"Can't set policy `%s'"
+					" on `%s' line %u: %s\n",
+					chain, policy, line,
+					iptc_strerror(errno));
+
+			if(!iptc_chg_classifier(chain, classifier, &handle))
+				exit_error(OTHER_PROBLEM,
+					"Can't change classifier '%s'"
+					"to '%s' line %u: %s\n",
+					chain, classifier, line,
+					iptc_strerror(errno));
+
 			ret = 1;
 
 		} else if (in_table) {
diff --git a/xtables.c b/xtables.c
index 8241687..5aeb755 100644
--- a/xtables.c
+++ b/xtables.c
@@ -440,7 +440,8 @@  struct xtables_target *find_target(const char *name, enum xt_tryload tryload)
 	    || strcmp(name, XTC_LABEL_ACCEPT) == 0
 	    || strcmp(name, XTC_LABEL_DROP) == 0
 	    || strcmp(name, XTC_LABEL_QUEUE) == 0
-	    || strcmp(name, XTC_LABEL_RETURN) == 0)
+	    || strcmp(name, XTC_LABEL_RETURN) == 0
+	    || strcmp(name, XTC_LABEL_CONTINUE) ==0 )
 		name = "standard";
 
 	for (ptr = xtables_targets; ptr; ptr = ptr->next) {
@@ -526,12 +527,14 @@  static int compatible_revision(const char *name, u_int8_t revision, int opt)
 
 static int compatible_match_revision(const char *name, u_int8_t revision)
 {
-	return compatible_revision(name, revision, afinfo.so_rev_match);
+	//return compatible_revision(name, revision, afinfo.so_rev_match);
+	return 1;
 }
 
 static int compatible_target_revision(const char *name, u_int8_t revision)
 {
-	return compatible_revision(name, revision, afinfo.so_rev_target);
+	//return compatible_revision(name, revision, afinfo.so_rev_target);
+	return 1;
 }
 
 void xtables_register_match(struct xtables_match *me)

diff --git a/include/libiptc/libxtc.h b/include/libiptc/libxtc.h
index 031afb5..5487536 100644
--- a/include/libiptc/libxtc.h
+++ b/include/libiptc/libxtc.h
@@ -26,7 +26,7 @@  typedef char xt_chainlabel[32];
 #define XTC_LABEL_DROP    "DROP"
 #define XTC_LABEL_QUEUE   "QUEUE"
 #define XTC_LABEL_RETURN  "RETURN"
-
+#define XTC_LABEL_CONTINUE "CONTINUE"
 
 #ifdef __cplusplus
 }