unsigned int seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir) { struct nf_conn_counter *acct; acct = nf_conn_acct_find(ct); if (!acct) return 0; return seq_printf(s, "packets=%llu bytes=%llu ", (unsigned long long)atomic64_read(&acct[dir].packets), (unsigned long long)atomic64_read(&acct[dir].bytes)); };
static int total_acct_packets(struct nf_conn *ct) { #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 26) BUG_ON(ct == NULL); return (ct->counters[IP_CT_DIR_ORIGINAL].packets + ct->counters[IP_CT_DIR_REPLY].packets); #else struct nf_conn_counter *acct; BUG_ON(ct == NULL); acct = nf_conn_acct_find(ct); if (!acct) return 0; return (acct[IP_CT_DIR_ORIGINAL].packets + acct[IP_CT_DIR_REPLY].packets); #endif }
/* function to be called by hook */ static unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; struct nf_conn_counter *acct; if (!skb) { return NF_ACCEPT; } if (in == NULL) { return NF_ACCEPT; } else if (in->name == NULL) { return NF_ACCEPT; } if (memcmp(devname, "all", 3) != 0) { if (memcmp(devname, in->name, 4) != 0) { return NF_ACCEPT; } } /* conntrack check */ if (skb->nfct == NULL) { /* if (net_ratelimit()) * pr_info("skb->nfct == NULL!\n"); */ return NF_ACCEPT; } ct = nf_ct_get(skb, &ctinfo); acct = nf_conn_acct_find(ct); if (!acct) { if (net_ratelimit()) pr_info("acct is NULL\n"); return NF_ACCEPT; } if (ct->proto.tcp.state == TCP_CONNTRACK_CLOSE_WAIT) { pr_info("%pI4 --> %pI4: %llu bytes CLOSE_WAIT\n", &iph->saddr, &iph->daddr, acct[IP_CT_DIR_ORIGINAL].bytes + acct[IP_CT_DIR_REPLY].bytes); } return NF_ACCEPT; }
static bool connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_connbytes_info *sinfo = par->matchinfo; const struct nf_conn *ct; enum ip_conntrack_info ctinfo; u_int64_t what = 0; /* initialize to make gcc happy */ u_int64_t bytes = 0; u_int64_t pkts = 0; const struct nf_conn_counter *counters; ct = nf_ct_get(skb, &ctinfo); if (!ct) return false; counters = nf_conn_acct_find(ct); if (!counters) return false; switch (sinfo->what) { case XT_CONNBYTES_PKTS: switch (sinfo->direction) { case XT_CONNBYTES_DIR_ORIGINAL: what = counters[IP_CT_DIR_ORIGINAL].packets; break; case XT_CONNBYTES_DIR_REPLY: what = counters[IP_CT_DIR_REPLY].packets; break; case XT_CONNBYTES_DIR_BOTH: what = counters[IP_CT_DIR_ORIGINAL].packets; what += counters[IP_CT_DIR_REPLY].packets; break; } break; case XT_CONNBYTES_BYTES: switch (sinfo->direction) { case XT_CONNBYTES_DIR_ORIGINAL: what = counters[IP_CT_DIR_ORIGINAL].bytes; break; case XT_CONNBYTES_DIR_REPLY: what = counters[IP_CT_DIR_REPLY].bytes; break; case XT_CONNBYTES_DIR_BOTH: what = counters[IP_CT_DIR_ORIGINAL].bytes; what += counters[IP_CT_DIR_REPLY].bytes; break; } break; case XT_CONNBYTES_AVGPKT: switch (sinfo->direction) { case XT_CONNBYTES_DIR_ORIGINAL: bytes = counters[IP_CT_DIR_ORIGINAL].bytes; pkts = counters[IP_CT_DIR_ORIGINAL].packets; break; case XT_CONNBYTES_DIR_REPLY: bytes = counters[IP_CT_DIR_REPLY].bytes; pkts = counters[IP_CT_DIR_REPLY].packets; break; case XT_CONNBYTES_DIR_BOTH: bytes = counters[IP_CT_DIR_ORIGINAL].bytes + counters[IP_CT_DIR_REPLY].bytes; pkts = counters[IP_CT_DIR_ORIGINAL].packets + counters[IP_CT_DIR_REPLY].packets; break; } if (pkts != 0) what = div64_u64(bytes, pkts); break; } if (sinfo->count.to) return what <= sinfo->count.to && what >= sinfo->count.from; else return what >= sinfo->count.from; }
static void nft_ct_get_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) { const struct nft_ct *priv = nft_expr_priv(expr); u32 *dest = ®s->data[priv->dreg]; enum ip_conntrack_info ctinfo; const struct nf_conn *ct; const struct nf_conn_help *help; const struct nf_conntrack_tuple *tuple; const struct nf_conntrack_helper *helper; unsigned int state; ct = nf_ct_get(pkt->skb, &ctinfo); switch (priv->key) { case NFT_CT_STATE: if (ct == NULL) state = NF_CT_STATE_INVALID_BIT; else if (nf_ct_is_untracked(ct)) state = NF_CT_STATE_UNTRACKED_BIT; else state = NF_CT_STATE_BIT(ctinfo); *dest = state; return; default: break; } if (ct == NULL) goto err; switch (priv->key) { case NFT_CT_DIRECTION: *dest = CTINFO2DIR(ctinfo); return; case NFT_CT_STATUS: *dest = ct->status; return; #ifdef CONFIG_NF_CONNTRACK_MARK case NFT_CT_MARK: *dest = ct->mark; return; #endif #ifdef CONFIG_NF_CONNTRACK_SECMARK case NFT_CT_SECMARK: *dest = ct->secmark; return; #endif case NFT_CT_EXPIRATION: *dest = jiffies_to_msecs(nf_ct_expires(ct)); return; case NFT_CT_HELPER: if (ct->master == NULL) goto err; help = nfct_help(ct->master); if (help == NULL) goto err; helper = rcu_dereference(help->helper); if (helper == NULL) goto err; strncpy((char *)dest, helper->name, NF_CT_HELPER_NAME_LEN); return; #ifdef CONFIG_NF_CONNTRACK_LABELS case NFT_CT_LABELS: { struct nf_conn_labels *labels = nf_ct_labels_find(ct); unsigned int size; if (!labels) { memset(dest, 0, NF_CT_LABELS_MAX_SIZE); return; } size = labels->words * sizeof(long); memcpy(dest, labels->bits, size); if (size < NF_CT_LABELS_MAX_SIZE) memset(((char *) dest) + size, 0, NF_CT_LABELS_MAX_SIZE - size); return; } #endif case NFT_CT_BYTES: /* fallthrough */ case NFT_CT_PKTS: { const struct nf_conn_acct *acct = nf_conn_acct_find(ct); u64 count = 0; if (acct) count = nft_ct_get_eval_counter(acct->counter, priv->key, priv->dir); memcpy(dest, &count, sizeof(count)); return; } default: break; } tuple = &ct->tuplehash[priv->dir].tuple; switch (priv->key) { case NFT_CT_L3PROTOCOL: *dest = nf_ct_l3num(ct); return; case NFT_CT_SRC: memcpy(dest, tuple->src.u3.all, nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); return; case NFT_CT_DST: memcpy(dest, tuple->dst.u3.all, nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); return; case NFT_CT_PROTOCOL: *dest = nf_ct_protonum(ct); return; case NFT_CT_PROTO_SRC: *dest = (__force __u16)tuple->src.u.all; return; case NFT_CT_PROTO_DST: *dest = (__force __u16)tuple->dst.u.all; return; default: break; } return; err: regs->verdict.code = NFT_BREAK; }
/* * sfe_cm_sync_rule() * Synchronize a connection's state. */ static void sfe_cm_sync_rule(struct sfe_ipv4_sync *sis) { struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple tuple; struct nf_conn *ct; struct nf_conn_counter *acct; /* * Create a tuple so as to be able to look up a connection */ memset(&tuple, 0, sizeof(tuple)); tuple.src.u3.ip = sis->src_ip; tuple.src.u.all = (__be16)sis->src_port; tuple.src.l3num = AF_INET; tuple.dst.u3.ip = sis->dest_ip; tuple.dst.dir = IP_CT_DIR_ORIGINAL; tuple.dst.protonum = (uint8_t)sis->protocol; tuple.dst.u.all = (__be16)sis->dest_port; DEBUG_TRACE("update connection - p: %d, s: %pI4:%u, d: %pI4:%u\n", (int)tuple.dst.protonum, &tuple.src.u3.ip, (unsigned int)ntohs(tuple.src.u.all), &tuple.dst.u3.ip, (unsigned int)ntohs(tuple.dst.u.all)); /* * Look up conntrack connection */ h = nf_conntrack_find_get(&init_net, NF_CT_DEFAULT_ZONE, &tuple); if (unlikely(!h)) { DEBUG_TRACE("no connection found\n"); return; } ct = nf_ct_tuplehash_to_ctrack(h); NF_CT_ASSERT(ct->timeout.data == (unsigned long)ct); /* * Only update if this is not a fixed timeout */ if (!test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) { ct->timeout.expires += sis->delta_jiffies; } acct = nf_conn_acct_find(ct); if (acct) { spin_lock_bh(&ct->lock); atomic64_set(&acct[IP_CT_DIR_ORIGINAL].packets, sis->src_packet_count); atomic64_set(&acct[IP_CT_DIR_ORIGINAL].bytes, sis->src_byte_count); atomic64_set(&acct[IP_CT_DIR_REPLY].packets, sis->dest_packet_count); atomic64_set(&acct[IP_CT_DIR_REPLY].bytes, sis->dest_byte_count); spin_unlock_bh(&ct->lock); } switch (sis->protocol) { case IPPROTO_TCP: spin_lock_bh(&ct->lock); if (ct->proto.tcp.seen[0].td_maxwin < sis->src_td_max_window) { ct->proto.tcp.seen[0].td_maxwin = sis->src_td_max_window; } if ((int32_t)(ct->proto.tcp.seen[0].td_end - sis->src_td_end) < 0) { ct->proto.tcp.seen[0].td_end = sis->src_td_end; } if ((int32_t)(ct->proto.tcp.seen[0].td_maxend - sis->src_td_max_end) < 0) { ct->proto.tcp.seen[0].td_maxend = sis->src_td_max_end; } if (ct->proto.tcp.seen[1].td_maxwin < sis->dest_td_max_window) { ct->proto.tcp.seen[1].td_maxwin = sis->dest_td_max_window; } if ((int32_t)(ct->proto.tcp.seen[1].td_end - sis->dest_td_end) < 0) { ct->proto.tcp.seen[1].td_end = sis->dest_td_end; } if ((int32_t)(ct->proto.tcp.seen[1].td_maxend - sis->dest_td_max_end) < 0) { ct->proto.tcp.seen[1].td_maxend = sis->dest_td_max_end; } spin_unlock_bh(&ct->lock); break; } /* * Release connection */ nf_ct_put(ct); }