Coverage Report

Created: 2024-08-28 06:17

/src/freeradius-server/src/protocols/radius/tcp.c
Line
Count
Source (jump to first uncovered line)
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
 */
25
RCSID("$Id: c8ca250f513459c54fa7978f6e18c21d3b328173 $")
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
0
{
33
0
  fr_packet_t *packet = fr_packet_alloc(NULL, false);
34
35
0
  if (!packet) return NULL;
36
37
0
  packet->socket.fd = sockfd;
38
39
0
  if (fr_tcp_read_packet(packet, RADIUS_MAX_ATTRIBUTES, flags) != 1) {
40
0
    fr_packet_free(&packet);
41
0
    return NULL;
42
0
  }
43
44
0
  return packet;
45
0
}
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_message_authenticator)
61
0
{
62
0
  ssize_t len;
63
64
  /*
65
   *  No data allocated.  Read the 4-byte header into
66
   *  a temporary buffer.
67
   */
68
0
  if (!packet->data) {
69
0
    int packet_len;
70
71
0
    len = recv(packet->socket.fd, packet->vector + packet->data_len,
72
0
         4 - packet->data_len, 0);
73
0
    if (len == 0) return -2; /* clean close */
74
75
0
#ifdef ECONNRESET
76
0
    if ((len < 0) && (errno == ECONNRESET)) { /* forced */
77
0
      return -2;
78
0
    }
79
0
#endif
80
81
0
    if (len < 0) {
82
0
      fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
83
0
      return -1;
84
0
    }
85
86
0
    packet->data_len += len;
87
0
    if (packet->data_len < 4) { /* want more data */
88
0
      return 0;
89
0
    }
90
91
0
    packet_len = fr_nbo_to_uint16(packet->vector + 2);
92
93
0
    if (packet_len < RADIUS_HEADER_LENGTH) {
94
0
      fr_strerror_const("Discarding packet: Smaller than RFC minimum of 20 bytes");
95
0
      return -1;
96
0
    }
97
98
    /*
99
     *  If the packet is too big, then the socket is bad.
100
     */
101
0
    if (packet_len > MAX_PACKET_LEN) {
102
0
      fr_strerror_const("Discarding packet: Larger than RFC limitation of 4096 bytes");
103
0
      return -1;
104
0
    }
105
106
0
    packet->data = talloc_array(packet, uint8_t, packet_len);
107
0
    if (!packet->data) {
108
0
      fr_strerror_const("Out of memory");
109
0
      return -1;
110
0
    }
111
112
0
    packet->data_len = packet_len;
113
0
    packet->partial = 4;
114
0
    memcpy(packet->data, packet->vector, 4);  //-V512
115
0
  }
116
117
  /*
118
   *  Try to read more data.
119
   */
120
0
  len = recv(packet->socket.fd, packet->data + packet->partial,
121
0
       packet->data_len - packet->partial, 0);
122
0
  if (len == 0) return -2; /* clean close */
123
124
0
#ifdef ECONNRESET
125
0
  if ((len < 0) && (errno == ECONNRESET)) { /* forced */
126
0
    return -2;
127
0
  }
128
0
#endif
129
130
0
  if (len < 0) {
131
0
    fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
132
0
    return -1;
133
0
  }
134
135
0
  packet->partial += len;
136
137
0
  if (packet->partial < packet->data_len) {
138
0
    return 0;
139
0
  }
140
141
  /*
142
   *  See if it's a well-formed RADIUS packet.
143
   */
144
0
  if (!fr_packet_ok(packet, max_attributes, require_message_authenticator, NULL)) {
145
0
    return -1;
146
0
  }
147
148
0
  if (fr_debug_lvl) {
149
0
    char ip_buf[INET6_ADDRSTRLEN], buffer[256];
150
151
0
    if (packet->socket.inet.src_ipaddr.af != AF_UNSPEC) {
152
0
      inet_ntop(packet->socket.inet.src_ipaddr.af, &packet->socket.inet.src_ipaddr.addr, ip_buf, sizeof(ip_buf));
153
0
      snprintf(buffer, sizeof(buffer), "host %s port %d", ip_buf, packet->socket.inet.src_port);
154
0
    } else {
155
0
      snprintf(buffer, sizeof(buffer), "socket %d", packet->socket.fd);
156
0
    }
157
158
0
  }
159
160
0
  packet->timestamp = fr_time();
161
162
0
  return 1;   /* done reading the packet */
163
0
}