Home | History | Annotate | Download | only in conntrack
      1 /*
      2  * (C) 2005-2011 by Pablo Neira Ayuso <pablo (at) netfilter.org>
      3  *
      4  * This program is free software; you can redistribute it and/or modify it
      5  * under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation; either version 2 of the License, or
      7  * (at your option) any later version.
      8  */
      9 
     10 #include "internal/internal.h"
     11 #include <stdbool.h>
     12 
     13 static int __cmp(int attr,
     14 		 const struct nf_conntrack *ct1,
     15 		 const struct nf_conntrack *ct2,
     16 		 unsigned int flags,
     17 		 int (*cmp)(const struct nf_conntrack *ct1,
     18 		 	    const struct nf_conntrack *ct2,
     19 			    unsigned int flags), bool strict)
     20 {
     21 	int a = test_bit(attr, ct1->head.set);
     22 	int b = test_bit(attr, ct2->head.set);
     23 	if (a && b) {
     24 		return cmp(ct1, ct2, flags);
     25 	} else if (!a && !b) {
     26 		return 1;
     27 	} else if (flags & NFCT_CMP_MASK &&
     28 		   test_bit(attr, ct1->head.set)) {
     29 		return strict ? 0 : cmp(ct1, ct2, flags);
     30 	} else if (flags & NFCT_CMP_STRICT) {
     31 		return strict ? 0 : cmp(ct1, ct2, flags);
     32 	}
     33 	return 1;
     34 }
     35 
     36 static int
     37 cmp_orig_l3proto(const struct nf_conntrack *ct1,
     38 		 const struct nf_conntrack *ct2,
     39 		 unsigned int flags)
     40 {
     41 	return (ct1->head.orig.l3protonum == ct2->head.orig.l3protonum);
     42 }
     43 
     44 static int
     45 cmp_icmp_id(const struct nf_conntrack *ct1,
     46 	    const struct nf_conntrack *ct2,
     47 	    unsigned int flags)
     48 {
     49 	return (ct1->head.orig.l4src.icmp.id == ct2->head.orig.l4src.icmp.id);
     50 }
     51 
     52 static int
     53 cmp_icmp_type(const struct nf_conntrack *ct1,
     54 	      const struct nf_conntrack *ct2,
     55 	      unsigned int flags)
     56 {
     57 	return (ct1->head.orig.l4dst.icmp.type ==
     58 		ct2->head.orig.l4dst.icmp.type);
     59 }
     60 
     61 static int
     62 cmp_icmp_code(const struct nf_conntrack *ct1,
     63 	      const struct nf_conntrack *ct2,
     64 	      unsigned int flags)
     65 {
     66 	return (ct1->head.orig.l4dst.icmp.code ==
     67 		ct2->head.orig.l4dst.icmp.code);
     68 }
     69 
     70 static int
     71 cmp_orig_port_src(const struct nf_conntrack *ct1,
     72 		  const struct nf_conntrack *ct2,
     73 		  unsigned int flags)
     74 {
     75 	return (ct1->head.orig.l4src.all == ct2->head.orig.l4src.all);
     76 }
     77 
     78 static int
     79 cmp_orig_port_dst(const struct nf_conntrack *ct1,
     80 		  const struct nf_conntrack *ct2,
     81 		  unsigned int flags)
     82 {
     83 	return (ct1->head.orig.l4dst.all == ct2->head.orig.l4dst.all);
     84 }
     85 
     86 static int
     87 cmp_orig_l4proto(const struct nf_conntrack *ct1,
     88 		 const struct nf_conntrack *ct2,
     89 		 unsigned int flags)
     90 {
     91 	if (ct1->head.orig.protonum != ct2->head.orig.protonum)
     92 		return 0;
     93 
     94 	switch(ct1->head.orig.protonum) {
     95 	case IPPROTO_ICMP:
     96 	case IPPROTO_ICMPV6:
     97 		if (!__cmp(ATTR_ICMP_ID, ct1, ct2, flags, cmp_icmp_id, true))
     98 			return 0;
     99 		if (!__cmp(ATTR_ICMP_CODE, ct1, ct2, flags, cmp_icmp_code, true))
    100 			return 0;
    101 		if (!__cmp(ATTR_ICMP_TYPE, ct1, ct2, flags, cmp_icmp_type, true))
    102 			return 0;
    103 		break;
    104 	case IPPROTO_TCP:
    105 	case IPPROTO_UDP:
    106 	case IPPROTO_UDPLITE:
    107 	case IPPROTO_DCCP:
    108 	case IPPROTO_SCTP:
    109 		if (!__cmp(ATTR_ORIG_PORT_SRC, ct1, ct2,
    110 			       flags, cmp_orig_port_src, true))
    111 			return 0;
    112 		if (!__cmp(ATTR_ORIG_PORT_DST, ct1, ct2,
    113 			       flags, cmp_orig_port_dst, true))
    114 			return 0;
    115 		break;
    116 	}
    117 	return 1;
    118 }
    119 
    120 static int
    121 cmp_orig_ipv4_src(const struct nf_conntrack *ct1,
    122 		  const struct nf_conntrack *ct2,
    123 		  unsigned int flags)
    124 {
    125 	return (ct1->head.orig.src.v4 == ct2->head.orig.src.v4);}
    126 
    127 static int
    128 cmp_orig_ipv4_dst(const struct nf_conntrack *ct1,
    129 		  const struct nf_conntrack *ct2,
    130 		  unsigned int flags)
    131 {
    132 	return (ct1->head.orig.dst.v4 == ct2->head.orig.dst.v4);}
    133 
    134 static int
    135 cmp_orig_ipv6_src(const struct nf_conntrack *ct1,
    136 		  const struct nf_conntrack *ct2,
    137 		  unsigned int flags)
    138 {
    139 	return (memcmp(&ct1->head.orig.src.v6, &ct2->head.orig.src.v6,
    140 		sizeof(struct in6_addr)) == 0);
    141 }
    142 
    143 static int
    144 cmp_orig_ipv6_dst(const struct nf_conntrack *ct1,
    145 		  const struct nf_conntrack *ct2,
    146 		  unsigned int flags)
    147 {
    148 	return (memcmp(&ct1->head.orig.dst.v6, &ct2->head.orig.dst.v6,
    149 		sizeof(struct in6_addr)) == 0);
    150 }
    151 
    152 static int
    153 cmp_orig_zone(const struct nf_conntrack *ct1,
    154 	      const struct nf_conntrack *ct2,
    155 	      unsigned int flags)
    156 {
    157 	return nfct_get_attr_u16(ct1, ATTR_ORIG_ZONE) ==
    158 	       nfct_get_attr_u16(ct2, ATTR_ORIG_ZONE);
    159 }
    160 
    161 int __cmp_orig(const struct nf_conntrack *ct1,
    162 	       const struct nf_conntrack *ct2,
    163 	       unsigned int flags)
    164 {
    165 	if (!__cmp(ATTR_ORIG_L3PROTO, ct1, ct2, flags, cmp_orig_l3proto, true))
    166 		return 0;
    167 	if (!__cmp(ATTR_ORIG_L4PROTO, ct1, ct2, flags, cmp_orig_l4proto, true))
    168 		return 0;
    169 	if (!__cmp(ATTR_ORIG_IPV4_SRC, ct1, ct2, flags, cmp_orig_ipv4_src, true))
    170 		return 0;
    171 	if (!__cmp(ATTR_ORIG_IPV4_DST, ct1, ct2, flags, cmp_orig_ipv4_dst, true))
    172 		return 0;
    173 	if (!__cmp(ATTR_ORIG_IPV6_SRC, ct1, ct2, flags, cmp_orig_ipv6_src, true))
    174 		return 0;
    175 	if (!__cmp(ATTR_ORIG_IPV6_DST, ct1, ct2, flags, cmp_orig_ipv6_dst, true))
    176 		return 0;
    177 	if (!__cmp(ATTR_ORIG_ZONE, ct1, ct2, flags, cmp_orig_zone, false))
    178 		return 0;
    179 
    180 	return 1;
    181 }
    182 
    183 static int
    184 cmp_repl_l3proto(const struct nf_conntrack *ct1,
    185 		 const struct nf_conntrack *ct2,
    186 		 unsigned int flags)
    187 {
    188 	return (ct1->repl.l3protonum == ct2->repl.l3protonum);
    189 }
    190 
    191 static int
    192 cmp_repl_port_src(const struct nf_conntrack *ct1,
    193 		  const struct nf_conntrack *ct2,
    194 		  unsigned int flags)
    195 {
    196 	return (ct1->repl.l4src.all == ct2->repl.l4src.all);
    197 }
    198 
    199 static int
    200 cmp_repl_port_dst(const struct nf_conntrack *ct1,
    201 		  const struct nf_conntrack *ct2,
    202 		  unsigned int flags)
    203 {
    204 	return (ct1->repl.l4dst.all == ct2->repl.l4dst.all);
    205 }
    206 
    207 static int
    208 cmp_repl_l4proto(const struct nf_conntrack *ct1,
    209 		 const struct nf_conntrack *ct2,
    210 		 unsigned int flags)
    211 {
    212 	if (ct1->repl.protonum != ct2->repl.protonum)
    213 		return 0;
    214 
    215 	switch(ct1->repl.protonum) {
    216 	case IPPROTO_ICMP:
    217 	case IPPROTO_ICMPV6:
    218 		if (!__cmp(ATTR_ICMP_ID, ct1, ct2, flags, cmp_icmp_id, true))
    219 			return 0;
    220 		if (!__cmp(ATTR_ICMP_CODE, ct1, ct2, flags, cmp_icmp_code, true))
    221 			return 0;
    222 		if (!__cmp(ATTR_ICMP_TYPE, ct1, ct2, flags, cmp_icmp_type, true))
    223 			return 0;
    224 		break;
    225 	case IPPROTO_TCP:
    226 	case IPPROTO_UDP:
    227 	case IPPROTO_UDPLITE:
    228 	case IPPROTO_DCCP:
    229 	case IPPROTO_SCTP:
    230 		if (!__cmp(ATTR_REPL_PORT_SRC, ct1, ct2,
    231 			       flags, cmp_repl_port_src, true))
    232 			return 0;
    233 		if (!__cmp(ATTR_REPL_PORT_DST, ct1, ct2,
    234 			       flags, cmp_repl_port_dst, true))
    235 			return 0;
    236 		break;
    237 	}
    238 	return 1;
    239 }
    240 
    241 static int
    242 cmp_repl_ipv4_src(const struct nf_conntrack *ct1,
    243 		  const struct nf_conntrack *ct2,
    244 		  unsigned int flags)
    245 {
    246 	return (ct1->repl.src.v4 == ct2->repl.src.v4);}
    247 
    248 static int
    249 cmp_repl_ipv4_dst(const struct nf_conntrack *ct1,
    250 		  const struct nf_conntrack *ct2,
    251 		  unsigned int flags)
    252 {
    253 	return (ct1->repl.dst.v4 == ct2->repl.dst.v4);}
    254 
    255 static int
    256 cmp_repl_ipv6_src(const struct nf_conntrack *ct1,
    257 		  const struct nf_conntrack *ct2,
    258 		  unsigned int flags)
    259 {
    260 	return (memcmp(&ct1->repl.src.v6, &ct2->repl.src.v6,
    261 		sizeof(struct in6_addr)) == 0);
    262 }
    263 
    264 static int
    265 cmp_repl_ipv6_dst(const struct nf_conntrack *ct1,
    266 		  const struct nf_conntrack *ct2,
    267 		  unsigned int flags)
    268 {
    269 	return (memcmp(&ct1->repl.dst.v6, &ct2->repl.dst.v6,
    270 		sizeof(struct in6_addr)) == 0);
    271 }
    272 
    273 static int
    274 cmp_repl_zone(const struct nf_conntrack *ct1,
    275 	      const struct nf_conntrack *ct2,
    276 	      unsigned int flags)
    277 {
    278 	return nfct_get_attr_u16(ct1, ATTR_REPL_ZONE) ==
    279 	       nfct_get_attr_u16(ct2, ATTR_REPL_ZONE);
    280 }
    281 
    282 static int cmp_repl(const struct nf_conntrack *ct1,
    283 		    const struct nf_conntrack *ct2,
    284 		    unsigned int flags)
    285 {
    286 	if (!__cmp(ATTR_REPL_L3PROTO, ct1, ct2, flags, cmp_repl_l3proto, true))
    287 		return 0;
    288 	if (!__cmp(ATTR_REPL_L4PROTO, ct1, ct2, flags, cmp_repl_l4proto, true))
    289 		return 0;
    290 	if (!__cmp(ATTR_REPL_IPV4_SRC, ct1, ct2, flags, cmp_repl_ipv4_src, true))
    291 		return 0;
    292 	if (!__cmp(ATTR_REPL_IPV4_DST, ct1, ct2, flags, cmp_repl_ipv4_dst, true))
    293 		return 0;
    294 	if (!__cmp(ATTR_REPL_IPV6_SRC, ct1, ct2, flags, cmp_repl_ipv6_src, true))
    295 		return 0;
    296 	if (!__cmp(ATTR_REPL_IPV6_DST, ct1, ct2, flags, cmp_repl_ipv6_dst, true))
    297 		return 0;
    298 	if (!__cmp(ATTR_REPL_ZONE, ct1, ct2, flags, cmp_repl_zone, false))
    299 		return 0;
    300 
    301 	return 1;
    302 }
    303 
    304 static int
    305 cmp_id(const struct nf_conntrack *ct1,
    306        const struct nf_conntrack *ct2,
    307        unsigned int flags)
    308 {
    309 	return (ct1->id == ct2->id);
    310 }
    311 
    312 static int
    313 cmp_mark(const struct nf_conntrack *ct1,
    314 	 const struct nf_conntrack *ct2,
    315 	 unsigned int flags)
    316 {
    317 	return nfct_get_attr_u32(ct1, ATTR_MARK) ==
    318 	       nfct_get_attr_u32(ct2, ATTR_MARK);
    319 }
    320 
    321 static int
    322 cmp_timeout(const struct nf_conntrack *ct1,
    323 	    const struct nf_conntrack *ct2,
    324 	    unsigned int flags)
    325 {
    326 	int ret = 0;
    327 
    328 #define __NFCT_CMP_TIMEOUT (NFCT_CMP_TIMEOUT_LE | NFCT_CMP_TIMEOUT_GT)
    329 
    330 	if (!(flags & __NFCT_CMP_TIMEOUT) &&
    331 	    ct1->timeout == ct2->timeout)
    332 		return 1;
    333 	else {
    334 		if (flags & NFCT_CMP_TIMEOUT_GT &&
    335 		    ct1->timeout > ct2->timeout)
    336 			ret = 1;
    337 		else if (flags & NFCT_CMP_TIMEOUT_LT &&
    338 			 ct1->timeout < ct2->timeout)
    339 		    	ret = 1;
    340 		else if (flags & NFCT_CMP_TIMEOUT_EQ &&
    341 			 ct1->timeout == ct2->timeout)
    342 			ret = 1;
    343 	}
    344 	return ret;
    345 }
    346 
    347 static int
    348 cmp_status(const struct nf_conntrack *ct1,
    349 	   const struct nf_conntrack *ct2,
    350 	   unsigned int flags)
    351 {
    352 	return ((ct1->status & ct2->status) == ct1->status);
    353 }
    354 
    355 static int
    356 cmp_tcp_state(const struct nf_conntrack *ct1,
    357 	      const struct nf_conntrack *ct2,
    358 	      unsigned int flags)
    359 {
    360 	return (ct1->protoinfo.tcp.state == ct2->protoinfo.tcp.state);
    361 }
    362 
    363 static int
    364 cmp_sctp_state(const struct nf_conntrack *ct1,
    365 	       const struct nf_conntrack *ct2,
    366 	       unsigned int flags)
    367 {
    368 	return (ct1->protoinfo.sctp.state == ct2->protoinfo.sctp.state);
    369 }
    370 
    371 static int
    372 cmp_dccp_state(const struct nf_conntrack *ct1,
    373 	       const struct nf_conntrack *ct2,
    374 	       unsigned int flags)
    375 {
    376 	return (ct1->protoinfo.dccp.state == ct2->protoinfo.dccp.state);
    377 }
    378 
    379 static int
    380 cmp_zone(const struct nf_conntrack *ct1,
    381 	 const struct nf_conntrack *ct2,
    382 	 unsigned int flags)
    383 {
    384 	return nfct_get_attr_u16(ct1, ATTR_ZONE) ==
    385 	       nfct_get_attr_u16(ct2, ATTR_ZONE);
    386 }
    387 
    388 static int
    389 cmp_secctx(const struct nf_conntrack *ct1,
    390 	   const struct nf_conntrack *ct2,
    391 	   unsigned int flags)
    392 {
    393 	if (ct1->secctx == NULL || ct2->secctx == NULL)
    394 		return ct1->secctx == ct2->secctx;
    395 	return strcmp(ct1->secctx, ct2->secctx) == 0;
    396 }
    397 
    398 static int __cmp_clabel(const struct nfct_bitmask *a,
    399 			const struct nfct_bitmask *b)
    400 {
    401 	unsigned int len, max;
    402 	const uint32_t *bits;
    403 
    404 	if (a == NULL || b == NULL)
    405 		return a == b;
    406 
    407 	if (a->words < b->words) {
    408 		bits = b->bits;
    409 		max = b->words;
    410 		len = a->words;
    411 	} else {
    412 		bits = a->bits;
    413 		max = a->words;
    414 		len = b->words;
    415 	}
    416 
    417 	while (max > len) {
    418 		if (bits[--max])
    419 			return 0;
    420 	}
    421 	/* bitmask sizes are equal or extra bits are not set */
    422 	return memcmp(a->bits, b->bits, len * sizeof(a->bits[0])) == 0;
    423 }
    424 
    425 static int cmp_clabel(const struct nf_conntrack *ct1,
    426 		      const struct nf_conntrack *ct2,
    427 		      unsigned int flags)
    428 {
    429 	return __cmp_clabel(nfct_get_attr(ct1, ATTR_CONNLABELS),
    430 			    nfct_get_attr(ct2, ATTR_CONNLABELS));
    431 
    432 }
    433 
    434 static int cmp_clabel_mask(const struct nf_conntrack *ct1,
    435 		      const struct nf_conntrack *ct2,
    436 		      unsigned int flags)
    437 {
    438 	return __cmp_clabel(nfct_get_attr(ct1, ATTR_CONNLABELS_MASK),
    439 			    nfct_get_attr(ct2, ATTR_CONNLABELS_MASK));
    440 
    441 }
    442 
    443 static int cmp_meta(const struct nf_conntrack *ct1,
    444 		    const struct nf_conntrack *ct2,
    445 		    unsigned int flags)
    446 {
    447 	if (!__cmp(ATTR_ID, ct1, ct2, flags, cmp_id, true))
    448 		return 0;
    449 	if (!__cmp(ATTR_MARK, ct1, ct2, flags, cmp_mark, false))
    450 		return 0;
    451 	if (!__cmp(ATTR_TIMEOUT, ct1, ct2, flags, cmp_timeout, true))
    452 		return 0;
    453 	if (!__cmp(ATTR_STATUS, ct1, ct2, flags, cmp_status, true))
    454 		return 0;
    455 	if (!__cmp(ATTR_TCP_STATE, ct1, ct2, flags, cmp_tcp_state, true))
    456 		return 0;
    457 	if (!__cmp(ATTR_SCTP_STATE, ct1, ct2, flags, cmp_sctp_state, true))
    458 		return 0;
    459 	if (!__cmp(ATTR_DCCP_STATE, ct1, ct2, flags, cmp_dccp_state, true))
    460 		return 0;
    461 	if (!__cmp(ATTR_ZONE, ct1, ct2, flags, cmp_zone, false))
    462 		return 0;
    463 	if (!__cmp(ATTR_SECCTX, ct1, ct2, flags, cmp_secctx, true))
    464 		return 0;
    465 	if (!__cmp(ATTR_CONNLABELS, ct1, ct2, flags, cmp_clabel, true))
    466 		return 0;
    467 	if (!__cmp(ATTR_CONNLABELS_MASK, ct1, ct2, flags, cmp_clabel_mask, true))
    468 		return 0;
    469 
    470 	return 1;
    471 }
    472 
    473 int __compare(const struct nf_conntrack *ct1,
    474 	      const struct nf_conntrack *ct2,
    475 	      unsigned int flags)
    476 {
    477 	if ((flags & ~(NFCT_CMP_MASK|NFCT_CMP_STRICT)) == NFCT_CMP_ALL)
    478 		return cmp_meta(ct1, ct2, flags) &&
    479 		       __cmp_orig(ct1, ct2, flags) &&
    480 		       cmp_repl(ct1, ct2, flags);
    481 
    482 	if (flags & NFCT_CMP_ORIG && !__cmp_orig(ct1, ct2, flags))
    483 		return 0;
    484 
    485 	if (flags & NFCT_CMP_REPL && !cmp_repl(ct1, ct2, flags))
    486 		return 0;
    487 
    488 	return 1;
    489 }
    490