/src/freeradius-server/src/freeradius-devel/util/socket.h
Line | Count | Source |
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 | 0 | # 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 | 0 | { |
93 | | /* |
94 | | * Check the protocol is sane |
95 | | */ |
96 | 0 | switch (proto) { |
97 | 0 | case IPPROTO_UDP: |
98 | 0 | case IPPROTO_TCP: |
99 | 0 | #ifdef IPPROTO_SCTP |
100 | 0 | case IPPROTO_SCTP: |
101 | 0 | #endif |
102 | 0 | return true; |
103 | | |
104 | 0 | default: |
105 | 0 | fr_strerror_printf("Unknown IP protocol %d", proto); |
106 | 0 | return false; |
107 | 0 | } |
108 | 0 | } Unexecuted instantiation: dl.c:fr_socket_proto_is_known Unexecuted instantiation: packet.c:fr_socket_proto_is_known Unexecuted instantiation: socket.c:fr_socket_proto_is_known Unexecuted instantiation: udp.c:fr_socket_proto_is_known Unexecuted instantiation: udp_queue.c:fr_socket_proto_is_known Unexecuted instantiation: base.c:fr_socket_proto_is_known Unexecuted instantiation: decode.c:fr_socket_proto_is_known Unexecuted instantiation: encode.c:fr_socket_proto_is_known Unexecuted instantiation: raw.c:fr_socket_proto_is_known Unexecuted instantiation: udp.c:fr_socket_proto_is_known Unexecuted instantiation: list.c:fr_socket_proto_is_known Unexecuted instantiation: tcp.c:fr_socket_proto_is_known Unexecuted instantiation: abinary.c:fr_socket_proto_is_known Unexecuted instantiation: vmps.c:fr_socket_proto_is_known |
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 | 0 | { |
123 | 0 | fr_socket_t tmp = *src; |
124 | |
|
125 | 0 | if (dst != src) *dst = tmp; /* copy non-address fields over */ |
126 | |
|
127 | 0 | dst->inet.dst_ipaddr = tmp.inet.src_ipaddr; |
128 | 0 | dst->inet.dst_port = tmp.inet.src_port; |
129 | 0 | dst->inet.src_ipaddr = tmp.inet.dst_ipaddr; |
130 | 0 | dst->inet.src_port = tmp.inet.dst_port; |
131 | 0 | } Unexecuted instantiation: dl.c:fr_socket_addr_swap Unexecuted instantiation: packet.c:fr_socket_addr_swap Unexecuted instantiation: socket.c:fr_socket_addr_swap Unexecuted instantiation: udp.c:fr_socket_addr_swap Unexecuted instantiation: udp_queue.c:fr_socket_addr_swap Unexecuted instantiation: base.c:fr_socket_addr_swap Unexecuted instantiation: decode.c:fr_socket_addr_swap Unexecuted instantiation: encode.c:fr_socket_addr_swap Unexecuted instantiation: raw.c:fr_socket_addr_swap Unexecuted instantiation: list.c:fr_socket_addr_swap Unexecuted instantiation: tcp.c:fr_socket_addr_swap Unexecuted instantiation: abinary.c:fr_socket_addr_swap Unexecuted instantiation: vmps.c:fr_socket_addr_swap |
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 | | */ |
151 | | static inline fr_socket_t *fr_socket_addr_init_inet(fr_socket_t *addr, |
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 | 0 | { |
156 | 0 | if (!fr_socket_proto_is_known(proto)) return NULL; |
157 | 0 |
|
158 | 0 | *addr = (fr_socket_t){ |
159 | 0 | .af = src_ipaddr->af, |
160 | 0 | .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM, |
161 | 0 | .inet = { |
162 | 0 | .ifindex = ifindex, |
163 | 0 | .src_ipaddr = *src_ipaddr, |
164 | 0 | .src_port = src_port, |
165 | 0 | .dst_ipaddr = *dst_ipaddr, |
166 | 0 | .dst_port = dst_port |
167 | 0 | } |
168 | 0 | }; |
169 | 0 |
|
170 | 0 | return addr; |
171 | 0 | } Unexecuted instantiation: dl.c:fr_socket_addr_init_inet Unexecuted instantiation: packet.c:fr_socket_addr_init_inet Unexecuted instantiation: socket.c:fr_socket_addr_init_inet Unexecuted instantiation: udp.c:fr_socket_addr_init_inet Unexecuted instantiation: udp_queue.c:fr_socket_addr_init_inet Unexecuted instantiation: base.c:fr_socket_addr_init_inet Unexecuted instantiation: decode.c:fr_socket_addr_init_inet Unexecuted instantiation: encode.c:fr_socket_addr_init_inet Unexecuted instantiation: raw.c:fr_socket_addr_init_inet Unexecuted instantiation: list.c:fr_socket_addr_init_inet Unexecuted instantiation: tcp.c:fr_socket_addr_init_inet Unexecuted instantiation: abinary.c:fr_socket_addr_init_inet Unexecuted instantiation: vmps.c:fr_socket_addr_init_inet |
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 | 0 | { |
195 | 0 | FR_SOCKET_ADDR_ALLOC_DEF_FUNC(fr_socket_addr_init_inet, |
196 | 0 | proto, ifindex, src_ipaddr, src_port, dst_ipaddr, dst_port) |
197 | 0 | } Unexecuted instantiation: dl.c:fr_socket_addr_alloc_inet Unexecuted instantiation: packet.c:fr_socket_addr_alloc_inet Unexecuted instantiation: socket.c:fr_socket_addr_alloc_inet Unexecuted instantiation: udp.c:fr_socket_addr_alloc_inet Unexecuted instantiation: udp_queue.c:fr_socket_addr_alloc_inet Unexecuted instantiation: base.c:fr_socket_addr_alloc_inet Unexecuted instantiation: decode.c:fr_socket_addr_alloc_inet Unexecuted instantiation: encode.c:fr_socket_addr_alloc_inet Unexecuted instantiation: raw.c:fr_socket_addr_alloc_inet Unexecuted instantiation: list.c:fr_socket_addr_alloc_inet Unexecuted instantiation: tcp.c:fr_socket_addr_alloc_inet Unexecuted instantiation: abinary.c:fr_socket_addr_alloc_inet Unexecuted instantiation: vmps.c:fr_socket_addr_alloc_inet |
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 | | */ |
213 | | static inline fr_socket_t *fr_socket_addr_init_inet_src(fr_socket_t *addr, |
214 | | int proto, int ifindex, fr_ipaddr_t const *ipaddr, int port) |
215 | 0 | { |
216 | 0 | if (!fr_socket_proto_is_known(proto)) return NULL; |
217 | 0 |
|
218 | 0 | *addr = (fr_socket_t){ |
219 | 0 | .af = ipaddr->af, |
220 | 0 | .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM, |
221 | 0 | .inet = { |
222 | 0 | .ifindex = ifindex, |
223 | 0 | .src_ipaddr = *ipaddr, |
224 | 0 | .src_port = port |
225 | 0 | } |
226 | 0 | }; |
227 | 0 |
|
228 | 0 | return addr; |
229 | 0 | } Unexecuted instantiation: dl.c:fr_socket_addr_init_inet_src Unexecuted instantiation: packet.c:fr_socket_addr_init_inet_src Unexecuted instantiation: socket.c:fr_socket_addr_init_inet_src Unexecuted instantiation: udp.c:fr_socket_addr_init_inet_src Unexecuted instantiation: udp_queue.c:fr_socket_addr_init_inet_src Unexecuted instantiation: base.c:fr_socket_addr_init_inet_src Unexecuted instantiation: decode.c:fr_socket_addr_init_inet_src Unexecuted instantiation: encode.c:fr_socket_addr_init_inet_src Unexecuted instantiation: raw.c:fr_socket_addr_init_inet_src Unexecuted instantiation: list.c:fr_socket_addr_init_inet_src Unexecuted instantiation: tcp.c:fr_socket_addr_init_inet_src Unexecuted instantiation: abinary.c:fr_socket_addr_init_inet_src Unexecuted instantiation: vmps.c:fr_socket_addr_init_inet_src |
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 | 0 | { |
247 | 0 | FR_SOCKET_ADDR_ALLOC_DEF_FUNC(fr_socket_addr_init_inet_src, proto, ifindex, ipaddr, port) |
248 | 0 | } Unexecuted instantiation: dl.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: packet.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: socket.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: udp.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: udp_queue.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: base.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: decode.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: encode.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: raw.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: list.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: tcp.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: abinary.c:fr_socket_addr_alloc_inet_src Unexecuted instantiation: vmps.c:fr_socket_addr_alloc_inet_src |
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 | 0 | { |
262 | 0 | if (!fr_socket_proto_is_known(proto)) return NULL; |
263 | 0 |
|
264 | 0 | *addr = (fr_socket_t){ |
265 | 0 | .af = ipaddr->af, |
266 | 0 | .type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM, |
267 | 0 | .inet = { |
268 | 0 | .dst_ipaddr = *ipaddr, |
269 | 0 | .dst_port = port |
270 | 0 | } |
271 | 0 | }; |
272 | 0 |
|
273 | 0 | return addr; |
274 | 0 | } Unexecuted instantiation: dl.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: packet.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: socket.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: udp.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: udp_queue.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: base.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: decode.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: encode.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: raw.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: list.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: tcp.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: abinary.c:fr_socket_addr_init_inet_dst Unexecuted instantiation: vmps.c:fr_socket_addr_init_inet_dst |
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 | 0 | { |
290 | 0 | FR_SOCKET_ADDR_ALLOC_DEF_FUNC(fr_socket_addr_init_inet_dst, proto, ipaddr, port) |
291 | 0 | } Unexecuted instantiation: dl.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: packet.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: socket.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: udp.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: udp_queue.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: base.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: decode.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: encode.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: raw.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: list.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: tcp.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: abinary.c:fr_socket_addr_alloc_inet_dst Unexecuted instantiation: vmps.c:fr_socket_addr_alloc_inet_dst |
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); |
300 | | int fr_socket_wait_for_connect(int sockfd, fr_time_delta_t timeout); |
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 |