The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
28 RCSIDH(socket_h, "$Id: 6a6460f79064afa6d29cc8c117a24a719ab3b6a7 $")
29 
30 #ifdef __cplusplus
31 extern "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 <stdbool.h>
40 #include <stdint.h>
41 #include <string.h>
42 #include <sys/time.h>
43 
44 #ifdef HAVE_SYS_UN_H
45 # include <sys/un.h>
46 /*
47  * The linux headers define the macro as:
48  *
49  * # define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
50  * + strlen ((ptr)->sun_path))
51  *
52  * Which trips UBSAN, because it sees an operation on a NULL pointer.
53  */
54 # undef SUN_LEN
55 # define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
56 #endif
57 
58 /** Holds information necessary for binding or connecting to a socket.
59  *
60  * May also be used in protocol contexts to store information necessary for
61  * returning packets to their originators.
62  */
63 typedef struct {
64  union {
65  struct {
66  int ifindex; //!< Source interface to bind to or originate the packet from.
67  uint16_t src_port; //!< Port to bind to, or originate the packet from.
68  uint16_t dst_port; //!< Port to connect to or send the packet to.
69 
70  fr_ipaddr_t src_ipaddr; //!< IP address to bind to, or originate the packet from.
71  fr_ipaddr_t dst_ipaddr; //!< IP address to connect to, or send the packet to.
72  } inet;
73 
74  struct {
75  char const *path; //!< Unix socket path.
76  } unix;
77  };
78  int af; //!< AF_INET, AF_INET6, or AF_UNIX
79  int type; //!< SOCK_STREAM, SOCK_DGRAM, etc.
80 
81  int fd; //!< File descriptor if this is a live socket.
82 } fr_socket_t;
83 
84 /** Check the proto value is sane/supported
85  *
86  * @param[in] proto to check
87  * @return
88  * - true if it is.
89  * - false if it's not.
90  */
91 static inline bool fr_socket_proto_is_known(int proto)
92 {
93  /*
94  * Check the protocol is sane
95  */
96  switch (proto) {
97  case IPPROTO_UDP:
98  case IPPROTO_TCP:
99 #ifdef IPPROTO_SCTP
100  case IPPROTO_SCTP:
101 #endif
102  return true;
103 
104  default:
105  fr_strerror_printf("Unknown IP protocol %d", proto);
106  return false;
107  }
108 }
109 
110 #define FR_SOCKET_ADDR_ALLOC_DEF_FUNC(_func, ...) \
111  fr_socket_t *addr; \
112  addr = talloc(ctx, fr_socket_t); \
113  if (unlikely(!addr)) return NULL; \
114  return _func(addr, ##__VA_ARGS__);
115 
116 /** Swap src/dst information of a fr_socket_t
117  *
118  * @param[out] dst Where to write the swapped addresses. May be the same as src.
119  * @param[in] src Socket address to swap.
120  */
121 static inline void fr_socket_addr_swap(fr_socket_t *dst, fr_socket_t const *src)
122 {
123  fr_socket_t tmp = *src;
124 
125  if (dst != src) *dst = tmp; /* copy non-address fields over */
126 
127  dst->inet.dst_ipaddr = tmp.inet.src_ipaddr;
128  dst->inet.dst_port = tmp.inet.src_port;
129  dst->inet.src_ipaddr = tmp.inet.dst_ipaddr;
130  dst->inet.src_port = tmp.inet.dst_port;
131 }
132 
133 /** Initialise a fr_socket_t for connecting to a remote host using a specific src interface, address and port
134  *
135  * Can also be used to record information from an incoming packet so that we can
136  * identify the correct return path later.
137  *
138  * @param[out] addr to initialise.
139  * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
140  * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
141  * indicate an unknown or unspecified interface.
142  * @param[in] src_ipaddr The source IP address of the packet, or source interface for
143  * packets to egress out of.
144  * @param[in] src_port The source port of the packet or the source
145  * @param[in] dst_ipaddr The destination IP address of the packet.
146  * @param[in] dst_port The destination port of the packet.
147  * @return
148  * - NULL if invalid parameters are provided.
149  * - An initialised fr_socket_t struct.
150  */
152  int proto,
153  int ifindex, fr_ipaddr_t const *src_ipaddr, int src_port,
154  fr_ipaddr_t const *dst_ipaddr, int dst_port)
155 {
156  if (!fr_socket_proto_is_known(proto)) return NULL;
157 
158  *addr = (fr_socket_t){
159  .af = src_ipaddr->af,
160  .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM,
161  .inet = {
162  .ifindex = ifindex,
163  .src_ipaddr = *src_ipaddr,
164  .src_port = src_port,
165  .dst_ipaddr = *dst_ipaddr,
166  .dst_port = dst_port
167  }
168  };
169 
170  return addr;
171 }
172 
173 /** Initialise a fr_socket_t for connecting to a remote host using a specific src interface, address and port
174  *
175  * Can also be used to record information from an incoming packet so that we can
176  * identify the correct return path later.
177  *
178  * @param[in] ctx to allocate a new #fr_socket_t struct in.
179  * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
180  * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
181  * indicate an unknown or unspecified interface.
182  * @param[in] src_ipaddr The source IP address of the packet, or source interface for
183  * packets to egress out of.
184  * @param[in] src_port The source port of the packet or the source
185  * @param[in] dst_ipaddr The destination IP address of the packet.
186  * @param[in] dst_port The destination port of the packet.
187  * @return
188  * - NULL if invalid parameters are provided.
189  * - An initialised fr_socket_t struct.
190  */
191 static inline fr_socket_t *fr_socket_addr_alloc_inet(TALLOC_CTX *ctx, int proto,
192  int ifindex, fr_ipaddr_t const *src_ipaddr, int src_port,
193  fr_ipaddr_t const *dst_ipaddr, int dst_port)
194 {
196  proto, ifindex, src_ipaddr, src_port, dst_ipaddr, dst_port)
197 }
198 
199 /** A variant of fr_socket_addr_alloc_inet will also allocates a #fr_socket_t
200  *
201 
202  * @param[out] addr to initialise.
203  * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
204  * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
205  * indicate an unknown or unspecified interface.
206  * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
207  * all addresses, but the AF must still be specified.
208  * @param[in] port The source port to bind to.
209  * @return
210  * - NULL if invalid parameters are provided.
211  * - An initialised fr_socket_t struct.
212  */
214  int proto, int ifindex, fr_ipaddr_t const *ipaddr, int port)
215 {
216  if (!fr_socket_proto_is_known(proto)) return NULL;
217 
218  *addr = (fr_socket_t){
219  .af = ipaddr->af,
220  .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM,
221  .inet = {
222  .ifindex = ifindex,
223  .src_ipaddr = *ipaddr,
224  .src_port = port
225  }
226  };
227 
228  return addr;
229 }
230 
231 /** A variant of fr_socket_addr_init_inet_src will also allocates a #fr_socket_t
232  *
233  * @param[in] ctx to allocate a new #fr_socket_t struct in.
234  * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
235  * @param[in] ifindex The interface to originate the packet from Pass <= 0 to
236  * indicate an unknown or unspecified interface.
237  * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
238  * all addresses, but the AF must still be specified.
239  * @param[in] port The source port to bind to.
240  * @return
241  * - NULL if invalid parameters are provided.
242  * - An initialised fr_socket_t struct.
243  */
244 static inline fr_socket_t *fr_socket_addr_alloc_inet_src(TALLOC_CTX *ctx, int proto,
245  int ifindex, fr_ipaddr_t const *ipaddr, int port)
246 {
248 }
249 /** Initialise a #fr_socket_t for connecting to a remote host
250  *
251  * @param[out] addr to initialise.
252  * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
253  * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
254  * all addresses, but the AF must still be specified.
255  * @param[in] port The source port to bind to.
256  * @return
257  * - NULL if invalid parameters are provided.
258  * - An initialised fr_socket_t struct.
259  */
260 static inline fr_socket_t *fr_socket_addr_init_inet_dst(fr_socket_t *addr, int proto, fr_ipaddr_t const *ipaddr, int port)
261 {
262  if (!fr_socket_proto_is_known(proto)) return NULL;
263 
264  *addr = (fr_socket_t){
265  .af = ipaddr->af,
266  .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM,
267  .inet = {
268  .dst_ipaddr = *ipaddr,
269  .dst_port = port
270  }
271  };
272 
273  return addr;
274 }
275 
276 /** A variant of fr_socket_addr_alloc_inet_dst that will also allocates a #fr_socket_t
277  *
278  * @param[in] ctx to allocate new #fr_socket_t struct in.
279  * @param[in] proto one of the IPPROTO_* macros, i.e. IPPROTO_TCP, IPPROTO_UDP
280  * @param[in] ipaddr The IP address to bind to. May be all zeros to bind to
281  * all addresses, but the AF must still be specified.
282  * @param[in] port The source port to bind to.
283  * @return
284  * - NULL if invalid parameters are provided.
285  * - An initialised fr_socket_t struct.
286  */
287 static inline fr_socket_t *fr_socket_addr_alloc_inet_dst(TALLOC_CTX *ctx, int proto,
288  fr_ipaddr_t const *ipaddr, int port)
289 {
291 }
292 
293 int fr_socket_client_unix(char const *path, bool async);
294 
295 int fr_socket_client_udp(char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port,
296  fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async);
297 
298 int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t *src_ipaddr,
299  fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async);
301 
302 int fr_socket_server_udp(fr_ipaddr_t const *ipaddr, uint16_t *port, char const *port_name, bool async);
303 
304 int fr_socket_server_tcp(fr_ipaddr_t const *ipaddr, uint16_t *port, char const *port_name, bool async);
305 
306 int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port);
307 
308 #ifdef __cplusplus
309 }
310 #endif
#define RCSIDH(h, id)
Definition: build.h:445
static int sockfd
Definition: dhcpclient.c:56
static fr_time_delta_t timeout
Definition: dhcpclient.c:54
int af
Address family.
Definition: inet.h:64
IPv4/6 prefix.
Definition: merged_model.c:272
unsigned short uint16_t
Definition: merged_model.c:31
static char const * proto(int id, int porttype)
Definition: radwho.c:85
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:244
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition: socket.h:78
int fd
File descriptor if this is a live socket.
Definition: socket.h:81
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition: socket.h:79
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:191
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:260
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:634
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:969
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:867
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:729
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:229
static bool fr_socket_proto_is_known(int proto)
Check the proto value is sane/supported.
Definition: socket.h:91
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:287
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:151
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:213
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:803
#define FR_SOCKET_ADDR_ALLOC_DEF_FUNC(_func,...)
Definition: socket.h:110
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:121
Holds information necessary for binding or connecting to a socket.
Definition: socket.h:63
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64