static inline int ctnetlink_dump_tuples(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple) { struct nfattr *nest_parms; struct nf_conntrack_l3proto *l3proto; int ret = 0; l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); if (likely(l3proto->tuple_to_nfattr)) ret = l3proto->tuple_to_nfattr(skb, tuple); NFA_NEST_END(skb, nest_parms); nf_ct_l3proto_put(l3proto); if (unlikely(ret < 0)) return ret; nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); ret = ctnetlink_dump_tuples_proto(skb, tuple); NFA_NEST_END(skb, nest_parms); return ret; nfattr_failure: return -1; }
static int ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait, const struct nf_conn *ct) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; struct nfattr *nest_parms; unsigned char *b; b = skb->tail; event |= NFNL_SUBSYS_CTNETLINK << 8; nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); nfmsg = NLMSG_DATA(nlh); nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; nfmsg->nfgen_family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) goto nfattr_failure; NFA_NEST_END(skb, nest_parms); nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) goto nfattr_failure; NFA_NEST_END(skb, nest_parms); if (ctnetlink_dump_status(skb, ct) < 0 || ctnetlink_dump_timeout(skb, ct) < 0 || ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 || ctnetlink_dump_protoinfo(skb, ct) < 0 || ctnetlink_dump_helpinfo(skb, ct) < 0 || ctnetlink_dump_mark(skb, ct) < 0 || ctnetlink_dump_id(skb, ct) < 0 || ctnetlink_dump_use(skb, ct) < 0) goto nfattr_failure; nlh->nlmsg_len = skb->tail - b; return skb->len; nlmsg_failure: nfattr_failure: skb_trim(skb, b - skb->data); return -1; }
static inline int ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) { struct nf_conntrack_protocol *proto = nf_ct_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); struct nfattr *nest_proto; int ret; if (!proto->to_nfattr) { nf_ct_proto_put(proto); return 0; } nest_proto = NFA_NEST(skb, CTA_PROTOINFO); ret = proto->to_nfattr(skb, nest_proto, ct); nf_ct_proto_put(proto); NFA_NEST_END(skb, nest_proto); return ret; nfattr_failure: return -1; }
static inline int ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) { struct nfattr *nest_helper; const struct nf_conn_help *help = nfct_help(ct); struct nf_conntrack_helper *helper; if (!help) return 0; rcu_read_lock(); helper = rcu_dereference(help->helper); if (!helper) goto out; nest_helper = NFA_NEST(skb, CTA_HELP); NFA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name); if (helper->to_nfattr) helper->to_nfattr(skb, ct); NFA_NEST_END(skb, nest_helper); out: rcu_read_unlock(); return 0; nfattr_failure: rcu_read_unlock(); return -1; }
static inline int ctnetlink_dump_tuples_ip(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple, struct nf_conntrack_l3proto *l3proto) { int ret = 0; struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); if (likely(l3proto->tuple_to_nfattr)) ret = l3proto->tuple_to_nfattr(skb, tuple); NFA_NEST_END(skb, nest_parms); return ret; nfattr_failure: return -1; }
static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa, const struct nf_conn *ct) { struct nfattr *nest_parms; read_lock_bh(&tcp_lock); nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP); NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t), &ct->proto.tcp.state); read_unlock_bh(&tcp_lock); NFA_NEST_END(skb, nest_parms); return 0; nfattr_failure: read_unlock_bh(&tcp_lock); return -1; }
static inline int ctnetlink_dump_tuples_proto(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple, struct nf_conntrack_l4proto *l4proto) { int ret = 0; struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); if (likely(l4proto->tuple_to_nfattr)) ret = l4proto->tuple_to_nfattr(skb, tuple); NFA_NEST_END(skb, nest_parms); return ret; nfattr_failure: return -1; }
static inline int ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct, enum ip_conntrack_dir dir) { enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG; struct nfattr *nest_count = NFA_NEST(skb, type); u_int32_t tmp; tmp = htonl(ct->counters[dir].packets); NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp); tmp = htonl(ct->counters[dir].bytes); NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp); NFA_NEST_END(skb, nest_count); return 0; nfattr_failure: return -1; }
static inline int ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) { struct nfattr *nest_helper; if (!ct->helper) return 0; nest_helper = NFA_NEST(skb, CTA_HELP); NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name); if (ct->helper->to_nfattr) ct->helper->to_nfattr(skb, ct); NFA_NEST_END(skb, nest_helper); return 0; nfattr_failure: return -1; }