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: 3b2c4721a1220faba30ce296edbab23acdb3eeda $")
24
25#include <freeradius-devel/util/log.h>
26#include <freeradius-devel/util/socket.h>
27#include <freeradius-devel/util/strerror.h>
28#include <freeradius-devel/util/syserror.h>
29#include <freeradius-devel/util/udp.h>
30
31#define FR_DEBUG_STRERROR_PRINTF if (fr_debug_lvl) fr_strerror_printf
32
33/** Send a packet via a UDP socket.
34 *
35 * @param[in] sock we're reading from.
36 * @param[in] flags to pass to send(), or sendto()
37 * @param[in] data to data to send
38 * @param[in] data_len length of data to send
39 * @return
40 * - 0 on success.
41 * - -1 on failure.
42 */
43int udp_send(fr_socket_t const *sock, int flags, void *data, size_t data_len)
44{
45 int ret;
46
47 fr_assert(sock->type == SOCK_DGRAM);
48
49 if (flags & UDP_FLAGS_CONNECTED) {
50 ret = (send(sock->fd, data, data_len, 0) == (ssize_t)data_len) ? 0 : -1;
51 } else {
52 struct sockaddr_storage dst, src;
53 socklen_t sizeof_dst, sizeof_src;
54
55 if (fr_ipaddr_to_sockaddr(&dst, &sizeof_dst,
56 &sock->inet.dst_ipaddr, sock->inet.dst_port) < 0) return -1;
57 if (fr_ipaddr_to_sockaddr(&src, &sizeof_src,
58 &sock->inet.src_ipaddr, sock->inet.src_port) < 0) return -1;
59
60 ret = sendfromto(sock->fd, data, data_len, 0,
61 sock->inet.ifindex,
62 (struct sockaddr *)&src, sizeof_src,
63 (struct sockaddr *)&dst, sizeof_dst);
64 }
65
66 if (ret < 0) fr_strerror_printf("udp_send failed: %s", fr_syserror(errno));
67
68 return ret;
69}
70
71
72/** Discard the next UDP packet
73 *
74 * @param[in] sockfd we're reading from.
75 */
77{
78 uint8_t data[4];
79 struct sockaddr_storage src;
80 socklen_t sizeof_src = sizeof(src);
81
82 return recvfrom(sockfd, data, sizeof(data), 0,
83 (struct sockaddr *)&src, &sizeof_src);
84}
85
86
87/** Peek at the header of a UDP packet.
88 *
89 * @param[in] sockfd we're reading from.
90 * @param[out] data pointer where data will be written
91 * @param[in] data_len length of data to read
92 * @param[in] flags for things
93 * @param[out] src_ipaddr of the packet.
94 * @param[out] src_port of the packet.
95 */
96ssize_t udp_recv_peek(int sockfd, void *data, size_t data_len, int flags, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
97{
98 ssize_t peeked;
99 struct sockaddr_storage src;
100 socklen_t sizeof_src = sizeof(src);
101
102 if (!src_ipaddr || ((flags & UDP_FLAGS_CONNECTED) != 0)) {
103 peeked = recv(sockfd, data, data_len, MSG_PEEK);
104 if (peeked < 0) {
105 if ((errno == EAGAIN) || (errno == EINTR)) return 0;
106 return -1;
107 }
108
109 return peeked;
110 }
111
112 peeked = recvfrom(sockfd, data, data_len, MSG_PEEK, (struct sockaddr *)&src, &sizeof_src);
113 if (peeked < 0) {
114 if ((errno == EAGAIN) || (errno == EINTR)) return 0;
115 return -1;
116 }
117
118 /*
119 * Convert AF. If unknown, discard packet.
120 */
121 if (fr_ipaddr_from_sockaddr(src_ipaddr, src_port, &src, sizeof_src) < 0) {
122 FR_DEBUG_STRERROR_PRINTF("Unknown address family");
123 (void) udp_recv_discard(sockfd);
124
125 return -1;
126 }
127
128 return peeked;
129}
130
131
132/** Read a UDP packet
133 *
134 * @param[in] sockfd we're reading from.
135 * @param[in] flags for things
136 * @param[out] socket_out Information about the src/dst address of the packet
137 * and the interface it was received on.
138 * @param[out] data pointer where data will be written
139 * @param[in] data_len length of data to read
140 * @param[out] when the packet was received.
141 * @return
142 * - > 0 on success (number of bytes read).
143 * - < 0 on failure.
144 */
145ssize_t udp_recv(int sockfd, int flags,
146 fr_socket_t *socket_out, void *data, size_t data_len, fr_time_t *when)
147{
148 int sock_flags = 0;
149 struct sockaddr_storage src;
150 struct sockaddr_storage dst;
151 socklen_t sizeof_src = sizeof(src);
152 socklen_t sizeof_dst = sizeof(dst);
153 ssize_t slen;
154
155 if ((flags & UDP_FLAGS_PEEK) != 0) sock_flags |= MSG_PEEK;
156
157 if (when) *when = fr_time_wrap(0);
158
159 /*
160 * Always initialise the output socket structure
161 */
162 *socket_out = (fr_socket_t){
163 .fd = sockfd,
164 .type = SOCK_DGRAM,
165 };
166
167 /*
168 * Connected sockets already know src/dst IP/port
169 */
170 if ((flags & UDP_FLAGS_CONNECTED) != 0) {
171 slen = recv(sockfd, data, data_len, sock_flags);
172 goto done;
173 }
174
175 /*
176 * Receive the packet. The OS will discard any data in the
177 * packet after "len" bytes.
178 */
179 slen = recvfromto(sockfd, data, data_len, sock_flags,
180 &socket_out->inet.ifindex,
181 (struct sockaddr *)&src, &sizeof_src,
182 (struct sockaddr *)&dst, &sizeof_dst,
183 when);
184 if (slen <= 0) goto done;
185
186 if (fr_ipaddr_from_sockaddr(&socket_out->inet.src_ipaddr, &socket_out->inet.src_port, &src, sizeof_src) < 0) {
187 fr_strerror_const_push("Failed converting src sockaddr to ipaddr");
188 return -1;
189 }
190 if (fr_ipaddr_from_sockaddr(&socket_out->inet.dst_ipaddr, &socket_out->inet.dst_port, &dst, sizeof_dst) < 0) {
191 fr_strerror_const_push("Failed converting dst sockaddr to ipaddr");
192 return -1;
193 }
194
195done:
196 if (slen < 0) {
197 if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) return 0;
198
199 fr_strerror_printf("Failed reading socket: %s", fr_syserror(errno));
200 return slen;
201 }
202
203 /*
204 * We didn't get it from the kernel
205 * so use our own time source.
206 */
207 if (when && fr_time_eq(*when, fr_time_wrap(0))) *when = fr_time();
208
209 return slen;
210}
#define RCSID(id)
Definition build.h:483
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:76
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:96
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:145
#define FR_DEBUG_STRERROR_PRINTF
Definition udp.c:31
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:43
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:80
#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:1265