📄 ip_conntrack_netlink.c
字号:
int err; DEBUGP("entered %s\n", __FUNCTION__); memset(tuple, 0, sizeof(*tuple)); nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]); if (!tb[CTA_TUPLE_IP-1]) return -EINVAL; err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple); if (err < 0) return err; if (!tb[CTA_TUPLE_PROTO-1]) return -EINVAL; err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple); if (err < 0) return err; /* orig and expect tuples get DIR_ORIGINAL */ if (type == CTA_TUPLE_REPLY) tuple->dst.dir = IP_CT_DIR_REPLY; else tuple->dst.dir = IP_CT_DIR_ORIGINAL; DUMP_TUPLE(tuple); DEBUGP("leaving\n"); return 0;}#ifdef CONFIG_IP_NF_NAT_NEEDEDstatic const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t),};static int ctnetlink_parse_nat_proto(struct nfattr *attr, const struct ip_conntrack *ct, struct ip_nat_range *range){ struct nfattr *tb[CTA_PROTONAT_MAX]; struct ip_nat_protocol *npt; DEBUGP("entered %s\n", __FUNCTION__); nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) return -EINVAL; npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); if (!npt->nfattr_to_range) { ip_nat_proto_put(npt); return 0; } /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */ if (npt->nfattr_to_range(tb, range) > 0) range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; ip_nat_proto_put(npt); DEBUGP("leaving\n"); return 0;}static const size_t cta_min_nat[CTA_NAT_MAX] = { [CTA_NAT_MINIP-1] = sizeof(u_int32_t), [CTA_NAT_MAXIP-1] = sizeof(u_int32_t),};static inline intctnetlink_parse_nat(struct nfattr *cda[], const struct ip_conntrack *ct, struct ip_nat_range *range){ struct nfattr *tb[CTA_NAT_MAX]; int err; DEBUGP("entered %s\n", __FUNCTION__); memset(range, 0, sizeof(*range)); nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]); if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) return -EINVAL; if (tb[CTA_NAT_MINIP-1]) range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]); if (!tb[CTA_NAT_MAXIP-1]) range->max_ip = range->min_ip; else range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]); if (range->min_ip) range->flags |= IP_NAT_RANGE_MAP_IPS; if (!tb[CTA_NAT_PROTO-1]) return 0; err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); if (err < 0) return err; DEBUGP("leaving\n"); return 0;}#endifstatic inline intctnetlink_parse_help(struct nfattr *attr, char **helper_name){ struct nfattr *tb[CTA_HELP_MAX]; DEBUGP("entered %s\n", __FUNCTION__); nfattr_parse_nested(tb, CTA_HELP_MAX, attr); if (!tb[CTA_HELP_NAME-1]) return -EINVAL; *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]); return 0;}static const size_t cta_min[CTA_MAX] = { [CTA_STATUS-1] = sizeof(u_int32_t), [CTA_TIMEOUT-1] = sizeof(u_int32_t), [CTA_MARK-1] = sizeof(u_int32_t), [CTA_USE-1] = sizeof(u_int32_t), [CTA_ID-1] = sizeof(u_int32_t)};static intctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *cda[], int *errp){ struct ip_conntrack_tuple_hash *h; struct ip_conntrack_tuple tuple; struct ip_conntrack *ct; int err = 0; DEBUGP("entered %s\n", __FUNCTION__); if (nfattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; if (cda[CTA_TUPLE_ORIG-1]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); else if (cda[CTA_TUPLE_REPLY-1]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); else { /* Flush the whole table */ ip_conntrack_flush(); return 0; } if (err < 0) return err; h = ip_conntrack_find_get(&tuple, NULL); if (!h) { DEBUGP("tuple not found in conntrack hash\n"); return -ENOENT; } ct = tuplehash_to_ctrack(h); if (cda[CTA_ID-1]) { u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1])); if (ct->id != id) { ip_conntrack_put(ct); return -ENOENT; } } if (del_timer(&ct->timeout)) ct->timeout.function((unsigned long)ct); ip_conntrack_put(ct); DEBUGP("leaving\n"); return 0;}static intctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *cda[], int *errp){ struct ip_conntrack_tuple_hash *h; struct ip_conntrack_tuple tuple; struct ip_conntrack *ct; struct sk_buff *skb2 = NULL; int err = 0; DEBUGP("entered %s\n", __FUNCTION__); if (nlh->nlmsg_flags & NLM_F_DUMP) { struct nfgenmsg *msg = NLMSG_DATA(nlh); u32 rlen; if (msg->nfgen_family != AF_INET) return -EAFNOSUPPORT; if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) {#ifdef CONFIG_IP_NF_CT_ACCT if ((*errp = netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table_w, ctnetlink_done)) != 0) return -EINVAL;#else return -ENOTSUPP;#endif } else { if ((*errp = netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table, ctnetlink_done)) != 0) return -EINVAL; } rlen = NLMSG_ALIGN(nlh->nlmsg_len); if (rlen > skb->len) rlen = skb->len; skb_pull(skb, rlen); return 0; } if (nfattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; if (cda[CTA_TUPLE_ORIG-1]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); else if (cda[CTA_TUPLE_REPLY-1]) err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); else return -EINVAL; if (err < 0) return err; h = ip_conntrack_find_get(&tuple, NULL); if (!h) { DEBUGP("tuple not found in conntrack hash"); return -ENOENT; } DEBUGP("tuple found\n"); ct = tuplehash_to_ctrack(h); err = -ENOMEM; skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); if (!skb2) { ip_conntrack_put(ct); return -ENOMEM; } NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_CT_NEW, 1, ct); ip_conntrack_put(ct); if (err <= 0) goto free; err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); if (err < 0) goto out; DEBUGP("leaving\n"); return 0;free: kfree_skb(skb2);out: return err;}static inline intctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[]){ unsigned long d; unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1])); d = ct->status ^ status; if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) /* unchangeable */ return -EINVAL; if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) /* SEEN_REPLY bit can only be set */ return -EINVAL; if (d & IPS_ASSURED && !(status & IPS_ASSURED)) /* ASSURED bit can only be set */ return -EINVAL; if (cda[CTA_NAT-1]) {#ifndef CONFIG_IP_NF_NAT_NEEDED return -EINVAL;#else unsigned int hooknum; struct ip_nat_range range; if (ctnetlink_parse_nat(cda, ct, &range) < 0) return -EINVAL; DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", NIPQUAD(range.min_ip), NIPQUAD(range.max_ip), htons(range.min.all), htons(range.max.all)); /* This is tricky but it works. ip_nat_setup_info needs the * hook number as parameter, so let's do the correct * conversion and run away */ if (status & IPS_SRC_NAT_DONE) hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */ else if (status & IPS_DST_NAT_DONE) hooknum = NF_IP_PRE_ROUTING; /* IP_NAT_MANIP_DST */ else return -EINVAL; /* Missing NAT flags */ DEBUGP("NAT status: %lu\n", status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); if (ip_nat_initialized(ct, HOOK2MANIP(hooknum))) return -EEXIST; ip_nat_setup_info(ct, &range, hooknum); DEBUGP("NAT status after setup_info: %lu\n", ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));#endif } /* Be careful here, modifying NAT bits can screw up things, * so don't let users modify them directly if they don't pass * ip_nat_range. */ ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); return 0;}static inline intctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[]){ struct ip_conntrack_helper *helper; char *helpname; int err; DEBUGP("entered %s\n", __FUNCTION__); /* don't change helper of sibling connections */ if (ct->master) return -EINVAL; err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname); if (err < 0) return err; helper = __ip_conntrack_helper_find_byname(helpname); if (!helper) { if (!strcmp(helpname, "")) helper = NULL; else return -EINVAL; } if (ct->helper) { if (!helper) { /* we had a helper before ... */ ip_ct_remove_expectations(ct); ct->helper = NULL; } else { /* need to zero data of old helper */ memset(&ct->help, 0, sizeof(ct->help)); } } ct->helper = helper; return 0;}static inline intctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[]){ u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); if (!del_timer(&ct->timeout)) return -ETIME; ct->timeout.expires = jiffies + timeout * HZ; add_timer(&ct->timeout); return 0;}static inline intctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[]){ struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1]; struct ip_conntrack_protocol *proto; u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; int err = 0; nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr); proto = ip_conntrack_proto_find_get(npt); if (proto->from_nfattr) err = proto->from_nfattr(tb, ct); ip_conntrack_proto_put(proto); return err;}static intctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[]){ int err; DEBUGP("entered %s\n", __FUNCTION__); if (cda[CTA_HELP-1]) { err = ctnetlink_change_helper(ct, cda); if (err < 0) return err; } if (cda[CTA_TIMEOUT-1]) { err = ctnetlink_change_timeout(ct, cda); if (err < 0) return err; } if (cda[CTA_STATUS-1]) { err = ctnetlink_change_status(ct, cda); if (err < 0) return err; } if (cda[CTA_PROTOINFO-1]) { err = ctnetlink_change_protoinfo(ct, cda); if (err < 0) return err; }#if defined(CONFIG_IP_NF_CONNTRACK_MARK) if (cda[CTA_MARK-1]) ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));#endif DEBUGP("all done\n"); return 0;}static intctnetlink_create_conntrack(struct nfattr *cda[], struct ip_conntrack_tuple *otuple, struct ip_conntrack_tuple *rtuple){ struct ip_conntrack *ct; int err = -EINVAL; DEBUGP("entered %s\n", __FUNCTION__); ct = ip_conntrack_alloc(otuple, rtuple); if (ct == NULL || IS_ERR(ct)) return -ENOMEM; if (!cda[CTA_TIMEOUT-1]) goto err; ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); ct->timeout.expires = jiffies + ct->timeout.expires * HZ; ct->status |= IPS_CONFIRMED; err = ctnetlink_change_status(ct, cda); if (err < 0) goto err; if (cda[CTA_PROTOINFO-1]) { err = ctnetlink_change_protoinfo(ct, cda); if (err < 0) return err; } ct->helper = ip_conntrack_helper_find_get(rtuple); add_timer(&ct->timeout); ip_conntrack_hash_insert(ct); if (ct->helper) ip_conntrack_helper_put(ct->helper);#if defined(CONFIG_IP_NF_CONNTRACK_MARK) if (cda[CTA_MARK-1]) ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));#endif DEBUGP("conntrack with id %u inserted\n", ct->id); return 0;err: ip_conntrack_free(ct); return err;}static int ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, struct nlmsghdr *nlh, struct nfattr *cda[], int *errp){ struct ip_conntrack_tuple otuple, rtuple; struct ip_conntrack_tuple_hash *h = NULL; int err = 0; DEBUGP("entered %s\n", __FUNCTION__); if (nfattr_bad_size(cda, CTA_MAX, cta_min)) return -EINVAL; if (cda[CTA_TUPLE_ORIG-1]) { err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG); if (err < 0) return err; } if (cda[CTA_TUPLE_REPLY-1]) { err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY); if (err < 0) return err; } write_lock_bh(&ip_conntrack_lock); if (cda[CTA_TUPLE_ORIG-1]) h = __ip_conntrack_find(&otuple, NULL); else if (cda[CTA_TUPLE_REPLY-1]) h = __ip_conntrack_find(&rtuple, NULL); if (h == NULL) { write_unlock_bh(&ip_conntrack_lock); DEBUGP("no such conntrack, create new\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -