aboutsummaryrefslogtreecommitdiff
path: root/include/socket.h
blob: 8347ef84de66e3f0ac364f898f4fd6604ec60a20 (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/*
 * InspIRCd -- Internet Relay Chat Daemon
 *
 *   Copyright (C) 2013, 2015-2016 Attila Molnar <attilamolnar@hush.com>
 *   Copyright (C) 2012-2013, 2017-2019 Sadie Powell <sadie@witchery.services>
 *   Copyright (C) 2012 Robby <robby@chatbelgie.be>
 *   Copyright (C) 2012 ChrisTX <xpipe@hotmail.de>
 *   Copyright (C) 2012 Adam <Adam@anope.org>
 *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
 *   Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
 *   Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
 *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
 *   Copyright (C) 2006, 2008, 2010 Craig Edwards <brain@inspircd.org>
 *
 * This file is part of InspIRCd.  InspIRCd 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, version 2.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#pragma once

#ifndef _WIN32
# include <netinet/in.h>
# include <sys/socket.h>
# include <sys/stat.h>
# include <sys/un.h>
#else
# include <afunix.h>
#endif

#include <cerrno>

/* Contains irc-specific definitions */
namespace irc
{
	/** This namespace contains various protocol-independent helper classes.
	 * It also contains some types which are often used by the core and modules
	 * in place of inet_* functions and types.
	 */
	namespace sockets
	{
		/** Represents a socket address. This can be an IP/port pair or a UNIX socket path. */
		union CoreExport sockaddrs
		{
			struct sockaddr sa;
			struct sockaddr_in in4;
			struct sockaddr_in6 in6;
			struct sockaddr_un un;

			/** Initializes this sockaddrs optionally as an unspecified socket address. */
			explicit sockaddrs(bool initialize = true);

			/** Returns the address segment of the socket address as a string. */
			std::string addr() const;

			/** Returns the family of the socket address (e.g. AF_INET). */
			int family() const;

			/** Store an IP address or UNIX socket path in this socket address.
			 * @param addr An IPv4 address, IPv6 address, or UNIX socket path.
			 * @return True if the IP address or UNIX socket paht was stored in this socket address; otherwise, false.
			 */
			inline bool from(const std::string& addr) { return addr.find('/') == std::string::npos ? from_ip(addr) : from_unix(addr); }

			/** Store an IP address in this socket address.
			 * @param addr An IPv4 or IPv6 address.
			 * @return True if the IP was stored in this socket address; otherwise, false.
			 */
			inline bool from_ip(const std::string& addr) { return from_ip_port(addr, 0); }

			/** Store an IP address and TCP port pair in this socket address.
			 * @param addr An IPv4 or IPv6 address.
			 * @param port A TCP port.
			 * @return True if the IP/port was stored in this socket address; otherwise, false.
			 */
			bool from_ip_port(const std::string& addr, int port);

			/** Store a UNIX socket path in this socket address.
			 * @param path A path to a UNIX socket.
			 * @return True if the UNIX socket path was stored in this socket address; otherwise, false.
			 */
			bool from_unix(const std::string& path);

			/** Returns the TCP port number of the socket address or 0 if not relevant to this family. */
			int port() const;

			/** Returns the size of the structure for use in networking syscalls. */
			socklen_t sa_size() const;

			/** Returns the whole socket address as a string. */
			std::string str() const;

			/** Determines if this socket address refers to the same endpoint as another socket address. */
			bool operator==(const sockaddrs& other) const;
			inline bool operator!=(const sockaddrs& other) const { return !(*this == other); }
		};

		struct CoreExport cidr_mask
		{
			/** Type, AF_INET or AF_INET6 */
			unsigned char type;
			/** Length of the mask in bits (0-128) */
			unsigned char length;
			/** Raw bits. Unused bits must be zero */
			unsigned char bits[16];

			cidr_mask() = default;
			/** Construct a CIDR mask from the string. Will normalize (127.0.0.1/8 => 127.0.0.0/8). */
			cidr_mask(const std::string& mask);
			/** Construct a CIDR mask of a given length from the given address */
			cidr_mask(const irc::sockets::sockaddrs& addr, unsigned char len);
			/** Equality of bits, type, and length */
			bool operator==(const cidr_mask& other) const;
			/** Ordering defined for maps */
			bool operator<(const cidr_mask& other) const;
			/** Match within this CIDR? */
			bool match(const irc::sockets::sockaddrs& addr) const;
			/** Human-readable string */
			std::string str() const;
		};

		/** Match CIDR, including an optional username/nickname part.
		 *
		 * This function will compare a human-readable address (plus
		 * optional username and nickname) against a human-readable
		 * CIDR mask, for example joe!bloggs\@1.2.3.4 against
		 * *!bloggs\@1.2.0.0/16. This method supports both IPV4 and
		 * IPV6 addresses.
		 * @param address The human readable address, e.g. fred\@1.2.3.4
		 * @param cidr_mask The human readable mask, e.g. *\@1.2.0.0/16
		 * @param match_with_username Does the  mask include a nickname segment?
		 * @return True if the mask matches the address
		 */
		CoreExport bool MatchCIDR(const std::string &address, const std::string &cidr_mask, bool match_with_username);

		/** Determines whether the specified file is a UNIX socket.
		 * @param file The path to the file to check.
		 * @return True if the file is a UNIX socket; otherwise, false.
		 */
		CoreExport bool isunix(const std::string& file);
	}
}

/** Represents information about a failed port binding. */
struct CoreExport FailedPort final
{
	/** The error which happened during binding. */
	int error;

	/** The endpoint on which we were attempting to bind. */
	irc::sockets::sockaddrs sa;

	/** The config tag that the listener was created from. */
	std::shared_ptr<ConfigTag> tag;

	FailedPort(int err, irc::sockets::sockaddrs& ep, std::shared_ptr<ConfigTag> cfg)
		: error(err)
		, sa(ep)
		, tag(cfg)
	{
	}
};

/** A list of failed port bindings, used for informational purposes on startup */
typedef std::vector<FailedPort> FailedPortList;

#include "socketengine.h"

/** This class handles incoming connections on client ports.
 * It will create a new User for every valid connection
 * and assign it a file descriptor.
 */
class CoreExport ListenSocket final
	: public EventHandler
{
public:
	std::shared_ptr<ConfigTag> bind_tag;
	const irc::sockets::sockaddrs bind_sa;

	class IOHookProvRef : public dynamic_reference_nocheck<IOHookProvider>
	{
	public:
		IOHookProvRef()
			: dynamic_reference_nocheck<IOHookProvider>(nullptr, std::string())
		{
		}
	};

	typedef std::array<IOHookProvRef, 2> IOHookProvList;

	/** IOHook providers for handling connections on this socket,
	 * may be empty.
	 */
	IOHookProvList iohookprovs;

	/** Create a new listening socket
	 */
	ListenSocket(std::shared_ptr<ConfigTag> tag, const irc::sockets::sockaddrs& bind_to);
	/** Close the socket
	 */
	~ListenSocket() override;

	/** Handles new connections, called by the socket engine
	 */
	void OnEventHandlerRead() override;

	/** Inspects the bind block belonging to this socket to set the name of the IO hook
	 * provider which this socket will use for incoming connections.
	 */
	void ResetIOHookProvider();
};