All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 /**
18  * $Id: 3d1794bffa841e33d7c761f94c6d22b82d62d4fe $
19  *
20  * @file udp.c
21  * @brief Functions to send/receive UDP packets.
22  *
23  * @copyright 2000-2003,2006 The FreeRADIUS server project
24  */
25 
26 RCSID("$Id: 3d1794bffa841e33d7c761f94c6d22b82d62d4fe $")
27 
28 #include <freeradius-devel/udp.h>
29 
30 /*
31  * This is easier than ifdef's in the function definition.
32  */
33 #ifdef WITH_UDPFROMTO
34 #define UDP_UNUSED
35 #else
36 #define UDP_UNUSED UNUSED
37 #endif
38 
39 #define FR_DEBUG_STRERROR_PRINTF if (fr_debug_lvl) fr_strerror_printf
40 
41 /** Send a packet via a UDP socket.
42  *
43  * @param[in] sockfd we're reading from.
44  * @param[in] data pointer to data to send
45  * @param[in] data_len length of data to send
46  * @param[in] flags to pass to send(), or sendto()
47  * @param[in] src_ipaddr of the packet.
48  * @param[in] src_port of the packet.
49  * @param[in] if_index of the packet.
50  * @param[in] dst_ipaddr of the packet.
51  * @param[in] dst_port of the packet.
52  */
53 ssize_t udp_send(int sockfd, void *data, size_t data_len, int flags,
54  UDP_UNUSED fr_ipaddr_t *src_ipaddr, UDP_UNUSED uint16_t src_port, UDP_UNUSED int if_index,
55  fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
56 {
57  int rcode;
58 
59  if (flags & UDP_FLAGS_CONNECTED) {
60  rcode = send(sockfd, data, data_len, 0);
61 
62  } else {
63  struct sockaddr_storage dst;
64  socklen_t sizeof_dst;
65 
66  /*
67  * @fixme: We shoul probably just move to sockaddr_storage for
68  * all IP address things.
69  */
70  if (!fr_ipaddr_to_sockaddr(dst_ipaddr, dst_port, &dst, &sizeof_dst)) {
71  return -1;
72  }
73 
74 #ifdef WITH_UDPFROMTO
75  /*
76  * And if they don't specify a source IP address, don't
77  * use udpfromto.
78  */
79  if ((src_ipaddr->af != AF_UNSPEC) && (dst_ipaddr->af != AF_UNSPEC) &&
80  !fr_is_inaddr_any(src_ipaddr)) {
81  struct sockaddr_storage src;
82  socklen_t sizeof_src;
83 
84  fr_ipaddr_to_sockaddr(src_ipaddr, src_port, &src, &sizeof_src);
85 
86  rcode = sendfromto(sockfd, data, data_len, 0,
87  (struct sockaddr *)&src, sizeof_src,
88  (struct sockaddr *)&dst, sizeof_dst, if_index);
89  } else
90 #endif
91  rcode = sendto(sockfd, data, data_len, 0,
92  (struct sockaddr *) &dst, sizeof_dst);
93  }
94 
95  if (rcode < 0) fr_strerror_printf("udp_sendto failed: %s", fr_syserror(errno));
96 
97  return rcode;
98 }
99 
100 
101 /** Discard the next UDP packet
102  *
103  * @param[in] sockfd we're reading from.
104  */
106 {
107  uint8_t data[4];
108  struct sockaddr_storage src;
109  socklen_t sizeof_src = sizeof(src);
110 
111  (void) recvfrom(sockfd, data, sizeof(data), 0,
112  (struct sockaddr *)&src, &sizeof_src);
113 }
114 
115 
116 /** Peek at the header of a UDP packet.
117  *
118  * @param[in] sockfd we're reading from.
119  * @param[out] data pointer where data will be written
120  * @param[in] data_len length of data to read
121  * @param[in] flags for things
122  * @param[out] src_ipaddr of the packet.
123  * @param[out] src_port of the packet.
124  */
125 ssize_t udp_recv_peek(int sockfd, void *data, size_t data_len, int flags, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
126 {
127  ssize_t peeked;
128  struct sockaddr_storage src;
129  socklen_t sizeof_src = sizeof(src);
130 
131  if (!src_ipaddr || ((flags & UDP_FLAGS_CONNECTED) != 0)) {
132  peeked = recv(sockfd, data, data_len, MSG_PEEK);
133  if (peeked < 0) {
134  if ((errno == EAGAIN) || (errno == EINTR)) return 0;
135  return -1;
136  }
137 
138  return peeked;
139  }
140 
141  peeked = recvfrom(sockfd, data, data_len, MSG_PEEK, (struct sockaddr *)&src, &sizeof_src);
142  if (peeked < 0) {
143  if ((errno == EAGAIN) || (errno == EINTR)) return 0;
144  return -1;
145  }
146 
147  /*
148  * Convert AF. If unknown, discard packet.
149  */
150  if (!fr_ipaddr_from_sockaddr(&src, sizeof_src, src_ipaddr, src_port)) {
151  FR_DEBUG_STRERROR_PRINTF("Unknown address family");
152  udp_recv_discard(sockfd);
153 
154  return -1;
155  }
156 
157  return peeked;
158 }
159 
160 
161 /** Read a UDP packet
162  *
163  * @param[in] sockfd we're reading from.
164  * @param[out] data pointer where data will be written
165  * @param[in] data_len length of data to read
166  * @param[in] flags for things
167  * @param[out] src_ipaddr of the packet.
168  * @param[out] src_port of the packet.
169  * @param[out] dst_ipaddr of the packet.
170  * @param[out] dst_port of the packet.
171  * @param[out] if_index of the interface that received the packet.
172  * @param[out] when the packet was received.
173  * @return
174  * - > 0 on success (number of bytes read).
175  * - < 0 on failure.
176  */
177 ssize_t udp_recv(int sockfd, void *data, size_t data_len, int flags,
178  fr_ipaddr_t *src_ipaddr, uint16_t *src_port,
179  fr_ipaddr_t *dst_ipaddr, uint16_t *dst_port, UDP_UNUSED int *if_index,
180  struct timeval *when)
181 {
182  int sock_flags = 0;
183  struct sockaddr_storage src;
184  struct sockaddr_storage dst;
185  socklen_t sizeof_src = sizeof(src);
186  socklen_t sizeof_dst = sizeof(dst);
187  ssize_t received;
188  uint16_t port;
189 
190  if ((flags & UDP_FLAGS_PEEK) != 0) sock_flags |= MSG_PEEK;
191 
192  /*
193  * Connected sockets already know src/dst IP/port
194  */
195  if ((flags & UDP_FLAGS_CONNECTED) != 0) return recv(sockfd, data, data_len, sock_flags);
196 
197  if (when) {
198  when->tv_sec = 0;
199  when->tv_usec = 0;
200  }
201 
202  /*
203  * Receive the packet. The OS will discard any data in the
204  * packet after "len" bytes.
205  */
206 #ifdef WITH_UDPFROMTO
207  if (dst_ipaddr) {
208  received = recvfromto(sockfd, data, data_len, sock_flags,
209  (struct sockaddr *)&src, &sizeof_src,
210  (struct sockaddr *)&dst, &sizeof_dst,
211  if_index, when);
212  } else {
213  received = recvfrom(sockfd, data, data_len, sock_flags,
214  (struct sockaddr *)&src, &sizeof_src);
215  }
216 #else
217  received = recvfrom(sockfd, data, data_len, sock_flags,
218  (struct sockaddr *)&src, &sizeof_src);
219 
220  /*
221  * Get the destination address, if requested.
222  */
223  if (dst_ipaddr && (getsockname(sockfd, (struct sockaddr *)&dst, &sizeof_dst) < 0)) return -1;
224 
225  if (if_index) *if_index = 0;
226 #endif
227 
228  if (received < 0) return received;
229 
230  if (!fr_ipaddr_from_sockaddr(&src, sizeof_src, src_ipaddr, &port)) return -1;
231  *src_port = port;
232 
233  if (when && !when->tv_sec) gettimeofday(when, NULL);
234 
235  if (dst_ipaddr) {
236  fr_ipaddr_from_sockaddr(&dst, sizeof_dst, dst_ipaddr, &port);
237  *dst_port = port;
238  }
239 
240  return received;
241 }
static int sockfd
Definition: radclient.c:59
int fr_ipaddr_from_sockaddr(struct sockaddr_storage const *sa, socklen_t salen, fr_ipaddr_t *ipaddr, uint16_t *port)
Definition: inet.c:1095
int fr_is_inaddr_any(fr_ipaddr_t *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition: packet.c:91
ssize_t udp_recv(int sockfd, void *data, size_t data_len, int flags, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_t *dst_ipaddr, uint16_t *dst_port, UDP_UNUSED int *if_index, struct timeval *when)
Read a UDP packet.
Definition: udp.c:177
ssize_t udp_send(int sockfd, void *data, size_t data_len, int flags, UDP_UNUSED fr_ipaddr_t *src_ipaddr, UDP_UNUSED uint16_t src_port, UDP_UNUSED int if_index, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
Send a packet via a UDP socket.
Definition: udp.c:53
int af
Address family.
Definition: inet.h:42
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
void udp_recv_discard(int sockfd)
Discard the next UDP packet.
Definition: udp.c:105
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:125
#define FR_DEBUG_STRERROR_PRINTF
Definition: udp.c:39
#define UDP_FLAGS_PEEK
Definition: udp.h:40
uint8_t data[]
Definition: eap_pwd.h:625
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
#define UDP_FLAGS_CONNECTED
Definition: udp.h:39
IPv4/6 prefix.
Definition: inet.h:41
#define UDP_UNUSED
Definition: udp.c:36
#define RCSID(id)
Definition: build.h:135
int fr_ipaddr_to_sockaddr(fr_ipaddr_t const *ipaddr, uint16_t port, struct sockaddr_storage *sa, socklen_t *salen)
Definition: inet.c:1057