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

📄 ipv6.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	DCCP over IPv6 *	Linux INET6 implementation * *	Based on net/dccp6/ipv6.c * *	Arnaldo Carvalho de Melo <acme@ghostprotocols.net> * *	This program is free software; you can redistribute it and/or *      modify it under the terms of the GNU General Public License *      as published by the Free Software Foundation; either version *      2 of the License, or (at your option) any later version. */#include <linux/module.h>#include <linux/random.h>#include <linux/xfrm.h>#include <net/addrconf.h>#include <net/inet_common.h>#include <net/inet_hashtables.h>#include <net/inet_sock.h>#include <net/inet6_connection_sock.h>#include <net/inet6_hashtables.h>#include <net/ip6_route.h>#include <net/ipv6.h>#include <net/protocol.h>#include <net/transp_v6.h>#include <net/ip6_checksum.h>#include <net/xfrm.h>#include "dccp.h"#include "ipv6.h"#include "feat.h"/* Socket used for sending RSTs and ACKs */static struct socket *dccp_v6_ctl_socket;static struct inet_connection_sock_af_ops dccp_ipv6_mapped;static struct inet_connection_sock_af_ops dccp_ipv6_af_ops;static int dccp_v6_get_port(struct sock *sk, unsigned short snum){	return inet_csk_get_port(&dccp_hashinfo, sk, snum,				 inet6_csk_bind_conflict);}static void dccp_v6_hash(struct sock *sk){	if (sk->sk_state != DCCP_CLOSED) {		if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) {			dccp_hash(sk);			return;		}		local_bh_disable();		__inet6_hash(&dccp_hashinfo, sk);		local_bh_enable();	}}/* add pseudo-header to DCCP checksum stored in skb->csum */static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,				      struct in6_addr *saddr,				      struct in6_addr *daddr){	return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);}static inline void dccp_v6_send_check(struct sock *sk, int unused_value,				      struct sk_buff *skb){	struct ipv6_pinfo *np = inet6_sk(sk);	struct dccp_hdr *dh = dccp_hdr(skb);	dccp_csum_outgoing(skb);	dh->dccph_checksum = dccp_v6_csum_finish(skb, &np->saddr, &np->daddr);}static inline __u32 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,						  __be16 sport, __be16 dport   ){	return secure_tcpv6_sequence_number(saddr, daddr, sport, dport);}static inline __u32 dccp_v6_init_sequence(struct sk_buff *skb){	return secure_dccpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,					     ipv6_hdr(skb)->saddr.s6_addr32,					     dccp_hdr(skb)->dccph_dport,					     dccp_hdr(skb)->dccph_sport     );}static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,			int type, int code, int offset, __be32 info){	struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data;	const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset);	struct ipv6_pinfo *np;	struct sock *sk;	int err;	__u64 seq;	sk = inet6_lookup(&dccp_hashinfo, &hdr->daddr, dh->dccph_dport,			  &hdr->saddr, dh->dccph_sport, inet6_iif(skb));	if (sk == NULL) {		ICMP6_INC_STATS_BH(__in6_dev_get(skb->dev), ICMP6_MIB_INERRORS);		return;	}	if (sk->sk_state == DCCP_TIME_WAIT) {		inet_twsk_put(inet_twsk(sk));		return;	}	bh_lock_sock(sk);	if (sock_owned_by_user(sk))		NET_INC_STATS_BH(LINUX_MIB_LOCKDROPPEDICMPS);	if (sk->sk_state == DCCP_CLOSED)		goto out;	np = inet6_sk(sk);	if (type == ICMPV6_PKT_TOOBIG) {		struct dst_entry *dst = NULL;		if (sock_owned_by_user(sk))			goto out;		if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED))			goto out;		/* icmp should have updated the destination cache entry */		dst = __sk_dst_check(sk, np->dst_cookie);		if (dst == NULL) {			struct inet_sock *inet = inet_sk(sk);			struct flowi fl;			/* BUGGG_FUTURE: Again, it is not clear how			   to handle rthdr case. Ignore this complexity			   for now.			 */			memset(&fl, 0, sizeof(fl));			fl.proto = IPPROTO_DCCP;			ipv6_addr_copy(&fl.fl6_dst, &np->daddr);			ipv6_addr_copy(&fl.fl6_src, &np->saddr);			fl.oif = sk->sk_bound_dev_if;			fl.fl_ip_dport = inet->dport;			fl.fl_ip_sport = inet->sport;			security_sk_classify_flow(sk, &fl);			err = ip6_dst_lookup(sk, &dst, &fl);			if (err) {				sk->sk_err_soft = -err;				goto out;			}			err = xfrm_lookup(&dst, &fl, sk, 0);			if (err < 0) {				sk->sk_err_soft = -err;				goto out;			}		} else			dst_hold(dst);		if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) {			dccp_sync_mss(sk, dst_mtu(dst));		} /* else let the usual retransmit timer handle it */		dst_release(dst);		goto out;	}	icmpv6_err_convert(type, code, &err);	seq = dccp_hdr_seq(dh);	/* Might be for an request_sock */	switch (sk->sk_state) {		struct request_sock *req, **prev;	case DCCP_LISTEN:		if (sock_owned_by_user(sk))			goto out;		req = inet6_csk_search_req(sk, &prev, dh->dccph_dport,					   &hdr->daddr, &hdr->saddr,					   inet6_iif(skb));		if (req == NULL)			goto out;		/*		 * ICMPs are not backlogged, hence we cannot get an established		 * socket here.		 */		BUG_TRAP(req->sk == NULL);		if (seq != dccp_rsk(req)->dreq_iss) {			NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);			goto out;		}		inet_csk_reqsk_queue_drop(sk, req, prev);		goto out;	case DCCP_REQUESTING:	case DCCP_RESPOND:  /* Cannot happen.			       It can, it SYNs are crossed. --ANK */		if (!sock_owned_by_user(sk)) {			DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);			sk->sk_err = err;			/*			 * Wake people up to see the error			 * (see connect in sock.c)			 */			sk->sk_error_report(sk);			dccp_done(sk);		} else			sk->sk_err_soft = err;		goto out;	}	if (!sock_owned_by_user(sk) && np->recverr) {		sk->sk_err = err;		sk->sk_error_report(sk);	} else		sk->sk_err_soft = err;out:	bh_unlock_sock(sk);	sock_put(sk);}static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,				 struct dst_entry *dst){	struct inet6_request_sock *ireq6 = inet6_rsk(req);	struct ipv6_pinfo *np = inet6_sk(sk);	struct sk_buff *skb;	struct ipv6_txoptions *opt = NULL;	struct in6_addr *final_p = NULL, final;	struct flowi fl;	int err = -1;	memset(&fl, 0, sizeof(fl));	fl.proto = IPPROTO_DCCP;	ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);	ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);	fl.fl6_flowlabel = 0;	fl.oif = ireq6->iif;	fl.fl_ip_dport = inet_rsk(req)->rmt_port;	fl.fl_ip_sport = inet_sk(sk)->sport;	security_req_classify_flow(req, &fl);	if (dst == NULL) {		opt = np->opt;		if (opt != NULL && opt->srcrt != NULL) {			const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;			ipv6_addr_copy(&final, &fl.fl6_dst);			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);			final_p = &final;		}		err = ip6_dst_lookup(sk, &dst, &fl);		if (err)			goto done;		if (final_p)			ipv6_addr_copy(&fl.fl6_dst, final_p);		err = xfrm_lookup(&dst, &fl, sk, 0);		if (err < 0)			goto done;	}	skb = dccp_make_response(sk, dst, req);	if (skb != NULL) {		struct dccp_hdr *dh = dccp_hdr(skb);		dh->dccph_checksum = dccp_v6_csum_finish(skb,							 &ireq6->loc_addr,							 &ireq6->rmt_addr);		ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);		err = ip6_xmit(sk, skb, &fl, opt, 0);		err = net_xmit_eval(err);	}done:	if (opt != NULL && opt != np->opt)		sock_kfree_s(sk, opt, opt->tot_len);	dst_release(dst);	return err;}static void dccp_v6_reqsk_destructor(struct request_sock *req){	if (inet6_rsk(req)->pktopts != NULL)		kfree_skb(inet6_rsk(req)->pktopts);}static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb){	struct ipv6hdr *rxip6h;	struct sk_buff *skb;	struct flowi fl;	if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)		return;	if (!ipv6_unicast_destination(rxskb))		return;	skb = dccp_ctl_make_reset(dccp_v6_ctl_socket, rxskb);	if (skb == NULL)		return;	rxip6h = ipv6_hdr(rxskb);	dccp_hdr(skb)->dccph_checksum = dccp_v6_csum_finish(skb, &rxip6h->saddr,							    &rxip6h->daddr);	memset(&fl, 0, sizeof(fl));	ipv6_addr_copy(&fl.fl6_dst, &rxip6h->saddr);	ipv6_addr_copy(&fl.fl6_src, &rxip6h->daddr);	fl.proto = IPPROTO_DCCP;	fl.oif = inet6_iif(rxskb);	fl.fl_ip_dport = dccp_hdr(skb)->dccph_dport;	fl.fl_ip_sport = dccp_hdr(skb)->dccph_sport;	security_skb_classify_flow(rxskb, &fl);	/* sk = NULL, but it is safe for now. RST socket required. */	if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {		if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {			ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0);			DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);			DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);			return;		}	}	kfree_skb(skb);}static struct request_sock_ops dccp6_request_sock_ops = {	.family		= AF_INET6,	.obj_size	= sizeof(struct dccp6_request_sock),	.rtx_syn_ack	= dccp_v6_send_response,	.send_ack	= dccp_reqsk_send_ack,	.destructor	= dccp_v6_reqsk_destructor,	.send_reset	= dccp_v6_ctl_send_reset,};static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb){	const struct dccp_hdr *dh = dccp_hdr(skb);	const struct ipv6hdr *iph = ipv6_hdr(skb);	struct sock *nsk;	struct request_sock **prev;	/* Find possible connection requests. */	struct request_sock *req = inet6_csk_search_req(sk, &prev,							dh->dccph_sport,							&iph->saddr,							&iph->daddr,							inet6_iif(skb));	if (req != NULL)		return dccp_check_req(sk, skb, req, prev);	nsk = __inet6_lookup_established(&dccp_hashinfo,					 &iph->saddr, dh->dccph_sport,					 &iph->daddr, ntohs(dh->dccph_dport),					 inet6_iif(skb));	if (nsk != NULL) {		if (nsk->sk_state != DCCP_TIME_WAIT) {			bh_lock_sock(nsk);			return nsk;		}		inet_twsk_put(inet_twsk(nsk));		return NULL;	}	return sk;}static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb){	struct request_sock *req;	struct dccp_request_sock *dreq;	struct inet6_request_sock *ireq6;	struct ipv6_pinfo *np = inet6_sk(sk);	const __be32 service = dccp_hdr_request(skb)->dccph_req_service;	struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);	if (skb->protocol == htons(ETH_P_IP))		return dccp_v4_conn_request(sk, skb);	if (!ipv6_unicast_destination(skb))		return 0;	/* discard, don't send a reset here */	if (dccp_bad_service_code(sk, service)) {		dcb->dccpd_reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;		goto drop;	}	/*	 * There are no SYN attacks on IPv6, yet...	 */	dcb->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY;	if (inet_csk_reqsk_queue_is_full(sk))		goto drop;

⌨️ 快捷键说明

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