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