The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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 
169 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)
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:207
#define NUM_ELEMENTS(_t)
Definition: build.h:335
unsigned short uint16_t
Definition: merged_model.c:31
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
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:45
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
static fr_slen_t data
Definition: value.h:1259