All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tcp.c
Go to the documentation of this file.
1 /*
2  * tcp.c TCP-specific functions.
3  *
4  * Version: $Id: 83218a945f69ede32825f1e851d7993b77b5b2ce $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright (C) 2009 Dante http://dante.net
21  */
22 
23 RCSID("$Id: 83218a945f69ede32825f1e851d7993b77b5b2ce $")
24 
25 #include <freeradius-devel/libradius.h>
26 
27 #ifdef WITH_TCP
28 
29 /* FIXME: into common RADIUS header? */
30 #define MAX_PACKET_LEN 4096
31 
33 {
34  RADIUS_PACKET *packet = fr_radius_alloc(NULL, false);
35 
36  if (!packet) return NULL;
37 
38  packet->sockfd = sockfd;
39 
40  if (fr_tcp_read_packet(packet, flags) != 1) {
41  fr_radius_free(&packet);
42  return NULL;
43  }
44 
45  return packet;
46 }
47 
48 
49 /*
50  * Receives a packet, assuming that the RADIUS_PACKET structure
51  * has been filled out already.
52  *
53  * This ASSUMES that the packet is allocated && fields
54  * initialized.
55  *
56  * This ASSUMES that the socket is marked as O_NONBLOCK, which
57  * the function above does set, if your system supports it.
58  *
59  * Calling this function MAY change sockfd,
60  * if src_ipaddr.af == AF_UNSPEC.
61  */
62 int fr_tcp_read_packet(RADIUS_PACKET *packet, int flags)
63 {
64  ssize_t len;
65 
66  /*
67  * No data allocated. Read the 4-byte header into
68  * a temporary buffer.
69  */
70  if (!packet->data) {
71  int packet_len;
72 
73  len = recv(packet->sockfd, packet->vector + packet->data_len,
74  4 - packet->data_len, 0);
75  if (len == 0) return -2; /* clean close */
76 
77 #ifdef ECONNRESET
78  if ((len < 0) && (errno == ECONNRESET)) { /* forced */
79  return -2;
80  }
81 #endif
82 
83  if (len < 0) {
84  fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
85  return -1;
86  }
87 
88  packet->data_len += len;
89  if (packet->data_len < 4) { /* want more data */
90  return 0;
91  }
92 
93  packet_len = (packet->vector[2] << 8) | packet->vector[3];
94 
95  if (packet_len < RADIUS_HDR_LEN) {
96  fr_strerror_printf("Discarding packet: Smaller than RFC minimum of 20 bytes");
97  return -1;
98  }
99 
100  /*
101  * If the packet is too big, then the socket is bad.
102  */
103  if (packet_len > MAX_PACKET_LEN) {
104  fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes");
105  return -1;
106  }
107 
108  packet->data = talloc_array(packet, uint8_t, packet_len);
109  if (!packet->data) {
110  fr_strerror_printf("Out of memory");
111  return -1;
112  }
113 
114  packet->data_len = packet_len;
115  packet->partial = 4;
116  memcpy(packet->data, packet->vector, 4);
117  }
118 
119  /*
120  * Try to read more data.
121  */
122  len = recv(packet->sockfd, packet->data + packet->partial,
123  packet->data_len - packet->partial, 0);
124  if (len == 0) return -2; /* clean close */
125 
126 #ifdef ECONNRESET
127  if ((len < 0) && (errno == ECONNRESET)) { /* forced */
128  return -2;
129  }
130 #endif
131 
132  if (len < 0) {
133  fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
134  return -1;
135  }
136 
137  packet->partial += len;
138 
139  if (packet->partial < packet->data_len) {
140  return 0;
141  }
142 
143  /*
144  * See if it's a well-formed RADIUS packet.
145  */
146  if (!fr_radius_ok(packet, flags, NULL)) {
147  return -1;
148  }
149 
150  /*
151  * Explicitly set the VP list to empty.
152  */
153  packet->vps = NULL;
154 
155  if (fr_debug_lvl) {
156  char ip_buf[INET6_ADDRSTRLEN], buffer[256];
157 
158  if (packet->src_ipaddr.af != AF_UNSPEC) {
159  inet_ntop(packet->src_ipaddr.af,
160  &packet->src_ipaddr.ipaddr,
161  ip_buf, sizeof(ip_buf));
162  snprintf(buffer, sizeof(buffer), "host %s port %d",
163  ip_buf, packet->src_port);
164  } else {
165  snprintf(buffer, sizeof(buffer), "socket %d",
166  packet->sockfd);
167  }
168 
169  }
170 
171  gettimeofday(&packet->timestamp, NULL);
172 
173  return 1; /* done reading the packet */
174 }
175 
176 #endif /* WITH_TCP */
int sockfd
Socket this packet was read from.
Definition: libradius.h:147
static int sockfd
Definition: radclient.c:59
struct timeval timestamp
When we received the packet.
Definition: libradius.h:159
fr_ipaddr_t src_ipaddr
Src IP address of packet.
Definition: libradius.h:149
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition: missing.c:538
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
uint8_t * data
Packet data (body).
Definition: libradius.h:160
uint16_t src_port
Src port of packet.
Definition: libradius.h:151
int fr_debug_lvl
Definition: misc.c:40
int af
Address family.
Definition: inet.h:42
int fr_tcp_read_packet(RADIUS_PACKET *packet, int flags)
Definition: tcp.c:62
size_t partial
Definition: libradius.h:168
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
bool fr_radius_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
See if the data pointed to by PTR is a valid RADIUS packet.
Definition: radius.c:731
RADIUS_PACKET * fr_radius_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new RADIUS_PACKET.
Definition: radius.c:1651
union fr_ipaddr_t::@1 ipaddr
uint8_t vector[AUTH_VECTOR_LEN]
RADIUS authentication vector.
Definition: libradius.h:157
void fr_radius_free(RADIUS_PACKET **)
Free a RADIUS_PACKET.
Definition: radius.c:1727
size_t data_len
Length of packet data.
Definition: libradius.h:161
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
#define RADIUS_HDR_LEN
Definition: net.h:69
#define MAX_PACKET_LEN
Definition: tcp.c:30
RADIUS_PACKET * fr_tcp_recv(int sockfd, int flags)
Definition: tcp.c:32
#define RCSID(id)
Definition: build.h:135