The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
23 RCSID("$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  */
43 int 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  */
96 ssize_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  */
145 ssize_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 
195 done:
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:444
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:1427
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:1378
IPv4/6 prefix.
Definition: merged_model.c:272
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
Definition: merged_model.c:31
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
static bool done
Definition: radclient.c:80
fr_assert(0)
#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:1259