diff options
Diffstat (limited to 'src/lib/net.c')
-rw-r--r-- | src/lib/net.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/lib/net.c b/src/lib/net.c new file mode 100644 index 0000000..7c899d7 --- /dev/null +++ b/src/lib/net.c @@ -0,0 +1,94 @@ +/* + * This program is is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 of the + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * @file net.c + * @brief Functions to parse raw packets. + * + * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org> + * @copyright 2014-2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org> + */ + #include <freeradius-devel/libradius.h> + #include <freeradius-devel/net.h> + +/** Calculate UDP checksum + * + * Zero out UDP checksum in UDP header before calling fr_udp_checksum to get 'expected' checksum. + * + * @param data Pointer to the start of the UDP header + * @param len value of udp length field in host byte order. Must be validated to make + * sure it won't overrun data buffer. + * @param checksum current checksum, leave as 0 to just enable validation. + * @param src_addr in network byte order. + * @param dst_addr in network byte order. + * @return 0 if the checksum is correct, else another number. + */ +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) +{ + uint64_t sum = 0; /* using 64bits avoids overflow check */ + uint16_t const *p = (uint16_t const *)data; + + uint16_t const *ip_src = (void const *) &src_addr.s_addr; + uint16_t const *ip_dst = (void const *) &dst_addr.s_addr; + uint16_t i; + + sum += *(ip_src++); + sum += *ip_src; + sum += *(ip_dst++); + sum += *ip_dst; + + sum += htons(IPPROTO_UDP); + sum += htons(len); + + for (i = len; i > 1; i -= 2) { + sum += *p++; + } + + if (i) { + sum += (0xff & *(uint8_t const *)p) << 8; + } + + sum -= checksum; + + while (sum >> 16) { + sum = (sum & 0xffff) + (sum >> 16); + } + + return ((uint16_t) ~sum); +} + +/** Calculate IP header checksum. + * + * Zero out IP header checksum in IP header before calling fr_iph_checksum to get 'expected' checksum. + * + * @param data Pointer to the start of the IP header + * @param ihl value of ip header length field (number of 32 bit words) + */ +uint16_t fr_iph_checksum(uint8_t const *data, uint8_t ihl) +{ + uint64_t sum = 0; + uint16_t const *p = (uint16_t const *)data; + + uint8_t nwords = (ihl << 1); /* number of 16-bit words */ + + for (sum = 0; nwords > 0; nwords--) { + sum += *p++; + } + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + return ((uint16_t) ~sum); +} |