The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
udp.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Utility functions for managing UDP sockets
18 *
19 * @file src/lib/util/udp.c
20 *
21 * @copyright 2000-2003,2006 The FreeRADIUS server project
22 */
23RCSID("$Id: 2af2d7838ecfb236c94cfd6fbef7cc1a5b01ae5e $")
24
25#include <freeradius-devel/util/log.h>
26#include <freeradius-devel/util/socket.h>
27#include <freeradius-devel/util/syserror.h>
28#include <freeradius-devel/util/udp.h>
29
30#define FR_DEBUG_STRERROR_PRINTF if (fr_debug_lvl) fr_strerror_printf
31
32/** Send a packet via a UDP socket.
33 *
34 * @param[in] sock we're reading from.
35 * @param[in] flags to pass to send(), or sendto()
36 * @param[in] data to data to send
37 * @param[in] data_len length of data to send
38 * @return
39 * - 0 on success.
40 * - -1 on failure.
41 */
42int udp_send(fr_socket_t const *sock, int flags, void *data, size_t data_len)
43{
44 int ret;
45
46 fr_assert(sock->type == SOCK_DGRAM);
47
48 if (flags & UDP_FLAGS_CONNECTED) {
49 ret = (send(sock->fd, data, data_len, 0) == (ssize_t)data_len) ? 0 : -1;
50 } else {
51 struct sockaddr_storage dst, src;
52 socklen_t sizeof_dst, sizeof_src;
53
54 if (fr_ipaddr_to_sockaddr(&dst, &sizeof_dst,
55 &sock->inet.dst_ipaddr, sock->inet.dst_port) < 0) return -1;
56 if (fr_ipaddr_to_sockaddr(&src, &sizeof_src,
57 &sock->inet.src_ipaddr, sock->inet.src_port) < 0) return -1;
58
59 ret = sendfromto(sock->fd, data, data_len, 0,
60 sock->inet.ifindex,
61 (struct sockaddr *)&src, sizeof_src,
62 (struct sockaddr *)&dst, sizeof_dst);
63 }
64
65 if (ret < 0) fr_strerror_printf("udp_send failed: %s", fr_syserror(errno));
66
67 return ret;
68}
69
70
71/** Discard the next UDP packet
72 *
73 * @param[in] sockfd we're reading from.
74 */
76{
77 uint8_t data[4];
78 struct sockaddr_storage src;
79 socklen_t sizeof_src = sizeof(src);
80
81 return recvfrom(sockfd, data, sizeof(data), 0,
82 (struct sockaddr *)&src, &sizeof_src);
83}
84
85
86/** Peek at the header of a UDP packet.
87 *
88 * @param[in] sockfd we're reading from.
89 * @param[out] data pointer where data will be written
90 * @param[in] data_len length of data to read
91 * @param[in] flags for things
92 * @param[out] src_ipaddr of the packet.
93 * @param[out] src_port of the packet.
94 */
95ssize_t udp_recv_peek(int sockfd, void *data, size_t data_len, int flags, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
96{
97 ssize_t peeked;
98 struct sockaddr_storage src;
99 socklen_t sizeof_src = sizeof(src);
100
101 if (!src_ipaddr || ((flags & UDP_FLAGS_CONNECTED) != 0)) {
102 peeked = recv(sockfd, data, data_len, MSG_PEEK);
103 if (peeked < 0) {
104 if ((errno == EAGAIN) || (errno == EINTR)) return 0;
105 return -1;
106 }
107
108 return peeked;
109 }
110
111 peeked = recvfrom(sockfd, data, data_len, MSG_PEEK, (struct sockaddr *)&src, &sizeof_src);
112 if (peeked < 0) {
113 if ((errno == EAGAIN) || (errno == EINTR)) return 0;
114 return -1;
115 }
116
117 /*
118 * Convert AF. If unknown, discard packet.
119 */
120 if (fr_ipaddr_from_sockaddr(src_ipaddr, src_port, &src, sizeof_src) < 0) {
121 FR_DEBUG_STRERROR_PRINTF("Unknown address family");
122 (void) udp_recv_discard(sockfd);
123
124 return -1;
125 }
126
127 return peeked;
128}
129
130
131/** Read a UDP packet
132 *
133 * @param[in] sockfd we're reading from.
134 * @param[in] flags for things
135 * @param[out] socket_out Information about the src/dst address of the packet
136 * and the interface it was received on.
137 * @param[out] data pointer where data will be written
138 * @param[in] data_len length of data to read
139 * @param[out] when the packet was received.
140 * @return
141 * - > 0 on success (number of bytes read).
142 * - < 0 on failure.
143 */
144ssize_t udp_recv(int sockfd, int flags,
145 fr_socket_t *socket_out, void *data, size_t data_len, fr_time_t *when)
146{
147 int sock_flags = 0;
148 struct sockaddr_storage src;
149 struct sockaddr_storage dst;
150 socklen_t sizeof_src = sizeof(src);
151 socklen_t sizeof_dst = sizeof(dst);
152 ssize_t slen;
153
154 if ((flags & UDP_FLAGS_PEEK) != 0) sock_flags |= MSG_PEEK;
155
156 if (when) *when = fr_time_wrap(0);
157
158 /*
159 * Always initialise the output socket structure
160 */
161 *socket_out = (fr_socket_t){
162 .fd = sockfd,
163 .type = SOCK_DGRAM,
164 };
165
166 /*
167 * Connected sockets already know src/dst IP/port
168 */
169 if ((flags & UDP_FLAGS_CONNECTED) != 0) {
170 slen = recv(sockfd, data, data_len, sock_flags);
171 goto done;
172 }
173
174 /*
175 * Receive the packet. The OS will discard any data in the
176 * packet after "len" bytes.
177 */
178 slen = recvfromto(sockfd, data, data_len, sock_flags,
179 &socket_out->inet.ifindex,
180 (struct sockaddr *)&src, &sizeof_src,
181 (struct sockaddr *)&dst, &sizeof_dst,
182 when);
183 if (slen <= 0) goto done;
184
185 if (fr_ipaddr_from_sockaddr(&socket_out->inet.src_ipaddr, &socket_out->inet.src_port, &src, sizeof_src) < 0) {
186 fr_strerror_const_push("Failed converting src sockaddr to ipaddr");
187 return -1;
188 }
189 if (fr_ipaddr_from_sockaddr(&socket_out->inet.dst_ipaddr, &socket_out->inet.dst_port, &dst, sizeof_dst) < 0) {
190 fr_strerror_const_push("Failed converting dst sockaddr to ipaddr");
191 return -1;
192 }
193
194done:
195 if (slen < 0) {
196 if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) return 0;
197
198 fr_strerror_printf("Failed reading socket: %s", fr_syserror(errno));
199 return slen;
200 }
201
202 /*
203 * We didn't get it from the kernel
204 * so use our own time source.
205 */
206 if (when && fr_time_eq(*when, fr_time_wrap(0))) *when = fr_time();
207
208 return slen;
209}
#define RCSID(id)
Definition build.h:485
static int sockfd
Definition dhcpclient.c:56
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
Definition inet.c:1441
int fr_ipaddr_to_sockaddr(struct sockaddr_storage *sa, socklen_t *salen, fr_ipaddr_t const *ipaddr, uint16_t port)
Convert our internal ip address representation to a sockaddr.
Definition inet.c:1392
IPv4/6 prefix.
int udp_recv_discard(int sockfd)
Discard the next UDP packet.
Definition udp.c:75
ssize_t udp_recv_peek(int sockfd, void *data, size_t data_len, int flags, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
Peek at the header of a UDP packet.
Definition udp.c:95
ssize_t udp_recv(int sockfd, int flags, fr_socket_t *socket_out, void *data, size_t data_len, fr_time_t *when)
Read a UDP packet.
Definition udp.c:144
#define FR_DEBUG_STRERROR_PRINTF
Definition udp.c:30
int udp_send(fr_socket_t const *sock, int flags, void *data, size_t data_len)
Send a packet via a UDP socket.
Definition udp.c:42
unsigned short uint16_t
long int ssize_t
unsigned char uint8_t
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:81
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_eq(_a, _b)
Definition time.h:241
"server local" time.
Definition time.h:69
#define UDP_FLAGS_PEEK
Definition udp.h:39
#define UDP_FLAGS_CONNECTED
Definition udp.h:38
int sendfromto(int fd, void *buf, size_t len, int flags, int ifindex, struct sockaddr *from, socklen_t from_len, struct sockaddr *to, socklen_t to_len)
Send packet via a file descriptor, setting the src address and outbound interface.
Definition udpfromto.c:391
int recvfromto(int fd, void *buf, size_t len, int flags, int *ifindex, struct sockaddr *from, socklen_t *from_len, struct sockaddr *to, socklen_t *to_len, fr_time_t *when)
Read a packet from a file descriptor, retrieving additional header information.
Definition udpfromto.c:191
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
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
#define fr_strerror_const_push(_msg)
Definition strerror.h:227
static fr_slen_t data
Definition value.h:1274