| /* |
| * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org> |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| */ |
| |
| #include "internal/internal.h" |
| #include <limits.h> |
| #include <libmnl/libmnl.h> |
| |
| static void __parse_ip(const struct nfattr *attr, |
| struct __nfct_tuple *tuple, |
| const int dir, |
| uint32_t *set) |
| { |
| struct nfattr *tb[CTA_IP_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_IP_MAX, attr); |
| |
| if (tb[CTA_IP_V4_SRC-1]) { |
| tuple->src.v4 = *(uint32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_IPV4_SRC, set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_IPV4_SRC, set); |
| break; |
| case __DIR_MASTER: |
| set_bit(ATTR_MASTER_IPV4_SRC, set); |
| break; |
| } |
| } |
| |
| if (tb[CTA_IP_V4_DST-1]) { |
| tuple->dst.v4 = *(uint32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]); |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_IPV4_DST, set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_IPV4_DST, set); |
| break; |
| case __DIR_MASTER: |
| set_bit(ATTR_MASTER_IPV4_DST, set); |
| break; |
| } |
| } |
| |
| if (tb[CTA_IP_V6_SRC-1]) { |
| memcpy(&tuple->src.v6, NFA_DATA(tb[CTA_IP_V6_SRC-1]), |
| sizeof(struct in6_addr)); |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_IPV6_SRC, set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_IPV6_SRC, set); |
| break; |
| case __DIR_MASTER: |
| set_bit(ATTR_MASTER_IPV6_SRC, set); |
| break; |
| } |
| } |
| |
| if (tb[CTA_IP_V6_DST-1]) { |
| memcpy(&tuple->dst.v6, NFA_DATA(tb[CTA_IP_V6_DST-1]), |
| sizeof(struct in6_addr)); |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_IPV6_DST, set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_IPV6_DST, set); |
| break; |
| case __DIR_MASTER: |
| set_bit(ATTR_MASTER_IPV6_DST, set); |
| break; |
| } |
| } |
| } |
| |
| static void __parse_proto(const struct nfattr *attr, |
| struct __nfct_tuple *tuple, |
| const int dir, |
| uint32_t *set) |
| { |
| struct nfattr *tb[CTA_PROTO_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_PROTO_MAX, attr); |
| |
| if (tb[CTA_PROTO_NUM-1]) { |
| tuple->protonum = *(uint8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_L4PROTO, set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_L4PROTO, set); |
| break; |
| case __DIR_MASTER: |
| set_bit(ATTR_MASTER_L4PROTO, set); |
| break; |
| } |
| } |
| |
| if (tb[CTA_PROTO_SRC_PORT-1]) { |
| tuple->l4src.tcp.port = |
| *(uint16_t *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]); |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_PORT_SRC, set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_PORT_SRC, set); |
| break; |
| case __DIR_MASTER: |
| set_bit(ATTR_MASTER_PORT_SRC, set); |
| break; |
| } |
| } |
| |
| if (tb[CTA_PROTO_DST_PORT-1]) { |
| tuple->l4dst.tcp.port = |
| *(uint16_t *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]); |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_PORT_DST, set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_PORT_DST, set); |
| break; |
| case __DIR_MASTER: |
| set_bit(ATTR_MASTER_PORT_DST, set); |
| break; |
| } |
| } |
| |
| if (tb[CTA_PROTO_ICMP_TYPE-1]) { |
| tuple->l4dst.icmp.type = |
| *(uint8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]); |
| set_bit(ATTR_ICMP_TYPE, set); |
| } |
| |
| if (tb[CTA_PROTO_ICMP_CODE-1]) { |
| tuple->l4dst.icmp.code = |
| *(uint8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]); |
| set_bit(ATTR_ICMP_CODE, set); |
| } |
| |
| if (tb[CTA_PROTO_ICMP_ID-1]) { |
| tuple->l4src.icmp.id = |
| *(uint16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); |
| set_bit(ATTR_ICMP_ID, set); |
| } |
| |
| if (tb[CTA_PROTO_ICMPV6_TYPE-1]) { |
| tuple->l4dst.icmp.type = |
| *(uint8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_TYPE-1]); |
| set_bit(ATTR_ICMP_TYPE, set); |
| } |
| |
| if (tb[CTA_PROTO_ICMPV6_CODE-1]) { |
| tuple->l4dst.icmp.code = |
| *(uint8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_CODE-1]); |
| set_bit(ATTR_ICMP_CODE, set); |
| } |
| |
| if (tb[CTA_PROTO_ICMPV6_ID-1]) { |
| tuple->l4src.icmp.id = |
| *(uint16_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_ID-1]); |
| set_bit(ATTR_ICMP_ID, set); |
| } |
| } |
| |
| void __parse_tuple(const struct nfattr *attr, |
| struct __nfct_tuple *tuple, |
| int dir, |
| uint32_t *set) |
| { |
| struct nfattr *tb[CTA_TUPLE_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_TUPLE_MAX, attr); |
| |
| if (tb[CTA_TUPLE_IP-1]) |
| __parse_ip(tb[CTA_TUPLE_IP-1], tuple, dir, set); |
| if (tb[CTA_TUPLE_PROTO-1]) |
| __parse_proto(tb[CTA_TUPLE_PROTO-1], tuple, dir, set); |
| |
| if (tb[CTA_TUPLE_ZONE-1]) { |
| tuple->zone = ntohs(*(uint16_t *)NFA_DATA(tb[CTA_TUPLE_ZONE-1])); |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_ZONE, set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_ZONE, set); |
| break; |
| } |
| } |
| } |
| |
| static void __parse_protoinfo_tcp(const struct nfattr *attr, |
| struct nf_conntrack *ct) |
| { |
| struct nfattr *tb[CTA_PROTOINFO_TCP_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr); |
| |
| if (tb[CTA_PROTOINFO_TCP_STATE-1]) { |
| ct->protoinfo.tcp.state = |
| *(uint8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]); |
| set_bit(ATTR_TCP_STATE, ct->head.set); |
| } |
| |
| if (tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL-1]) { |
| memcpy(&ct->protoinfo.tcp.wscale[__DIR_ORIG], |
| NFA_DATA(tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL-1]), |
| sizeof(uint8_t)); |
| set_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set); |
| } |
| |
| if (tb[CTA_PROTOINFO_TCP_WSCALE_REPLY-1]) { |
| memcpy(&ct->protoinfo.tcp.wscale[__DIR_REPL], |
| NFA_DATA(tb[CTA_PROTOINFO_TCP_WSCALE_REPLY-1]), |
| sizeof(uint8_t)); |
| set_bit(ATTR_TCP_WSCALE_REPL, ct->head.set); |
| } |
| |
| if (tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL-1]) { |
| memcpy(&ct->protoinfo.tcp.flags[0], |
| NFA_DATA(tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL-1]), |
| sizeof(struct nf_ct_tcp_flags)); |
| set_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set); |
| set_bit(ATTR_TCP_MASK_ORIG, ct->head.set); |
| } |
| |
| if (tb[CTA_PROTOINFO_TCP_FLAGS_REPLY-1]) { |
| memcpy(&ct->protoinfo.tcp.flags[1], |
| NFA_DATA(tb[CTA_PROTOINFO_TCP_FLAGS_REPLY-1]), |
| sizeof(struct nf_ct_tcp_flags)); |
| set_bit(ATTR_TCP_FLAGS_REPL, ct->head.set); |
| set_bit(ATTR_TCP_MASK_REPL, ct->head.set); |
| } |
| } |
| |
| static void __parse_protoinfo_sctp(const struct nfattr *attr, |
| struct nf_conntrack *ct) |
| { |
| struct nfattr *tb[CTA_PROTOINFO_SCTP_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_PROTOINFO_SCTP_MAX, attr); |
| |
| if (tb[CTA_PROTOINFO_SCTP_STATE-1]) { |
| ct->protoinfo.sctp.state = |
| *(uint8_t *)NFA_DATA(tb[CTA_PROTOINFO_SCTP_STATE-1]); |
| set_bit(ATTR_SCTP_STATE, ct->head.set); |
| } |
| |
| if (tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL-1]) { |
| ct->protoinfo.sctp.vtag[__DIR_ORIG] = |
| ntohl(*(uint32_t *)NFA_DATA(tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL-1])); |
| set_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set); |
| } |
| |
| if (tb[CTA_PROTOINFO_SCTP_VTAG_REPLY-1]) { |
| ct->protoinfo.sctp.vtag[__DIR_REPL] = |
| ntohl(*(uint32_t *)NFA_DATA(tb[CTA_PROTOINFO_SCTP_VTAG_REPLY-1])); |
| set_bit(ATTR_SCTP_VTAG_REPL, ct->head.set); |
| } |
| |
| } |
| |
| static void __parse_protoinfo_dccp(const struct nfattr *attr, |
| struct nf_conntrack *ct) |
| { |
| struct nfattr *tb[CTA_PROTOINFO_DCCP_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_PROTOINFO_DCCP_MAX, attr); |
| |
| if (tb[CTA_PROTOINFO_DCCP_STATE-1]) { |
| ct->protoinfo.dccp.state = |
| *(uint8_t *)NFA_DATA(tb[CTA_PROTOINFO_DCCP_STATE-1]); |
| set_bit(ATTR_DCCP_STATE, ct->head.set); |
| } |
| if (tb[CTA_PROTOINFO_DCCP_ROLE-1]) { |
| ct->protoinfo.dccp.role = |
| *(uint8_t *)NFA_DATA(tb[CTA_PROTOINFO_DCCP_ROLE-1]); |
| set_bit(ATTR_DCCP_ROLE, ct->head.set); |
| } |
| if (tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ-1]) { |
| uint64_t tmp; |
| memcpy(&tmp, |
| NFA_DATA(tb[CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ-1]), |
| sizeof(tmp)); |
| ct->protoinfo.dccp.handshake_seq = __be64_to_cpu(tmp); |
| set_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set); |
| } |
| } |
| |
| static void __parse_protoinfo(const struct nfattr *attr, |
| struct nf_conntrack *ct) |
| { |
| struct nfattr *tb[CTA_PROTOINFO_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_PROTOINFO_MAX, attr); |
| |
| if (tb[CTA_PROTOINFO_TCP-1]) |
| __parse_protoinfo_tcp(tb[CTA_PROTOINFO_TCP-1], ct); |
| |
| if (tb[CTA_PROTOINFO_SCTP-1]) |
| __parse_protoinfo_sctp(tb[CTA_PROTOINFO_SCTP-1], ct); |
| |
| if (tb[CTA_PROTOINFO_DCCP-1]) |
| __parse_protoinfo_dccp(tb[CTA_PROTOINFO_DCCP-1], ct); |
| } |
| |
| static void __parse_counters(const struct nfattr *attr, |
| struct nf_conntrack *ct, |
| int dir) |
| { |
| struct nfattr *tb[CTA_COUNTERS_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_COUNTERS_MAX, attr); |
| if (tb[CTA_COUNTERS_PACKETS-1] || tb[CTA_COUNTERS32_PACKETS-1]) { |
| |
| if (tb[CTA_COUNTERS32_PACKETS-1]) |
| ct->counters[dir].packets |
| = ntohl(*(uint32_t *) |
| NFA_DATA(tb[CTA_COUNTERS32_PACKETS-1])); |
| |
| if (tb[CTA_COUNTERS_PACKETS-1]) { |
| uint64_t tmp; |
| memcpy(&tmp, |
| NFA_DATA(tb[CTA_COUNTERS_PACKETS-1]), |
| sizeof(tmp)); |
| ct->counters[dir].packets = __be64_to_cpu(tmp); |
| } |
| |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_COUNTER_PACKETS, ct->head.set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_COUNTER_PACKETS, ct->head.set); |
| break; |
| } |
| } |
| if (tb[CTA_COUNTERS_BYTES-1] || tb[CTA_COUNTERS32_BYTES-1]) { |
| |
| if (tb[CTA_COUNTERS32_BYTES-1]) |
| ct->counters[dir].bytes |
| = ntohl(*(uint32_t *) |
| NFA_DATA(tb[CTA_COUNTERS32_BYTES-1])); |
| |
| if (tb[CTA_COUNTERS_BYTES-1]) { |
| uint64_t tmp; |
| memcpy(&tmp, |
| NFA_DATA(tb[CTA_COUNTERS_BYTES-1]), |
| sizeof(tmp)); |
| ct->counters[dir].bytes = __be64_to_cpu(tmp); |
| } |
| |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_COUNTER_BYTES, ct->head.set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_COUNTER_BYTES, ct->head.set); |
| break; |
| } |
| } |
| } |
| |
| static void |
| __parse_nat_seq(const struct nfattr *attr, struct nf_conntrack *ct, int dir) |
| { |
| struct nfattr *tb[CTA_NAT_SEQ_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_NAT_SEQ_MAX, attr); |
| |
| if (tb[CTA_NAT_SEQ_CORRECTION_POS-1]) { |
| ct->natseq[dir].correction_pos = |
| ntohl(*(uint32_t *)NFA_DATA(tb[CTA_NAT_SEQ_CORRECTION_POS-1])); |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ct->head.set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_NAT_SEQ_CORRECTION_POS, ct->head.set); |
| break; |
| } |
| } |
| |
| if (tb[CTA_NAT_SEQ_OFFSET_BEFORE-1]) { |
| ct->natseq[dir].offset_before = |
| ntohl(*(uint32_t *)NFA_DATA(tb[CTA_NAT_SEQ_OFFSET_BEFORE-1])); |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, ct->head.set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, ct->head.set); |
| break; |
| } |
| } |
| |
| if (tb[CTA_NAT_SEQ_OFFSET_AFTER-1]) { |
| ct->natseq[dir].offset_after = |
| ntohl(*(uint32_t *)NFA_DATA(tb[CTA_NAT_SEQ_OFFSET_AFTER-1])); |
| switch(dir) { |
| case __DIR_ORIG: |
| set_bit(ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ct->head.set); |
| break; |
| case __DIR_REPL: |
| set_bit(ATTR_REPL_NAT_SEQ_OFFSET_AFTER, ct->head.set); |
| break; |
| } |
| } |
| } |
| |
| static void |
| __parse_helper(const struct nfattr *attr, struct nf_conntrack *ct) |
| { |
| struct nfattr *tb[CTA_HELP_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_HELP_MAX, attr); |
| if (!tb[CTA_HELP_NAME-1]) |
| return; |
| |
| strncpy(ct->helper_name, |
| NFA_DATA(tb[CTA_HELP_NAME-1]), |
| NFCT_HELPER_NAME_MAX); |
| ct->helper_name[NFCT_HELPER_NAME_MAX-1] = '\0'; |
| set_bit(ATTR_HELPER_NAME, ct->head.set); |
| } |
| |
| static void |
| __parse_secctx(const struct nfattr *attr, struct nf_conntrack *ct) |
| { |
| struct nfattr *tb[CTA_SECCTX_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_SECCTX_MAX, attr); |
| if (!tb[CTA_SECCTX_NAME-1]) |
| return; |
| |
| ct->secctx = strdup(NFA_DATA(tb[CTA_SECCTX_NAME-1])); |
| if (ct->secctx) |
| set_bit(ATTR_SECCTX, ct->head.set); |
| } |
| |
| int __parse_message_type(const struct nlmsghdr *nlh) |
| { |
| uint16_t type = NFNL_MSG_TYPE(nlh->nlmsg_type); |
| uint16_t flags = nlh->nlmsg_flags; |
| int ret = NFCT_T_UNKNOWN; |
| |
| if (type == IPCTNL_MSG_CT_NEW) { |
| if (flags & (NLM_F_CREATE|NLM_F_EXCL)) |
| ret = NFCT_T_NEW; |
| else |
| ret = NFCT_T_UPDATE; |
| } else if (type == IPCTNL_MSG_CT_DELETE) |
| ret = NFCT_T_DESTROY; |
| |
| return ret; |
| } |
| |
| static void |
| __parse_timestamp(const struct nfattr *attr, struct nf_conntrack *ct) |
| { |
| struct nfattr *tb[CTA_TIMESTAMP_MAX]; |
| |
| nfnl_parse_nested(tb, CTA_TIMESTAMP_MAX, attr); |
| if (tb[CTA_TIMESTAMP_START-1]) { |
| uint64_t tmp; |
| memcpy(&tmp, NFA_DATA(tb[CTA_TIMESTAMP_START-1]), sizeof(tmp)); |
| ct->timestamp.start = __be64_to_cpu(tmp); |
| set_bit(ATTR_TIMESTAMP_START, ct->head.set); |
| } |
| if (tb[CTA_TIMESTAMP_STOP-1]) { |
| uint64_t tmp; |
| memcpy(&tmp, NFA_DATA(tb[CTA_TIMESTAMP_STOP-1]), sizeof(tmp)); |
| ct->timestamp.stop = __be64_to_cpu(tmp); |
| set_bit(ATTR_TIMESTAMP_STOP, ct->head.set); |
| } |
| } |
| |
| static void |
| __parse_labels(const struct nfattr *attr, struct nf_conntrack *ct) |
| { |
| struct nfct_bitmask *mask; |
| uint16_t len; |
| |
| len = NFA_PAYLOAD(attr); |
| if (len) { |
| mask = nfct_bitmask_new((len * CHAR_BIT) - 1); |
| if (!mask) |
| return; |
| memcpy(mask->bits, NFA_DATA(attr), len); |
| nfct_set_attr(ct, ATTR_CONNLABELS, mask); |
| } |
| } |
| |
| void __parse_conntrack(const struct nlmsghdr *nlh, |
| struct nfattr *cda[], |
| struct nf_conntrack *ct) |
| { |
| struct nfgenmsg *nfhdr = NLMSG_DATA(nlh); |
| |
| if (cda[CTA_TUPLE_ORIG-1]) { |
| ct->head.orig.l3protonum = nfhdr->nfgen_family; |
| set_bit(ATTR_ORIG_L3PROTO, ct->head.set); |
| |
| __parse_tuple(cda[CTA_TUPLE_ORIG-1], |
| &ct->head.orig, __DIR_ORIG, ct->head.set); |
| } |
| |
| if (cda[CTA_TUPLE_REPLY-1]) { |
| ct->repl.l3protonum = nfhdr->nfgen_family; |
| set_bit(ATTR_REPL_L3PROTO, ct->head.set); |
| |
| __parse_tuple(cda[CTA_TUPLE_REPLY-1], |
| &ct->repl, __DIR_REPL, ct->head.set); |
| } |
| |
| if (cda[CTA_TUPLE_MASTER-1]) { |
| ct->master.l3protonum = nfhdr->nfgen_family; |
| set_bit(ATTR_MASTER_L3PROTO, ct->head.set); |
| |
| __parse_tuple(cda[CTA_TUPLE_MASTER-1], |
| &ct->master, __DIR_MASTER, ct->head.set); |
| } |
| |
| if (cda[CTA_NAT_SEQ_ADJ_ORIG-1]) |
| __parse_nat_seq(cda[CTA_NAT_SEQ_ADJ_ORIG-1], ct, __DIR_ORIG); |
| |
| if (cda[CTA_NAT_SEQ_ADJ_REPLY-1]) |
| __parse_nat_seq(cda[CTA_NAT_SEQ_ADJ_REPLY-1], ct, __DIR_REPL); |
| |
| if (cda[CTA_STATUS-1]) { |
| ct->status = ntohl(*(uint32_t *)NFA_DATA(cda[CTA_STATUS-1])); |
| set_bit(ATTR_STATUS, ct->head.set); |
| } |
| |
| if (cda[CTA_PROTOINFO-1]) |
| __parse_protoinfo(cda[CTA_PROTOINFO-1], ct); |
| |
| if (cda[CTA_TIMEOUT-1]) { |
| ct->timeout = ntohl(*(uint32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); |
| set_bit(ATTR_TIMEOUT, ct->head.set); |
| } |
| |
| if (cda[CTA_MARK-1]) { |
| ct->mark = ntohl(*(uint32_t *)NFA_DATA(cda[CTA_MARK-1])); |
| set_bit(ATTR_MARK, ct->head.set); |
| } |
| |
| if (cda[CTA_SECMARK-1]) { |
| ct->secmark = ntohl(*(uint32_t *)NFA_DATA(cda[CTA_SECMARK-1])); |
| set_bit(ATTR_SECMARK, ct->head.set); |
| } |
| |
| if (cda[CTA_COUNTERS_ORIG-1]) |
| __parse_counters(cda[CTA_COUNTERS_ORIG-1], ct, __DIR_ORIG); |
| |
| if (cda[CTA_COUNTERS_REPLY-1]) |
| __parse_counters(cda[CTA_COUNTERS_REPLY-1], ct, __DIR_REPL); |
| |
| if (cda[CTA_USE-1]) { |
| ct->use = ntohl(*(uint32_t *)NFA_DATA(cda[CTA_USE-1])); |
| set_bit(ATTR_USE, ct->head.set); |
| } |
| |
| if (cda[CTA_ID-1]) { |
| ct->id = ntohl(*(uint32_t *)NFA_DATA(cda[CTA_ID-1])); |
| set_bit(ATTR_ID, ct->head.set); |
| } |
| |
| if (cda[CTA_HELP-1]) |
| __parse_helper(cda[CTA_HELP-1], ct); |
| |
| if (cda[CTA_ZONE-1]) { |
| ct->zone = ntohs(*(uint16_t *)NFA_DATA(cda[CTA_ZONE-1])); |
| set_bit(ATTR_ZONE, ct->head.set); |
| } |
| |
| if (cda[CTA_SECCTX-1]) |
| __parse_secctx(cda[CTA_SECCTX-1], ct); |
| |
| if (cda[CTA_TIMESTAMP-1]) |
| __parse_timestamp(cda[CTA_TIMESTAMP-1], ct); |
| |
| if (cda[CTA_LABELS-1]) |
| __parse_labels(cda[CTA_LABELS-1], ct); |
| } |