⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inet_diag.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			    !valid_cc(bytecode, bytecode_len, len - op->no))				return -EINVAL;			break;		case INET_DIAG_BC_NOP:			if (op->yes < 4 || op->yes > len + 4)				return -EINVAL;			break;		default:			return -EINVAL;		}		bc  += op->yes;		len -= op->yes;	}	return len == 0 ? 0 : -EINVAL;}static int inet_csk_diag_dump(struct sock *sk,			      struct sk_buff *skb,			      struct netlink_callback *cb){	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);	if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {		struct inet_diag_entry entry;		struct rtattr *bc = (struct rtattr *)(r + 1);		struct inet_sock *inet = inet_sk(sk);		entry.family = sk->sk_family;#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)		if (entry.family == AF_INET6) {			struct ipv6_pinfo *np = inet6_sk(sk);			entry.saddr = np->rcv_saddr.s6_addr32;			entry.daddr = np->daddr.s6_addr32;		} else#endif		{			entry.saddr = &inet->rcv_saddr;			entry.daddr = &inet->daddr;		}		entry.sport = inet->num;		entry.dport = ntohs(inet->dport);		entry.userlocks = sk->sk_userlocks;		if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))			return 0;	}	return inet_csk_diag_fill(sk, skb, r->idiag_ext,				  NETLINK_CB(cb->skb).pid,				  cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);}static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,			       struct sk_buff *skb,			       struct netlink_callback *cb){	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);	if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {		struct inet_diag_entry entry;		struct rtattr *bc = (struct rtattr *)(r + 1);		entry.family = tw->tw_family;#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)		if (tw->tw_family == AF_INET6) {			struct inet6_timewait_sock *tw6 =						inet6_twsk((struct sock *)tw);			entry.saddr = tw6->tw_v6_rcv_saddr.s6_addr32;			entry.daddr = tw6->tw_v6_daddr.s6_addr32;		} else#endif		{			entry.saddr = &tw->tw_rcv_saddr;			entry.daddr = &tw->tw_daddr;		}		entry.sport = tw->tw_num;		entry.dport = ntohs(tw->tw_dport);		entry.userlocks = 0;		if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))			return 0;	}	return inet_twsk_diag_fill(tw, skb, r->idiag_ext,				   NETLINK_CB(cb->skb).pid,				   cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);}static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,			      struct request_sock *req, u32 pid, u32 seq,			      const struct nlmsghdr *unlh){	const struct inet_request_sock *ireq = inet_rsk(req);	struct inet_sock *inet = inet_sk(sk);	unsigned char *b = skb_tail_pointer(skb);	struct inet_diag_msg *r;	struct nlmsghdr *nlh;	long tmo;	nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));	nlh->nlmsg_flags = NLM_F_MULTI;	r = NLMSG_DATA(nlh);	r->idiag_family = sk->sk_family;	r->idiag_state = TCP_SYN_RECV;	r->idiag_timer = 1;	r->idiag_retrans = req->retrans;	r->id.idiag_if = sk->sk_bound_dev_if;	r->id.idiag_cookie[0] = (u32)(unsigned long)req;	r->id.idiag_cookie[1] = (u32)(((unsigned long)req >> 31) >> 1);	tmo = req->expires - jiffies;	if (tmo < 0)		tmo = 0;	r->id.idiag_sport = inet->sport;	r->id.idiag_dport = ireq->rmt_port;	r->id.idiag_src[0] = ireq->loc_addr;	r->id.idiag_dst[0] = ireq->rmt_addr;	r->idiag_expires = jiffies_to_msecs(tmo);	r->idiag_rqueue = 0;	r->idiag_wqueue = 0;	r->idiag_uid = sock_i_uid(sk);	r->idiag_inode = 0;#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)	if (r->idiag_family == AF_INET6) {		ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,			       &inet6_rsk(req)->loc_addr);		ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,			       &inet6_rsk(req)->rmt_addr);	}#endif	nlh->nlmsg_len = skb_tail_pointer(skb) - b;	return skb->len;nlmsg_failure:	nlmsg_trim(skb, b);	return -1;}static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,			       struct netlink_callback *cb){	struct inet_diag_entry entry;	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);	struct inet_connection_sock *icsk = inet_csk(sk);	struct listen_sock *lopt;	struct rtattr *bc = NULL;	struct inet_sock *inet = inet_sk(sk);	int j, s_j;	int reqnum, s_reqnum;	int err = 0;	s_j = cb->args[3];	s_reqnum = cb->args[4];	if (s_j > 0)		s_j--;	entry.family = sk->sk_family;	read_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock);	lopt = icsk->icsk_accept_queue.listen_opt;	if (!lopt || !lopt->qlen)		goto out;	if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {		bc = (struct rtattr *)(r + 1);		entry.sport = inet->num;		entry.userlocks = sk->sk_userlocks;	}	for (j = s_j; j < lopt->nr_table_entries; j++) {		struct request_sock *req, *head = lopt->syn_table[j];		reqnum = 0;		for (req = head; req; reqnum++, req = req->dl_next) {			struct inet_request_sock *ireq = inet_rsk(req);			if (reqnum < s_reqnum)				continue;			if (r->id.idiag_dport != ireq->rmt_port &&			    r->id.idiag_dport)				continue;			if (bc) {				entry.saddr =#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)					(entry.family == AF_INET6) ?					inet6_rsk(req)->loc_addr.s6_addr32 :#endif					&ireq->loc_addr;				entry.daddr =#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)					(entry.family == AF_INET6) ?					inet6_rsk(req)->rmt_addr.s6_addr32 :#endif					&ireq->rmt_addr;				entry.dport = ntohs(ireq->rmt_port);				if (!inet_diag_bc_run(RTA_DATA(bc),						    RTA_PAYLOAD(bc), &entry))					continue;			}			err = inet_diag_fill_req(skb, sk, req,					       NETLINK_CB(cb->skb).pid,					       cb->nlh->nlmsg_seq, cb->nlh);			if (err < 0) {				cb->args[3] = j + 1;				cb->args[4] = reqnum;				goto out;			}		}		s_reqnum = 0;	}out:	read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);	return err;}static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb){	int i, num;	int s_i, s_num;	struct inet_diag_req *r = NLMSG_DATA(cb->nlh);	const struct inet_diag_handler *handler;	struct inet_hashinfo *hashinfo;	handler = inet_diag_lock_handler(cb->nlh->nlmsg_type);	if (!handler)		goto no_handler;	hashinfo = handler->idiag_hashinfo;	s_i = cb->args[1];	s_num = num = cb->args[2];	if (cb->args[0] == 0) {		if (!(r->idiag_states & (TCPF_LISTEN | TCPF_SYN_RECV)))			goto skip_listen_ht;		inet_listen_lock(hashinfo);		for (i = s_i; i < INET_LHTABLE_SIZE; i++) {			struct sock *sk;			struct hlist_node *node;			num = 0;			sk_for_each(sk, node, &hashinfo->listening_hash[i]) {				struct inet_sock *inet = inet_sk(sk);				if (num < s_num) {					num++;					continue;				}				if (r->id.idiag_sport != inet->sport &&				    r->id.idiag_sport)					goto next_listen;				if (!(r->idiag_states & TCPF_LISTEN) ||				    r->id.idiag_dport ||				    cb->args[3] > 0)					goto syn_recv;				if (inet_csk_diag_dump(sk, skb, cb) < 0) {					inet_listen_unlock(hashinfo);					goto done;				}syn_recv:				if (!(r->idiag_states & TCPF_SYN_RECV))					goto next_listen;				if (inet_diag_dump_reqs(skb, sk, cb) < 0) {					inet_listen_unlock(hashinfo);					goto done;				}next_listen:				cb->args[3] = 0;				cb->args[4] = 0;				++num;			}			s_num = 0;			cb->args[3] = 0;			cb->args[4] = 0;		}		inet_listen_unlock(hashinfo);skip_listen_ht:		cb->args[0] = 1;		s_i = num = s_num = 0;	}	if (!(r->idiag_states & ~(TCPF_LISTEN | TCPF_SYN_RECV)))		goto unlock;	for (i = s_i; i < hashinfo->ehash_size; i++) {		struct inet_ehash_bucket *head = &hashinfo->ehash[i];		rwlock_t *lock = inet_ehash_lockp(hashinfo, i);		struct sock *sk;		struct hlist_node *node;		if (i > s_i)			s_num = 0;		read_lock_bh(lock);		num = 0;		sk_for_each(sk, node, &head->chain) {			struct inet_sock *inet = inet_sk(sk);			if (num < s_num)				goto next_normal;			if (!(r->idiag_states & (1 << sk->sk_state)))				goto next_normal;			if (r->id.idiag_sport != inet->sport &&			    r->id.idiag_sport)				goto next_normal;			if (r->id.idiag_dport != inet->dport &&			    r->id.idiag_dport)				goto next_normal;			if (inet_csk_diag_dump(sk, skb, cb) < 0) {				read_unlock_bh(lock);				goto done;			}next_normal:			++num;		}		if (r->idiag_states & TCPF_TIME_WAIT) {			struct inet_timewait_sock *tw;			inet_twsk_for_each(tw, node,				    &head->twchain) {				if (num < s_num)					goto next_dying;				if (r->id.idiag_sport != tw->tw_sport &&				    r->id.idiag_sport)					goto next_dying;				if (r->id.idiag_dport != tw->tw_dport &&				    r->id.idiag_dport)					goto next_dying;				if (inet_twsk_diag_dump(tw, skb, cb) < 0) {					read_unlock_bh(lock);					goto done;				}next_dying:				++num;			}		}		read_unlock_bh(lock);	}done:	cb->args[1] = i;	cb->args[2] = num;unlock:	inet_diag_unlock_handler(handler);no_handler:	return skb->len;}static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh){	int hdrlen = sizeof(struct inet_diag_req);	if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX ||	    nlmsg_len(nlh) < hdrlen)		return -EINVAL;	if (nlh->nlmsg_flags & NLM_F_DUMP) {		if (nlmsg_attrlen(nlh, hdrlen)) {			struct nlattr *attr;			attr = nlmsg_find_attr(nlh, hdrlen,					       INET_DIAG_REQ_BYTECODE);			if (attr == NULL ||			    nla_len(attr) < sizeof(struct inet_diag_bc_op) ||			    inet_diag_bc_audit(nla_data(attr), nla_len(attr)))				return -EINVAL;		}		return netlink_dump_start(idiagnl, skb, nlh,					  inet_diag_dump, NULL);	}	return inet_diag_get_exact(skb, nlh);}static DEFINE_MUTEX(inet_diag_mutex);static void inet_diag_rcv(struct sk_buff *skb){	mutex_lock(&inet_diag_mutex);	netlink_rcv_skb(skb, &inet_diag_rcv_msg);	mutex_unlock(&inet_diag_mutex);}int inet_diag_register(const struct inet_diag_handler *h){	const __u16 type = h->idiag_type;	int err = -EINVAL;	if (type >= INET_DIAG_GETSOCK_MAX)		goto out;	mutex_lock(&inet_diag_table_mutex);	err = -EEXIST;	if (inet_diag_table[type] == NULL) {		inet_diag_table[type] = h;		err = 0;	}	mutex_unlock(&inet_diag_table_mutex);out:	return err;}EXPORT_SYMBOL_GPL(inet_diag_register);void inet_diag_unregister(const struct inet_diag_handler *h){	const __u16 type = h->idiag_type;	if (type >= INET_DIAG_GETSOCK_MAX)		return;	mutex_lock(&inet_diag_table_mutex);	inet_diag_table[type] = NULL;	mutex_unlock(&inet_diag_table_mutex);}EXPORT_SYMBOL_GPL(inet_diag_unregister);static int __init inet_diag_init(void){	const int inet_diag_table_size = (INET_DIAG_GETSOCK_MAX *					  sizeof(struct inet_diag_handler *));	int err = -ENOMEM;	inet_diag_table = kzalloc(inet_diag_table_size, GFP_KERNEL);	if (!inet_diag_table)		goto out;	idiagnl = netlink_kernel_create(&init_net, NETLINK_INET_DIAG, 0,					inet_diag_rcv, NULL, THIS_MODULE);	if (idiagnl == NULL)		goto out_free_table;	err = 0;out:	return err;out_free_table:	kfree(inet_diag_table);	goto out;}static void __exit inet_diag_exit(void){	sock_release(idiagnl->sk_socket);	kfree(inet_diag_table);}module_init(inet_diag_init);module_exit(inet_diag_exit);MODULE_LICENSE("GPL");MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_INET_DIAG);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -