10 #include <libmnl/libmnl.h>
11 #include <linux/netfilter/nfnetlink.h>
12 #include <linux/netfilter/nfnetlink_conntrack.h>
14 static int parse_counters_cb(
const struct nlattr *attr,
void *data)
16 const struct nlattr **tb = data;
17 int type = mnl_attr_get_type(attr);
19 if (mnl_attr_type_valid(attr, CTA_COUNTERS_MAX) < 0)
23 case CTA_COUNTERS_PACKETS:
24 case CTA_COUNTERS_BYTES:
25 if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
26 perror(
"mnl_attr_validate");
35 static void print_counters(
const struct nlattr *nest)
37 struct nlattr *tb[CTA_COUNTERS_MAX+1] = {};
39 mnl_attr_parse_nested(nest, parse_counters_cb, tb);
40 if (tb[CTA_COUNTERS_PACKETS]) {
41 printf(
"packets=%"PRIu64
" ",
42 be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_PACKETS])));
44 if (tb[CTA_COUNTERS_BYTES]) {
45 printf(
"bytes=%"PRIu64
" ",
46 be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_BYTES])));
50 static int parse_ip_cb(
const struct nlattr *attr,
void *data)
52 const struct nlattr **tb = data;
53 int type = mnl_attr_get_type(attr);
55 if (mnl_attr_type_valid(attr, CTA_IP_MAX) < 0)
61 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
62 perror(
"mnl_attr_validate");
68 if (mnl_attr_validate2(attr, MNL_TYPE_BINARY,
69 sizeof(
struct in6_addr)) < 0) {
70 perror(
"mnl_attr_validate2");
79 static void print_ip(
const struct nlattr *nest)
81 struct nlattr *tb[CTA_IP_MAX+1] = {};
83 mnl_attr_parse_nested(nest, parse_ip_cb, tb);
84 if (tb[CTA_IP_V4_SRC]) {
85 struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_SRC]);
86 printf(
"src=%s ", inet_ntoa(*in));
88 if (tb[CTA_IP_V4_DST]) {
89 struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_DST]);
90 printf(
"dst=%s ", inet_ntoa(*in));
92 if (tb[CTA_IP_V6_SRC]) {
93 struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_SRC]);
94 char out[INET6_ADDRSTRLEN];
96 if (!inet_ntop(AF_INET6, in, out,
sizeof(out)))
97 printf(
"src=%s ", out);
99 if (tb[CTA_IP_V6_DST]) {
100 struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_DST]);
101 char out[INET6_ADDRSTRLEN];
103 if (!inet_ntop(AF_INET6, in, out,
sizeof(out)))
104 printf(
"dst=%s ", out);
108 static int parse_proto_cb(
const struct nlattr *attr,
void *data)
110 const struct nlattr **tb = data;
111 int type = mnl_attr_get_type(attr);
113 if (mnl_attr_type_valid(attr, CTA_PROTO_MAX) < 0)
118 case CTA_PROTO_ICMP_TYPE:
119 case CTA_PROTO_ICMP_CODE:
120 if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
121 perror(
"mnl_attr_validate");
125 case CTA_PROTO_SRC_PORT:
126 case CTA_PROTO_DST_PORT:
127 case CTA_PROTO_ICMP_ID:
128 if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
129 perror(
"mnl_attr_validate");
138 static void print_proto(
const struct nlattr *nest)
140 struct nlattr *tb[CTA_PROTO_MAX+1] = {};
142 mnl_attr_parse_nested(nest, parse_proto_cb, tb);
143 if (tb[CTA_PROTO_NUM]) {
144 printf(
"proto=%u ", mnl_attr_get_u8(tb[CTA_PROTO_NUM]));
146 if (tb[CTA_PROTO_SRC_PORT]) {
148 ntohs(mnl_attr_get_u16(tb[CTA_PROTO_SRC_PORT])));
150 if (tb[CTA_PROTO_DST_PORT]) {
152 ntohs(mnl_attr_get_u16(tb[CTA_PROTO_DST_PORT])));
154 if (tb[CTA_PROTO_ICMP_ID]) {
156 ntohs(mnl_attr_get_u16(tb[CTA_PROTO_ICMP_ID])));
158 if (tb[CTA_PROTO_ICMP_TYPE]) {
159 printf(
"type=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
161 if (tb[CTA_PROTO_ICMP_CODE]) {
162 printf(
"code=%u ", mnl_attr_get_u8(tb[CTA_PROTO_ICMP_CODE]));
166 static int parse_tuple_cb(
const struct nlattr *attr,
void *data)
168 const struct nlattr **tb = data;
169 int type = mnl_attr_get_type(attr);
171 if (mnl_attr_type_valid(attr, CTA_TUPLE_MAX) < 0)
176 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
177 perror(
"mnl_attr_validate");
181 case CTA_TUPLE_PROTO:
182 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
183 perror(
"mnl_attr_validate");
192 static void print_tuple(
const struct nlattr *nest)
194 struct nlattr *tb[CTA_TUPLE_MAX+1] = {};
196 mnl_attr_parse_nested(nest, parse_tuple_cb, tb);
197 if (tb[CTA_TUPLE_IP]) {
198 print_ip(tb[CTA_TUPLE_IP]);
200 if (tb[CTA_TUPLE_PROTO]) {
201 print_proto(tb[CTA_TUPLE_PROTO]);
205 static int data_attr_cb(
const struct nlattr *attr,
void *data)
207 const struct nlattr **tb = data;
208 int type = mnl_attr_get_type(attr);
210 if (mnl_attr_type_valid(attr, CTA_MAX) < 0)
215 case CTA_COUNTERS_ORIG:
216 case CTA_COUNTERS_REPLY:
217 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
218 perror(
"mnl_attr_validate");
225 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
226 perror(
"mnl_attr_validate");
235 static int data_cb(
const struct nlmsghdr *nlh,
void *data)
237 struct nlattr *tb[CTA_MAX+1] = {};
238 struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
240 mnl_attr_parse(nlh,
sizeof(*nfg), data_attr_cb, tb);
241 if (tb[CTA_TUPLE_ORIG])
242 print_tuple(tb[CTA_TUPLE_ORIG]);
245 printf(
"mark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_MARK])));
248 printf(
"secmark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_SECMARK])));
250 if (tb[CTA_COUNTERS_ORIG]) {
252 print_counters(tb[CTA_COUNTERS_ORIG]);
255 if (tb[CTA_COUNTERS_REPLY]) {
257 print_counters(tb[CTA_COUNTERS_REPLY]);
267 char buf[MNL_SOCKET_BUFFER_SIZE];
268 struct nlmsghdr *nlh;
269 struct nfgenmsg *nfh;
270 uint32_t seq, portid;
273 nl = mnl_socket_open(NETLINK_NETFILTER);
275 perror(
"mnl_socket_open");
279 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
280 perror(
"mnl_socket_bind");
284 nlh = mnl_nlmsg_put_header(buf);
285 nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET;
286 nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
287 nlh->nlmsg_seq = seq = time(NULL);
289 nfh = mnl_nlmsg_put_extra_header(nlh,
sizeof(
struct nfgenmsg));
290 nfh->nfgen_family = AF_INET;
291 nfh->version = NFNETLINK_V0;
294 ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
296 perror(
"mnl_socket_sendto");
299 portid = mnl_socket_get_portid(nl);
302 ret = mnl_socket_recvfrom(nl, buf,
sizeof(buf));
304 perror(
"mnl_socket_recvfrom");
308 ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL);
310 perror(
"mnl_cb_run");
312 }
else if (ret <= MNL_CB_STOP)
316 mnl_socket_close(nl);