The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 46c241f3adc0ec015c1bf226ac60b2380d867057 $")
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 int af; //!< AF_INET, AF_INET6, or AF_UNIX
76 int type; //!< SOCK_STREAM, SOCK_DGRAM, etc.
77
78 int fd; //!< File descriptor if this is a live socket.
80
81/** Check the proto value is sane/supported
82 *
83 * @param[in] proto to check
84 * @return
85 * - true if it is.
86 * - false if it's not.
87 */
88static inline bool fr_socket_proto_is_known(int proto)
89{
90 /*
91 * Check the protocol is sane
92 */
93 switch (proto) {
94 case IPPROTO_UDP:
95 case IPPROTO_TCP:
96#ifdef IPPROTO_SCTP
97 case IPPROTO_SCTP:
98#endif
99 return true;
100
101 default:
102 fr_strerror_printf("Unknown IP protocol %d", proto);
103 return false;
104 }
105}
106
107#define FR_SOCKET_ADDR_ALLOC_DEF_FUNC(_func, ...) \
108 fr_socket_t *addr; \
109 addr = talloc(ctx, fr_socket_t); \
110 if (unlikely(!addr)) return NULL; \
111 return _func(addr, ##__VA_ARGS__);
112
113/** Swap src/dst information of a fr_socket_t
114 *
115 * @param[out] dst Where to write the swapped addresses. May be the same as src.
116 * @param[in] src Socket address to swap.
117 */
118static inline void fr_socket_addr_swap(fr_socket_t *dst, fr_socket_t const *src)
119{
120 fr_socket_t tmp = *src;
121
122 if (dst != src) *dst = tmp; /* copy non-address fields over */
123
124 dst->inet.dst_ipaddr = tmp.inet.src_ipaddr;
125 dst->inet.dst_port = tmp.inet.src_port;
126 dst->inet.src_ipaddr = tmp.inet.dst_ipaddr;
127 dst->inet.src_port = tmp.inet.dst_port;
128}
129
130/** Initialise a fr_socket_t for connecting to a remote host using a specific src interface, address and port
131 *
132 * Can also be used to record information from an incoming packet so that we can
133 * identify the correct return path later.
134 *
135 * @param[out] addr to initialise.
136 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
137 * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
138 * indicate an unknown or unspecified interface.
139 * @param[in] src_ipaddr The source IP address of the packet, or source interface for
140 * packets to egress out of.
141 * @param[in] src_port The source port of the packet or the source
142 * @param[in] dst_ipaddr The destination IP address of the packet.
143 * @param[in] dst_port The destination port of the packet.
144 * @return
145 * - NULL if invalid parameters are provided.
146 * - An initialised fr_socket_t struct.
147 */
149 int proto,
150 int ifindex, fr_ipaddr_t const *src_ipaddr, int src_port,
151 fr_ipaddr_t const *dst_ipaddr, int dst_port)
152{
153 if (!fr_socket_proto_is_known(proto)) return NULL;
154
155 *addr = (fr_socket_t){
156 .af = src_ipaddr->af,
157 .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM,
158 .inet = {
159 .ifindex = ifindex,
160 .src_ipaddr = *src_ipaddr,
161 .src_port = src_port,
162 .dst_ipaddr = *dst_ipaddr,
163 .dst_port = dst_port
164 }
165 };
166
167 return addr;
168}
169
170/** Initialise a fr_socket_t for connecting to a remote host using a specific src interface, address and port
171 *
172 * Can also be used to record information from an incoming packet so that we can
173 * identify the correct return path later.
174 *
175 * @param[in] ctx to allocate a new #fr_socket_t struct in.
176 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
177 * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
178 * indicate an unknown or unspecified interface.
179 * @param[in] src_ipaddr The source IP address of the packet, or source interface for
180 * packets to egress out of.
181 * @param[in] src_port The source port of the packet or the source
182 * @param[in] dst_ipaddr The destination IP address of the packet.
183 * @param[in] dst_port The destination port of the packet.
184 * @return
185 * - NULL if invalid parameters are provided.
186 * - An initialised fr_socket_t struct.
187 */
188static inline fr_socket_t *fr_socket_addr_alloc_inet(TALLOC_CTX *ctx, int proto,
189 int ifindex, fr_ipaddr_t const *src_ipaddr, int src_port,
190 fr_ipaddr_t const *dst_ipaddr, int dst_port)
191{
193 proto, ifindex, src_ipaddr, src_port, dst_ipaddr, dst_port)
194}
195
196/** A variant of fr_socket_addr_alloc_inet will also allocates a #fr_socket_t
197 *
198
199 * @param[out] addr to initialise.
200 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
201 * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
202 * indicate an unknown or unspecified interface.
203 * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
204 * all addresses, but the AF must still be specified.
205 * @param[in] port The source port to bind to.
206 * @return
207 * - NULL if invalid parameters are provided.
208 * - An initialised fr_socket_t struct.
209 */
211 int proto, int ifindex, fr_ipaddr_t const *ipaddr, int port)
212{
213 if (!fr_socket_proto_is_known(proto)) return NULL;
214
215 *addr = (fr_socket_t){
216 .af = ipaddr->af,
217 .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM,
218 .inet = {
219 .ifindex = ifindex,
220 .src_ipaddr = *ipaddr,
221 .src_port = port
222 }
223 };
224
225 return addr;
226}
227
228/** A variant of fr_socket_addr_init_inet_src will also allocates a #fr_socket_t
229 *
230 * @param[in] ctx to allocate a new #fr_socket_t struct in.
231 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
232 * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
233 * indicate an unknown or unspecified interface.
234 * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
235 * all addresses, but the AF must still be specified.
236 * @param[in] port The source port to bind to.
237 * @return
238 * - NULL if invalid parameters are provided.
239 * - An initialised fr_socket_t struct.
240 */
241static inline fr_socket_t *fr_socket_addr_alloc_inet_src(TALLOC_CTX *ctx, int proto,
242 int ifindex, fr_ipaddr_t const *ipaddr, int port)
243{
245}
246/** Initialise a #fr_socket_t for connecting to a remote host
247 *
248 * @param[out] addr to initialise.
249 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
250 * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
251 * all addresses, but the AF must still be specified.
252 * @param[in] port The source port to bind to.
253 * @return
254 * - NULL if invalid parameters are provided.
255 * - An initialised fr_socket_t struct.
256 */
257static inline fr_socket_t *fr_socket_addr_init_inet_dst(fr_socket_t *addr, int proto, fr_ipaddr_t const *ipaddr, int port)
258{
259 if (!fr_socket_proto_is_known(proto)) return NULL;
260
261 *addr = (fr_socket_t){
262 .af = ipaddr->af,
263 .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM,
264 .inet = {
265 .dst_ipaddr = *ipaddr,
266 .dst_port = port
267 }
268 };
269
270 return addr;
271}
272
273/** A variant of fr_socket_addr_alloc_inet_dst that will also allocates a #fr_socket_t
274 *
275 * @param[in] ctx to allocate new #fr_socket_t struct in.
276 * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
277 * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
278 * all addresses, but the AF must still be specified.
279 * @param[in] port The source port to bind to.
280 * @return
281 * - NULL if invalid parameters are provided.
282 * - An initialised fr_socket_t struct.
283 */
284static inline fr_socket_t *fr_socket_addr_alloc_inet_dst(TALLOC_CTX *ctx, int proto,
285 fr_ipaddr_t const *ipaddr, int port)
286{
288}
289
290int fr_socket_client_unix(char const *path, bool async);
291
292int fr_socket_client_udp(char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port,
293 fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async);
294
295int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t *src_ipaddr,
296 fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async);
298
299int fr_socket_server_udp(fr_ipaddr_t const *ipaddr, uint16_t *port, char const *port_name, bool async);
300
301int fr_socket_server_tcp(fr_ipaddr_t const *ipaddr, uint16_t *port, char const *port_name, bool async);
302
303int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port);
304
305#ifdef __cplusplus
306}
307#endif
#define RCSIDH(h, id)
Definition build.h:489
static int sockfd
Definition dhcpclient.c:55
int af
Address family.
Definition inet.h:63
IPv4/6 prefix.
unsigned short uint16_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:241
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:75
int fd
File descriptor if this is a live socket.
Definition socket.h:78
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition socket.h:76
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:148
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:948
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:846
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:284
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:88
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:188
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:210
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:782
#define FR_SOCKET_ADDR_ALLOC_DEF_FUNC(_func,...)
Definition socket.h:107
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:257
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:118
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