1 /* 2 * lib/netfilter/exp_obj.c Conntrack Expectation 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 * Copyright (c) 2012 Rich Fought <rich.fought (at) watchguard.com> 13 */ 14 15 #include <sys/types.h> 16 #include <netinet/in.h> 17 #include <linux/netfilter/nfnetlink_conntrack.h> 18 #include <linux/netfilter/nf_conntrack_common.h> 19 #include <linux/netfilter/nf_conntrack_tcp.h> 20 21 #include <netlink-private/netlink.h> 22 #include <netlink/netfilter/nfnl.h> 23 #include <netlink/netfilter/exp.h> 24 25 // The 32-bit attribute mask in the common object header isn't 26 // big enough to handle all attributes of an expectation. So 27 // we'll for sure specify optional attributes + parent attributes 28 // that are required for valid object comparison. Comparison of 29 // these parent attributes will include nested attributes. 30 31 /** @cond SKIP */ 32 #define EXP_ATTR_FAMILY (1UL << 0) // 8-bit 33 #define EXP_ATTR_TIMEOUT (1UL << 1) // 32-bit 34 #define EXP_ATTR_ID (1UL << 2) // 32-bit 35 #define EXP_ATTR_HELPER_NAME (1UL << 3) // string 36 #define EXP_ATTR_ZONE (1UL << 4) // 16-bit 37 #define EXP_ATTR_FLAGS (1UL << 5) // 32-bit 38 #define EXP_ATTR_CLASS (1UL << 6) // 32-bit 39 #define EXP_ATTR_FN (1UL << 7) // String 40 // Tuples 41 #define EXP_ATTR_EXPECT_IP_SRC (1UL << 8) 42 #define EXP_ATTR_EXPECT_IP_DST (1UL << 9) 43 #define EXP_ATTR_EXPECT_L4PROTO_NUM (1UL << 10) 44 #define EXP_ATTR_EXPECT_L4PROTO_PORTS (1UL << 11) 45 #define EXP_ATTR_EXPECT_L4PROTO_ICMP (1UL << 12) 46 #define EXP_ATTR_MASTER_IP_SRC (1UL << 13) 47 #define EXP_ATTR_MASTER_IP_DST (1UL << 14) 48 #define EXP_ATTR_MASTER_L4PROTO_NUM (1UL << 15) 49 #define EXP_ATTR_MASTER_L4PROTO_PORTS (1UL << 16) 50 #define EXP_ATTR_MASTER_L4PROTO_ICMP (1UL << 17) 51 #define EXP_ATTR_MASK_IP_SRC (1UL << 18) 52 #define EXP_ATTR_MASK_IP_DST (1UL << 19) 53 #define EXP_ATTR_MASK_L4PROTO_NUM (1UL << 20) 54 #define EXP_ATTR_MASK_L4PROTO_PORTS (1UL << 21) 55 #define EXP_ATTR_MASK_L4PROTO_ICMP (1UL << 22) 56 #define EXP_ATTR_NAT_IP_SRC (1UL << 23) 57 #define EXP_ATTR_NAT_IP_DST (1UL << 24) 58 #define EXP_ATTR_NAT_L4PROTO_NUM (1UL << 25) 59 #define EXP_ATTR_NAT_L4PROTO_PORTS (1UL << 26) 60 #define EXP_ATTR_NAT_L4PROTO_ICMP (1UL << 27) 61 #define EXP_ATTR_NAT_DIR (1UL << 28) 62 /** @endcond */ 63 64 static void exp_free_data(struct nl_object *c) 65 { 66 struct nfnl_exp *exp = (struct nfnl_exp *) c; 67 68 if (exp == NULL) 69 return; 70 71 nl_addr_put(exp->exp_expect.src); 72 nl_addr_put(exp->exp_expect.dst); 73 nl_addr_put(exp->exp_master.src); 74 nl_addr_put(exp->exp_master.dst); 75 nl_addr_put(exp->exp_mask.src); 76 nl_addr_put(exp->exp_mask.dst); 77 nl_addr_put(exp->exp_nat.src); 78 nl_addr_put(exp->exp_nat.dst); 79 80 free(exp->exp_fn); 81 free(exp->exp_helper_name); 82 } 83 84 static int exp_clone(struct nl_object *_dst, struct nl_object *_src) 85 { 86 struct nfnl_exp *dst = (struct nfnl_exp *) _dst; 87 struct nfnl_exp *src = (struct nfnl_exp *) _src; 88 struct nl_addr *addr; 89 90 // Expectation 91 if (src->exp_expect.src) { 92 addr = nl_addr_clone(src->exp_expect.src); 93 if (!addr) 94 return -NLE_NOMEM; 95 dst->exp_expect.src = addr; 96 } 97 98 if (src->exp_expect.dst) { 99 addr = nl_addr_clone(src->exp_expect.dst); 100 if (!addr) 101 return -NLE_NOMEM; 102 dst->exp_expect.dst = addr; 103 } 104 105 // Master CT 106 if (src->exp_master.src) { 107 addr = nl_addr_clone(src->exp_master.src); 108 if (!addr) 109 return -NLE_NOMEM; 110 dst->exp_master.src = addr; 111 } 112 113 if (src->exp_master.dst) { 114 addr = nl_addr_clone(src->exp_master.dst); 115 if (!addr) 116 return -NLE_NOMEM; 117 dst->exp_master.dst = addr; 118 } 119 120 // Mask 121 if (src->exp_mask.src) { 122 addr = nl_addr_clone(src->exp_mask.src); 123 if (!addr) 124 return -NLE_NOMEM; 125 dst->exp_mask.src = addr; 126 } 127 128 if (src->exp_mask.dst) { 129 addr = nl_addr_clone(src->exp_mask.dst); 130 if (!addr) 131 return -NLE_NOMEM; 132 dst->exp_mask.dst = addr; 133 } 134 135 // NAT 136 if (src->exp_nat.src) { 137 addr = nl_addr_clone(src->exp_nat.src); 138 if (!addr) 139 return -NLE_NOMEM; 140 dst->exp_nat.src = addr; 141 } 142 143 if (src->exp_nat.dst) { 144 addr = nl_addr_clone(src->exp_nat.dst); 145 if (!addr) 146 return -NLE_NOMEM; 147 dst->exp_nat.dst = addr; 148 } 149 150 if (src->exp_fn) 151 dst->exp_fn = strdup(src->exp_fn); 152 153 if (src->exp_helper_name) 154 dst->exp_helper_name = strdup(src->exp_helper_name); 155 156 return 0; 157 } 158 159 static void dump_addr(struct nl_dump_params *p, struct nl_addr *addr, int port) 160 { 161 char buf[64]; 162 163 if (addr) 164 nl_dump(p, "%s", nl_addr2str(addr, buf, sizeof(buf))); 165 166 if (port) 167 nl_dump(p, ":%u ", port); 168 else if (addr) 169 nl_dump(p, " "); 170 } 171 172 static void dump_icmp(struct nl_dump_params *p, struct nfnl_exp *exp, int tuple) 173 { 174 if (nfnl_exp_test_icmp(exp, tuple)) { 175 176 nl_dump(p, "icmp type %d ", nfnl_exp_get_icmp_type(exp, tuple)); 177 178 nl_dump(p, "code %d ", nfnl_exp_get_icmp_code(exp, tuple)); 179 180 nl_dump(p, "id %d ", nfnl_exp_get_icmp_id(exp, tuple)); 181 } 182 } 183 184 static void exp_dump_tuples(struct nfnl_exp *exp, struct nl_dump_params *p) 185 { 186 struct nl_addr *tuple_src, *tuple_dst; 187 int tuple_sport, tuple_dport; 188 int i = 0; 189 char buf[64]; 190 191 for (i = NFNL_EXP_TUPLE_EXPECT; i < NFNL_EXP_TUPLE_MAX; i++) { 192 tuple_src = NULL; 193 tuple_dst = NULL; 194 tuple_sport = 0; 195 tuple_dport = 0; 196 197 // Test needed for NAT case 198 if (nfnl_exp_test_src(exp, i)) 199 tuple_src = nfnl_exp_get_src(exp, i); 200 if (nfnl_exp_test_dst(exp, i)) 201 tuple_dst = nfnl_exp_get_dst(exp, i); 202 203 // Don't have tests for individual ports/types/codes/ids, 204 if (nfnl_exp_test_l4protonum(exp, i)) { 205 nl_dump(p, "%s ", 206 nl_ip_proto2str(nfnl_exp_get_l4protonum(exp, i), buf, sizeof(buf))); 207 } 208 209 if (nfnl_exp_test_ports(exp, i)) { 210 tuple_sport = nfnl_exp_get_src_port(exp, i); 211 tuple_dport = nfnl_exp_get_dst_port(exp, i); 212 } 213 214 dump_addr(p, tuple_src, tuple_sport); 215 dump_addr(p, tuple_dst, tuple_dport); 216 dump_icmp(p, exp, 0); 217 } 218 219 if (nfnl_exp_test_nat_dir(exp)) 220 nl_dump(p, "nat dir %s ", exp->exp_nat_dir); 221 222 } 223 224 /* FIXME Compatible with /proc/net/nf_conntrack */ 225 static void exp_dump_line(struct nl_object *a, struct nl_dump_params *p) 226 { 227 struct nfnl_exp *exp = (struct nfnl_exp *) a; 228 229 nl_new_line(p); 230 231 exp_dump_tuples(exp, p); 232 233 nl_dump(p, "\n"); 234 } 235 236 static void exp_dump_details(struct nl_object *a, struct nl_dump_params *p) 237 { 238 struct nfnl_exp *exp = (struct nfnl_exp *) a; 239 char buf[64]; 240 int fp = 0; 241 242 exp_dump_line(a, p); 243 244 nl_dump(p, " id 0x%x ", exp->exp_id); 245 nl_dump_line(p, "family %s ", 246 nl_af2str(exp->exp_family, buf, sizeof(buf))); 247 248 if (nfnl_exp_test_timeout(exp)) { 249 uint64_t timeout_ms = nfnl_exp_get_timeout(exp) * 1000UL; 250 nl_dump(p, "timeout %s ", 251 nl_msec2str(timeout_ms, buf, sizeof(buf))); 252 } 253 254 if (nfnl_exp_test_helper_name(exp)) 255 nl_dump(p, "helper %s ", exp->exp_helper_name); 256 257 if (nfnl_exp_test_fn(exp)) 258 nl_dump(p, "fn %s ", exp->exp_fn); 259 260 if (nfnl_exp_test_class(exp)) 261 nl_dump(p, "class %u ", nfnl_exp_get_class(exp)); 262 263 if (nfnl_exp_test_zone(exp)) 264 nl_dump(p, "zone %u ", nfnl_exp_get_zone(exp)); 265 266 if (nfnl_exp_test_flags(exp)) 267 nl_dump(p, "<"); 268 #define PRINT_FLAG(str) \ 269 { nl_dump(p, "%s%s", fp++ ? "," : "", (str)); } 270 271 if (exp->exp_flags & NF_CT_EXPECT_PERMANENT) 272 PRINT_FLAG("PERMANENT"); 273 if (exp->exp_flags & NF_CT_EXPECT_INACTIVE) 274 PRINT_FLAG("INACTIVE"); 275 if (exp->exp_flags & NF_CT_EXPECT_USERSPACE) 276 PRINT_FLAG("USERSPACE"); 277 #undef PRINT_FLAG 278 279 if (nfnl_exp_test_flags(exp)) 280 nl_dump(p, ">"); 281 282 nl_dump(p, "\n"); 283 } 284 285 static int exp_cmp_l4proto_ports (union nfnl_exp_protodata *a, union nfnl_exp_protodata *b) { 286 // Must return 0 for match, 1 for mismatch 287 int d = 0; 288 d = ( (a->port.src != b->port.src) || 289 (a->port.dst != b->port.dst) ); 290 291 return d; 292 } 293 294 static int exp_cmp_l4proto_icmp (union nfnl_exp_protodata *a, union nfnl_exp_protodata *b) { 295 // Must return 0 for match, 1 for mismatch 296 int d = 0; 297 d = ( (a->icmp.code != b->icmp.code) || 298 (a->icmp.type != b->icmp.type) || 299 (a->icmp.id != b->icmp.id) ); 300 301 return d; 302 } 303 304 static int exp_compare(struct nl_object *_a, struct nl_object *_b, 305 uint32_t attrs, int flags) 306 { 307 struct nfnl_exp *a = (struct nfnl_exp *) _a; 308 struct nfnl_exp *b = (struct nfnl_exp *) _b; 309 int diff = 0; 310 311 #define EXP_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, EXP_ATTR_##ATTR, a, b, EXPR) 312 #define EXP_DIFF_VAL(ATTR, FIELD) EXP_DIFF(ATTR, a->FIELD != b->FIELD) 313 #define EXP_DIFF_STRING(ATTR, FIELD) EXP_DIFF(ATTR, (strcmp(a->FIELD, b->FIELD) != 0)) 314 #define EXP_DIFF_ADDR(ATTR, FIELD) \ 315 ((flags & LOOSE_COMPARISON) \ 316 ? EXP_DIFF(ATTR, nl_addr_cmp_prefix(a->FIELD, b->FIELD)) \ 317 : EXP_DIFF(ATTR, nl_addr_cmp(a->FIELD, b->FIELD))) 318 #define EXP_DIFF_L4PROTO_PORTS(ATTR, FIELD) \ 319 EXP_DIFF(ATTR, exp_cmp_l4proto_ports(&(a->FIELD), &(b->FIELD))) 320 #define EXP_DIFF_L4PROTO_ICMP(ATTR, FIELD) \ 321 EXP_DIFF(ATTR, exp_cmp_l4proto_icmp(&(a->FIELD), &(b->FIELD))) 322 323 diff |= EXP_DIFF_VAL(FAMILY, exp_family); 324 diff |= EXP_DIFF_VAL(TIMEOUT, exp_timeout); 325 diff |= EXP_DIFF_VAL(ID, exp_id); 326 diff |= EXP_DIFF_VAL(ZONE, exp_zone); 327 diff |= EXP_DIFF_VAL(CLASS, exp_class); 328 diff |= EXP_DIFF_VAL(FLAGS, exp_flags); 329 diff |= EXP_DIFF_VAL(NAT_DIR, exp_nat_dir); 330 331 diff |= EXP_DIFF_STRING(FN, exp_fn); 332 diff |= EXP_DIFF_STRING(HELPER_NAME, exp_helper_name); 333 334 diff |= EXP_DIFF_ADDR(EXPECT_IP_SRC, exp_expect.src); 335 diff |= EXP_DIFF_ADDR(EXPECT_IP_DST, exp_expect.dst); 336 diff |= EXP_DIFF_VAL(EXPECT_L4PROTO_NUM, exp_expect.proto.l4protonum); 337 diff |= EXP_DIFF_L4PROTO_PORTS(EXPECT_L4PROTO_PORTS, exp_expect.proto.l4protodata); 338 diff |= EXP_DIFF_L4PROTO_ICMP(EXPECT_L4PROTO_ICMP, exp_expect.proto.l4protodata); 339 340 diff |= EXP_DIFF_ADDR(MASTER_IP_SRC, exp_master.src); 341 diff |= EXP_DIFF_ADDR(MASTER_IP_DST, exp_master.dst); 342 diff |= EXP_DIFF_VAL(MASTER_L4PROTO_NUM, exp_master.proto.l4protonum); 343 diff |= EXP_DIFF_L4PROTO_PORTS(MASTER_L4PROTO_PORTS, exp_master.proto.l4protodata); 344 diff |= EXP_DIFF_L4PROTO_ICMP(MASTER_L4PROTO_ICMP, exp_master.proto.l4protodata); 345 346 diff |= EXP_DIFF_ADDR(MASK_IP_SRC, exp_mask.src); 347 diff |= EXP_DIFF_ADDR(MASK_IP_DST, exp_mask.dst); 348 diff |= EXP_DIFF_VAL(MASK_L4PROTO_NUM, exp_mask.proto.l4protonum); 349 diff |= EXP_DIFF_L4PROTO_PORTS(MASK_L4PROTO_PORTS, exp_mask.proto.l4protodata); 350 diff |= EXP_DIFF_L4PROTO_ICMP(MASK_L4PROTO_ICMP, exp_mask.proto.l4protodata); 351 352 diff |= EXP_DIFF_ADDR(NAT_IP_SRC, exp_nat.src); 353 diff |= EXP_DIFF_ADDR(NAT_IP_DST, exp_nat.dst); 354 diff |= EXP_DIFF_VAL(NAT_L4PROTO_NUM, exp_nat.proto.l4protonum); 355 diff |= EXP_DIFF_L4PROTO_PORTS(NAT_L4PROTO_PORTS, exp_nat.proto.l4protodata); 356 diff |= EXP_DIFF_L4PROTO_ICMP(NAT_L4PROTO_ICMP, exp_nat.proto.l4protodata); 357 358 #undef EXP_DIFF 359 #undef EXP_DIFF_VAL 360 #undef EXP_DIFF_STRING 361 #undef EXP_DIFF_ADDR 362 #undef EXP_DIFF_L4PROTO_PORTS 363 #undef EXP_DIFF_L4PROTO_ICMP 364 365 return diff; 366 } 367 368 // CLI arguments? 369 static const struct trans_tbl exp_attrs[] = { 370 __ADD(EXP_ATTR_FAMILY, family) 371 __ADD(EXP_ATTR_TIMEOUT, timeout) 372 __ADD(EXP_ATTR_ID, id) 373 __ADD(EXP_ATTR_HELPER_NAME, helpername) 374 __ADD(EXP_ATTR_ZONE, zone) 375 __ADD(EXP_ATTR_CLASS, class) 376 __ADD(EXP_ATTR_FLAGS, flags) 377 __ADD(EXP_ATTR_FN, function) 378 __ADD(EXP_ATTR_EXPECT_IP_SRC, expectipsrc) 379 __ADD(EXP_ATTR_EXPECT_IP_DST, expectipdst) 380 __ADD(EXP_ATTR_EXPECT_L4PROTO_NUM, expectprotonum) 381 __ADD(EXP_ATTR_EXPECT_L4PROTO_PORTS, expectports) 382 __ADD(EXP_ATTR_EXPECT_L4PROTO_ICMP, expecticmp) 383 __ADD(EXP_ATTR_MASTER_IP_SRC, masteripsrc) 384 __ADD(EXP_ATTR_MASTER_IP_DST, masteripdst) 385 __ADD(EXP_ATTR_MASTER_L4PROTO_NUM, masterprotonum) 386 __ADD(EXP_ATTR_MASTER_L4PROTO_PORTS, masterports) 387 __ADD(EXP_ATTR_MASTER_L4PROTO_ICMP, mastericmp) 388 __ADD(EXP_ATTR_MASK_IP_SRC, maskipsrc) 389 __ADD(EXP_ATTR_MASK_IP_DST, maskipdst) 390 __ADD(EXP_ATTR_MASK_L4PROTO_NUM, maskprotonum) 391 __ADD(EXP_ATTR_MASK_L4PROTO_PORTS, maskports) 392 __ADD(EXP_ATTR_MASK_L4PROTO_ICMP, maskicmp) 393 __ADD(EXP_ATTR_NAT_IP_SRC, natipsrc) 394 __ADD(EXP_ATTR_NAT_IP_DST, natipdst) 395 __ADD(EXP_ATTR_NAT_L4PROTO_NUM, natprotonum) 396 __ADD(EXP_ATTR_NAT_L4PROTO_PORTS, natports) 397 __ADD(EXP_ATTR_NAT_L4PROTO_ICMP, naticmp) 398 __ADD(EXP_ATTR_NAT_DIR, natdir) 399 }; 400 401 static char *exp_attrs2str(int attrs, char *buf, size_t len) 402 { 403 return __flags2str(attrs, buf, len, exp_attrs, ARRAY_SIZE(exp_attrs)); 404 } 405 406 /** 407 * @name Allocation/Freeing 408 * @{ 409 */ 410 411 struct nfnl_exp *nfnl_exp_alloc(void) 412 { 413 return (struct nfnl_exp *) nl_object_alloc(&exp_obj_ops); 414 } 415 416 void nfnl_exp_get(struct nfnl_exp *exp) 417 { 418 nl_object_get((struct nl_object *) exp); 419 } 420 421 void nfnl_exp_put(struct nfnl_exp *exp) 422 { 423 nl_object_put((struct nl_object *) exp); 424 } 425 426 /** @} */ 427 428 /** 429 * @name Attributes 430 * @{ 431 */ 432 433 void nfnl_exp_set_family(struct nfnl_exp *exp, uint8_t family) 434 { 435 exp->exp_family = family; 436 exp->ce_mask |= EXP_ATTR_FAMILY; 437 } 438 439 uint8_t nfnl_exp_get_family(const struct nfnl_exp *exp) 440 { 441 if (exp->ce_mask & EXP_ATTR_FAMILY) 442 return exp->exp_family; 443 else 444 return AF_UNSPEC; 445 } 446 447 void nfnl_exp_set_flags(struct nfnl_exp *exp, uint32_t flags) 448 { 449 exp->exp_flags |= flags; 450 exp->ce_mask |= EXP_ATTR_FLAGS; 451 } 452 453 int nfnl_exp_test_flags(const struct nfnl_exp *exp) 454 { 455 return !!(exp->ce_mask & EXP_ATTR_FLAGS); 456 } 457 458 void nfnl_exp_unset_flags(struct nfnl_exp *exp, uint32_t flags) 459 { 460 exp->exp_flags &= ~flags; 461 exp->ce_mask |= EXP_ATTR_FLAGS; 462 } 463 464 uint32_t nfnl_exp_get_flags(const struct nfnl_exp *exp) 465 { 466 return exp->exp_flags; 467 } 468 469 static const struct trans_tbl flag_table[] = { 470 __ADD(IPS_EXPECTED, expected) 471 __ADD(IPS_SEEN_REPLY, seen_reply) 472 __ADD(IPS_ASSURED, assured) 473 }; 474 475 char * nfnl_exp_flags2str(int flags, char *buf, size_t len) 476 { 477 return __flags2str(flags, buf, len, flag_table, 478 ARRAY_SIZE(flag_table)); 479 } 480 481 int nfnl_exp_str2flags(const char *name) 482 { 483 return __str2flags(name, flag_table, ARRAY_SIZE(flag_table)); 484 } 485 486 void nfnl_exp_set_timeout(struct nfnl_exp *exp, uint32_t timeout) 487 { 488 exp->exp_timeout = timeout; 489 exp->ce_mask |= EXP_ATTR_TIMEOUT; 490 } 491 492 int nfnl_exp_test_timeout(const struct nfnl_exp *exp) 493 { 494 return !!(exp->ce_mask & EXP_ATTR_TIMEOUT); 495 } 496 497 uint32_t nfnl_exp_get_timeout(const struct nfnl_exp *exp) 498 { 499 return exp->exp_timeout; 500 } 501 502 void nfnl_exp_set_id(struct nfnl_exp *exp, uint32_t id) 503 { 504 exp->exp_id = id; 505 exp->ce_mask |= EXP_ATTR_ID; 506 } 507 508 int nfnl_exp_test_id(const struct nfnl_exp *exp) 509 { 510 return !!(exp->ce_mask & EXP_ATTR_ID); 511 } 512 513 uint32_t nfnl_exp_get_id(const struct nfnl_exp *exp) 514 { 515 return exp->exp_id; 516 } 517 518 int nfnl_exp_set_helper_name(struct nfnl_exp *exp, void *name) 519 { 520 free(exp->exp_helper_name); 521 exp->exp_helper_name = strdup(name); 522 if (!exp->exp_helper_name) 523 return -NLE_NOMEM; 524 525 exp->ce_mask |= EXP_ATTR_HELPER_NAME; 526 return 0; 527 } 528 529 int nfnl_exp_test_helper_name(const struct nfnl_exp *exp) 530 { 531 return !!(exp->ce_mask & EXP_ATTR_HELPER_NAME); 532 } 533 534 const char * nfnl_exp_get_helper_name(const struct nfnl_exp *exp) 535 { 536 return exp->exp_helper_name; 537 } 538 539 void nfnl_exp_set_zone(struct nfnl_exp *exp, uint16_t zone) 540 { 541 exp->exp_zone = zone; 542 exp->ce_mask |= EXP_ATTR_ZONE; 543 } 544 545 int nfnl_exp_test_zone(const struct nfnl_exp *exp) 546 { 547 return !!(exp->ce_mask & EXP_ATTR_ZONE); 548 } 549 550 uint16_t nfnl_exp_get_zone(const struct nfnl_exp *exp) 551 { 552 return exp->exp_zone; 553 } 554 555 void nfnl_exp_set_class(struct nfnl_exp *exp, uint32_t class) 556 { 557 exp->exp_class = class; 558 exp->ce_mask |= EXP_ATTR_CLASS; 559 } 560 561 int nfnl_exp_test_class(const struct nfnl_exp *exp) 562 { 563 return !!(exp->ce_mask & EXP_ATTR_CLASS); 564 } 565 566 uint32_t nfnl_exp_get_class(const struct nfnl_exp *exp) 567 { 568 return exp->exp_class; 569 } 570 571 int nfnl_exp_set_fn(struct nfnl_exp *exp, void *fn) 572 { 573 free(exp->exp_fn); 574 exp->exp_fn = strdup(fn); 575 if (!exp->exp_fn) 576 return -NLE_NOMEM; 577 578 exp->ce_mask |= EXP_ATTR_FN; 579 return 0; 580 } 581 582 int nfnl_exp_test_fn(const struct nfnl_exp *exp) 583 { 584 return !!(exp->ce_mask & EXP_ATTR_FN); 585 } 586 587 const char * nfnl_exp_get_fn(const struct nfnl_exp *exp) 588 { 589 return exp->exp_fn; 590 } 591 592 void nfnl_exp_set_nat_dir(struct nfnl_exp *exp, uint8_t nat_dir) 593 { 594 exp->exp_nat_dir = nat_dir; 595 exp->ce_mask |= EXP_ATTR_NAT_DIR; 596 } 597 598 int nfnl_exp_test_nat_dir(const struct nfnl_exp *exp) 599 { 600 return !!(exp->ce_mask & EXP_ATTR_NAT_DIR); 601 } 602 603 uint8_t nfnl_exp_get_nat_dir(const struct nfnl_exp *exp) 604 { 605 return exp->exp_nat_dir; 606 } 607 608 #define EXP_GET_TUPLE(e, t) \ 609 (t == NFNL_EXP_TUPLE_MASTER) ? \ 610 &(e->exp_master) : \ 611 (t == NFNL_EXP_TUPLE_MASK) ? \ 612 &(e->exp_mask) : \ 613 (t == NFNL_EXP_TUPLE_NAT) ? \ 614 &(e->exp_nat) : &(exp->exp_expect) 615 616 static int exp_get_src_attr(int tuple) 617 { 618 int attr = 0; 619 620 switch (tuple) { 621 case NFNL_EXP_TUPLE_MASTER: 622 attr = EXP_ATTR_MASTER_IP_SRC; 623 break; 624 case NFNL_EXP_TUPLE_MASK: 625 attr = EXP_ATTR_MASK_IP_SRC; 626 break; 627 case NFNL_EXP_TUPLE_NAT: 628 attr = EXP_ATTR_NAT_IP_SRC; 629 break; 630 case NFNL_EXP_TUPLE_EXPECT: 631 default : 632 attr = EXP_ATTR_EXPECT_IP_SRC; 633 } 634 635 return attr; 636 } 637 638 static int exp_get_dst_attr(int tuple) 639 { 640 int attr = 0; 641 642 switch (tuple) { 643 case NFNL_EXP_TUPLE_MASTER: 644 attr = EXP_ATTR_MASTER_IP_DST; 645 break; 646 case NFNL_EXP_TUPLE_MASK: 647 attr = EXP_ATTR_MASK_IP_DST; 648 break; 649 case NFNL_EXP_TUPLE_NAT: 650 attr = EXP_ATTR_NAT_IP_DST; 651 break; 652 case NFNL_EXP_TUPLE_EXPECT: 653 default : 654 attr = EXP_ATTR_EXPECT_IP_DST; 655 } 656 657 return attr; 658 } 659 660 661 static int exp_set_addr(struct nfnl_exp *exp, struct nl_addr *addr, 662 int attr, struct nl_addr ** exp_addr) 663 { 664 if (exp->ce_mask & EXP_ATTR_FAMILY) { 665 if (addr->a_family != exp->exp_family) 666 return -NLE_AF_MISMATCH; 667 } else 668 nfnl_exp_set_family(exp, addr->a_family); 669 670 if (*exp_addr) 671 nl_addr_put(*exp_addr); 672 673 nl_addr_get(addr); 674 *exp_addr = addr; 675 exp->ce_mask |= attr; 676 677 return 0; 678 } 679 680 int nfnl_exp_set_src(struct nfnl_exp *exp, int tuple, struct nl_addr *addr) 681 { 682 struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 683 684 return exp_set_addr(exp, addr, exp_get_src_attr(tuple), &dir->src); 685 } 686 687 int nfnl_exp_set_dst(struct nfnl_exp *exp, int tuple, struct nl_addr *addr) 688 { 689 struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 690 691 return exp_set_addr(exp, addr, exp_get_dst_attr(tuple), &dir->dst); 692 } 693 694 int nfnl_exp_test_src(const struct nfnl_exp *exp, int tuple) 695 { 696 return !!(exp->ce_mask & exp_get_src_attr(tuple)); 697 } 698 699 int nfnl_exp_test_dst(const struct nfnl_exp *exp, int tuple) 700 { 701 return !!(exp->ce_mask & exp_get_dst_attr(tuple)); 702 } 703 704 struct nl_addr *nfnl_exp_get_src(const struct nfnl_exp *exp, int tuple) 705 { 706 const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 707 708 if (!(exp->ce_mask & exp_get_src_attr(tuple))) 709 return NULL; 710 return dir->src; 711 } 712 713 struct nl_addr *nfnl_exp_get_dst(const struct nfnl_exp *exp, int tuple) 714 { 715 const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 716 717 if (!(exp->ce_mask & exp_get_dst_attr(tuple))) 718 return NULL; 719 return dir->dst; 720 } 721 722 static int exp_get_l4protonum_attr(int tuple) 723 { 724 int attr = 0; 725 726 switch (tuple) { 727 case NFNL_EXP_TUPLE_MASTER: 728 attr = EXP_ATTR_MASTER_L4PROTO_NUM; 729 break; 730 case NFNL_EXP_TUPLE_MASK: 731 attr = EXP_ATTR_MASK_L4PROTO_NUM; 732 break; 733 case NFNL_EXP_TUPLE_NAT: 734 attr = EXP_ATTR_NAT_L4PROTO_NUM; 735 break; 736 case NFNL_EXP_TUPLE_EXPECT: 737 default : 738 attr = EXP_ATTR_EXPECT_L4PROTO_NUM; 739 } 740 741 return attr; 742 } 743 744 void nfnl_exp_set_l4protonum(struct nfnl_exp *exp, int tuple, uint8_t l4protonum) 745 { 746 struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 747 748 dir->proto.l4protonum = l4protonum; 749 exp->ce_mask |= exp_get_l4protonum_attr(tuple); 750 } 751 752 int nfnl_exp_test_l4protonum(const struct nfnl_exp *exp, int tuple) 753 { 754 return !!(exp->ce_mask & exp_get_l4protonum_attr(tuple)); 755 } 756 757 uint8_t nfnl_exp_get_l4protonum(const struct nfnl_exp *exp, int tuple) 758 { 759 const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 760 return dir->proto.l4protonum; 761 } 762 763 static int exp_get_l4ports_attr(int tuple) 764 { 765 int attr = 0; 766 767 switch (tuple) { 768 case NFNL_EXP_TUPLE_MASTER: 769 attr = EXP_ATTR_MASTER_L4PROTO_PORTS; 770 break; 771 case NFNL_EXP_TUPLE_MASK: 772 attr = EXP_ATTR_MASK_L4PROTO_PORTS; 773 break; 774 case NFNL_EXP_TUPLE_NAT: 775 attr = EXP_ATTR_NAT_L4PROTO_PORTS; 776 break; 777 case NFNL_EXP_TUPLE_EXPECT: 778 default : 779 attr = EXP_ATTR_EXPECT_L4PROTO_PORTS; 780 } 781 782 return attr; 783 } 784 785 void nfnl_exp_set_ports(struct nfnl_exp *exp, int tuple, uint16_t srcport, uint16_t dstport) 786 { 787 struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 788 789 dir->proto.l4protodata.port.src = srcport; 790 dir->proto.l4protodata.port.dst = dstport; 791 792 exp->ce_mask |= exp_get_l4ports_attr(tuple); 793 } 794 795 int nfnl_exp_test_ports(const struct nfnl_exp *exp, int tuple) 796 { 797 return !!(exp->ce_mask & exp_get_l4ports_attr(tuple)); 798 } 799 800 uint16_t nfnl_exp_get_src_port(const struct nfnl_exp *exp, int tuple) 801 { 802 const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 803 return dir->proto.l4protodata.port.src; 804 } 805 806 uint16_t nfnl_exp_get_dst_port(const struct nfnl_exp *exp, int tuple) 807 { 808 const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 809 810 return dir->proto.l4protodata.port.dst; 811 } 812 813 static int exp_get_l4icmp_attr(int tuple) 814 { 815 int attr = 0; 816 817 switch (tuple) { 818 case NFNL_EXP_TUPLE_MASTER: 819 attr = EXP_ATTR_MASTER_L4PROTO_ICMP; 820 break; 821 case NFNL_EXP_TUPLE_MASK: 822 attr = EXP_ATTR_MASK_L4PROTO_ICMP; 823 break; 824 case NFNL_EXP_TUPLE_NAT: 825 attr = EXP_ATTR_NAT_L4PROTO_ICMP; 826 break; 827 case NFNL_EXP_TUPLE_EXPECT: 828 default : 829 attr = EXP_ATTR_EXPECT_L4PROTO_ICMP; 830 } 831 832 return attr; 833 } 834 835 void nfnl_exp_set_icmp(struct nfnl_exp *exp, int tuple, uint16_t id, uint8_t type, uint8_t code) 836 { 837 struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 838 839 dir->proto.l4protodata.icmp.id = id; 840 dir->proto.l4protodata.icmp.type = type; 841 dir->proto.l4protodata.icmp.code = code; 842 843 exp->ce_mask |= exp_get_l4icmp_attr(tuple); 844 } 845 846 int nfnl_exp_test_icmp(const struct nfnl_exp *exp, int tuple) 847 { 848 int attr = exp_get_l4icmp_attr(tuple); 849 return !!(exp->ce_mask & attr); 850 } 851 852 uint16_t nfnl_exp_get_icmp_id(const struct nfnl_exp *exp, int tuple) 853 { 854 const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 855 856 return dir->proto.l4protodata.icmp.id; 857 } 858 859 uint8_t nfnl_exp_get_icmp_type(const struct nfnl_exp *exp, int tuple) 860 { 861 const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 862 863 return dir->proto.l4protodata.icmp.type; 864 } 865 866 uint8_t nfnl_exp_get_icmp_code(const struct nfnl_exp *exp, int tuple) 867 { 868 const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple); 869 870 return dir->proto.l4protodata.icmp.code; 871 } 872 873 /** @} */ 874 875 struct nl_object_ops exp_obj_ops = { 876 .oo_name = "netfilter/exp", 877 .oo_size = sizeof(struct nfnl_exp), 878 .oo_free_data = exp_free_data, 879 .oo_clone = exp_clone, 880 .oo_dump = { 881 [NL_DUMP_LINE] = exp_dump_line, 882 [NL_DUMP_DETAILS] = exp_dump_details, 883 }, 884 .oo_compare = exp_compare, 885 .oo_attrs2str = exp_attrs2str, 886 }; 887 888 /** @} */ 889