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@suug.ch> 10 * Copyright (c) 2007 Philip Craig <philipc@snapgear.com> 11 * Copyright (c) 2007 Secure Computing Corporation 12 * Copyright (c) 2012 Rich Fought <rich.fought@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 64static 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 84static 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 159static 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 172static 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 184static 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 */ 225static 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 236static 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 285static 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 294static 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 304static 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? 369static 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 401static 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 411struct nfnl_exp *nfnl_exp_alloc(void) 412{ 413 return (struct nfnl_exp *) nl_object_alloc(&exp_obj_ops); 414} 415 416void nfnl_exp_get(struct nfnl_exp *exp) 417{ 418 nl_object_get((struct nl_object *) exp); 419} 420 421void 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 433void 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 439uint8_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 447void 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 453int nfnl_exp_test_flags(const struct nfnl_exp *exp) 454{ 455 return !!(exp->ce_mask & EXP_ATTR_FLAGS); 456} 457 458void 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 464uint32_t nfnl_exp_get_flags(const struct nfnl_exp *exp) 465{ 466 return exp->exp_flags; 467} 468 469static 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 475char * 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 481int nfnl_exp_str2flags(const char *name) 482{ 483 return __str2flags(name, flag_table, ARRAY_SIZE(flag_table)); 484} 485 486void 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 492int nfnl_exp_test_timeout(const struct nfnl_exp *exp) 493{ 494 return !!(exp->ce_mask & EXP_ATTR_TIMEOUT); 495} 496 497uint32_t nfnl_exp_get_timeout(const struct nfnl_exp *exp) 498{ 499 return exp->exp_timeout; 500} 501 502void 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 508int nfnl_exp_test_id(const struct nfnl_exp *exp) 509{ 510 return !!(exp->ce_mask & EXP_ATTR_ID); 511} 512 513uint32_t nfnl_exp_get_id(const struct nfnl_exp *exp) 514{ 515 return exp->exp_id; 516} 517 518int 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 529int nfnl_exp_test_helper_name(const struct nfnl_exp *exp) 530{ 531 return !!(exp->ce_mask & EXP_ATTR_HELPER_NAME); 532} 533 534const char * nfnl_exp_get_helper_name(const struct nfnl_exp *exp) 535{ 536 return exp->exp_helper_name; 537} 538 539void 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 545int nfnl_exp_test_zone(const struct nfnl_exp *exp) 546{ 547 return !!(exp->ce_mask & EXP_ATTR_ZONE); 548} 549 550uint16_t nfnl_exp_get_zone(const struct nfnl_exp *exp) 551{ 552 return exp->exp_zone; 553} 554 555void 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 561int nfnl_exp_test_class(const struct nfnl_exp *exp) 562{ 563 return !!(exp->ce_mask & EXP_ATTR_CLASS); 564} 565 566uint32_t nfnl_exp_get_class(const struct nfnl_exp *exp) 567{ 568 return exp->exp_class; 569} 570 571int 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 582int nfnl_exp_test_fn(const struct nfnl_exp *exp) 583{ 584 return !!(exp->ce_mask & EXP_ATTR_FN); 585} 586 587const char * nfnl_exp_get_fn(const struct nfnl_exp *exp) 588{ 589 return exp->exp_fn; 590} 591 592void 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 598int nfnl_exp_test_nat_dir(const struct nfnl_exp *exp) 599{ 600 return !!(exp->ce_mask & EXP_ATTR_NAT_DIR); 601} 602 603uint8_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 616static 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 638static 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 661static 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 680int 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 687int 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 694int nfnl_exp_test_src(const struct nfnl_exp *exp, int tuple) 695{ 696 return !!(exp->ce_mask & exp_get_src_attr(tuple)); 697} 698 699int nfnl_exp_test_dst(const struct nfnl_exp *exp, int tuple) 700{ 701 return !!(exp->ce_mask & exp_get_dst_attr(tuple)); 702} 703 704struct 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 713struct 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 722static 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 744void 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 752int nfnl_exp_test_l4protonum(const struct nfnl_exp *exp, int tuple) 753{ 754 return !!(exp->ce_mask & exp_get_l4protonum_attr(tuple)); 755} 756 757uint8_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 763static 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 785void 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 795int nfnl_exp_test_ports(const struct nfnl_exp *exp, int tuple) 796{ 797 return !!(exp->ce_mask & exp_get_l4ports_attr(tuple)); 798} 799 800uint16_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 806uint16_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 813static 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 835void 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 846int 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 852uint16_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 859uint8_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 866uint8_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 875struct 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