📄 inet_diag.c
字号:
!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 + -