📄 tcp_diag.c
字号:
switch (op->code) { case TCPDIAG_BC_NOP: break; case TCPDIAG_BC_JMP: yes = 0; break; case TCPDIAG_BC_S_GE: yes = inet->num >= op[1].no; break; case TCPDIAG_BC_S_LE: yes = inet->num <= op[1].no; break; case TCPDIAG_BC_D_GE: yes = ntohs(inet->dport) >= op[1].no; break; case TCPDIAG_BC_D_LE: yes = ntohs(inet->dport) <= op[1].no; break; case TCPDIAG_BC_AUTO: yes = !(sk->sk_userlocks & SOCK_BINDPORT_LOCK); break; case TCPDIAG_BC_S_COND: case TCPDIAG_BC_D_COND: { struct tcpdiag_hostcond *cond = (struct tcpdiag_hostcond*)(op+1); u32 *addr; if (cond->port != -1 && cond->port != (op->code == TCPDIAG_BC_S_COND ? inet->num : ntohs(inet->dport))) { yes = 0; break; } if (cond->prefix_len == 0) break;#ifdef CONFIG_IPV6 if (sk->sk_family == AF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); if (op->code == TCPDIAG_BC_S_COND) addr = (u32*)&np->rcv_saddr; else addr = (u32*)&np->daddr; } else#endif { if (op->code == TCPDIAG_BC_S_COND) addr = &inet->rcv_saddr; else addr = &inet->daddr; } if (bitstring_match(addr, cond->addr, cond->prefix_len)) break; if (sk->sk_family == AF_INET6 && cond->family == AF_INET) { if (addr[0] == 0 && addr[1] == 0 && addr[2] == htonl(0xffff) && bitstring_match(addr+3, cond->addr, cond->prefix_len)) break; } yes = 0; break; } } if (yes) { len -= op->yes; bc += op->yes; } else { len -= op->no; bc += op->no; } } return (len == 0);}static int valid_cc(const void *bc, int len, int cc){ while (len >= 0) { const struct tcpdiag_bc_op *op = bc; if (cc > len) return 0; if (cc == len) return 1; if (op->yes < 4) return 0; len -= op->yes; bc += op->yes; } return 0;}static int tcpdiag_bc_audit(const void *bytecode, int bytecode_len){ const unsigned char *bc = bytecode; int len = bytecode_len; while (len > 0) { struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc;//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len); switch (op->code) { case TCPDIAG_BC_AUTO: case TCPDIAG_BC_S_COND: case TCPDIAG_BC_D_COND: case TCPDIAG_BC_S_GE: case TCPDIAG_BC_S_LE: case TCPDIAG_BC_D_GE: case TCPDIAG_BC_D_LE: if (op->yes < 4 || op->yes > len+4) return -EINVAL; case TCPDIAG_BC_JMP: if (op->no < 4 || op->no > len+4) return -EINVAL; if (op->no < len && !valid_cc(bytecode, bytecode_len, len-op->no)) return -EINVAL; break; case TCPDIAG_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 tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb){ int i, num; int s_i, s_num; struct tcpdiagreq *r = NLMSG_DATA(cb->nlh); struct rtattr *bc = NULL; if (cb->nlh->nlmsg_len > 4+NLMSG_SPACE(sizeof(struct tcpdiagreq))) bc = (struct rtattr*)(r+1); s_i = cb->args[1]; s_num = num = cb->args[2]; if (cb->args[0] == 0) { if (!(r->tcpdiag_states&(TCPF_LISTEN|TCPF_SYN_RECV))) goto skip_listen_ht; tcp_listen_lock(); for (i = s_i; i < TCP_LHTABLE_SIZE; i++) { struct sock *sk; struct hlist_node *node; if (i > s_i) s_num = 0; num = 0; sk_for_each(sk, node, &tcp_listening_hash[i]) { struct inet_opt *inet = inet_sk(sk); if (num < s_num) goto next_listen; if (!(r->tcpdiag_states&TCPF_LISTEN) || r->id.tcpdiag_dport) goto next_listen; if (r->id.tcpdiag_sport != inet->sport && r->id.tcpdiag_sport) goto next_listen; if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk)) goto next_listen; if (tcpdiag_fill(skb, sk, r->tcpdiag_ext, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq) <= 0) { tcp_listen_unlock(); goto done; }next_listen: ++num; } } tcp_listen_unlock();skip_listen_ht: cb->args[0] = 1; s_i = num = s_num = 0; } if (!(r->tcpdiag_states&~(TCPF_LISTEN|TCPF_SYN_RECV))) return skb->len; for (i = s_i; i < tcp_ehash_size; i++) { struct tcp_ehash_bucket *head = &tcp_ehash[i]; struct sock *sk; struct hlist_node *node; if (i > s_i) s_num = 0; read_lock_bh(&head->lock); num = 0; sk_for_each(sk, node, &head->chain) { struct inet_opt *inet = inet_sk(sk); if (num < s_num) goto next_normal; if (!(r->tcpdiag_states & (1 << sk->sk_state))) goto next_normal; if (r->id.tcpdiag_sport != inet->sport && r->id.tcpdiag_sport) goto next_normal; if (r->id.tcpdiag_dport != inet->dport && r->id.tcpdiag_dport) goto next_normal; if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk)) goto next_normal; if (tcpdiag_fill(skb, sk, r->tcpdiag_ext, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq) <= 0) { read_unlock_bh(&head->lock); goto done; }next_normal: ++num; } if (r->tcpdiag_states&TCPF_TIME_WAIT) { sk_for_each(sk, node, &tcp_ehash[i + tcp_ehash_size].chain) { struct inet_opt *inet = inet_sk(sk); if (num < s_num) goto next_dying; if (r->id.tcpdiag_sport != inet->sport && r->id.tcpdiag_sport) goto next_dying; if (r->id.tcpdiag_dport != inet->dport && r->id.tcpdiag_dport) goto next_dying; if (bc && !tcpdiag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), sk)) goto next_dying; if (tcpdiag_fill(skb, sk, r->tcpdiag_ext, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq) <= 0) { read_unlock_bh(&head->lock); goto done; }next_dying: ++num; } } read_unlock_bh(&head->lock); }done: cb->args[1] = i; cb->args[2] = num; return skb->len;}static int tcpdiag_dump_done(struct netlink_callback *cb){ return 0;}static __inline__ inttcpdiag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh){ if (!(nlh->nlmsg_flags&NLM_F_REQUEST)) return 0; if (nlh->nlmsg_type != TCPDIAG_GETSOCK) goto err_inval; if (NLMSG_LENGTH(sizeof(struct tcpdiagreq)) > skb->len) goto err_inval; if (nlh->nlmsg_flags&NLM_F_DUMP) { if (nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(struct tcpdiagreq))) { struct rtattr *rta = (struct rtattr*)(NLMSG_DATA(nlh) + sizeof(struct tcpdiagreq)); if (rta->rta_type != TCPDIAG_REQ_BYTECODE || rta->rta_len < 8 || rta->rta_len > nlh->nlmsg_len - NLMSG_SPACE(sizeof(struct tcpdiagreq))) goto err_inval; if (tcpdiag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta))) goto err_inval; } return netlink_dump_start(tcpnl, skb, nlh, tcpdiag_dump, tcpdiag_dump_done); } else { return tcpdiag_get_exact(skb, nlh); }err_inval: return -EINVAL;}static inline void tcpdiag_rcv_skb(struct sk_buff *skb){ int err; struct nlmsghdr * nlh; if (skb->len >= NLMSG_SPACE(0)) { nlh = (struct nlmsghdr *)skb->data; if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) return; err = tcpdiag_rcv_msg(skb, nlh); if (err || nlh->nlmsg_flags & NLM_F_ACK) netlink_ack(skb, nlh, err); }}static void tcpdiag_rcv(struct sock *sk, int len){ struct sk_buff *skb; while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { tcpdiag_rcv_skb(skb); kfree_skb(skb); }}void __init tcpdiag_init(void){ tcpnl = netlink_kernel_create(NETLINK_TCPDIAG, tcpdiag_rcv); if (tcpnl == NULL) panic("tcpdiag_init: Cannot create netlink socket.");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -