The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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: c8ca250f513459c54fa7978f6e18c21d3b328173 $
19 *
20 * @file protocols/radius/packet.c
21 * @brief TCP-specific functions.
22 *
23 * @copyright (C) 2009 Dante http://dante.net
24 */
25RCSID("$Id: c8ca250f513459c54fa7978f6e18c21d3b328173 $")
26
27#include <freeradius-devel/radius/radius.h>
28#include <freeradius-devel/util/syserror.h>
29#include "tcp.h"
30
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 */
60int fr_tcp_read_packet(fr_packet_t *packet, uint32_t max_attributes, bool require_message_authenticator)
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_message_authenticator, 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:576
#define RCSID(id)
Definition build.h:483
#define MAX_PACKET_LEN
Definition defs.h:68
static int sockfd
Definition dhcpclient.c:56
int fr_debug_lvl
Definition log.c:43
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
long int ssize_t
unsigned char uint8_t
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:146
#define RADIUS_HEADER_LENGTH
Definition net.h:80
bool fr_packet_ok(fr_packet_t *packet, uint32_t max_attributes, bool require_message_authenticator, fr_radius_decode_fail_t *reason)
See if the data pointed to by PTR is a valid RADIUS packet.
Definition packet.c:119
#define RADIUS_MAX_ATTRIBUTES
Definition radius.h:40
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_message_authenticator)
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