The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
socket.h
Go to the documentation of this file.
1#pragma once
2
3/*
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or (at
7 * your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19/** Functions for establishing and managing low level sockets
20 *
21 * @file src/lib/util/socket.c
22 *
23 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 * @author Alan DeKok (aland@freeradius.org)
25 *
26 * @copyright 2015 The FreeRADIUS project
27 */
28RCSIDH(socket_h, "$Id: f3564a19c0b718a20ccd1c2f628b0a924e4aae61 $")
29
30#ifdef __cplusplus
31extern "C" {
32#endif
33
34#include <freeradius-devel/build.h>
35#include <freeradius-devel/missing.h>
36#include <freeradius-devel/util/inet.h>
37#include <freeradius-devel/util/time.h>
38
39#include <sys/time.h>
40
41#ifdef HAVE_SYS_UN_H
42# include <sys/un.h>
43/*
44 * The linux headers define the macro as:
45 *
46 * # define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
47 * + strlen ((ptr)->sun_path))
48 *
49 * Which trips UBSAN, because it sees an operation on a NULL pointer.
50 */
51# undef SUN_LEN
52# define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
53#endif
54
55/** Holds information necessary for binding or connecting to a socket.
56 *
57 * May also be used in protocol contexts to store information necessary for
58 * returning packets to their originators.
59 */
60typedef struct {
61 union {
62 struct {
63 int ifindex; //!< Source interface to bind to or originate the packet from.
64 uint16_t src_port; //!< Port to bind to, or originate the packet from.
65 uint16_t dst_port; //!< Port to connect to or send the packet to.
66
67 fr_ipaddr_t src_ipaddr; //!< IP address to bind to, or originate the packet from.
68 fr_ipaddr_t dst_ipaddr; //!< IP address to connect to, or send the packet to.
69 } inet;
70
71 struct {
72 char const *path; //!< Unix socket path.
73 } unix;
74
75 struct {
76 char const *path; //!< Filename
77 } file;
78
79 struct {
80 char const *server; //!< Virtual server filename
81 } virtual;
82 };
83 int af; //!< AF_INET, AF_INET6, or AF_UNIX
84 int type; //!< SOCK_STREAM, SOCK_DGRAM, etc.
85
86 int fd; //!< File descriptor if this is a live socket.
88
89/** Check the proto value is sane/supported
90 *
91 * @param[in] proto to check
92 * @return
93 * - true if it is.
94 * - false if it's not.
95 */
96static inline bool fr_socket_proto_is_known(int proto)
97{
98 /*
99 * Check the protocol is sane
100 */
101 switch (proto) {
102 case IPPROTO_UDP:
103 case IPPROTO_TCP:
104#ifdef IPPROTO_SCTP
105 case IPPROTO_SCTP:
106#endif
107 return true;
108
109 default:
110 fr_strerror_printf("Unknown IP protocol %d", proto);
111 return false;
112 }
113}
114
115#define FR_SOCKET_ADDR_ALLOC_DEF_FUNC(_func, ...) \
116 fr_socket_t *addr; \
117 addr = talloc(ctx, fr_socket_t); \
118 if (unlikely(!addr)) return NULL; \
119 return _func(addr, ##__VA_ARGS__);
120
121/** Swap src/dst information of a fr_socket_t
122 *
123 * @param[out] dst Where to write the swapped addresses. May be the same as src.
124 * @param[in] src Socket address to swap.
125 */
126static inline void fr_socket_addr_swap(fr_socket_t *dst, fr_socket_t const *src)
127{
128 fr_socket_t tmp = *src;
129
130 if (dst != src) *dst = tmp; /* copy non-address fields over */
131
132 dst->inet.dst_ipaddr = tmp.inet.src_ipaddr;
133 dst->inet.dst_port = tmp.inet.src_port;
134 dst->inet.src_ipaddr = tmp.inet.dst_ipaddr;
135 dst->inet.src_port = tmp.inet.dst_port;
136}
137
138/** Initialise a fr_socket_t for connecting to a remote host using a specific src interface, address and port
139 *
140 * Can also be used to record information from an incoming packet so that we can
141 * identify the correct return path later.
142 *
143 * @param[out] addr to initialise.
144 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
145 * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
146 * indicate an unknown or unspecified interface.
147 * @param[in] src_ipaddr The source IP address of the packet, or source interface for
148 * packets to egress out of.
149 * @param[in] src_port The source port of the packet or the source
150 * @param[in] dst_ipaddr The destination IP address of the packet.
151 * @param[in] dst_port The destination port of the packet.
152 * @return
153 * - NULL if invalid parameters are provided.
154 * - An initialised fr_socket_t struct.
155 */
157 int proto,
158 int ifindex, fr_ipaddr_t const *src_ipaddr, int src_port,
159 fr_ipaddr_t const *dst_ipaddr, int dst_port)
160{
161 if (!fr_socket_proto_is_known(proto)) return NULL;
162
163 *addr = (fr_socket_t){
164 .af = src_ipaddr->af,
165 .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM,
166 .inet = {
167 .ifindex = ifindex,
168 .src_ipaddr = *src_ipaddr,
169 .src_port = src_port,
170 .dst_ipaddr = *dst_ipaddr,
171 .dst_port = dst_port
172 }
173 };
174
175 return addr;
176}
177
178/** Initialise a fr_socket_t for connecting to a remote host using a specific src interface, address and port
179 *
180 * Can also be used to record information from an incoming packet so that we can
181 * identify the correct return path later.
182 *
183 * @param[in] ctx to allocate a new #fr_socket_t struct in.
184 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
185 * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
186 * indicate an unknown or unspecified interface.
187 * @param[in] src_ipaddr The source IP address of the packet, or source interface for
188 * packets to egress out of.
189 * @param[in] src_port The source port of the packet or the source
190 * @param[in] dst_ipaddr The destination IP address of the packet.
191 * @param[in] dst_port The destination port of the packet.
192 * @return
193 * - NULL if invalid parameters are provided.
194 * - An initialised fr_socket_t struct.
195 */
196static inline fr_socket_t *fr_socket_addr_alloc_inet(TALLOC_CTX *ctx, int proto,
197 int ifindex, fr_ipaddr_t const *src_ipaddr, int src_port,
198 fr_ipaddr_t const *dst_ipaddr, int dst_port)
199{
201 proto, ifindex, src_ipaddr, src_port, dst_ipaddr, dst_port)
202}
203
204/** A variant of fr_socket_addr_alloc_inet will also allocates a #fr_socket_t
205 *
206
207 * @param[out] addr to initialise.
208 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
209 * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
210 * indicate an unknown or unspecified interface.
211 * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
212 * all addresses, but the AF must still be specified.
213 * @param[in] port The source port to bind to.
214 * @return
215 * - NULL if invalid parameters are provided.
216 * - An initialised fr_socket_t struct.
217 */
219 int proto, int ifindex, fr_ipaddr_t const *ipaddr, int port)
220{
221 if (!fr_socket_proto_is_known(proto)) return NULL;
222
223 *addr = (fr_socket_t){
224 .af = ipaddr->af,
225 .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM,
226 .inet = {
227 .ifindex = ifindex,
228 .src_ipaddr = *ipaddr,
229 .src_port = port
230 }
231 };
232
233 return addr;
234}
235
236/** A variant of fr_socket_addr_init_inet_src will also allocates a #fr_socket_t
237 *
238 * @param[in] ctx to allocate a new #fr_socket_t struct in.
239 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
240 * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
241 * indicate an unknown or unspecified interface.
242 * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
243 * all addresses, but the AF must still be specified.
244 * @param[in] port The source port to bind to.
245 * @return
246 * - NULL if invalid parameters are provided.
247 * - An initialised fr_socket_t struct.
248 */
249static inline fr_socket_t *fr_socket_addr_alloc_inet_src(TALLOC_CTX *ctx, int proto,
250 int ifindex, fr_ipaddr_t const *ipaddr, int port)
251{
253}
254/** Initialise a #fr_socket_t for connecting to a remote host
255 *
256 * @param[out] addr to initialise.
257 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
258 * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
259 * all addresses, but the AF must still be specified.
260 * @param[in] port The source port to bind to.
261 * @return
262 * - NULL if invalid parameters are provided.
263 * - An initialised fr_socket_t struct.
264 */
265static inline fr_socket_t *fr_socket_addr_init_inet_dst(fr_socket_t *addr, int proto, fr_ipaddr_t const *ipaddr, int port)
266{
267 if (!fr_socket_proto_is_known(proto)) return NULL;
268
269 *addr = (fr_socket_t){
270 .af = ipaddr->af,
271 .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM,
272 .inet = {
273 .dst_ipaddr = *ipaddr,
274 .dst_port = port
275 }
276 };
277
278 return addr;
279}
280
281/** A variant of fr_socket_addr_alloc_inet_dst that will also allocates a #fr_socket_t
282 *
283 * @param[in] ctx to allocate new #fr_socket_t struct in.
284 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
285 * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
286 * all addresses, but the AF must still be specified.
287 * @param[in] port The source port to bind to.
288 * @return
289 * - NULL if invalid parameters are provided.
290 * - An initialised fr_socket_t struct.
291 */
292static inline fr_socket_t *fr_socket_addr_alloc_inet_dst(TALLOC_CTX *ctx, int proto,
293 fr_ipaddr_t const *ipaddr, int port)
294{
296}
297
298int fr_socket_client_unix(char const *path, bool async);
299
300int fr_socket_client_udp(char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port,
301 fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async);
302
303int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t *src_ipaddr,
304 fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async);
306
307int fr_socket_server_udp(fr_ipaddr_t const *ipaddr, uint16_t *port, char const *port_name, bool async);
308
309int fr_socket_server_tcp(fr_ipaddr_t const *ipaddr, uint16_t *port, char const *port_name, bool async);
310
311int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port);
312
313ssize_t fr_socket_to_str(char *out, size_t outlen, fr_socket_t const *sock, bool received) CC_HINT(nonnull);
314
315
316#ifdef __cplusplus
317}
318#endif
int const char * file
Definition acutest.h:702
#define RCSIDH(h, id)
Definition build.h:513
static int sockfd
Definition dhcpclient.c:55
int af
Address family.
Definition inet.h:63
IPv4/6 prefix.
unsigned short uint16_t
long int ssize_t
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
static fr_socket_t * fr_socket_addr_alloc_inet_src(TALLOC_CTX *ctx, int proto, int ifindex, fr_ipaddr_t const *ipaddr, int port)
A variant of fr_socket_addr_init_inet_src will also allocates a fr_socket_t.
Definition socket.h:249
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:83
int fd
File descriptor if this is a live socket.
Definition socket.h:86
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition socket.h:84
static fr_socket_t * fr_socket_addr_init_inet(fr_socket_t *addr, int proto, int ifindex, fr_ipaddr_t const *src_ipaddr, int src_port, fr_ipaddr_t const *dst_ipaddr, int dst_port)
Initialise a fr_socket_t for connecting to a remote host using a specific src interface,...
Definition socket.h:156
int fr_socket_client_udp(char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected UDP socket.
Definition socket.c:613
int fr_socket_server_tcp(fr_ipaddr_t const *ipaddr, uint16_t *port, char const *port_name, bool async)
Open an IPv4/IPv6 TCP socket.
Definition socket.c:945
int fr_socket_server_udp(fr_ipaddr_t const *ipaddr, uint16_t *port, char const *port_name, bool async)
Open an IPv4/IPv6 unconnected UDP socket.
Definition socket.c:843
int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t *src_ipaddr, fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected TCP socket.
Definition socket.c:708
static fr_socket_t * fr_socket_addr_alloc_inet_dst(TALLOC_CTX *ctx, int proto, fr_ipaddr_t const *ipaddr, int port)
A variant of fr_socket_addr_alloc_inet_dst that will also allocates a fr_socket_t.
Definition socket.h:292
int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
Bind a UDP/TCP v4/v6 socket to a given ipaddr src port, and interface.
Definition socket.c:200
static bool fr_socket_proto_is_known(int proto)
Check the proto value is sane/supported.
Definition socket.h:96
ssize_t fr_socket_to_str(char *out, size_t outlen, fr_socket_t const *sock, bool received)
Print an fr_socket_t to a string.
Definition socket.c:1018
static fr_socket_t * fr_socket_addr_alloc_inet(TALLOC_CTX *ctx, int proto, int ifindex, fr_ipaddr_t const *src_ipaddr, int src_port, fr_ipaddr_t const *dst_ipaddr, int dst_port)
Initialise a fr_socket_t for connecting to a remote host using a specific src interface,...
Definition socket.h:196
static fr_socket_t * fr_socket_addr_init_inet_src(fr_socket_t *addr, int proto, int ifindex, fr_ipaddr_t const *ipaddr, int port)
A variant of fr_socket_addr_alloc_inet will also allocates a fr_socket_t.
Definition socket.h:218
int fr_socket_wait_for_connect(int sockfd, fr_time_delta_t timeout)
Wait for a socket to be connected, with an optional timeout.
Definition socket.c:779
#define FR_SOCKET_ADDR_ALLOC_DEF_FUNC(_func,...)
Definition socket.h:115
static fr_socket_t * fr_socket_addr_init_inet_dst(fr_socket_t *addr, int proto, fr_ipaddr_t const *ipaddr, int port)
Initialise a fr_socket_t for connecting to a remote host.
Definition socket.h:265
int fr_socket_client_unix(char const *path, bool async)
static void fr_socket_addr_swap(fr_socket_t *dst, fr_socket_t const *src)
Swap src/dst information of a fr_socket_t.
Definition socket.h:126
Holds information necessary for binding or connecting to a socket.
Definition socket.h:60
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1030