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

📄 tcp_diag.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
		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 + -