diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c
index 4ca63e939066..1a87585c533f 100644
--- a/extensions/libebt_ip.c
+++ b/extensions/libebt_ip.c
@@ -291,6 +291,133 @@ static void brip_print(const void *ip, const struct xt_entry_match *match,
 	}
 }
 
+static const char *brip_xlate_proto_to_name(uint8_t proto)
+{
+	switch (proto) {
+	case IPPROTO_TCP:
+		return "tcp";
+	case IPPROTO_UDP:
+		return "udp";
+	case IPPROTO_UDPLITE:
+		return "udplite";
+	case IPPROTO_SCTP:
+		return "sctp";
+	case IPPROTO_DCCP:
+		return "dccp";
+	default:
+		return NULL;
+	}
+}
+
+static void brip_xlate_th(struct xt_xlate *xl,
+			  const struct ebt_ip_info *info, int bit,
+			  const char *pname)
+{
+	const uint16_t *ports;
+
+	if ((info->bitmask & bit) == 0)
+		return;
+
+	switch (bit) {
+	case EBT_IP_SPORT:
+		if (pname)
+			xt_xlate_add(xl, "%s sport ", pname);
+		else
+			xt_xlate_add(xl, "@th,0,16 ");
+
+		ports = info->sport;
+		break;
+	case EBT_IP_DPORT:
+		if (pname)
+			xt_xlate_add(xl, "%s dport ", pname);
+		else
+			xt_xlate_add(xl, "@th,16,16 ");
+
+		ports = info->dport;
+		break;
+	default:
+		return;
+	}
+
+	if (info->invflags & bit)
+		xt_xlate_add(xl, "!= ");
+
+	if (ports[0] == ports[1])
+		xt_xlate_add(xl, "%d ", ports[0]);
+	else
+		xt_xlate_add(xl, "%d-%d ", ports[0], ports[1]);
+}
+
+static void brip_xlate_nh(struct xt_xlate *xl,
+			  const struct ebt_ip_info *info, int bit)
+{
+	struct in_addr *addrp, *maskp;
+
+	if ((info->bitmask & bit) == 0)
+		return;
+
+	switch (bit) {
+	case EBT_IP_SOURCE:
+		xt_xlate_add(xl, "ip saddr ");
+		addrp = (struct in_addr *)&info->saddr;
+		maskp = (struct in_addr *)&info->smsk;
+		break;
+	case EBT_IP_DEST:
+		xt_xlate_add(xl, "ip daddr ");
+		addrp = (struct in_addr *)&info->daddr;
+		maskp = (struct in_addr *)&info->dmsk;
+		break;
+	default:
+		return;
+	}
+
+	if (info->invflags & bit)
+		xt_xlate_add(xl, "!= ");
+
+	xt_xlate_add(xl, "%s%s ", xtables_ipaddr_to_numeric(addrp),
+				  xtables_ipmask_to_numeric(maskp));
+}
+
+static int brip_xlate(struct xt_xlate *xl,
+		      const struct xt_xlate_mt_params *params)
+{
+	const struct ebt_ip_info *info = (const void *)params->match->data;
+	const char *pname = NULL;
+
+	brip_xlate_nh(xl, info, EBT_IP_SOURCE);
+	brip_xlate_nh(xl, info, EBT_IP_DEST);
+
+	if (info->bitmask & EBT_IP_TOS) {
+		xt_xlate_add(xl, "ip dscp ");
+		if (info->invflags & EBT_IP_TOS)
+			xt_xlate_add(xl, "!= ");
+		xt_xlate_add(xl, "0x%02X ", info->tos & ~0x3); /* remove ECN bits */
+	}
+	if (info->bitmask & EBT_IP_PROTO) {
+		struct protoent *pe;
+
+		if (info->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT) &&
+		    (info->invflags & EBT_IP_PROTO) == 0) {
+			/* port number given and not inverted, no need to print this */
+			pname = brip_xlate_proto_to_name(info->protocol);
+		} else {
+			xt_xlate_add(xl, "ip protocol ");
+			if (info->invflags & EBT_IP_PROTO)
+				xt_xlate_add(xl, "!= ");
+			pe = getprotobynumber(info->protocol);
+			if (pe == NULL)
+				xt_xlate_add(xl, "%d ", info->protocol);
+			else
+				xt_xlate_add(xl, "%s ", pe->p_name);
+		}
+	}
+
+	brip_xlate_th(xl, info, EBT_IP_SPORT, pname);
+	brip_xlate_th(xl, info, EBT_IP_DPORT, pname);
+
+	return 1;
+}
+
 static struct xtables_match brip_match = {
 	.name		= "ip",
 	.revision	= 0,
@@ -303,6 +430,7 @@ static struct xtables_match brip_match = {
 	.parse		= brip_parse,
 	.final_check	= brip_final_check,
 	.print		= brip_print,
+	.xlate		= brip_xlate,
 	.extra_opts	= brip_opts,
 };
 
diff --git a/extensions/libebt_limit.c b/extensions/libebt_limit.c
index 988f678a5169..75c066bf694c 100644
--- a/extensions/libebt_limit.c
+++ b/extensions/libebt_limit.c
@@ -159,6 +159,31 @@ static void brlimit_print(const void *ip, const struct xt_entry_match *match,
 	printf("--limit-burst %u ", r->burst);
 }
 
+static void print_rate_xlate(struct xt_xlate *xl, uint32_t period)
+{
+	unsigned int i;
+
+	for (i = 1; i < sizeof(g_rates)/sizeof(struct rates); i++)
+		if (period > g_rates[i].mult ||
+		    g_rates[i].mult/period < g_rates[i].mult%period)
+			break;
+
+	xt_xlate_add(xl, "%u/%s ", g_rates[i-1].mult / period, g_rates[i-1].name);
+}
+
+static int brlimit_xlate(struct xt_xlate *xl,
+			 const struct xt_xlate_mt_params *params)
+{
+	const struct ebt_limit_info *r = (const void *)params->match->data;
+
+	xt_xlate_add(xl, "limit rate ");
+	print_rate_xlate(xl, r->avg);
+	if (r->burst != 0)
+		xt_xlate_add(xl, " burst %u packets", r->burst);
+
+	return 1;
+}
+
 static struct xtables_match brlimit_match = {
 	.name		= "limit",
 	.revision	= 0,
@@ -170,6 +195,7 @@ static struct xtables_match brlimit_match = {
 	.help		= brlimit_print_help,
 	.parse		= brlimit_parse,
 	.print		= brlimit_print,
+	.xlate		= brlimit_xlate,
 	.extra_opts	= brlimit_opts,
 };
 
diff --git a/extensions/libebt_log.c b/extensions/libebt_log.c
index f170af0334ee..a86bdebaaae0 100644
--- a/extensions/libebt_log.c
+++ b/extensions/libebt_log.c
@@ -176,6 +176,27 @@ static void brlog_print(const void *ip, const struct xt_entry_target *target,
 	printf(" ");
 }
 
+static int brlog_xlate(struct xt_xlate *xl,
+		       const struct xt_xlate_tg_params *params)
+{
+	const struct ebt_log_info *loginfo = (const void *)params->target->data;
+
+	xt_xlate_add(xl, "log");
+	if (loginfo->prefix[0]) {
+		if (params->escape_quotes)
+			xt_xlate_add(xl, " prefix \\\"%s\\\"", loginfo->prefix);
+		else
+			xt_xlate_add(xl, " prefix \"%s\"", loginfo->prefix);
+	}
+
+	if (loginfo->loglevel != LOG_DEFAULT_LEVEL)
+		xt_xlate_add(xl, " level %s", eight_priority[loginfo->loglevel].c_name);
+
+	xt_xlate_add(xl, " flags ether ");
+
+	return 1;
+}
+
 static struct xtables_target brlog_target = {
 	.name		= "log",
 	.revision	= 0,
@@ -188,6 +209,7 @@ static struct xtables_target brlog_target = {
 	.parse		= brlog_parse,
 	.final_check	= brlog_final_check,
 	.print		= brlog_print,
+	.xlate		= brlog_xlate,
 	.extra_opts	= brlog_opts,
 };
 
diff --git a/extensions/libebt_mark.c b/extensions/libebt_mark.c
index 7b80b22e63c0..94f489e37e01 100644
--- a/extensions/libebt_mark.c
+++ b/extensions/libebt_mark.c
@@ -170,6 +170,49 @@ static void brmark_final_check(unsigned int flags)
 			      "You must specify some option");
 }
 
+static const char* brmark_verdict(int verdict)
+{
+	switch (verdict) {
+	case EBT_ACCEPT: return "accept";
+	case EBT_DROP: return "drop";
+	case EBT_CONTINUE: return "continue";
+	case EBT_RETURN: return "return";
+	}
+
+	return "";
+}
+
+static int brmark_xlate(struct xt_xlate *xl,
+			const struct xt_xlate_tg_params *params)
+{
+	const struct ebt_mark_t_info *info = (const void*)params->target->data;
+	int tmp;
+
+	tmp = info->target & ~EBT_VERDICT_BITS;
+
+	xt_xlate_add(xl, "meta mark set ");
+
+	switch (tmp) {
+	case MARK_SET_VALUE:
+		break;
+	case MARK_OR_VALUE:
+		xt_xlate_add(xl, "meta mark or ");
+		break;
+	case MARK_XOR_VALUE:
+		xt_xlate_add(xl, "meta mark xor ");
+		break;
+	case MARK_AND_VALUE:
+		xt_xlate_add(xl, "meta mark and ");
+		break;
+	default:
+		return 0;
+	}
+
+	tmp = info->target & EBT_VERDICT_BITS;
+	xt_xlate_add(xl, "0x%lx %s ", info->mark, brmark_verdict(tmp));
+	return 1;
+}
+
 static struct xtables_target brmark_target = {
 	.name		= "mark",
 	.revision	= 0,
@@ -182,6 +225,7 @@ static struct xtables_target brmark_target = {
 	.parse		= brmark_parse,
 	.final_check	= brmark_final_check,
 	.print		= brmark_print,
+	.xlate		= brmark_xlate,
 	.extra_opts	= brmark_opts,
 };
 
diff --git a/extensions/libebt_mark_m.c b/extensions/libebt_mark_m.c
index eb08dbabbb46..1e8d21db5e2e 100644
--- a/extensions/libebt_mark_m.c
+++ b/extensions/libebt_mark_m.c
@@ -97,6 +97,30 @@ static void brmark_m_print(const void *ip, const struct xt_entry_match *match,
 		printf("0x%lx ", info->mark);
 }
 
+static int brmark_m_xlate(struct xt_xlate *xl,
+			  const struct xt_xlate_mt_params *params)
+{
+	const struct ebt_mark_m_info *info = (const void*)params->match->data;
+	enum xt_op op = XT_OP_EQ;
+
+	if (info->invert)
+		op = XT_OP_NEQ;
+
+	xt_xlate_add(xl, "meta mark ");
+
+	if (info->bitmask == EBT_MARK_OR) {
+		xt_xlate_add(xl, " and %0x%x %s0", info->mask,
+			     info->invert ? "" : "!= ");
+	} else if (info->mask != 0xffffffffU) {
+		xt_xlate_add(xl, " and 0x%x %s 0x%x", info->mask,
+			   op == XT_OP_EQ ? "==" : "!=", info->mark);
+	} else {
+		xt_xlate_add(xl, " %s0x%x",
+			   op == XT_OP_EQ ? "" : "!= ", info->mark);
+	}
+
+	return 1;
+}
 static struct xtables_match brmark_m_match = {
 	.name		= "mark_m",
 	.revision	= 0,
@@ -109,6 +133,7 @@ static struct xtables_match brmark_m_match = {
 	.parse		= brmark_m_parse,
 	.final_check	= brmark_m_final_check,
 	.print		= brmark_m_print,
+	.xlate		= brmark_m_xlate,
 	.extra_opts	= brmark_m_opts,
 };
 
diff --git a/extensions/libebt_nflog.c b/extensions/libebt_nflog.c
index 5f1d13b1251a..57f092919cf9 100644
--- a/extensions/libebt_nflog.c
+++ b/extensions/libebt_nflog.c
@@ -124,6 +124,30 @@ brnflog_print(const void *ip, const struct xt_entry_target *target,
 		printf("--nflog-threshold %d ", info->threshold);
 }
 
+static int brnflog_xlate(struct xt_xlate *xl,
+			 const struct xt_xlate_tg_params *params)
+{
+	const struct ebt_nflog_info *info = (void *)params->target->data;
+
+	xt_xlate_add(xl, "log ");
+	if (info->prefix[0] != '\0') {
+		if (params->escape_quotes)
+			xt_xlate_add(xl, "prefix \\\"%s\\\" ", info->prefix);
+		else
+			xt_xlate_add(xl, "prefix \"%s\" ", info->prefix);
+
+	}
+
+	xt_xlate_add(xl, "group %u ", info->group);
+
+	if (info->len)
+		xt_xlate_add(xl, "snaplen %u ", info->len);
+	if (info->threshold != EBT_NFLOG_DEFAULT_THRESHOLD)
+		xt_xlate_add(xl, "queue-threshold %u ", info->threshold);
+
+	return 1;
+}
+
 static struct xtables_target brnflog_watcher = {
 	.name		= "nflog",
 	.revision	= 0,
@@ -135,6 +159,7 @@ static struct xtables_target brnflog_watcher = {
 	.help		= brnflog_help,
 	.parse		= brnflog_parse,
 	.print		= brnflog_print,
+	.xlate		= brnflog_xlate,
 	.extra_opts	= brnflog_opts,
 };
 
