All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 /**
17  * $Id: 2beaeea6ff911d12ac7800070141e40edd91c96f $
18  * @file net.c
19  * @brief Functions to parse raw packets.
20  *
21  * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
22  * @copyright 2014-2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23  */
24 #include <freeradius-devel/libradius.h>
25 #include <freeradius-devel/net.h>
26 
27 /** Strings for L4 protocols
28  *
29  */
31  { "UDP", IPPROTO_UDP },
32  { "TCP", IPPROTO_TCP },
33  { NULL, 0 }
34 };
35 
36 /** Strings for socket types
37  *
38  */
40  { "UDP", SOCK_DGRAM },
41  { "TCP", SOCK_STREAM },
42  { NULL, 0 }
43 };
44 
45 /** Strings for address families
46  *
47  */
49  { "IPv4", AF_INET },
50  { "IPv6", AF_INET6 },
51  { NULL, 0 }
52 };
53 
54 /** Check whether fr_link_layer_offset can process a link_layer
55  *
56  * @param link_layer to check.
57  * @return
58  * - true if supported.
59  * - false if not supported.
60  */
61 bool fr_link_layer_supported(int link_layer)
62 {
63  switch (link_layer) {
64  case DLT_EN10MB:
65  case DLT_RAW:
66  case DLT_NULL:
67  case DLT_LOOP:
68  case DLT_LINUX_SLL:
69  case DLT_PFLOG:
70  return true;
71 
72  default:
73  return false;
74  }
75 }
76 
77 /** Returns the length of the link layer header
78  *
79  * Libpcap does not include a decoding function to skip the L2 header, but it does
80  * at least inform us of the type.
81  *
82  * Unfortunately some headers are of variable length (like ethernet), so additional
83  * decoding logic is required.
84  *
85  * @note No header data is returned, this is only meant to be used to determine how
86  * data to consume before attempting to parse the IP header.
87  *
88  * @param data start of packet data.
89  * @param len caplen.
90  * @param link_layer value returned from pcap_linktype.
91  * @return
92  * - Length of the header.
93  * - -1 on failure.
94  */
95 ssize_t fr_link_layer_offset(uint8_t const *data, size_t len, int link_layer)
96 {
97  uint8_t const *p = data;
98 
99  switch (link_layer) {
100  case DLT_RAW:
101  break;
102 
103  case DLT_NULL:
104  case DLT_LOOP:
105  p += 4;
106  if (((size_t)(p - data)) > len) {
107  ood:
108  fr_strerror_printf("Out of data, needed %zu bytes, have %zu bytes",
109  (size_t)(p - data), len);
110  return -1;
111  }
112  break;
113 
114  case DLT_EN10MB:
115  {
116  uint16_t ether_type; /* Ethernet type */
117  int i;
118 
119  p += 12; /* SRC/DST Mac-Addresses */
120  if (((size_t)(p - data)) > len) {
121  goto ood;
122  }
123 
124  for (i = 0; i < 3; i++) {
125  ether_type = ntohs(*((uint16_t const *) p));
126  switch (ether_type) {
127  /*
128  * There are a number of devices out there which
129  * double tag with 0x8100 *sigh*
130  */
131  case 0x8100: /* CVLAN */
132  case 0x9100: /* SVLAN */
133  case 0x9200: /* SVLAN */
134  case 0x9300: /* SVLAN */
135  p += 4;
136  if (((size_t)(p - data)) > len) {
137  goto ood;
138  }
139  break;
140 
141  default:
142  p += 2;
143  if (((size_t)(p - data)) > len) {
144  goto ood;
145  }
146  goto done;
147  }
148  }
149  fr_strerror_printf("Exceeded maximum level of VLAN tag nesting (2)");
150  return -1;
151  }
152 
153  case DLT_LINUX_SLL:
154  p += 16;
155  if (((size_t)(p - data)) > len) {
156  goto ood;
157  }
158  break;
159 
160  case DLT_PFLOG:
161  p += 28;
162  if (((size_t)(p - data)) > len) {
163  goto ood;
164  }
165  break;
166 
167  default:
168  fr_strerror_printf("Unsupported link layer type %i", link_layer);
169  return -1;
170  }
171 
172 done:
173  return p - data;
174 }
175 
176 /** Check UDP header is valid
177  *
178  * @param data Pointer to the start of the UDP header
179  * @param remaining bits of received packet
180  * @param ip pointer to IP header structure
181  * @return
182  * - 1 if checksum is incorrect.
183  * - 0 if UDP payload lenght and checksum are correct
184  * - -1 on validation error.
185  */
186  int fr_udp_header_check(uint8_t const *data, uint16_t remaining, ip_header_t const * ip)
187  {
188  int ret = 0;
189  udp_header_t const *udp;
190 
191  /*
192  * UDP header validation.
193  */
194  udp = (udp_header_t const *)data;
195  uint16_t udp_len;
196  ssize_t diff;
197  uint16_t expected;
198 
199  udp_len = ntohs(udp->len);
200  diff = udp_len - remaining;
201  /* Truncated data */
202  if (diff > 0) {
203  fr_strerror_printf("packet too small by %zi bytes, UDP header + Payload should be %hu bytes",
204  diff, udp_len);
205  return -1;
206  }
207  /* Trailing data */
208  else if (diff < 0) {
209  fr_strerror_printf("Packet too big by %zi bytes, UDP header + Payload should be %hu bytes",
210  diff * -1, udp_len);
211  return -1;
212  }
213 
214  expected = fr_udp_checksum((uint8_t const *) udp, ntohs(udp->len), udp->checksum,
215  ip->ip_src, ip->ip_dst);
216  if (udp->checksum != expected) {
217  fr_strerror_printf("DHCP: UDP checksum invalid, packet: 0x%04hx calculated: 0x%04hx",
218  ntohs(udp->checksum), ntohs(expected));
219  /* Not a fatal error */
220  ret = 1;
221  }
222 
223  return ret;
224  }
225 
226 /** Calculate UDP checksum
227  *
228  * Zero out UDP checksum in UDP header before calling #fr_udp_checksum to get 'expected' checksum.
229  *
230  * @param data Pointer to the start of the UDP header
231  * @param len value of udp length field in host byte order. Must be validated to make
232  * sure it won't overrun data buffer.
233  * @param checksum current checksum, leave as 0 to just enable validation.
234  * @param src_addr in network byte order.
235  * @param dst_addr in network byte order.
236  * @return
237  * - 0 if the checksum is correct.
238  * - !0 if checksum is incorrect.
239  */
240 uint16_t fr_udp_checksum(uint8_t const *data, uint16_t len, uint16_t checksum,
241  struct in_addr const src_addr, struct in_addr const dst_addr)
242 {
243  uint64_t sum = 0; /* using 64bits avoids overflow check */
244  uint16_t const *p = (uint16_t const *)data;
245 
246  uint16_t const *ip_src = (void const *) &src_addr.s_addr;
247  uint16_t const *ip_dst = (void const *) &dst_addr.s_addr;
248  uint16_t i;
249 
250  sum += *(ip_src++);
251  sum += *ip_src;
252  sum += *(ip_dst++);
253  sum += *ip_dst;
254 
255  sum += htons(IPPROTO_UDP);
256  sum += htons(len);
257 
258  for (i = len; i > 1; i -= 2) sum += *p++;
259  if (i) sum += (0xff & *(uint8_t const *)p) << 8;
260 
261  sum -= checksum;
262 
263  while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
264 
265  return ((uint16_t) ~sum);
266 }
267 
268 /** Calculate IP header checksum.
269  *
270  * Zero out IP header checksum in IP header before calling fr_ip_header_checksum to get 'expected' checksum.
271  *
272  * @param data Pointer to the start of the IP header
273  * @param ihl value of ip header length field (number of 32 bit words)
274  */
275 uint16_t fr_ip_header_checksum(uint8_t const *data, uint8_t ihl)
276 {
277  uint64_t sum = 0;
278  uint16_t const *p = (uint16_t const *)data;
279 
280  uint8_t nwords = (ihl << 1); /* number of 16-bit words */
281 
282  for (sum = 0; nwords > 0; nwords--) {
283  sum += *p++;
284  }
285  sum = (sum >> 16) + (sum & 0xffff);
286  sum += (sum >> 16);
287  return ((uint16_t) ~sum);
288 }
Definition: net.h:46
uint16_t fr_ip_header_checksum(uint8_t const *data, uint8_t ihl)
Calculate IP header checksum.
Definition: net.c:275
bool fr_link_layer_supported(int link_layer)
Check whether fr_link_layer_offset can process a link_layer.
Definition: net.c:61
Definition: net.h:42
udp_header_t
Definition: net.h:134
ssize_t fr_link_layer_offset(uint8_t const *data, size_t len, int link_layer)
Returns the length of the link layer header.
Definition: net.c:95
Definition: net.h:43
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:186
static bool done
Definition: radclient.c:53
FR_NAME_NUMBER const fr_net_sock_type_table[]
Strings for socket types.
Definition: net.c:39
FR_NAME_NUMBER const fr_net_af_table[]
Strings for address families.
Definition: net.c:48
uint8_t data[]
Definition: eap_pwd.h:625
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:240
Definition: net.h:41
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
ip_header_t
Definition: net.h:113
Definition: net.h:44
FR_NAME_NUMBER const fr_net_ip_proto_table[]
Strings for L4 protocols.
Definition: net.c:30