The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
net.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2 of the
4 * License as published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
14 */
15
16/** Functions for parsing raw network packets
17 *
18 * @file src/lib/util/net.c
19 *
20 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
21 * @copyright 2014-2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
22 */
23#include <freeradius-devel/util/net.h>
24
25/** Strings for L4 protocols
26 *
27 */
29 { L("ICMP"), IPPROTO_ICMP },
30 { L("ICMPv6"), IPPROTO_ICMPV6 },
31 { L("TCP"), IPPROTO_TCP },
32 { L("UDP"), IPPROTO_UDP }
33};
35
36/** Strings for socket types
37 *
38 */
40 { L("TCP"), SOCK_STREAM },
41 { L("UDP"), SOCK_DGRAM }
42};
44
45/** Strings for address families
46 *
47 */
49 { L("IPv4"), AF_INET },
50 { L("IPv6"), AF_INET6 }
51};
53
54/** Check UDP header is valid
55 *
56 * @param data Pointer to the start of the UDP header
57 * @param remaining bits of received packet
58 * @param ip pointer to IP header structure
59 * @return
60 * - 1 if checksum is incorrect.
61 * - 0 if UDP payload length and checksum are correct
62 * - -1 on validation error.
63 */
64 int fr_udp_header_check(uint8_t const *data, uint16_t remaining, ip_header_t const * ip)
65 {
66 int ret = 0;
67 udp_header_t const *udp;
68
69 /*
70 * UDP header validation.
71 */
72 uint16_t udp_len;
73 ssize_t actual_len;
74 uint16_t expected;
75
76 udp = (udp_header_t const *)data;
77 udp_len = ntohs(udp->len);
78 actual_len = remaining;
79 /* Truncated data */
80 if (udp_len > actual_len) {
81 fr_strerror_printf("packet too small by %zi bytes, UDP header + Payload should be %hu bytes",
82 (udp_len - actual_len), udp_len);
83 return -1;
84 }
85 /* Trailing data */
86 else if (udp_len < actual_len) {
87 fr_strerror_printf("Packet too big by %zi bytes, UDP header + Payload should be %hu bytes",
88 (actual_len - udp_len), udp_len);
89 return -1;
90 }
91
92 /* coverity[tainted_data] */
93 expected = fr_udp_checksum((uint8_t const *) udp, udp_len, udp->checksum,
94 ip->ip_src, ip->ip_dst);
95 if (udp->checksum != expected) {
96 fr_strerror_printf("UDP checksum invalid, packet: 0x%04hx calculated: 0x%04hx",
97 ntohs(udp->checksum), ntohs(expected));
98 /* Not a fatal error */
99 ret = 1;
100 }
101
102 return ret;
103 }
104
105/** Calculate UDP checksum
106 *
107 * Zero out UDP checksum in UDP header before calling #fr_udp_checksum to get 'expected' checksum.
108 *
109 * @param data Pointer to the start of the UDP header
110 * @param len value of udp length field in host byte order. Must be validated to make
111 * sure it won't overrun data buffer.
112 * @param checksum current checksum, leave as 0 to just enable validation.
113 * @param src_addr in network byte order.
114 * @param dst_addr in network byte order.
115 * @return
116 * - 0 if the checksum is correct.
117 * - !0 if checksum is incorrect.
118 */
120 struct in_addr const src_addr, struct in_addr const dst_addr)
121{
122 uint64_t sum = 0; /* using 64bits avoids overflow check */
123 uint16_t const *p = (uint16_t const *)data;
124
125 uint16_t const *ip_src = (void const *) &src_addr.s_addr;
126 uint16_t const *ip_dst = (void const *) &dst_addr.s_addr;
127 uint16_t i;
128
129 sum += *(ip_src++);
130 sum += *ip_src;
131 sum += *(ip_dst++);
132 sum += *ip_dst;
133
134 sum += htons(IPPROTO_UDP);
135 sum += htons(len);
136
137 for (i = len; i > 1; i -= 2) sum += *p++;
138 if (i) sum += (0xff & *(uint8_t const *)p) << 8;
139
140 sum -= checksum;
141
142 while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
143
144 return ((uint16_t) ~sum);
145}
146
147/** Calculate IP header checksum.
148 *
149 * Zero out IP header checksum in IP header before calling fr_ip_header_checksum to get 'expected' checksum.
150 *
151 * @param data Pointer to the start of the IP header
152 * @param ihl value of ip header length field (number of 32 bit words)
153 */
155{
156 uint64_t sum = 0;
157 uint16_t const *p = (uint16_t const *)data;
158
159 uint8_t nwords = (ihl << 1); /* number of 16-bit words */
160
161 for (sum = 0; nwords > 0; nwords--) {
162 sum += *p++;
163 }
164 sum = (sum >> 16) + (sum & 0xffff);
165 sum += (sum >> 16);
166 return ((uint16_t) ~sum);
167}
168
169uint16_t fr_ip6_pesudo_header_checksum(struct in6_addr const *src, struct in6_addr const *dst, uint16_t ip_len, uint8_t ip_next)
170{
171 uint64_t sum = 0;
172 ip_pseudo_header6_t ip6; /* Keep correct alignment for the pointer */
173 uint8_t const *p = (uint8_t const *) &ip6;
174 int8_t nwords = sizeof(ip6) >> 1; /* number of 16-bit words */
175
176 memcpy(&ip6.ip_src, src, sizeof(ip6.ip_src));
177 memcpy(&ip6.ip_dst, dst, sizeof(ip6.ip_dst));
178 ip6.ip_len = ip_len;
179 ip6.ip_next = ip_next;
180
181 for (sum = 0; nwords > 0; nwords--) {
182 uint16_t word;
183 memcpy(&word, p, sizeof(word)); /* Can't use a uint16_t * as GCC flags this for unaligned access */
184 sum += word;
185 p += sizeof(word);
186 }
187 sum = (sum >> 16) + (sum & 0xffff);
188 sum += (sum >> 16);
189 return ((uint16_t) ~sum);
190}
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define NUM_ELEMENTS(_t)
Definition build.h:337
unsigned short uint16_t
long int ssize_t
unsigned char uint8_t
size_t fr_net_af_table_len
Definition net.c:52
fr_table_num_sorted_t const fr_net_sock_type_table[]
Strings for socket types.
Definition net.c:39
uint16_t fr_ip6_pesudo_header_checksum(struct in6_addr const *src, struct in6_addr const *dst, uint16_t ip_len, uint8_t ip_next)
Definition net.c:169
fr_table_num_sorted_t const fr_net_ip_proto_table[]
Strings for L4 protocols.
Definition net.c:28
int fr_udp_header_check(uint8_t const *data, uint16_t remaining, ip_header_t const *ip)
Check UDP header is valid.
Definition net.c:64
uint16_t fr_udp_checksum(uint8_t const *data, uint16_t len, uint16_t checksum, struct in_addr const src_addr, struct in_addr const dst_addr)
Calculate UDP checksum.
Definition net.c:119
size_t fr_net_ip_proto_table_len
Definition net.c:34
fr_table_num_sorted_t const fr_net_af_table[]
Strings for address families.
Definition net.c:48
uint16_t fr_ip_header_checksum(uint8_t const *data, uint8_t ihl)
Calculate IP header checksum.
Definition net.c:154
size_t fr_net_sock_type_table_len
Definition net.c:43
uint32_t ip_next
upper 24 bits must be zero
Definition net.h:131
uint32_t ip_len
length
Definition net.h:130
struct in6_addr ip_src ip_dst
Src and Dst address.
Definition net.h:129
uint16_t len
UDP length.
Definition net.h:141
uint16_t checksum
UDP checksum.
Definition net.h:142
struct in_addr ip_src ip_dst
Src and Dst address.
Definition net.h:115
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
static fr_slen_t data
Definition value.h:1265