2056 lines · 49.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * INET		An implementation of the TCP/IP protocol suite for the LINUX *		operating system.  INET is implemented using the  BSD Socket *		interface as the means of communication with the user level. * *		PF_INET protocol family socket handler. * * Authors:	Ross Biro *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> *		Florian La Roche, <flla@stud.uni-sb.de> *		Alan Cox, <A.Cox@swansea.ac.uk> * * Changes (see also sock.c) * *		piggy, *		Karl Knutson	:	Socket protocol table *		A.N.Kuznetsov	:	Socket death error in accept(). *		John Richardson :	Fix non blocking error in connect() *					so sockets that fail to connect *					don't return -EINPROGRESS. *		Alan Cox	:	Asynchronous I/O support *		Alan Cox	:	Keep correct socket pointer on sock *					structures *					when accept() ed *		Alan Cox	:	Semantics of SO_LINGER aren't state *					moved to close when you look carefully. *					With this fixed and the accept bug fixed *					some RPC stuff seems happier. *		Niibe Yutaka	:	4.4BSD style write async I/O *		Alan Cox, *		Tony Gale 	:	Fixed reuse semantics. *		Alan Cox	:	bind() shouldn't abort existing but dead *					sockets. Stops FTP netin:.. I hope. *		Alan Cox	:	bind() works correctly for RAW sockets. *					Note that FreeBSD at least was broken *					in this respect so be careful with *					compatibility tests... *		Alan Cox	:	routing cache support *		Alan Cox	:	memzero the socket structure for *					compactness. *		Matt Day	:	nonblock connect error handler *		Alan Cox	:	Allow large numbers of pending sockets *					(eg for big web sites), but only if *					specifically application requested. *		Alan Cox	:	New buffering throughout IP. Used *					dumbly. *		Alan Cox	:	New buffering now used smartly. *		Alan Cox	:	BSD rather than common sense *					interpretation of listen. *		Germano Caronni	:	Assorted small races. *		Alan Cox	:	sendmsg/recvmsg basic support. *		Alan Cox	:	Only sendmsg/recvmsg now supported. *		Alan Cox	:	Locked down bind (see security list). *		Alan Cox	:	Loosened bind a little. *		Mike McLagan	:	ADD/DEL DLCI Ioctls *	Willy Konynenberg	:	Transparent proxying support. *		David S. Miller	:	New socket lookup architecture. *					Some other random speedups. *		Cyrus Durgin	:	Cleaned up file for kmod hacks. *		Andi Kleen	:	Fix inet_stream_connect TCP race. */ #define pr_fmt(fmt) "IPv4: " fmt #include <linux/err.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/kernel.h>#include <linux/kmod.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/sockios.h>#include <linux/net.h>#include <linux/capability.h>#include <linux/fcntl.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/stat.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/netfilter_ipv4.h>#include <linux/random.h>#include <linux/slab.h> #include <linux/uaccess.h> #include <linux/inet.h>#include <linux/igmp.h>#include <linux/inetdevice.h>#include <linux/netdevice.h>#include <net/checksum.h>#include <net/ip.h>#include <net/protocol.h>#include <net/arp.h>#include <net/route.h>#include <net/ip_fib.h>#include <net/inet_connection_sock.h>#include <net/gro.h>#include <net/gso.h>#include <net/tcp.h>#include <net/psp.h>#include <net/udp.h>#include <net/ping.h>#include <linux/skbuff.h>#include <net/sock.h>#include <net/raw.h>#include <net/icmp.h>#include <net/inet_common.h>#include <net/ip_tunnels.h>#include <net/xfrm.h>#include <net/net_namespace.h>#include <net/secure_seq.h>#ifdef CONFIG_IP_MROUTE#include <linux/mroute.h>#endif#include <net/l3mdev.h>#include <net/compat.h>#include <net/rps.h> #include <trace/events/sock.h> /* Keep the definition of IPv6 disable here for now, to avoid annoying linker * issues in case IPv6=m */int disable_ipv6_mod;EXPORT_SYMBOL(disable_ipv6_mod); /* The inetsw table contains everything that inet_create needs to * build a new socket. */static struct list_head inetsw[SOCK_MAX];static DEFINE_SPINLOCK(inetsw_lock); /* New destruction routine */ void inet_sock_destruct(struct sock *sk){	struct inet_sock *inet = inet_sk(sk); 	__skb_queue_purge(&sk->sk_receive_queue);	__skb_queue_purge(&sk->sk_error_queue); 	sk_mem_reclaim_final(sk); 	if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) {		pr_err("Attempt to release TCP socket in state %d %p\n",		       sk->sk_state, sk);		return;	}	if (!sock_flag(sk, SOCK_DEAD)) {		pr_err("Attempt to release alive inet socket %p\n", sk);		return;	} 	WARN_ON_ONCE(atomic_read(&sk->sk_rmem_alloc));	WARN_ON_ONCE(refcount_read(&sk->sk_wmem_alloc));	WARN_ON_ONCE(sk->sk_wmem_queued);	WARN_ON_ONCE(sk->sk_forward_alloc); 	kfree(rcu_dereference_protected(inet->inet_opt, 1));	dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1));	dst_release(rcu_dereference_protected(sk->sk_rx_dst, 1));	psp_sk_assoc_free(sk);}EXPORT_SYMBOL(inet_sock_destruct); /* *	The routines beyond this point handle the behaviour of an AF_INET *	socket object. Mostly it punts to the subprotocols of IP to do *	the work. */ /* *	Automatically bind an unbound socket. */ static int inet_autobind(struct sock *sk){	struct inet_sock *inet;	/* We may need to bind the socket. */	lock_sock(sk);	inet = inet_sk(sk);	if (!inet->inet_num) {		if (sk->sk_prot->get_port(sk, 0)) {			release_sock(sk);			return -EAGAIN;		}		inet->inet_sport = htons(inet->inet_num);	}	release_sock(sk);	return 0;} int __inet_listen_sk(struct sock *sk, int backlog){	unsigned char old_state = sk->sk_state;	int err, tcp_fastopen; 	if (!((1 << old_state) & (TCPF_CLOSE | TCPF_LISTEN)))		return -EINVAL; 	WRITE_ONCE(sk->sk_max_ack_backlog, backlog);	/* Really, if the socket is already in listen state	 * we can only allow the backlog to be adjusted.	 */	if (old_state != TCP_LISTEN) {		/* Enable TFO w/o requiring TCP_FASTOPEN socket option.		 * Note that only TCP sockets (SOCK_STREAM) will reach here.		 * Also fastopen backlog may already been set via the option		 * because the socket was in TCP_LISTEN state previously but		 * was shutdown() rather than close().		 */		tcp_fastopen = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_fastopen);		if ((tcp_fastopen & TFO_SERVER_WO_SOCKOPT1) &&		    (tcp_fastopen & TFO_SERVER_ENABLE) &&		    !inet_csk(sk)->icsk_accept_queue.fastopenq.max_qlen) {			fastopen_queue_tune(sk, backlog);			tcp_fastopen_init_key_once(sock_net(sk));		} 		err = inet_csk_listen_start(sk);		if (err)			return err; 		tcp_call_bpf(sk, BPF_SOCK_OPS_TCP_LISTEN_CB, 0, NULL);	}	return 0;} /* *	Move a socket into listening state. */int inet_listen(struct socket *sock, int backlog){	struct sock *sk = sock->sk;	int err = -EINVAL; 	lock_sock(sk); 	if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM)		goto out; 	err = __inet_listen_sk(sk, backlog); out:	release_sock(sk);	return err;}EXPORT_SYMBOL(inet_listen); /* *	Create an inet socket. */ static int inet_create(struct net *net, struct socket *sock, int protocol,		       int kern){	struct sock *sk;	struct inet_protosw *answer;	struct inet_sock *inet;	struct proto *answer_prot;	unsigned char answer_flags;	int try_loading_module = 0;	int err; 	if (protocol < 0 || protocol >= IPPROTO_MAX)		return -EINVAL; 	sock->state = SS_UNCONNECTED; 	/* Look for the requested type/protocol pair. */lookup_protocol:	err = -ESOCKTNOSUPPORT;	rcu_read_lock();	list_for_each_entry_rcu(answer, &inetsw[sock->type], list) { 		err = 0;		/* Check the non-wild match. */		if (protocol == answer->protocol) {			if (protocol != IPPROTO_IP)				break;		} else {			/* Check for the two wild cases. */			if (IPPROTO_IP == protocol) {				protocol = answer->protocol;				break;			}			if (IPPROTO_IP == answer->protocol)				break;		}		err = -EPROTONOSUPPORT;	} 	if (unlikely(err)) {		if (try_loading_module < 2) {			rcu_read_unlock();			/*			 * Be more specific, e.g. net-pf-2-proto-132-type-1			 * (net-pf-PF_INET-proto-IPPROTO_SCTP-type-SOCK_STREAM)			 */			if (++try_loading_module == 1)				request_module("net-pf-%d-proto-%d-type-%d",					       PF_INET, protocol, sock->type);			/*			 * Fall back to generic, e.g. net-pf-2-proto-132			 * (net-pf-PF_INET-proto-IPPROTO_SCTP)			 */			else				request_module("net-pf-%d-proto-%d",					       PF_INET, protocol);			goto lookup_protocol;		} else			goto out_rcu_unlock;	} 	err = -EPERM;	if (sock->type == SOCK_RAW && !kern &&	    !ns_capable(net->user_ns, CAP_NET_RAW))		goto out_rcu_unlock; 	sock->ops = answer->ops;	answer_prot = answer->prot;	answer_flags = answer->flags;	rcu_read_unlock(); 	WARN_ON(!answer_prot->slab); 	err = -ENOMEM;	sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, kern);	if (!sk)		goto out; 	err = 0;	if (INET_PROTOSW_REUSE & answer_flags)		sk->sk_reuse = SK_CAN_REUSE; 	if (INET_PROTOSW_ICSK & answer_flags)		inet_init_csk_locks(sk); 	inet = inet_sk(sk);	inet_assign_bit(IS_ICSK, sk, INET_PROTOSW_ICSK & answer_flags); 	inet_clear_bit(NODEFRAG, sk); 	if (SOCK_RAW == sock->type) {		inet->inet_num = protocol;		if (IPPROTO_RAW == protocol)			inet_set_bit(HDRINCL, sk);	} 	if (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc))		inet->pmtudisc = IP_PMTUDISC_DONT;	else		inet->pmtudisc = IP_PMTUDISC_WANT; 	atomic_set(&inet->inet_id, 0); 	sock_init_data(sock, sk); 	sk->sk_destruct	   = inet_sock_destruct;	sk->sk_protocol	   = protocol;	sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;	sk->sk_txrehash = READ_ONCE(net->core.sysctl_txrehash); 	inet->uc_ttl	= -1;	inet_set_bit(MC_LOOP, sk);	inet->mc_ttl	= 1;	inet_set_bit(MC_ALL, sk);	inet->mc_index	= 0;	inet->mc_list	= NULL;	inet->rcv_tos	= 0; 	if (inet->inet_num) {		/* It assumes that any protocol which allows		 * the user to assign a number at socket		 * creation time automatically		 * shares.		 */		inet->inet_sport = htons(inet->inet_num);		/* Add to protocol hash chains. */		err = sk->sk_prot->hash(sk);		if (err)			goto out_sk_release;	} 	if (sk->sk_prot->init) {		err = sk->sk_prot->init(sk);		if (err)			goto out_sk_release;	} 	if (!kern) {		err = BPF_CGROUP_RUN_PROG_INET_SOCK(sk);		if (err)			goto out_sk_release;	}out:	return err;out_rcu_unlock:	rcu_read_unlock();	goto out;out_sk_release:	sk_common_release(sk);	sock->sk = NULL;	goto out;}  /* *	The peer socket should always be NULL (or else). When we call this *	function we are destroying the object and from then on nobody *	should refer to it. */int inet_release(struct socket *sock){	struct sock *sk = sock->sk; 	if (sk) {		long timeout; 		if (!sk->sk_kern_sock)			BPF_CGROUP_RUN_PROG_INET_SOCK_RELEASE(sk); 		/* Applications forget to leave groups before exiting */		ip_mc_drop_socket(sk); 		/* If linger is set, we don't return until the close		 * is complete.  Otherwise we return immediately. The		 * actually closing is done the same either way.		 *		 * If the close is due to the process exiting, we never		 * linger..		 */		timeout = 0;		if (sock_flag(sk, SOCK_LINGER) &&		    !(current->flags & PF_EXITING))			timeout = sk->sk_lingertime;		sk->sk_prot->close(sk, timeout);		sock->sk = NULL;	}	return 0;}EXPORT_SYMBOL(inet_release); int inet_bind_sk(struct sock *sk, struct sockaddr_unsized *uaddr, int addr_len){	u32 flags = BIND_WITH_LOCK;	int err; 	/* If the socket has its own bind function then use it. (RAW) */	if (sk->sk_prot->bind) {		return sk->sk_prot->bind(sk, uaddr, addr_len);	}	if (addr_len < sizeof(struct sockaddr_in))		return -EINVAL; 	/* BPF prog is run before any checks are done so that if the prog	 * changes context in a wrong way it will be caught.	 */	err = BPF_CGROUP_RUN_PROG_INET_BIND_LOCK(sk, uaddr, &addr_len,						 CGROUP_INET4_BIND, &flags);	if (err)		return err; 	return __inet_bind(sk, uaddr, addr_len, flags);} int inet_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int addr_len){	return inet_bind_sk(sock->sk, uaddr, addr_len);}EXPORT_SYMBOL(inet_bind); int __inet_bind(struct sock *sk, struct sockaddr_unsized *uaddr, int addr_len,		u32 flags){	struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;	struct inet_sock *inet = inet_sk(sk);	struct net *net = sock_net(sk);	unsigned short snum;	int chk_addr_ret;	u32 tb_id = RT_TABLE_LOCAL;	int err; 	if (addr->sin_family != AF_INET) {		/* Compatibility games : accept AF_UNSPEC (mapped to AF_INET)		 * only if s_addr is INADDR_ANY.		 */		err = -EAFNOSUPPORT;		if (addr->sin_family != AF_UNSPEC ||		    addr->sin_addr.s_addr != htonl(INADDR_ANY))			goto out;	} 	tb_id = l3mdev_fib_table_by_index(net, sk->sk_bound_dev_if) ? : tb_id;	chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id);

Lines 1–500 of 2056.