The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
tcp.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program 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
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; 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: 5a4f0eddf250741283547456c223d3bf87be030b $
19  *
20  * @file protocols/radius/packet.c
21  * @brief TCP-specific functions.
22  *
23  * @copyright (C) 2009 Dante http://dante.net
24  */
25 RCSID("$Id: 5a4f0eddf250741283547456c223d3bf87be030b $")
26 
27 #include <freeradius-devel/radius/radius.h>
28 #include <freeradius-devel/util/syserror.h>
29 #include "tcp.h"
30 
31 fr_packet_t *fr_tcp_recv(int sockfd, int flags)
32 {
33  fr_packet_t *packet = fr_packet_alloc(NULL, false);
34 
35  if (!packet) return NULL;
36 
37  packet->socket.fd = sockfd;
38 
39  if (fr_tcp_read_packet(packet, RADIUS_MAX_ATTRIBUTES, flags) != 1) {
40  fr_packet_free(&packet);
41  return NULL;
42  }
43 
44  return packet;
45 }
46 
47 /*
48  * Receives a packet, assuming that the fr_packet_t structure
49  * has been filled out already.
50  *
51  * This ASSUMES that the packet is allocated && fields
52  * initialized.
53  *
54  * This ASSUMES that the socket is marked as O_NONBLOCK, which
55  * the function above does set, if your system supports it.
56  *
57  * Calling this function MAY change sockfd,
58  * if src_ipaddr.af == AF_UNSPEC.
59  */
60 int fr_tcp_read_packet(fr_packet_t *packet, uint32_t max_attributes, bool require_ma)
61 {
62  ssize_t len;
63 
64  /*
65  * No data allocated. Read the 4-byte header into
66  * a temporary buffer.
67  */
68  if (!packet->data) {
69  int packet_len;
70 
71  len = recv(packet->socket.fd, packet->vector + packet->data_len,
72  4 - packet->data_len, 0);
73  if (len == 0) return -2; /* clean close */
74 
75 #ifdef ECONNRESET
76  if ((len < 0) && (errno == ECONNRESET)) { /* forced */
77  return -2;
78  }
79 #endif
80 
81  if (len < 0) {
82  fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
83  return -1;
84  }
85 
86  packet->data_len += len;
87  if (packet->data_len < 4) { /* want more data */
88  return 0;
89  }
90 
91  packet_len = fr_nbo_to_uint16(packet->vector + 2);
92 
93  if (packet_len < RADIUS_HEADER_LENGTH) {
94  fr_strerror_const("Discarding packet: Smaller than RFC minimum of 20 bytes");
95  return -1;
96  }
97 
98  /*
99  * If the packet is too big, then the socket is bad.
100  */
101  if (packet_len > MAX_PACKET_LEN) {
102  fr_strerror_const("Discarding packet: Larger than RFC limitation of 4096 bytes");
103  return -1;
104  }
105 
106  packet->data = talloc_array(packet, uint8_t, packet_len);
107  if (!packet->data) {
108  fr_strerror_const("Out of memory");
109  return -1;
110  }
111 
112  packet->data_len = packet_len;
113  packet->partial = 4;
114  memcpy(packet->data, packet->vector, 4); //-V512
115  }
116 
117  /*
118  * Try to read more data.
119  */
120  len = recv(packet->socket.fd, packet->data + packet->partial,
121  packet->data_len - packet->partial, 0);
122  if (len == 0) return -2; /* clean close */
123 
124 #ifdef ECONNRESET
125  if ((len < 0) && (errno == ECONNRESET)) { /* forced */
126  return -2;
127  }
128 #endif
129 
130  if (len < 0) {
131  fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
132  return -1;
133  }
134 
135  packet->partial += len;
136 
137  if (packet->partial < packet->data_len) {
138  return 0;
139  }
140 
141  /*
142  * See if it's a well-formed RADIUS packet.
143  */
144  if (!fr_packet_ok(packet, max_attributes, require_ma, NULL)) {
145  return -1;
146  }
147 
148  if (fr_debug_lvl) {
149  char ip_buf[INET6_ADDRSTRLEN], buffer[256];
150 
151  if (packet->socket.inet.src_ipaddr.af != AF_UNSPEC) {
152  inet_ntop(packet->socket.inet.src_ipaddr.af, &packet->socket.inet.src_ipaddr.addr, ip_buf, sizeof(ip_buf));
153  snprintf(buffer, sizeof(buffer), "host %s port %d", ip_buf, packet->socket.inet.src_port);
154  } else {
155  snprintf(buffer, sizeof(buffer), "socket %d", packet->socket.fd);
156  }
157 
158  }
159 
160  packet->timestamp = fr_time();
161 
162  return 1; /* done reading the packet */
163 }
static int const char char buffer[256]
Definition: acutest.h:574
#define RCSID(id)
Definition: build.h:444
#define MAX_PACKET_LEN
Definition: defs.h:68
static int sockfd
Definition: dhcpclient.c:56
int fr_debug_lvl
Definition: log.c:42
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition: packet.c:38
void fr_packet_free(fr_packet_t **packet_p)
Free a fr_packet_t.
Definition: packet.c:89
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition: missing.c:443
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition: nbo.h:137
#define RADIUS_HEADER_LENGTH
Definition: net.h:80
bool fr_packet_ok(fr_packet_t *packet, uint32_t max_attributes, bool require_ma, decode_fail_t *reason)
See if the data pointed to by PTR is a valid RADIUS packet.
Definition: packet.c:115
#define RADIUS_MAX_ATTRIBUTES
Definition: radius.h:39
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:689
#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
fr_packet_t * fr_tcp_recv(int sockfd, int flags)
Definition: tcp.c:31
int fr_tcp_read_packet(fr_packet_t *packet, uint32_t max_attributes, bool require_ma)
Definition: tcp.c:60
RADIUS over TCP.
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
size_t partial
Definition: packet.h:77
uint8_t vector[RADIUS_AUTH_VECTOR_LENGTH]
RADIUS authentication vector.
Definition: packet.h:69
fr_time_t timestamp
When we received the packet.
Definition: packet.h:58
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition: socket.h:78
int fd
File descriptor if this is a live socket.
Definition: socket.h:81
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223