Home | History | Annotate | Download | only in netfilter
      1 /*
      2  * lib/netfilter/ct_obj.c	Conntrack Object
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2003-2008 Thomas Graf <tgraf (at) suug.ch>
     10  * Copyright (c) 2007 Philip Craig <philipc (at) snapgear.com>
     11  * Copyright (c) 2007 Secure Computing Corporation
     12  */
     13 
     14 #include <sys/types.h>
     15 #include <linux/netfilter/nfnetlink_conntrack.h>
     16 #include <linux/netfilter/nf_conntrack_common.h>
     17 #include <linux/netfilter/nf_conntrack_tcp.h>
     18 
     19 #include <netlink-private/netlink.h>
     20 #include <netlink/netfilter/nfnl.h>
     21 #include <netlink/netfilter/ct.h>
     22 
     23 /** @cond SKIP */
     24 #define CT_ATTR_FAMILY		(1UL << 0)
     25 #define CT_ATTR_PROTO		(1UL << 1)
     26 
     27 #define CT_ATTR_TCP_STATE	(1UL << 2)
     28 
     29 #define CT_ATTR_STATUS		(1UL << 3)
     30 #define CT_ATTR_TIMEOUT		(1UL << 4)
     31 #define CT_ATTR_MARK		(1UL << 5)
     32 #define CT_ATTR_USE		(1UL << 6)
     33 #define CT_ATTR_ID		(1UL << 7)
     34 
     35 #define CT_ATTR_ORIG_SRC	(1UL << 8)
     36 #define CT_ATTR_ORIG_DST	(1UL << 9)
     37 #define CT_ATTR_ORIG_SRC_PORT	(1UL << 10)
     38 #define CT_ATTR_ORIG_DST_PORT	(1UL << 11)
     39 #define CT_ATTR_ORIG_ICMP_ID	(1UL << 12)
     40 #define CT_ATTR_ORIG_ICMP_TYPE	(1UL << 13)
     41 #define CT_ATTR_ORIG_ICMP_CODE	(1UL << 14)
     42 #define CT_ATTR_ORIG_PACKETS	(1UL << 15)
     43 #define CT_ATTR_ORIG_BYTES	(1UL << 16)
     44 
     45 #define CT_ATTR_REPL_SRC	(1UL << 17)
     46 #define CT_ATTR_REPL_DST	(1UL << 18)
     47 #define CT_ATTR_REPL_SRC_PORT	(1UL << 19)
     48 #define CT_ATTR_REPL_DST_PORT	(1UL << 20)
     49 #define CT_ATTR_REPL_ICMP_ID	(1UL << 21)
     50 #define CT_ATTR_REPL_ICMP_TYPE	(1UL << 22)
     51 #define CT_ATTR_REPL_ICMP_CODE	(1UL << 23)
     52 #define CT_ATTR_REPL_PACKETS	(1UL << 24)
     53 #define CT_ATTR_REPL_BYTES	(1UL << 25)
     54 #define CT_ATTR_TIMESTAMP	(1UL << 26)
     55 #define CT_ATTR_ZONE	(1UL << 27)
     56 /** @endcond */
     57 
     58 static void ct_free_data(struct nl_object *c)
     59 {
     60 	struct nfnl_ct *ct = (struct nfnl_ct *) c;
     61 
     62 	if (ct == NULL)
     63 		return;
     64 
     65 	nl_addr_put(ct->ct_orig.src);
     66 	nl_addr_put(ct->ct_orig.dst);
     67 	nl_addr_put(ct->ct_repl.src);
     68 	nl_addr_put(ct->ct_repl.dst);
     69 }
     70 
     71 static int ct_clone(struct nl_object *_dst, struct nl_object *_src)
     72 {
     73 	struct nfnl_ct *dst = (struct nfnl_ct *) _dst;
     74 	struct nfnl_ct *src = (struct nfnl_ct *) _src;
     75 	struct nl_addr *addr;
     76 
     77 	if (src->ct_orig.src) {
     78 		addr = nl_addr_clone(src->ct_orig.src);
     79 		if (!addr)
     80 			return -NLE_NOMEM;
     81 		dst->ct_orig.src = addr;
     82 	}
     83 
     84 	if (src->ct_orig.dst) {
     85 		addr = nl_addr_clone(src->ct_orig.dst);
     86 		if (!addr)
     87 			return -NLE_NOMEM;
     88 		dst->ct_orig.dst = addr;
     89 	}
     90 
     91 	if (src->ct_repl.src) {
     92 		addr = nl_addr_clone(src->ct_repl.src);
     93 		if (!addr)
     94 			return -NLE_NOMEM;
     95 		dst->ct_repl.src = addr;
     96 	}
     97 
     98 	if (src->ct_repl.dst) {
     99 		addr = nl_addr_clone(src->ct_repl.dst);
    100 		if (!addr)
    101 			return -NLE_NOMEM;
    102 		dst->ct_repl.dst = addr;
    103 	}
    104 
    105 	return 0;
    106 }
    107 
    108 static void dump_addr(struct nl_dump_params *p, struct nl_addr *addr, int port)
    109 {
    110 	char buf[64];
    111 
    112 	if (addr)
    113 		nl_dump(p, "%s", nl_addr2str(addr, buf, sizeof(buf)));
    114 
    115 	if (port)
    116 		nl_dump(p, ":%u ", port);
    117 	else if (addr)
    118 		nl_dump(p, " ");
    119 }
    120 
    121 static void dump_icmp(struct nl_dump_params *p, struct nfnl_ct *ct, int reply)
    122 {
    123 	if (nfnl_ct_test_icmp_type(ct, reply))
    124 		nl_dump(p, "icmp type %d ", nfnl_ct_get_icmp_type(ct, reply));
    125 
    126 	if (nfnl_ct_test_icmp_code(ct, reply))
    127 		nl_dump(p, "code %d ", nfnl_ct_get_icmp_code(ct, reply));
    128 
    129 	if (nfnl_ct_test_icmp_id(ct, reply))
    130 		nl_dump(p, "id %d ", nfnl_ct_get_icmp_id(ct, reply));
    131 }
    132 
    133 static void ct_dump_tuples(struct nfnl_ct *ct, struct nl_dump_params *p)
    134 {
    135 	struct nl_addr *orig_src, *orig_dst, *reply_src, *reply_dst;
    136 	int orig_sport = 0, orig_dport = 0, reply_sport = 0, reply_dport = 0;
    137 	int sync = 0;
    138 
    139 	orig_src = nfnl_ct_get_src(ct, 0);
    140 	orig_dst = nfnl_ct_get_dst(ct, 0);
    141 	reply_src = nfnl_ct_get_src(ct, 1);
    142 	reply_dst = nfnl_ct_get_dst(ct, 1);
    143 
    144 	if (nfnl_ct_test_src_port(ct, 0))
    145 		orig_sport = nfnl_ct_get_src_port(ct, 0);
    146 
    147 	if (nfnl_ct_test_dst_port(ct, 0))
    148 		orig_dport = nfnl_ct_get_dst_port(ct, 0);
    149 
    150 	if (nfnl_ct_test_src_port(ct, 1))
    151 		reply_sport = nfnl_ct_get_src_port(ct, 1);
    152 
    153 	if (nfnl_ct_test_dst_port(ct, 1))
    154 		reply_dport = nfnl_ct_get_dst_port(ct, 1);
    155 
    156 	if (orig_src && orig_dst && reply_src && reply_dst &&
    157 	    orig_sport == reply_dport && orig_dport == reply_sport &&
    158 	    !nl_addr_cmp(orig_src, reply_dst) &&
    159 	    !nl_addr_cmp(orig_dst, reply_src))
    160 		sync = 1;
    161 
    162 	dump_addr(p, orig_src, orig_sport);
    163 	nl_dump(p, sync ? "<-> " : "-> ");
    164 	dump_addr(p, orig_dst, orig_dport);
    165 	dump_icmp(p, ct, 0);
    166 
    167 	if (!sync) {
    168 		dump_addr(p, reply_src, reply_sport);
    169 		nl_dump(p, "<- ");
    170 		dump_addr(p, reply_dst, reply_dport);
    171 		dump_icmp(p, ct, 1);
    172 	}
    173 }
    174 
    175 /* Compatible with /proc/net/nf_conntrack */
    176 static void ct_dump_line(struct nl_object *a, struct nl_dump_params *p)
    177 {
    178 	struct nfnl_ct *ct = (struct nfnl_ct *) a;
    179 	char buf[64];
    180 
    181 	nl_new_line(p);
    182 
    183 	if (nfnl_ct_test_proto(ct))
    184 		nl_dump(p, "%s ",
    185 		  nl_ip_proto2str(nfnl_ct_get_proto(ct), buf, sizeof(buf)));
    186 
    187 	if (nfnl_ct_test_tcp_state(ct))
    188 		nl_dump(p, "%s ",
    189 			nfnl_ct_tcp_state2str(nfnl_ct_get_tcp_state(ct),
    190 					      buf, sizeof(buf)));
    191 
    192 	ct_dump_tuples(ct, p);
    193 
    194 	if (nfnl_ct_test_mark(ct) && nfnl_ct_get_mark(ct))
    195 		nl_dump(p, "mark %u ", nfnl_ct_get_mark(ct));
    196 
    197 	if (nfnl_ct_test_zone(ct))
    198 		nl_dump(p, "zone %hu ", nfnl_ct_get_zone(ct));
    199 
    200 	if (nfnl_ct_test_timestamp(ct)) {
    201 		const struct nfnl_ct_timestamp *tstamp = nfnl_ct_get_timestamp(ct);
    202 		int64_t delta_time = tstamp->stop - tstamp->start;
    203 
    204 		if (delta_time > 0)
    205 			delta_time /= NSEC_PER_SEC;
    206 		else
    207 			delta_time = 0;
    208 		nl_dump(p, "delta-time %llu ", delta_time);
    209 	}
    210 
    211 	nl_dump(p, "\n");
    212 }
    213 
    214 static void ct_dump_details(struct nl_object *a, struct nl_dump_params *p)
    215 {
    216 	struct nfnl_ct *ct = (struct nfnl_ct *) a;
    217 	char buf[64];
    218 	int fp = 0;
    219 
    220 	ct_dump_line(a, p);
    221 
    222 	nl_dump(p, "    id 0x%x ", ct->ct_id);
    223 	nl_dump_line(p, "family %s ",
    224 		nl_af2str(ct->ct_family, buf, sizeof(buf)));
    225 
    226 	if (nfnl_ct_test_use(ct))
    227 		nl_dump(p, "refcnt %u ", nfnl_ct_get_use(ct));
    228 
    229 	if (nfnl_ct_test_timeout(ct)) {
    230 		uint64_t timeout_ms = nfnl_ct_get_timeout(ct) * 1000UL;
    231 		nl_dump(p, "timeout %s ",
    232 			nl_msec2str(timeout_ms, buf, sizeof(buf)));
    233 	}
    234 
    235 	if (ct->ct_status)
    236 		nl_dump(p, "<");
    237 
    238 #define PRINT_FLAG(str) \
    239 	{ nl_dump(p, "%s%s", fp++ ? "," : "", (str)); }
    240 
    241 	if (ct->ct_status & IPS_EXPECTED)
    242 		PRINT_FLAG("EXPECTED");
    243 	if (!(ct->ct_status & IPS_SEEN_REPLY))
    244 		PRINT_FLAG("NOREPLY");
    245 	if (ct->ct_status & IPS_ASSURED)
    246 		PRINT_FLAG("ASSURED");
    247 	if (!(ct->ct_status & IPS_CONFIRMED))
    248 		PRINT_FLAG("NOTSENT");
    249 	if (ct->ct_status & IPS_SRC_NAT)
    250 		PRINT_FLAG("SNAT");
    251 	if (ct->ct_status & IPS_DST_NAT)
    252 		PRINT_FLAG("DNAT");
    253 	if (ct->ct_status & IPS_SEQ_ADJUST)
    254 		PRINT_FLAG("SEQADJUST");
    255 	if (!(ct->ct_status & IPS_SRC_NAT_DONE))
    256 		PRINT_FLAG("SNAT_INIT");
    257 	if (!(ct->ct_status & IPS_DST_NAT_DONE))
    258 		PRINT_FLAG("DNAT_INIT");
    259 	if (ct->ct_status & IPS_DYING)
    260 		PRINT_FLAG("DYING");
    261 	if (ct->ct_status & IPS_FIXED_TIMEOUT)
    262 		PRINT_FLAG("FIXED_TIMEOUT");
    263 #undef PRINT_FLAG
    264 
    265 	if (ct->ct_status)
    266 		nl_dump(p, ">");
    267 	nl_dump(p, "\n");
    268 }
    269 
    270 static void ct_dump_stats(struct nl_object *a, struct nl_dump_params *p)
    271 {
    272 	struct nfnl_ct *ct = (struct nfnl_ct *) a;
    273 	double res;
    274 	char *unit;
    275 	uint64_t packets;
    276 	const char * const names[] = {"rx", "tx"};
    277 	int i;
    278 
    279 	ct_dump_details(a, p);
    280 
    281 	if (!nfnl_ct_test_bytes(ct, 0) ||
    282 	    !nfnl_ct_test_packets(ct, 0) ||
    283 	    !nfnl_ct_test_bytes(ct, 1) ||
    284 	    !nfnl_ct_test_packets(ct, 1))
    285 	    {
    286 		nl_dump_line(p, "    Statistics are not available.\n");
    287 		nl_dump_line(p, "    Please set sysctl net.netfilter.nf_conntrack_acct=1\n");
    288 		nl_dump_line(p, "    (Require kernel 2.6.27)\n");
    289 		return;
    290 	    }
    291 
    292 	nl_dump_line(p, "        # packets      volume\n");
    293 	for (i=0; i<=1; i++) {
    294 		res = nl_cancel_down_bytes(nfnl_ct_get_bytes(ct, i), &unit);
    295 		packets = nfnl_ct_get_packets(ct, i);
    296 		nl_dump_line(p, "    %s %10" PRIu64  " %7.2f %s\n", names[i], packets, res, unit);
    297 	}
    298 }
    299 
    300 static int ct_compare(struct nl_object *_a, struct nl_object *_b,
    301 			uint32_t attrs, int flags)
    302 {
    303 	struct nfnl_ct *a = (struct nfnl_ct *) _a;
    304 	struct nfnl_ct *b = (struct nfnl_ct *) _b;
    305 	int diff = 0;
    306 
    307 #define CT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, CT_ATTR_##ATTR, a, b, EXPR)
    308 #define CT_DIFF_VAL(ATTR, FIELD) CT_DIFF(ATTR, a->FIELD != b->FIELD)
    309 #define CT_DIFF_ADDR(ATTR, FIELD) \
    310 	((flags & LOOSE_COMPARISON) \
    311 		? CT_DIFF(ATTR, nl_addr_cmp_prefix(a->FIELD, b->FIELD)) \
    312 		: CT_DIFF(ATTR, nl_addr_cmp(a->FIELD, b->FIELD)))
    313 
    314 	diff |= CT_DIFF_VAL(FAMILY,		ct_family);
    315 	diff |= CT_DIFF_VAL(PROTO,		ct_proto);
    316 	diff |= CT_DIFF_VAL(TCP_STATE,		ct_protoinfo.tcp.state);
    317 	diff |= CT_DIFF_VAL(TIMEOUT,		ct_timeout);
    318 	diff |= CT_DIFF_VAL(MARK,		ct_mark);
    319 	diff |= CT_DIFF_VAL(USE,		ct_use);
    320 	diff |= CT_DIFF_VAL(ID,			ct_id);
    321 	diff |= CT_DIFF_ADDR(ORIG_SRC,		ct_orig.src);
    322 	diff |= CT_DIFF_ADDR(ORIG_DST,		ct_orig.dst);
    323 	diff |= CT_DIFF_VAL(ORIG_SRC_PORT,	ct_orig.proto.port.src);
    324 	diff |= CT_DIFF_VAL(ORIG_DST_PORT,	ct_orig.proto.port.dst);
    325 	diff |= CT_DIFF_VAL(ORIG_ICMP_ID,	ct_orig.proto.icmp.id);
    326 	diff |= CT_DIFF_VAL(ORIG_ICMP_TYPE,	ct_orig.proto.icmp.type);
    327 	diff |= CT_DIFF_VAL(ORIG_ICMP_CODE,	ct_orig.proto.icmp.code);
    328 	diff |= CT_DIFF_VAL(ORIG_PACKETS,	ct_orig.packets);
    329 	diff |= CT_DIFF_VAL(ORIG_BYTES,		ct_orig.bytes);
    330 	diff |= CT_DIFF_ADDR(REPL_SRC,		ct_repl.src);
    331 	diff |= CT_DIFF_ADDR(REPL_DST,		ct_repl.dst);
    332 	diff |= CT_DIFF_VAL(REPL_SRC_PORT,	ct_repl.proto.port.src);
    333 	diff |= CT_DIFF_VAL(REPL_DST_PORT,	ct_repl.proto.port.dst);
    334 	diff |= CT_DIFF_VAL(REPL_ICMP_ID,	ct_repl.proto.icmp.id);
    335 	diff |= CT_DIFF_VAL(REPL_ICMP_TYPE,	ct_repl.proto.icmp.type);
    336 	diff |= CT_DIFF_VAL(REPL_ICMP_CODE,	ct_repl.proto.icmp.code);
    337 	diff |= CT_DIFF_VAL(REPL_PACKETS,	ct_repl.packets);
    338 	diff |= CT_DIFF_VAL(REPL_BYTES,		ct_repl.bytes);
    339 
    340 	if (flags & LOOSE_COMPARISON)
    341 		diff |= CT_DIFF(STATUS, (a->ct_status ^ b->ct_status) &
    342 					b->ct_status_mask);
    343 	else
    344 		diff |= CT_DIFF(STATUS, a->ct_status != b->ct_status);
    345 
    346 #undef CT_DIFF
    347 #undef CT_DIFF_VAL
    348 #undef CT_DIFF_ADDR
    349 
    350 	return diff;
    351 }
    352 
    353 static const struct trans_tbl ct_attrs[] = {
    354 	__ADD(CT_ATTR_FAMILY,		family)
    355 	__ADD(CT_ATTR_PROTO,		proto)
    356 	__ADD(CT_ATTR_TCP_STATE,	tcpstate)
    357 	__ADD(CT_ATTR_STATUS,		status)
    358 	__ADD(CT_ATTR_TIMEOUT,		timeout)
    359 	__ADD(CT_ATTR_MARK,		mark)
    360 	__ADD(CT_ATTR_USE,		use)
    361 	__ADD(CT_ATTR_ID,		id)
    362 	__ADD(CT_ATTR_ORIG_SRC,		origsrc)
    363 	__ADD(CT_ATTR_ORIG_DST,		origdst)
    364 	__ADD(CT_ATTR_ORIG_SRC_PORT,	origsrcport)
    365 	__ADD(CT_ATTR_ORIG_DST_PORT,	origdstport)
    366 	__ADD(CT_ATTR_ORIG_ICMP_ID,	origicmpid)
    367 	__ADD(CT_ATTR_ORIG_ICMP_TYPE,	origicmptype)
    368 	__ADD(CT_ATTR_ORIG_ICMP_CODE,	origicmpcode)
    369 	__ADD(CT_ATTR_ORIG_PACKETS,	origpackets)
    370 	__ADD(CT_ATTR_ORIG_BYTES,	origbytes)
    371 	__ADD(CT_ATTR_REPL_SRC,		replysrc)
    372 	__ADD(CT_ATTR_REPL_DST,		replydst)
    373 	__ADD(CT_ATTR_REPL_SRC_PORT,	replysrcport)
    374 	__ADD(CT_ATTR_REPL_DST_PORT,	replydstport)
    375 	__ADD(CT_ATTR_REPL_ICMP_ID,	replyicmpid)
    376 	__ADD(CT_ATTR_REPL_ICMP_TYPE,	replyicmptype)
    377 	__ADD(CT_ATTR_REPL_ICMP_CODE,	replyicmpcode)
    378 	__ADD(CT_ATTR_REPL_PACKETS,	replypackets)
    379 	__ADD(CT_ATTR_REPL_BYTES,	replybytes)
    380 };
    381 
    382 static char *ct_attrs2str(int attrs, char *buf, size_t len)
    383 {
    384 	return __flags2str(attrs, buf, len, ct_attrs, ARRAY_SIZE(ct_attrs));
    385 }
    386 
    387 /**
    388  * @name Allocation/Freeing
    389  * @{
    390  */
    391 
    392 struct nfnl_ct *nfnl_ct_alloc(void)
    393 {
    394 	return (struct nfnl_ct *) nl_object_alloc(&ct_obj_ops);
    395 }
    396 
    397 void nfnl_ct_get(struct nfnl_ct *ct)
    398 {
    399 	nl_object_get((struct nl_object *) ct);
    400 }
    401 
    402 void nfnl_ct_put(struct nfnl_ct *ct)
    403 {
    404 	nl_object_put((struct nl_object *) ct);
    405 }
    406 
    407 /** @} */
    408 
    409 /**
    410  * @name Attributes
    411  * @{
    412  */
    413 
    414 void nfnl_ct_set_family(struct nfnl_ct *ct, uint8_t family)
    415 {
    416 	ct->ct_family = family;
    417 	ct->ce_mask |= CT_ATTR_FAMILY;
    418 }
    419 
    420 uint8_t nfnl_ct_get_family(const struct nfnl_ct *ct)
    421 {
    422 	if (ct->ce_mask & CT_ATTR_FAMILY)
    423 		return ct->ct_family;
    424 	else
    425 		return AF_UNSPEC;
    426 }
    427 
    428 void nfnl_ct_set_proto(struct nfnl_ct *ct, uint8_t proto)
    429 {
    430 	ct->ct_proto = proto;
    431 	ct->ce_mask |= CT_ATTR_PROTO;
    432 }
    433 
    434 int nfnl_ct_test_proto(const struct nfnl_ct *ct)
    435 {
    436 	return !!(ct->ce_mask & CT_ATTR_PROTO);
    437 }
    438 
    439 uint8_t nfnl_ct_get_proto(const struct nfnl_ct *ct)
    440 {
    441 	return ct->ct_proto;
    442 }
    443 
    444 void nfnl_ct_set_tcp_state(struct nfnl_ct *ct, uint8_t state)
    445 {
    446 	ct->ct_protoinfo.tcp.state = state;
    447 	ct->ce_mask |= CT_ATTR_TCP_STATE;
    448 }
    449 
    450 int nfnl_ct_test_tcp_state(const struct nfnl_ct *ct)
    451 {
    452 	return !!(ct->ce_mask & CT_ATTR_TCP_STATE);
    453 }
    454 
    455 uint8_t nfnl_ct_get_tcp_state(const struct nfnl_ct *ct)
    456 {
    457 	return ct->ct_protoinfo.tcp.state;
    458 }
    459 
    460 static const struct trans_tbl tcp_states[] = {
    461 	__ADD(TCP_CONNTRACK_NONE,NONE)
    462 	__ADD(TCP_CONNTRACK_SYN_SENT,SYN_SENT)
    463 	__ADD(TCP_CONNTRACK_SYN_RECV,SYN_RECV)
    464 	__ADD(TCP_CONNTRACK_ESTABLISHED,ESTABLISHED)
    465 	__ADD(TCP_CONNTRACK_FIN_WAIT,FIN_WAIT)
    466 	__ADD(TCP_CONNTRACK_CLOSE_WAIT,CLOSE_WAIT)
    467 	__ADD(TCP_CONNTRACK_LAST_ACK,LAST_ACK)
    468 	__ADD(TCP_CONNTRACK_TIME_WAIT,TIME_WAIT)
    469 	__ADD(TCP_CONNTRACK_CLOSE,CLOSE)
    470 	__ADD(TCP_CONNTRACK_LISTEN,LISTEN)
    471 };
    472 
    473 char *nfnl_ct_tcp_state2str(uint8_t state, char *buf, size_t len)
    474 {
    475 	return __type2str(state, buf, len, tcp_states, ARRAY_SIZE(tcp_states));
    476 }
    477 
    478 int nfnl_ct_str2tcp_state(const char *name)
    479 {
    480         return __str2type(name, tcp_states, ARRAY_SIZE(tcp_states));
    481 }
    482 
    483 void nfnl_ct_set_status(struct nfnl_ct *ct, uint32_t status)
    484 {
    485 	ct->ct_status_mask |= status;
    486 	ct->ct_status |= status;
    487 	ct->ce_mask |= CT_ATTR_STATUS;
    488 }
    489 
    490 void nfnl_ct_unset_status(struct nfnl_ct *ct, uint32_t status)
    491 {
    492 	ct->ct_status_mask |= status;
    493 	ct->ct_status &= ~status;
    494 	ct->ce_mask |= CT_ATTR_STATUS;
    495 }
    496 
    497 int nfnl_ct_test_status(const struct nfnl_ct *ct)
    498 {
    499 	return !!(ct->ce_mask & CT_ATTR_STATUS);
    500 }
    501 
    502 uint32_t nfnl_ct_get_status(const struct nfnl_ct *ct)
    503 {
    504 	return ct->ct_status;
    505 }
    506 
    507 static const struct trans_tbl status_flags[] = {
    508 	__ADD(IPS_EXPECTED, expected)
    509 	__ADD(IPS_SEEN_REPLY, seen_reply)
    510 	__ADD(IPS_ASSURED, assured)
    511 	__ADD(IPS_CONFIRMED, confirmed)
    512 	__ADD(IPS_SRC_NAT, snat)
    513 	__ADD(IPS_DST_NAT, dnat)
    514 	__ADD(IPS_SEQ_ADJUST, seqadjust)
    515 	__ADD(IPS_SRC_NAT_DONE, snat_done)
    516 	__ADD(IPS_DST_NAT_DONE, dnat_done)
    517 	__ADD(IPS_DYING, dying)
    518 	__ADD(IPS_FIXED_TIMEOUT, fixed_timeout)
    519 };
    520 
    521 char * nfnl_ct_status2str(int flags, char *buf, size_t len)
    522 {
    523 	return __flags2str(flags, buf, len, status_flags,
    524 			   ARRAY_SIZE(status_flags));
    525 }
    526 
    527 int nfnl_ct_str2status(const char *name)
    528 {
    529 	return __str2flags(name, status_flags, ARRAY_SIZE(status_flags));
    530 }
    531 
    532 void nfnl_ct_set_timeout(struct nfnl_ct *ct, uint32_t timeout)
    533 {
    534 	ct->ct_timeout = timeout;
    535 	ct->ce_mask |= CT_ATTR_TIMEOUT;
    536 }
    537 
    538 int nfnl_ct_test_timeout(const struct nfnl_ct *ct)
    539 {
    540 	return !!(ct->ce_mask & CT_ATTR_TIMEOUT);
    541 }
    542 
    543 uint32_t nfnl_ct_get_timeout(const struct nfnl_ct *ct)
    544 {
    545 	return ct->ct_timeout;
    546 }
    547 
    548 void nfnl_ct_set_mark(struct nfnl_ct *ct, uint32_t mark)
    549 {
    550 	ct->ct_mark = mark;
    551 	ct->ce_mask |= CT_ATTR_MARK;
    552 }
    553 
    554 int nfnl_ct_test_mark(const struct nfnl_ct *ct)
    555 {
    556 	return !!(ct->ce_mask & CT_ATTR_MARK);
    557 }
    558 
    559 uint32_t nfnl_ct_get_mark(const struct nfnl_ct *ct)
    560 {
    561 	return ct->ct_mark;
    562 }
    563 
    564 void nfnl_ct_set_use(struct nfnl_ct *ct, uint32_t use)
    565 {
    566 	ct->ct_use = use;
    567 	ct->ce_mask |= CT_ATTR_USE;
    568 }
    569 
    570 int nfnl_ct_test_use(const struct nfnl_ct *ct)
    571 {
    572 	return !!(ct->ce_mask & CT_ATTR_USE);
    573 }
    574 
    575 uint32_t nfnl_ct_get_use(const struct nfnl_ct *ct)
    576 {
    577 	return ct->ct_use;
    578 }
    579 
    580 void nfnl_ct_set_id(struct nfnl_ct *ct, uint32_t id)
    581 {
    582 	ct->ct_id = id;
    583 	ct->ce_mask |= CT_ATTR_ID;
    584 }
    585 
    586 int nfnl_ct_test_id(const struct nfnl_ct *ct)
    587 {
    588 	return !!(ct->ce_mask & CT_ATTR_ID);
    589 }
    590 
    591 uint32_t nfnl_ct_get_id(const struct nfnl_ct *ct)
    592 {
    593 	return ct->ct_id;
    594 }
    595 
    596 void nfnl_ct_set_zone(struct nfnl_ct *ct, uint16_t zone)
    597 {
    598 	ct->ct_zone = zone;
    599 	ct->ce_mask |= CT_ATTR_ZONE;
    600 }
    601 
    602 int nfnl_ct_test_zone(const struct nfnl_ct *ct)
    603 {
    604 	return !!(ct->ce_mask & CT_ATTR_ZONE);
    605 }
    606 
    607 uint16_t nfnl_ct_get_zone(const struct nfnl_ct *ct)
    608 {
    609 	return ct->ct_zone;
    610 }
    611 
    612 static int ct_set_addr(struct nfnl_ct *ct, struct nl_addr *addr,
    613 		int attr, struct nl_addr ** ct_addr)
    614 {
    615 	if (ct->ce_mask & CT_ATTR_FAMILY) {
    616 		if (addr->a_family != ct->ct_family)
    617 			return -NLE_AF_MISMATCH;
    618 	} else
    619 		nfnl_ct_set_family(ct, addr->a_family);
    620 
    621 	if (*ct_addr)
    622 		nl_addr_put(*ct_addr);
    623 
    624 	nl_addr_get(addr);
    625 	*ct_addr = addr;
    626 	ct->ce_mask |= attr;
    627 
    628 	return 0;
    629 }
    630 
    631 int nfnl_ct_set_src(struct nfnl_ct *ct, int repl, struct nl_addr *addr)
    632 {
    633 	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    634 	int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC;
    635 	return ct_set_addr(ct, addr, attr, &dir->src);
    636 }
    637 
    638 int nfnl_ct_set_dst(struct nfnl_ct *ct, int repl, struct nl_addr *addr)
    639 {
    640 	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    641 	int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST;
    642 	return ct_set_addr(ct, addr, attr, &dir->dst);
    643 }
    644 
    645 struct nl_addr *nfnl_ct_get_src(const struct nfnl_ct *ct, int repl)
    646 {
    647 	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    648 	int attr = repl ? CT_ATTR_REPL_SRC : CT_ATTR_ORIG_SRC;
    649 	if (!(ct->ce_mask & attr))
    650 		return NULL;
    651 	return dir->src;
    652 }
    653 
    654 struct nl_addr *nfnl_ct_get_dst(const struct nfnl_ct *ct, int repl)
    655 {
    656 	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    657 	int attr = repl ? CT_ATTR_REPL_DST : CT_ATTR_ORIG_DST;
    658 	if (!(ct->ce_mask & attr))
    659 		return NULL;
    660 	return dir->dst;
    661 }
    662 
    663 void nfnl_ct_set_src_port(struct nfnl_ct *ct, int repl, uint16_t port)
    664 {
    665 	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    666 	int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT;
    667 
    668 	dir->proto.port.src = port;
    669 	ct->ce_mask |= attr;
    670 }
    671 
    672 int nfnl_ct_test_src_port(const struct nfnl_ct *ct, int repl)
    673 {
    674 	int attr = repl ? CT_ATTR_REPL_SRC_PORT : CT_ATTR_ORIG_SRC_PORT;
    675 	return !!(ct->ce_mask & attr);
    676 }
    677 
    678 uint16_t nfnl_ct_get_src_port(const struct nfnl_ct *ct, int repl)
    679 {
    680 	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    681 
    682 	return dir->proto.port.src;
    683 }
    684 
    685 void nfnl_ct_set_dst_port(struct nfnl_ct *ct, int repl, uint16_t port)
    686 {
    687 	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    688 	int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT;
    689 
    690 	dir->proto.port.dst = port;
    691 	ct->ce_mask |= attr;
    692 }
    693 
    694 int nfnl_ct_test_dst_port(const struct nfnl_ct *ct, int repl)
    695 {
    696 	int attr = repl ? CT_ATTR_REPL_DST_PORT : CT_ATTR_ORIG_DST_PORT;
    697 	return !!(ct->ce_mask & attr);
    698 }
    699 
    700 uint16_t nfnl_ct_get_dst_port(const struct nfnl_ct *ct, int repl)
    701 {
    702 	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    703 
    704 	return dir->proto.port.dst;
    705 }
    706 
    707 void nfnl_ct_set_icmp_id(struct nfnl_ct *ct, int repl, uint16_t id)
    708 {
    709 	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    710 	int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID;
    711 
    712 	dir->proto.icmp.id = id;
    713 	ct->ce_mask |= attr;
    714 }
    715 
    716 int nfnl_ct_test_icmp_id(const struct nfnl_ct *ct, int repl)
    717 {
    718 	int attr = repl ? CT_ATTR_REPL_ICMP_ID : CT_ATTR_ORIG_ICMP_ID;
    719 	return !!(ct->ce_mask & attr);
    720 }
    721 
    722 uint16_t nfnl_ct_get_icmp_id(const struct nfnl_ct *ct, int repl)
    723 {
    724 	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    725 
    726 	return dir->proto.icmp.id;
    727 }
    728 
    729 void nfnl_ct_set_icmp_type(struct nfnl_ct *ct, int repl, uint8_t type)
    730 {
    731 	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    732 	int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE;
    733 
    734 	dir->proto.icmp.type = type;
    735 	ct->ce_mask |= attr;
    736 }
    737 
    738 int nfnl_ct_test_icmp_type(const struct nfnl_ct *ct, int repl)
    739 {
    740 	int attr = repl ? CT_ATTR_REPL_ICMP_TYPE : CT_ATTR_ORIG_ICMP_TYPE;
    741 	return !!(ct->ce_mask & attr);
    742 }
    743 
    744 uint8_t nfnl_ct_get_icmp_type(const struct nfnl_ct *ct, int repl)
    745 {
    746 	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    747 
    748 	return dir->proto.icmp.type;
    749 }
    750 
    751 void nfnl_ct_set_icmp_code(struct nfnl_ct *ct, int repl, uint8_t code)
    752 {
    753 	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    754 	int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE;
    755 
    756 	dir->proto.icmp.code = code;
    757 	ct->ce_mask |= attr;
    758 }
    759 
    760 int nfnl_ct_test_icmp_code(const struct nfnl_ct *ct, int repl)
    761 {
    762 	int attr = repl ? CT_ATTR_REPL_ICMP_CODE : CT_ATTR_ORIG_ICMP_CODE;
    763 	return !!(ct->ce_mask & attr);
    764 }
    765 
    766 uint8_t nfnl_ct_get_icmp_code(const struct nfnl_ct *ct, int repl)
    767 {
    768 	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    769 
    770 	return dir->proto.icmp.code;
    771 }
    772 
    773 void nfnl_ct_set_packets(struct nfnl_ct *ct, int repl, uint64_t packets)
    774 {
    775 	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    776 	int attr = repl ? CT_ATTR_REPL_PACKETS : CT_ATTR_ORIG_PACKETS;
    777 
    778 	dir->packets = packets;
    779 	ct->ce_mask |= attr;
    780 }
    781 
    782 int nfnl_ct_test_packets(const struct nfnl_ct *ct, int repl)
    783 {
    784 	int attr = repl ? CT_ATTR_REPL_PACKETS : CT_ATTR_ORIG_PACKETS;
    785 	return !!(ct->ce_mask & attr);
    786 }
    787 
    788 uint64_t nfnl_ct_get_packets(const struct nfnl_ct *ct, int repl)
    789 {
    790 	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    791 
    792 	return dir->packets;
    793 }
    794 
    795 void nfnl_ct_set_bytes(struct nfnl_ct *ct, int repl, uint64_t bytes)
    796 {
    797 	struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    798 	int attr = repl ? CT_ATTR_REPL_BYTES : CT_ATTR_ORIG_BYTES;
    799 
    800 	dir->bytes = bytes;
    801 	ct->ce_mask |= attr;
    802 }
    803 
    804 int nfnl_ct_test_bytes(const struct nfnl_ct *ct, int repl)
    805 {
    806 	int attr = repl ? CT_ATTR_REPL_BYTES : CT_ATTR_ORIG_BYTES;
    807 	return !!(ct->ce_mask & attr);
    808 }
    809 
    810 uint64_t nfnl_ct_get_bytes(const struct nfnl_ct *ct, int repl)
    811 {
    812 	const struct nfnl_ct_dir *dir = repl ? &ct->ct_repl : &ct->ct_orig;
    813 
    814 	return dir->bytes;
    815 }
    816 
    817 void nfnl_ct_set_timestamp(struct nfnl_ct *ct, uint64_t start, uint64_t stop)
    818 {
    819 	ct->ct_tstamp.start = start;
    820 	ct->ct_tstamp.stop = stop;
    821 	ct->ce_mask |= CT_ATTR_TIMESTAMP;
    822 }
    823 
    824 int nfnl_ct_test_timestamp(const struct nfnl_ct *ct)
    825 {
    826 	return !!(ct->ce_mask & CT_ATTR_TIMESTAMP);
    827 }
    828 
    829 const struct nfnl_ct_timestamp *nfnl_ct_get_timestamp(const struct nfnl_ct *ct)
    830 {
    831 	return &ct->ct_tstamp;
    832 }
    833 
    834 /** @} */
    835 
    836 struct nl_object_ops ct_obj_ops = {
    837 	.oo_name		= "netfilter/ct",
    838 	.oo_size		= sizeof(struct nfnl_ct),
    839 	.oo_free_data		= ct_free_data,
    840 	.oo_clone		= ct_clone,
    841 	.oo_dump = {
    842 	    [NL_DUMP_LINE]	= ct_dump_line,
    843 	    [NL_DUMP_DETAILS]	= ct_dump_details,
    844 	    [NL_DUMP_STATS]	= ct_dump_stats,
    845 	},
    846 	.oo_compare		= ct_compare,
    847 	.oo_attrs2str		= ct_attrs2str,
    848 };
    849 
    850 /** @} */
    851