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 /**
18  * $Id: ab4ad5ed2201c5e327faa9f9374efecff886a9e4 $
19  *
20  * @file protocols/dhcpv4/udp.c
21  * @brief Send/recv DHCP packets using udp sockets.
22  *
23  * @copyright 2008,2017 The FreeRADIUS server project
24  * @copyright 2008 Alan DeKok (aland@deployingradius.com)
25  */
26 #include "dhcpv4.h"
27 #include "attrs.h"
28 
29 #include <freeradius-devel/util/pair.h>
30 #include <freeradius-devel/util/proto.h>
31 #include <freeradius-devel/util/udpfromto.h>
32 #include <freeradius-devel/util/syserror.h>
33 
34 /** Send DHCP packet using a connectionless UDP socket
35  *
36  * @param packet to send
37  * @return
38  * - >= 0 if successful.
39  * - < 0 if failed.
40  */
42 {
43  int ret;
44  struct sockaddr_storage dst;
45  socklen_t sizeof_dst;
46  struct sockaddr_storage src;
47  socklen_t sizeof_src;
48 
49  fr_ipaddr_to_sockaddr(&src, &sizeof_src, &packet->socket.inet.src_ipaddr, packet->socket.inet.src_port);
50  fr_ipaddr_to_sockaddr(&dst, &sizeof_dst, &packet->socket.inet.dst_ipaddr, packet->socket.inet.dst_port);
51  if (packet->data_len == 0) {
52  fr_strerror_const("No data to send");
53  return -1;
54  }
55 
56  errno = 0;
57 
58  ret = sendfromto(packet->socket.fd, packet->data, packet->data_len, 0,
59  packet->socket.inet.ifindex,
60  (struct sockaddr *)&src, sizeof_src,
61  (struct sockaddr *)&dst, sizeof_dst);
62  if ((ret < 0) && errno) fr_strerror_printf("dhcp_send_socket: %s", fr_syserror(errno));
63 
64  return ret;
65 }
66 
67 /** Receive DHCP packet using a connectionless UDP socket
68  *
69  * @param sockfd handle.
70  * @return
71  * - pointer to fr_packet_t if successful.
72  * - NULL if failed.
73  */
75 {
76  struct sockaddr_storage src;
77  struct sockaddr_storage dst;
78  socklen_t sizeof_src;
79  socklen_t sizeof_dst;
80  fr_packet_t *packet;
81  uint8_t *data;
82  ssize_t data_len;
83  fr_ipaddr_t src_ipaddr, dst_ipaddr;
84  uint16_t src_port, dst_port;
85  int ifindex = 0;
86  fr_time_t when;
87 
88  data = talloc_zero_array(NULL, uint8_t, MAX_PACKET_SIZE);
89  if (!data) {
90  fr_strerror_const("Out of memory");
91  return NULL;
92  }
93 
94  sizeof_src = sizeof(src);
95  sizeof_dst = sizeof(dst);
96  data_len = recvfromto(sockfd, data, MAX_PACKET_SIZE, 0,
97  &ifindex,
98  (struct sockaddr *)&src, &sizeof_src,
99  (struct sockaddr *)&dst, &sizeof_dst, &when);
100 
101  if (data_len <= 0) {
102  fr_strerror_printf("Failed reading data from DHCP socket: %s", fr_syserror(errno));
103  talloc_free(data);
104  return NULL;
105  }
106 
107  if (!fr_cond_assert(data_len <= (ssize_t)talloc_array_length(data))) {
108  talloc_free(data); /* Bounds check for tainted scalar (Coverity) */
109  return NULL;
110  }
111  sizeof_dst = sizeof(dst);
112 
113  /*
114  * This should never fail...
115  */
116  if (getsockname(sockfd, (struct sockaddr *) &dst, &sizeof_dst) < 0) {
117  fr_strerror_printf("getsockname failed: %s", fr_syserror(errno));
118  talloc_free(data);
119  return NULL;
120  }
121 
122  fr_ipaddr_from_sockaddr(&dst_ipaddr, &dst_port, &dst, sizeof_dst);
123  fr_ipaddr_from_sockaddr(&src_ipaddr, &src_port, &src, sizeof_src);
124 
125  if (!fr_dhcpv4_ok(data, data_len, NULL, NULL)) return NULL;
126 
127  packet = fr_dhcpv4_packet_alloc(data, data_len);
128  if (!packet) return NULL;
129 
130  fr_socket_addr_init_inet(&packet->socket, IPPROTO_UDP, ifindex, &src_ipaddr, src_port, &dst_ipaddr, dst_port);
131 
132  talloc_steal(packet, data);
133  packet->data = data;
134  packet->socket.fd = sockfd;
135 
136  packet->timestamp = when;
137  return packet;
138 }
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
static int sockfd
Definition: dhcpclient.c:56
Implementation of the DHCPv4 protocol.
#define MAX_PACKET_SIZE
Definition: dhcpv4.h:106
fr_packet_t * fr_dhcpv4_packet_alloc(uint8_t const *data, ssize_t data_len)
Definition: packet.c:401
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
talloc_free(reap)
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
bool fr_dhcpv4_ok(uint8_t const *data, ssize_t data_len, uint8_t *message_type, uint32_t *xid)
Check received DHCP request is valid and build fr_packet_t structure if it is.
Definition: base.c:215
fr_packet_t * fr_dhcpv4_udp_packet_recv(int sockfd)
Receive DHCP packet using a connectionless UDP socket.
Definition: udp.c:74
int fr_dhcpv4_udp_packet_send(fr_packet_t *packet)
Send DHCP packet using a connectionless UDP socket.
Definition: udp.c:41
VQP attributes.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
"server local" time.
Definition: time.h:69
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
fr_socket_t socket
This packet was received on.
Definition: packet.h:57
uint8_t * data
Packet data (body).
Definition: packet.h:63
size_t data_len
Length of packet data.
Definition: packet.h:64
fr_time_t timestamp
When we received the packet.
Definition: packet.h:58
int fd
File descriptor if this is a live socket.
Definition: socket.h:81
static fr_socket_t * fr_socket_addr_init_inet(fr_socket_t *addr, int proto, int ifindex, fr_ipaddr_t const *src_ipaddr, int src_port, fr_ipaddr_t const *dst_ipaddr, int dst_port)
Initialise a fr_socket_t for connecting to a remote host using a specific src interface,...
Definition: socket.h:151
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223
static fr_slen_t data
Definition: value.h:1259