summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extensions/libct_proto_dccp.c17
-rw-r--r--extensions/libct_proto_gre.c9
-rw-r--r--extensions/libct_proto_icmp.c8
-rw-r--r--extensions/libct_proto_icmpv6.c8
-rw-r--r--extensions/libct_proto_sctp.c12
-rw-r--r--extensions/libct_proto_tcp.c10
-rw-r--r--extensions/libct_proto_udp.c9
-rw-r--r--extensions/libct_proto_udplite.c9
-rw-r--r--include/conntrack.h30
-rw-r--r--src/conntrack.c283
10 files changed, 391 insertions, 4 deletions
diff --git a/extensions/libct_proto_dccp.c b/extensions/libct_proto_dccp.c
index f6258ad..e9da474 100644
--- a/extensions/libct_proto_dccp.c
+++ b/extensions/libct_proto_dccp.c
@@ -198,6 +198,22 @@ static int parse_options(char c,
return 1;
}
+
+static const char *dccp_roles[__DCCP_CONNTRACK_ROLE_MAX] = {
+ [DCCP_CONNTRACK_ROLE_CLIENT] = "client",
+ [DCCP_CONNTRACK_ROLE_SERVER] = "server",
+};
+
+static const struct ct_print_opts dccp_print_opts[] = {
+ { "--sport", ATTR_ORIG_PORT_SRC, CT_ATTR_TYPE_BE16, 0, NULL },
+ { "--dport", ATTR_ORIG_PORT_DST, CT_ATTR_TYPE_BE16, 0, NULL },
+ { "--reply-port-src", ATTR_REPL_PORT_SRC, CT_ATTR_TYPE_BE16, 0, NULL },
+ { "--reply-port-dst", ATTR_REPL_PORT_DST, CT_ATTR_TYPE_BE16, 0, NULL },
+ { "--state", ATTR_DCCP_STATE, CT_ATTR_TYPE_U8, DCCP_CONNTRACK_MAX, dccp_states },
+ { "--role", ATTR_DCCP_ROLE, CT_ATTR_TYPE_U8, __DCCP_CONNTRACK_ROLE_MAX, dccp_roles },
+ {},
+};
+
#define DCCP_VALID_FLAGS_MAX 2
static unsigned int dccp_valid_flags[DCCP_VALID_FLAGS_MAX] = {
CT_DCCP_ORIG_SPORT | CT_DCCP_ORIG_DPORT,
@@ -235,6 +251,7 @@ static struct ctproto_handler dccp = {
.protonum = IPPROTO_DCCP,
.parse_opts = parse_options,
.final_check = final_check,
+ .print_opts = dccp_print_opts,
.help = help,
.opts = opts,
.version = VERSION,
diff --git a/extensions/libct_proto_gre.c b/extensions/libct_proto_gre.c
index 2dc63d1..a36d111 100644
--- a/extensions/libct_proto_gre.c
+++ b/extensions/libct_proto_gre.c
@@ -144,6 +144,14 @@ static int parse_options(char c,
return 1;
}
+static const struct ct_print_opts gre_print_opts[] = {
+ { "--srckey", ATTR_ORIG_PORT_SRC, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--dstkey", ATTR_ORIG_PORT_DST, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--reply-key-src", ATTR_REPL_PORT_SRC, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--reply-key-dst", ATTR_REPL_PORT_DST, CT_ATTR_TYPE_BE16, 0, 0 },
+ {},
+};
+
#define GRE_VALID_FLAGS_MAX 2
static unsigned int gre_valid_flags[GRE_VALID_FLAGS_MAX] = {
CT_GRE_ORIG_SKEY | CT_GRE_ORIG_DKEY,
@@ -181,6 +189,7 @@ static struct ctproto_handler gre = {
.protonum = IPPROTO_GRE,
.parse_opts = parse_options,
.final_check = final_check,
+ .print_opts = gre_print_opts,
.help = help,
.opts = opts,
.version = VERSION,
diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c
index 7fc82bd..ec52c39 100644
--- a/extensions/libct_proto_icmp.c
+++ b/extensions/libct_proto_icmp.c
@@ -102,6 +102,13 @@ static int parse(char c,
return 1;
}
+static const struct ct_print_opts icmp_print_opts[] = {
+ { "--icmp-type", ATTR_ICMP_TYPE, CT_ATTR_TYPE_U8, 0, 0 },
+ { "--icmp-code", ATTR_ICMP_CODE, CT_ATTR_TYPE_U8, 0, 0 },
+ { "--icmp-id", ATTR_ICMP_ID, CT_ATTR_TYPE_BE16, 0, 0 },
+ {}
+};
+
static void final_check(unsigned int flags,
unsigned int cmd,
struct nf_conntrack *ct)
@@ -117,6 +124,7 @@ static struct ctproto_handler icmp = {
.protonum = IPPROTO_ICMP,
.parse_opts = parse,
.final_check = final_check,
+ .print_opts = icmp_print_opts,
.help = help,
.opts = opts,
.version = VERSION,
diff --git a/extensions/libct_proto_icmpv6.c b/extensions/libct_proto_icmpv6.c
index f872c23..fe16a1d 100644
--- a/extensions/libct_proto_icmpv6.c
+++ b/extensions/libct_proto_icmpv6.c
@@ -105,6 +105,13 @@ static int parse(char c,
return 1;
}
+static const struct ct_print_opts icmpv6_print_opts[] = {
+ {"--icmpv6-type", ATTR_ICMP_TYPE, CT_ATTR_TYPE_U8, 0, 0},
+ {"--icmpv6-code", ATTR_ICMP_CODE, CT_ATTR_TYPE_U8, 0, 0},
+ {"--icmpv6-id", ATTR_ICMP_ID, CT_ATTR_TYPE_BE16, 0, 0},
+ {},
+};
+
static void final_check(unsigned int flags,
unsigned int cmd,
struct nf_conntrack *ct)
@@ -119,6 +126,7 @@ static struct ctproto_handler icmpv6 = {
.protonum = IPPROTO_ICMPV6,
.parse_opts = parse,
.final_check = final_check,
+ .print_opts = icmpv6_print_opts,
.help = help,
.opts = opts,
.version = VERSION,
diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c
index 04828bf..a58ccde 100644
--- a/extensions/libct_proto_sctp.c
+++ b/extensions/libct_proto_sctp.c
@@ -198,6 +198,17 @@ parse_options(char c, struct nf_conntrack *ct,
return 1;
}
+static const struct ct_print_opts sctp_print_opts[] = {
+ { "--sport", ATTR_ORIG_PORT_SRC, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--dport", ATTR_ORIG_PORT_DST, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--reply-port-src", ATTR_REPL_PORT_SRC, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--reply-port-dst", ATTR_REPL_PORT_DST, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--state", ATTR_SCTP_STATE, CT_ATTR_TYPE_U8, SCTP_CONNTRACK_MAX, sctp_states },
+ { "--orig-vtag", ATTR_SCTP_VTAG_ORIG, CT_ATTR_TYPE_BE32, 0, 0 },
+ { "--reply-vtag", ATTR_SCTP_VTAG_REPL, CT_ATTR_TYPE_BE32, 0, 0 },
+ {},
+};
+
#define SCTP_VALID_FLAGS_MAX 2
static unsigned int dccp_valid_flags[SCTP_VALID_FLAGS_MAX] = {
CT_SCTP_ORIG_SPORT | CT_SCTP_ORIG_DPORT,
@@ -235,6 +246,7 @@ static struct ctproto_handler sctp = {
.protonum = IPPROTO_SCTP,
.parse_opts = parse_options,
.final_check = final_check,
+ .print_opts = sctp_print_opts,
.help = help,
.opts = opts,
.version = VERSION,
diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c
index 8a37a55..3da0dc6 100644
--- a/extensions/libct_proto_tcp.c
+++ b/extensions/libct_proto_tcp.c
@@ -177,6 +177,15 @@ static int parse_options(char c,
return 1;
}
+static const struct ct_print_opts tcp_print_opts[] = {
+ { "--sport", ATTR_ORIG_PORT_SRC, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--dport", ATTR_ORIG_PORT_DST, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--reply-port-src", ATTR_REPL_PORT_SRC, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--reply-port-dst", ATTR_REPL_PORT_DST, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--state", ATTR_TCP_STATE, CT_ATTR_TYPE_U8, TCP_CONNTRACK_MAX, tcp_states },
+ {},
+};
+
#define TCP_VALID_FLAGS_MAX 2
static unsigned int tcp_valid_flags[TCP_VALID_FLAGS_MAX] = {
CT_TCP_ORIG_SPORT | CT_TCP_ORIG_DPORT,
@@ -228,6 +237,7 @@ static struct ctproto_handler tcp = {
.protonum = IPPROTO_TCP,
.parse_opts = parse_options,
.final_check = final_check,
+ .print_opts = tcp_print_opts,
.help = help,
.opts = opts,
.version = VERSION,
diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c
index e30637c..fe43548 100644
--- a/extensions/libct_proto_udp.c
+++ b/extensions/libct_proto_udp.c
@@ -144,6 +144,14 @@ static int parse_options(char c,
return 1;
}
+static const struct ct_print_opts udp_print_opts[] = {
+ {"--sport", ATTR_ORIG_PORT_SRC, CT_ATTR_TYPE_BE16, 0, 0},
+ {"--dport", ATTR_ORIG_PORT_DST, CT_ATTR_TYPE_BE16, 0, 0},
+ {"--reply-port-src", ATTR_REPL_PORT_SRC, CT_ATTR_TYPE_BE16, 0, 0},
+ {"--reply-port-dst", ATTR_REPL_PORT_DST, CT_ATTR_TYPE_BE16, 0, 0},
+ {},
+};
+
#define UDP_VALID_FLAGS_MAX 2
static unsigned int udp_valid_flags[UDP_VALID_FLAGS_MAX] = {
CT_UDP_ORIG_SPORT | CT_UDP_ORIG_DPORT,
@@ -181,6 +189,7 @@ static struct ctproto_handler udp = {
.protonum = IPPROTO_UDP,
.parse_opts = parse_options,
.final_check = final_check,
+ .print_opts = udp_print_opts,
.help = help,
.opts = opts,
.version = VERSION,
diff --git a/extensions/libct_proto_udplite.c b/extensions/libct_proto_udplite.c
index f46cef0..2bece38 100644
--- a/extensions/libct_proto_udplite.c
+++ b/extensions/libct_proto_udplite.c
@@ -148,6 +148,14 @@ static int parse_options(char c,
return 1;
}
+static const struct ct_print_opts udplite_print_opts[] = {
+ { "--sport", ATTR_ORIG_PORT_SRC, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--dport", ATTR_ORIG_PORT_DST, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--reply-port-src", ATTR_REPL_PORT_SRC, CT_ATTR_TYPE_BE16, 0, 0 },
+ { "--reply-port-dst", ATTR_REPL_PORT_DST, CT_ATTR_TYPE_BE16, 0, 0 },
+ {},
+};
+
#define UDPLITE_VALID_FLAGS_MAX 2
static unsigned int udplite_valid_flags[UDPLITE_VALID_FLAGS_MAX] = {
CT_UDPLITE_ORIG_SPORT | CT_UDPLITE_ORIG_DPORT,
@@ -186,6 +194,7 @@ static struct ctproto_handler udplite = {
.protonum = IPPROTO_UDPLITE,
.parse_opts = parse_options,
.final_check = final_check,
+ .print_opts = udplite_print_opts,
.help = help,
.opts = opts,
.version = VERSION,
diff --git a/include/conntrack.h b/include/conntrack.h
index 37ccf6e..1c1720e 100644
--- a/include/conntrack.h
+++ b/include/conntrack.h
@@ -8,6 +8,9 @@
#include <netinet/in.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
#define NUMBER_OF_CMD 19
#define NUMBER_OF_OPT 29
@@ -32,6 +35,8 @@ struct ctproto_handler {
unsigned int command,
struct nf_conntrack *ct);
+ const struct ct_print_opts *print_opts;
+
void (*help)(void);
struct option *opts;
@@ -53,6 +58,31 @@ void exit_error(enum exittype status, const char *msg, ...);
extern void register_proto(struct ctproto_handler *h);
+enum ct_attr_type {
+ CT_ATTR_TYPE_NONE = 0,
+ CT_ATTR_TYPE_U8,
+ CT_ATTR_TYPE_BE16,
+ CT_ATTR_TYPE_U16,
+ CT_ATTR_TYPE_BE32,
+ CT_ATTR_TYPE_U32,
+ CT_ATTR_TYPE_U64,
+ CT_ATTR_TYPE_U32_BITMAP,
+ CT_ATTR_TYPE_IPV4,
+ CT_ATTR_TYPE_IPV6,
+};
+
+struct ct_print_opts {
+ const char *name;
+ enum nf_conntrack_attr type;
+ enum ct_attr_type datatype;
+ short val_mapping_count;
+ const char **val_mapping;
+};
+
+extern int ct_snprintf_opts(char *buf, unsigned int len,
+ const struct nf_conntrack *ct,
+ const struct ct_print_opts *attrs);
+
extern void register_tcp(void);
extern void register_udp(void);
extern void register_udplite(void);
diff --git a/src/conntrack.c b/src/conntrack.c
index 6e8363e..d05a599 100644
--- a/src/conntrack.c
+++ b/src/conntrack.c
@@ -54,6 +54,7 @@
#include <sys/socket.h>
#include <sys/time.h>
#include <time.h>
+#include <inttypes.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
@@ -608,6 +609,252 @@ void register_proto(struct ctproto_handler *h)
list_add(&h->head, &proto_list);
}
+#define BUFFER_SIZE(ret, size, len, offset) do { \
+ if ((int)ret > (int)len) \
+ ret = len; \
+ size += ret; \
+ offset += ret; \
+ len -= ret; \
+} while(0)
+
+static int ct_snprintf_u32_bitmap(char *buf, size_t size,
+ const struct nf_conntrack *ct,
+ const struct ct_print_opts *attr)
+{
+ unsigned int offset = 0, ret, len = size;
+ bool found = false;
+ uint32_t val;
+ int i;
+
+ val = nfct_get_attr_u32(ct, attr->type);
+
+ for (i = 0; i < attr->val_mapping_count; i++) {
+ if (!(val & (1 << i)))
+ continue;
+ if (!attr->val_mapping[i])
+ continue;
+
+ ret = snprintf(buf + offset, len, "%s,", attr->val_mapping[i]);
+ BUFFER_SIZE(ret, size, len, offset);
+ found = true;
+ }
+
+ if (found) {
+ offset--;
+ ret = snprintf(buf + offset, len, " ");
+ BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ return offset;
+}
+
+static int ct_snprintf_attr(char *buf, size_t size,
+ const struct nf_conntrack *ct,
+ const struct ct_print_opts *attr)
+{
+ char ipstr[INET6_ADDRSTRLEN] = {};
+ unsigned int offset = 0;
+ int type = attr->type;
+ int len = size, ret;
+
+ ret = snprintf(buf, len, "%s ", attr->name);
+ BUFFER_SIZE(ret, size, len, offset);
+
+ switch (attr->datatype) {
+ case CT_ATTR_TYPE_U8:
+ if (attr->val_mapping)
+ ret = snprintf(buf + offset, len, "%s ",
+ attr->val_mapping[nfct_get_attr_u8(ct, type)]);
+ else
+ ret = snprintf(buf + offset, len, "%u ",
+ nfct_get_attr_u8(ct, type));
+ break;
+ case CT_ATTR_TYPE_BE16:
+ ret = snprintf(buf + offset, len, "%u ",
+ ntohs(nfct_get_attr_u16(ct, type)));
+ break;
+ case CT_ATTR_TYPE_U16:
+ ret = snprintf(buf + offset, len, "%u ",
+ nfct_get_attr_u16(ct, type));
+ break;
+ case CT_ATTR_TYPE_BE32:
+ ret = snprintf(buf + offset, len, "%u ",
+ ntohl(nfct_get_attr_u32(ct, type)));
+ break;
+ case CT_ATTR_TYPE_U32:
+ ret = snprintf(buf + offset, len, "%u ",
+ nfct_get_attr_u32(ct, type));
+ break;
+ case CT_ATTR_TYPE_U64:
+ ret = snprintf(buf + offset, len, "%lu ",
+ nfct_get_attr_u64(ct, type));
+ break;
+ case CT_ATTR_TYPE_IPV4:
+ inet_ntop(AF_INET, nfct_get_attr(ct, type),
+ ipstr, sizeof(ipstr));
+ ret = snprintf(buf + offset, len, "%s ", ipstr);
+ break;
+ case CT_ATTR_TYPE_IPV6:
+ inet_ntop(AF_INET6, nfct_get_attr(ct, type),
+ ipstr, sizeof(ipstr));
+ ret = snprintf(buf + offset, len, "%s ", ipstr);
+ break;
+ case CT_ATTR_TYPE_U32_BITMAP:
+ ret = ct_snprintf_u32_bitmap(buf + offset, len, ct, attr);
+ if (ret == 0 && type == ATTR_STATUS)
+ ret = snprintf(buf + offset, len, "UNSET ");
+ break;
+ default:
+ /* Unsupported datatype, should not ever happen */
+ ret = 0;
+ break;
+ }
+ BUFFER_SIZE(ret, size, len, offset);
+
+ return offset;
+}
+
+int ct_snprintf_opts(char *buf, unsigned int len, const struct nf_conntrack *ct,
+ const struct ct_print_opts *attrs)
+{
+ unsigned int size = 0, offset = 0, ret;
+ int i;
+
+ for (i = 0; attrs[i].name; ++i) {
+ if (!nfct_attr_is_set(ct, attrs[i].type))
+ continue;
+
+ ret = ct_snprintf_attr(buf + offset, len, ct, &attrs[i]);
+ BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ return offset;
+}
+
+static const struct ct_print_opts attrs_ip_map[] = {
+ [ATTR_ORIG_IPV4_SRC] = { "-s", ATTR_ORIG_IPV4_SRC, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_ORIG_IPV4_DST] = { "-d", ATTR_ORIG_IPV4_DST, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_DNAT_IPV4] = { "-g", ATTR_REPL_IPV4_SRC, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_SNAT_IPV4] = { "-n", ATTR_REPL_IPV4_DST, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_REPL_IPV4_SRC] = { "-r", ATTR_REPL_IPV4_SRC, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_REPL_IPV4_DST] = { "-q", ATTR_REPL_IPV4_DST, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_ORIG_IPV6_SRC] = { "-s", ATTR_ORIG_IPV6_SRC, CT_ATTR_TYPE_IPV6, 0, 0 },
+ [ATTR_ORIG_IPV6_DST] = { "-d", ATTR_ORIG_IPV6_DST, CT_ATTR_TYPE_IPV6, 0, 0 },
+ [ATTR_DNAT_IPV6] = { "-g", ATTR_REPL_IPV6_SRC, CT_ATTR_TYPE_IPV6, 0, 0 },
+ [ATTR_SNAT_IPV6] = { "-n", ATTR_REPL_IPV6_DST, CT_ATTR_TYPE_IPV6, 0, 0 },
+ [ATTR_REPL_IPV6_SRC] = { "-r", ATTR_REPL_IPV6_SRC, CT_ATTR_TYPE_IPV6, 0, 0 },
+ [ATTR_REPL_IPV6_DST] = { "-q", ATTR_REPL_IPV6_DST, CT_ATTR_TYPE_IPV6, 0, 0 },
+};
+
+static const char *conntrack_status_map[] = {
+ [IPS_SEEN_REPLY_BIT] = "SEEN_REPLY",
+ [IPS_ASSURED_BIT] = "ASSURED",
+ [IPS_FIXED_TIMEOUT_BIT] = "FIXED_TIMEOUT",
+ [IPS_EXPECTED_BIT] = "EXPECTED"
+};
+
+static struct ct_print_opts attrs_generic[] = {
+ { "-t", ATTR_TIMEOUT, CT_ATTR_TYPE_U32, 0, 0 },
+ { "-u", ATTR_STATUS, CT_ATTR_TYPE_U32_BITMAP,
+ sizeof(conntrack_status_map)/sizeof(conntrack_status_map[0]),
+ conntrack_status_map },
+ { "-c", ATTR_SECMARK, CT_ATTR_TYPE_U32, 0, 0 },
+ { "-w", ATTR_ZONE, CT_ATTR_TYPE_U16, 0, 0 },
+ { "--orig-zone", ATTR_ORIG_ZONE, CT_ATTR_TYPE_U16, 0, 0 },
+ { "--reply-zone", ATTR_REPL_ZONE, CT_ATTR_TYPE_U16, 0, 0 },
+ {},
+};
+
+static int ct_save_snprintf(char *buf, size_t len,
+ const struct nf_conntrack *ct,
+ struct nfct_labelmap *map,
+ enum nf_conntrack_msg_type type)
+{
+ struct ct_print_opts tuple_attr_print[5] = {};
+ unsigned int size = 0, offset = 0;
+ struct ctproto_handler *cur;
+ uint8_t l3proto, l4proto;
+ int tuple_attrs[4] = {};
+ unsigned i;
+ int ret;
+
+ switch (type) {
+ case NFCT_T_NEW:
+ ret = snprintf(buf + offset, len, "-I ");
+ BUFFER_SIZE(ret, size, len, offset);
+ break;
+ case NFCT_T_UPDATE:
+ ret = snprintf(buf + offset, len, "-U ");
+ BUFFER_SIZE(ret, size, len, offset);
+ break;
+ case NFCT_T_DESTROY:
+ ret = snprintf(buf + offset, len, "-D ");
+ BUFFER_SIZE(ret, size, len, offset);
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ ret = ct_snprintf_opts(buf + offset, len, ct, attrs_generic);
+ BUFFER_SIZE(ret, size, len, offset);
+
+ l3proto = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO);
+ if (!l3proto)
+ l3proto = nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO);
+ switch (l3proto) {
+ case AF_INET:
+ tuple_attrs[0] = ATTR_ORIG_IPV4_SRC;
+ tuple_attrs[1] = ATTR_ORIG_IPV4_DST;
+ tuple_attrs[2] = nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) ?
+ ATTR_DNAT_IPV4 : ATTR_REPL_IPV4_SRC;
+ tuple_attrs[3] = nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) ?
+ ATTR_SNAT_IPV4 : ATTR_REPL_IPV4_DST;
+ break;
+ case AF_INET6:
+ tuple_attrs[0] = ATTR_ORIG_IPV6_SRC;
+ tuple_attrs[1] = ATTR_ORIG_IPV6_DST;
+ tuple_attrs[2] = nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) ?
+ ATTR_DNAT_IPV6 : ATTR_REPL_IPV6_SRC;
+ tuple_attrs[3] = nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) ?
+ ATTR_SNAT_IPV6 : ATTR_REPL_IPV6_DST;
+ break;
+ default:
+ fprintf(stderr, "WARNING: unsupported l3proto %d, skipping.\n",
+ l3proto);
+ return 0;
+ }
+
+ for (i = 0; i < sizeof(tuple_attrs) / sizeof(tuple_attrs[0]); i++) {
+ memcpy(&tuple_attr_print[i], &attrs_ip_map[tuple_attrs[i]],
+ sizeof(tuple_attr_print[0]));
+ }
+
+ ret = ct_snprintf_opts(buf + offset, len, ct, tuple_attr_print);
+ BUFFER_SIZE(ret, size, len, offset);
+
+ l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO);
+
+ /* is it in the list of supported protocol? */
+ list_for_each_entry(cur, &proto_list, head) {
+ if (cur->protonum != l4proto)
+ continue;
+
+ ret = snprintf(buf + offset, len, "-p %s ", cur->name);
+ BUFFER_SIZE(ret, size, len, offset);
+
+ ret = ct_snprintf_opts(buf + offset, len, ct, cur->print_opts);
+ BUFFER_SIZE(ret, size, len, offset);
+ break;
+ }
+
+ /* skip trailing space, if any */
+ for (; size && buf[size-1] == ' '; --size)
+ buf[size-1] = '\0';
+
+ return size;
+}
+
extern struct ctproto_handler ct_proto_unknown;
static struct ctproto_handler *findproto(char *name, int *pnum)
@@ -857,6 +1104,7 @@ enum {
_O_KTMS = (1 << 4),
_O_CL = (1 << 5),
_O_US = (1 << 6),
+ _O_SAVE = (1 << 7),
};
enum {
@@ -867,7 +1115,7 @@ enum {
};
static struct parse_parameter {
- const char *parameter[7];
+ const char *parameter[8];
size_t size;
unsigned int value[8];
} parse_array[PARSE_MAX] = {
@@ -875,8 +1123,8 @@ static struct parse_parameter {
{ IPS_ASSURED, IPS_SEEN_REPLY, 0, IPS_FIXED_TIMEOUT, IPS_EXPECTED, IPS_OFFLOAD, IPS_HW_OFFLOAD} },
{ {"ALL", "NEW", "UPDATES", "DESTROY"}, 4,
{ CT_EVENT_F_ALL, CT_EVENT_F_NEW, CT_EVENT_F_UPD, CT_EVENT_F_DEL } },
- { {"xml", "extended", "timestamp", "id", "ktimestamp", "labels", "userspace" }, 7,
- { _O_XML, _O_EXT, _O_TMS, _O_ID, _O_KTMS, _O_CL, _O_US },
+ { {"xml", "extended", "timestamp", "id", "ktimestamp", "labels", "userspace", "save"}, 8,
+ { _O_XML, _O_EXT, _O_TMS, _O_ID, _O_KTMS, _O_CL, _O_US, _O_SAVE },
},
};
@@ -1462,6 +1710,11 @@ static int event_cb(const struct nlmsghdr *nlh, void *data)
nfct_filter(obj, ct))
goto out;
+ if (output_mask & _O_SAVE) {
+ ct_save_snprintf(buf, sizeof(buf), ct, labelmap, type);
+ goto done;
+ }
+
if (output_mask & _O_XML) {
op_type = NFCT_O_XML;
if (dump_xml_header_done) {
@@ -1486,7 +1739,7 @@ static int event_cb(const struct nlmsghdr *nlh, void *data)
op_flags |= NFCT_OF_ID;
nfct_snprintf_labels(buf, sizeof(buf), ct, type, op_type, op_flags, labelmap);
-
+done:
if (output_mask & _O_US) {
if (nlh->nlmsg_pid)
userspace = true;
@@ -1515,6 +1768,11 @@ static int dump_cb(enum nf_conntrack_msg_type type,
if (nfct_filter(obj, ct))
return NFCT_CB_CONTINUE;
+ if (output_mask & _O_SAVE) {
+ ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_NEW);
+ goto done;
+ }
+
if (output_mask & _O_XML) {
op_type = NFCT_O_XML;
if (dump_xml_header_done) {
@@ -1531,6 +1789,7 @@ static int dump_cb(enum nf_conntrack_msg_type type,
op_flags |= NFCT_OF_ID;
nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags, labelmap);
+done:
printf("%s\n", buf);
counter++;
@@ -1557,6 +1816,11 @@ static int delete_cb(enum nf_conntrack_msg_type type,
"Operation failed: %s",
err2str(errno, CT_DELETE));
+ if (output_mask & _O_SAVE) {
+ ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_DESTROY);
+ goto done;
+ }
+
if (output_mask & _O_XML)
op_type = NFCT_O_XML;
if (output_mask & _O_EXT)
@@ -1565,6 +1829,7 @@ static int delete_cb(enum nf_conntrack_msg_type type,
op_flags |= NFCT_OF_ID;
nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags);
+done:
printf("%s\n", buf);
counter++;
@@ -1580,6 +1845,11 @@ static int print_cb(enum nf_conntrack_msg_type type,
unsigned int op_type = NFCT_O_DEFAULT;
unsigned int op_flags = 0;
+ if (output_mask & _O_SAVE) {
+ ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_NEW);
+ goto done;
+ }
+
if (output_mask & _O_XML)
op_type = NFCT_O_XML;
if (output_mask & _O_EXT)
@@ -1588,6 +1858,7 @@ static int print_cb(enum nf_conntrack_msg_type type,
op_flags |= NFCT_OF_ID;
nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags, labelmap);
+done:
printf("%s\n", buf);
return NFCT_CB_CONTINUE;
@@ -2451,6 +2722,10 @@ int main(int argc, char *argv[])
parse_parameter(optarg, &output_mask, PARSE_OUTPUT);
if (output_mask & _O_CL)
labelmap_init();
+ if ((output_mask & _O_SAVE) &&
+ (output_mask & (_O_EXT |_O_TMS |_O_ID | _O_KTMS | _O_CL | _O_XML)))
+ exit_error(OTHER_PROBLEM,
+ "cannot combine save output with any other output type, use -o save only");
break;
case 'z':
options |= CT_OPT_ZERO;