diff --git a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp b/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp index 9a05a98130..79fbfd1124 100644 --- a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp +++ b/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp @@ -27,9 +27,14 @@ EthernetInterface::EthernetInterface() nsapi_error_t EthernetInterface::set_network(const char *ip_address, const char *netmask, const char *gateway) { _dhcp = false; + strncpy(_ip_address, ip_address ? ip_address : "", sizeof(_ip_address)); + _ip_address[sizeof(_ip_address) - 1] = '\0'; strncpy(_netmask, netmask ? netmask : "", sizeof(_netmask)); + _netmask[sizeof(_netmask) - 1] = '\0'; strncpy(_gateway, gateway ? gateway : "", sizeof(_gateway)); + _gateway[sizeof(_gateway) - 1] = '\0'; + return NSAPI_ERROR_OK; } diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_random.c b/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_random.c new file mode 100644 index 0000000000..7c1cf8de0e --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_random.c @@ -0,0 +1,53 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lwip_random.h" + +#if FEATURE_COMMON_PAL + +#include "randLIB.h" + +void lwip_seed_random(void) +{ + randLIB_seed_random(); +} + +void lwip_add_random_seed(uint64_t seed) +{ + randLIB_add_seed(seed); +} + +inline uint32_t lwip_get_random(void) +{ + return randLIB_get_32bit(); +} + +#else + +void lwip_seed_random(void) +{ +} + +void lwip_add_random_seed(uint64_t seed) +{ +} + +uint32_t lwip_get_random(void) +{ + return rand(); +} + +#endif diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_random.h b/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_random.h new file mode 100644 index 0000000000..2734924cf8 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_random.h @@ -0,0 +1,54 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LWIP_HDR_RANDOM_H +#define LWIP_HDR_RANDOM_H + +#include "lwip/opt.h" +#include "lwip/debug.h" +#include "lwip/def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Init seed for Pseudo Random + * + * Function shall seed the pseudo-random generator. Function + * is called during lwip initialisation. + */ +void lwip_seed_random(void); + +/** Update seed for pseudo-random generator + * + * Adds seed information to existing generator, to perturb the + * sequence. + * + * @param seed 64 bits of data to add to the seed. + */ +void lwip_add_random_seed(uint64_t seed); + +/** Generates random number. + * + * @return 32-bit random number + */ +uint32_t lwip_get_random(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_RANDOM_H */ diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_tcp_isn.c b/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_tcp_isn.c new file mode 100644 index 0000000000..5ddd47522b --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_tcp_isn.c @@ -0,0 +1,185 @@ +/** + * @file + * + * Reference implementation of the TCP ISN algorithm standardized in RFC 6528. + * Produce TCP Initial Sequence Numbers by combining an MD5-generated hash + * based on the new TCP connection's identity and a stable secret, with the + * current time at 4-microsecond granularity. + * + * Specifically, the implementation uses MD5 to compute a hash of the input + * buffer, which contains both the four-tuple of the new TCP connection (local + * and remote IP address and port), as well as a 16-byte secret to make the + * results unpredictable to external parties. The secret must be given at + * initialization time and should ideally remain the same across system + * reboots. To be sure: the spoofing-resistance of the resulting ISN depends + * mainly on the strength of the supplied secret! + * + * The implementation takes 32 bits from the computed hash, and adds to it the + * current time, in 4-microsecond units. The current time is computed from a + * boot time given at initialization, and the current uptime as provided by + * sys_now(). Thus, it assumes that sys_now() returns a time value that is + * relative to the boot time, i.e., that it starts at 0 at system boot, and + * only ever increases monotonically. + * + * For efficiency reasons, a single MD5 input buffer is used, and partially + * filled in at initialization time. Specifically, of this 64-byte buffer, the + * first 36 bytes are used for the four-way TCP tuple data, followed by the + * 16-byte secret, followed by 12-byte zero padding. The 64-byte size of the + * buffer should achieve the best performance for the actual MD5 computation. + * + * Basic usage: + * + * 1. in your lwipopts.h, add the following lines: + * + * #include + * struct ip_addr; + * u32_t lwip_hook_tcp_isn(const struct ip_addr *local_ip, u16_t local_port, + * const struct ip_addr *remote_ip, u16_t remote_port); + * "#define LWIP_HOOK_TCP_ISN lwip_hook_tcp_isn"; + * + * 2. from your own code, call lwip_init_tcp_isn() at initialization time, with + * appropriate parameters. + */ + +/* + * Copyright (c) 2016 The MINIX 3 Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: David van Moolenbroek + */ + +#include "lwip_tcp_isn.h" +#include "lwip/ip_addr.h" +#include "lwip/sys.h" +#include + +/* pull in md5 of ppp? */ +#define PPP_SUPPORT 1 +#include "netif/ppp/ppp_opts.h" +#include "netif/ppp/ppp.h" +#include "netif/ppp/pppcrypt.h" +#if !LWIP_USE_EXTERNAL_POLARSSL && !LWIP_USE_EXTERNAL_MBEDTLS +#undef LWIP_INCLUDED_POLARSSL_MD5 +#define LWIP_INCLUDED_POLARSSL_MD5 1 +#include "netif/ppp/polarssl/lwip_md5.c" +#endif +#if LWIP_USE_EXTERNAL_MBEDTLS +#include "mbedtls/inc/mbedtls/md5.h" +#define md5_context mbedtls_md5_context +#endif + +static u8_t input[64]; +static u32_t base_time; + +/** + * Initialize the TCP ISN module, with the boot time and a secret. + * + * @param boot_time Wall clock boot time of the system, in seconds. + * @param secret_16_bytes A 16-byte secret used to randomize the TCP ISNs. + */ +void +lwip_init_tcp_isn(u32_t boot_time, const u8_t *secret_16_bytes) +{ + /* Initialize the input buffer with the secret and trailing zeroes. */ + memset(input, 0, sizeof(input)); + + MEMCPY(&input[36], secret_16_bytes, 16); + + /* Save the boot time in 4-us units. Overflow is no problem here. */ + base_time = boot_time * 250000; +} + +/** + * Hook to generate an Initial Sequence Number (ISN) for a new TCP connection. + * + * @param local_ip The local IP address. + * @param local_port The local port number, in host-byte order. + * @param remote_ip The remote IP address. + * @param remote_port The remote port number, in host-byte order. + * @return The ISN to use for the new TCP connection. + */ +u32_t +lwip_hook_tcp_isn(const ip_addr_t *local_ip, u16_t local_port, + const ip_addr_t *remote_ip, u16_t remote_port) +{ + md5_context ctx; + u8_t output[16]; + u32_t isn; + +#if LWIP_IPV4 && LWIP_IPV6 + if (IP_IS_V6(local_ip)) +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV6 + { + const ip6_addr_t *local_ip6, *remote_ip6; + + local_ip6 = ip_2_ip6(local_ip); + remote_ip6 = ip_2_ip6(remote_ip); + + SMEMCPY(&input[0], &local_ip6->addr, 16); + SMEMCPY(&input[16], &remote_ip6->addr, 16); + } +#endif /* LWIP_IPV6 */ +#if LWIP_IPV4 && LWIP_IPV6 + else +#endif /* LWIP_IPV4 && LWIP_IPV6 */ +#if LWIP_IPV4 + { + const ip4_addr_t *local_ip4, *remote_ip4; + + local_ip4 = ip_2_ip4(local_ip); + remote_ip4 = ip_2_ip4(remote_ip); + + /* Represent IPv4 addresses as IPv4-mapped IPv6 addresses, to ensure that + * the IPv4 and IPv6 address spaces are completely disjoint. */ + memset(&input[0], 0, 10); + input[10] = 0xff; + input[11] = 0xff; + SMEMCPY(&input[12], &local_ip4->addr, 4); + memset(&input[16], 0, 10); + input[26] = 0xff; + input[27] = 0xff; + SMEMCPY(&input[28], &remote_ip4->addr, 4); + } +#endif /* LWIP_IPV4 */ + + input[32] = local_port >> 8; + input[33] = local_port & 0xff; + input[34] = remote_port >> 8; + input[35] = remote_port & 0xff; + + /* The secret and padding are already filled in. */ + + /* Generate the hash, using MD5. */ + lwip_md5_starts(&ctx); + lwip_md5_update(&ctx, input, sizeof(input)); + lwip_md5_finish(&ctx, output); + + /* Arbitrarily take the first 32 bits from the generated hash. */ + MEMCPY(&isn, output, sizeof(isn)); + + /* Add the current time in 4-microsecond units. */ + return isn + base_time + sys_now() * 250; +} diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_tcp_isn.h b/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_tcp_isn.h new file mode 100644 index 0000000000..ebaeca2472 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-sys/lwip_tcp_isn.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 The MINIX 3 Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: David van Moolenbroek + */ + +#ifndef LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H +#define LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void lwip_init_tcp_isn(u32_t boot_time, const u8_t *secret_16_bytes); +u32_t lwip_hook_tcp_isn(const ip_addr_t *local_ip, u16_t local_port, + const ip_addr_t *remote_ip, u16_t remote_port); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_HDR_CONTRIB_ADDONS_TCP_ISN_H */ diff --git a/features/FEATURE_LWIP/lwip-interface/lwip_stack.c b/features/FEATURE_LWIP/lwip-interface/lwip_stack.c index 8717ec4caf..a1e7709d3e 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwip_stack.c +++ b/features/FEATURE_LWIP/lwip-interface/lwip_stack.c @@ -34,6 +34,7 @@ #include "lwip/udp.h" #include "emac_api.h" +#include "lwip_tcp_isn.h" #if DEVICE_EMAC #define MBED_NETIF_INIT_FN emac_lwip_if_init @@ -108,7 +109,9 @@ static void mbed_lwip_socket_callback(struct netconn *nc, enum netconn_evt eh, u /* TCP/IP and Network Interface Initialisation */ static struct netif lwip_netif; +#if LWIP_IPV4 static bool lwip_dhcp = false; +#endif static char lwip_mac_address[NSAPI_MAC_SIZE]; #if !LWIP_IPV4 || !LWIP_IPV6 @@ -189,7 +192,9 @@ static bool convert_lwip_addr_to_mbed(nsapi_addr_t *out, const ip_addr_t *in) return true; } #endif +#if LWIP_IPV6 && LWIP_IPV4 return false; +#endif } static const ip_addr_t *mbed_lwip_get_ipv4_addr(const struct netif *netif) @@ -324,15 +329,23 @@ static void mbed_lwip_netif_status_irq(struct netif *lwip_netif) static void mbed_lwip_set_mac_address(void) { #if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) - snprintf(lwip_mac_address, NSAPI_MAC_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x", + (void) snprintf(lwip_mac_address, NSAPI_MAC_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x", MBED_MAC_ADDR_0, MBED_MAC_ADDR_1, MBED_MAC_ADDR_2, MBED_MAC_ADDR_3, MBED_MAC_ADDR_4, MBED_MAC_ADDR_5); #else char mac[6]; mbed_mac_address(mac); - snprintf(lwip_mac_address, NSAPI_MAC_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x", + (void) snprintf(lwip_mac_address, NSAPI_MAC_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); #endif + + /* Use mac address as additional seed to random number generator */ + uint64_t seed = mac[0]; + for (uint8_t i = 1; i < 8; i++) { + seed <<= 8; + seed |= mac[i % 6]; + } + lwip_add_random_seed(seed); } /* LWIP interface implementation */ @@ -357,7 +370,9 @@ char *mbed_lwip_get_ip_address(char *buf, nsapi_size_t buflen) return ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen); } #endif +#if LWIP_IPV6 && LWIP_IPV4 return NULL; +#endif } const char *mbed_lwip_get_netmask(char *buf, nsapi_size_t buflen) @@ -390,9 +405,20 @@ char *mbed_lwip_get_gateway(char *buf, nsapi_size_t buflen) nsapi_error_t mbed_lwip_init(emac_interface_t *emac) { + // Check if we've already brought up lwip if (!mbed_lwip_get_mac_address()) { + // Seed lwip random + lwip_seed_random(); + // Set up network + // Initialise TCP sequence number + uint32_t tcp_isn_secret[4]; + for (int i = 0; i < 4; i++) { + tcp_isn_secret[i] = LWIP_RAND(); + } + lwip_init_tcp_isn(0, (u8_t *) &tcp_isn_secret); + sys_sem_new(&lwip_tcpip_inited, 0); sys_sem_new(&lwip_netif_linked, 0); sys_sem_new(&lwip_netif_has_addr, 0); @@ -656,7 +682,7 @@ static nsapi_error_t mbed_lwip_socket_open(nsapi_stack_t *stack, nsapi_socket_t return NSAPI_ERROR_NO_SOCKET; } - u8_t lwip_proto = proto == NSAPI_TCP ? NETCONN_TCP : NETCONN_UDP; + enum netconn_type lwip_proto = proto == NSAPI_TCP ? NETCONN_TCP : NETCONN_UDP; #if LWIP_IPV6 && LWIP_IPV4 const ip_addr_t *ip_addr; diff --git a/features/FEATURE_LWIP/lwip-interface/lwipopts.h b/features/FEATURE_LWIP/lwip-interface/lwipopts.h index b652165350..537f8c3a21 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwipopts.h +++ b/features/FEATURE_LWIP/lwip-interface/lwipopts.h @@ -176,7 +176,7 @@ // Support Multicast #include "stdlib.h" #define LWIP_IGMP LWIP_IPV4 -#define LWIP_RAND() rand() +#define LWIP_RAND() lwip_get_random() #define LWIP_COMPAT_SOCKETS 0 #define LWIP_POSIX_SOCKETS_IO_NAMES 0 @@ -275,4 +275,12 @@ #error A transport mechanism (Ethernet or PPP) must be defined #endif +#include +#include "lwip_random.h" +#include "lwip_tcp_isn.h" +#define LWIP_HOOK_TCP_ISN lwip_hook_tcp_isn +#if MBEDTLS_MD5_C +#define LWIP_USE_EXTERNAL_MBEDTLS 1 +#endif + #endif /* LWIPOPTS_H_ */