Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added an MTU oversize packet error generator.

  • Loading branch information...
commit 95d52d70b7f24d83d0ca03e9cd9738497470b11b 1 parent f23750d
Caleb James DeLisle authored
View
7 admin/angel/Core.c
@@ -35,6 +35,8 @@
#include "interface/TUNConfigurator.h"
#include "interface/TUNInterface.h"
#include "interface/PipeInterface.h"
+#include "interface/InterfaceConnector.h"
+#include "interface/ICMP6Generator.h"
#include "io/ArrayReader.h"
#include "io/ArrayWriter.h"
#include "io/FileWriter.h"
@@ -159,7 +161,10 @@ void Core_initTunnel(String* desiredDeviceName,
eh);
struct TUNInterface* tun = TUNInterface_new(tunPtr, eventBase, alloc);
- Ducttape_setUserInterface(dt, &tun->iface);
+
+ struct ICMP6Generator* icmp = ICMP6Generator_new(alloc);
+ InterfaceConnector_connect(&icmp->external, &tun->iface);
+ Ducttape_setUserInterface(dt, &icmp->internal);
TUNConfigurator_setIpAddress(assignedTunName, ipAddr, addressPrefix, logger, eh);
TUNConfigurator_setMTU(assignedTunName, DEFAULT_MTU, logger, eh);
View
1  interface/CMakeLists.txt
@@ -31,6 +31,7 @@ add_library(interface
TUNConfigurator_${SYSTEM}.c
InterfaceConnector.c
SessionManager.c
+ ICMP6Generator.c
)
target_link_libraries(interface
View
165 interface/ICMP6Generator.c
@@ -0,0 +1,165 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "interface/ICMP6Generator.h"
+#include "util/Checksum.h"
+#include "util/Bits.h"
+#include "util/log/Log.h"
+#include "util/Identity.h"
+#include "wire/Headers.h"
+#include "wire/Error.h"
+
+#include <stddef.h>
+#ifdef Linux
+ #include <linux/ipv6.h>
+ #include <linux/icmpv6.h>
+#else
+ #include <netinet/in.h>
+ #include <netinet/ip_icmp.h>
+#endif
+
+/** MTU at switch layer, not including switch header overhead. */
+#define EXPECTED_MTU \
+ (1492 /* PPPoE */ \
+ - Headers_IP4Header_SIZE \
+ - Headers_UDPHeader_SIZE \
+ - 20 /* CryptoAuth in ESTABLISHED state. */ )
+
+
+#define CJDNS_OVERHEAD \
+ (Headers_SwitchHeader_SIZE \
+ + 4 /* handle */ \
+ + Headers_CryptoAuth_SIZE \
+ /* IPv6 header goes here but operating system subtracts it. */ \
+ + Headers_CryptoAuth_SIZE)
+
+
+struct ICMP6Generator_pvt
+{
+ struct ICMP6Generator pub;
+
+ Identity
+};
+
+static inline uint8_t numForType(enum ICMP6Generator_Type type)
+{
+ switch (type) {
+ case ICMP6Generator_Type_NO_ROUTE_TO_HOST: return ICMPV6_DEST_UNREACH;
+ case ICMP6Generator_Type_PACKET_TOO_BIG: return ICMPV6_PKT_TOOBIG;
+ default: return 0;
+ }
+}
+
+/**
+ * Generate an ICMPv6 message.
+ * The message parameter must contain all content which will be beneath the ICMPv6 header
+ * including the MTU in the case of a "packet too big" message.
+ *
+ * @param message a message containing the content. This message must have enough padding
+ * to contain an additional ICMP header and IPv6 header totaling 44 bytes.
+ * @param sourceAddr the IPv6 address which this ICMP message will be said to have come from.
+ * @param destAddr the IPv6 address which this ICMP message will be directed to.
+ * @param type the ICMP message type/code for this message.
+ * @param mtu the MTU value for this message.
+*/
+void ICMP6Generator_generate(struct Message* msg,
+ const uint8_t* restrict sourceAddr,
+ const uint8_t* restrict destAddr,
+ enum ICMP6Generator_Type type,
+ uint32_t mtu)
+{
+ Message_shift(msg, Headers_ICMP6Header_SIZE);
+ struct Headers_ICMP6Header* icmp6 = (struct Headers_ICMP6Header*) msg->bytes;
+ Message_shift(msg, Headers_IP6Header_SIZE);
+ struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) msg->bytes;
+
+ if (ICMP6Generator_MIN_IPV6_MTU < msg->length) {
+ msg->length = ICMP6Generator_MIN_IPV6_MTU;
+ }
+ uint16_t contentLen = msg->length - Headers_IP6Header_SIZE;
+
+ icmp6->type = numForType(type);
+ icmp6->code = 0;
+ icmp6->checksum = 0;
+ icmp6->additional = Endian_hostToBigEndian32(mtu);
+
+ ip6->versionClassAndFlowLabel = 0;
+ Headers_setIpVersion(ip6);
+ ip6->flowLabelLow_be = 0;
+ ip6->payloadLength_be = Endian_hostToBigEndian16(contentLen);
+ ip6->nextHeader = IPPROTO_ICMPV6;
+ ip6->hopLimit = 64;
+
+ Bits_memcpyConst(ip6->sourceAddr, sourceAddr, 16);
+ Bits_memcpyConst(ip6->destinationAddr, destAddr, 16);
+
+ icmp6->checksum = Checksum_icmp6(ip6->sourceAddr, (uint8_t*)icmp6, contentLen);
+}
+
+/** Message from the external (TUN facing) interface. */
+static uint8_t incoming(struct Message* msg, struct Interface* iface)
+{
+ struct ICMP6Generator_pvt* ctx =
+ Identity_cast((struct ICMP6Generator_pvt*)
+ (((uint8_t*)iface) - offsetof(struct ICMP6Generator, external)));
+
+ // source address for packets coming from the router.
+ const uint8_t magicAddr[] = { 0xfc,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 };
+
+ struct Headers_IP6Header* header = (struct Headers_IP6Header*) msg->bytes;
+ // TODO calculate this on a per-node basis.
+ if (msg->length >= Headers_IP6Header_SIZE
+ && Headers_getIpVersion(header) == 6
+ && msg->length > (EXPECTED_MTU - CJDNS_OVERHEAD))
+ {
+ uint8_t destAddr[16];
+ Bits_memcpyConst(destAddr, header->sourceAddr, 16);
+ ICMP6Generator_generate(msg,
+ magicAddr,
+ destAddr,
+ ICMP6Generator_Type_PACKET_TOO_BIG,
+ (EXPECTED_MTU - CJDNS_OVERHEAD));
+
+ Interface_sendMessage(msg, &ctx->pub.external);
+ return Error_NONE;
+ }
+ return Interface_sendMessage(msg, &ctx->pub.internal);
+}
+
+/** Message from the internal (Ducttape facing) interface. */
+static uint8_t outgoing(struct Message* msg, struct Interface* iface)
+{
+ struct ICMP6Generator_pvt* ctx =
+ Identity_cast((struct ICMP6Generator_pvt*)
+ (((uint8_t*)iface) - offsetof(struct ICMP6Generator, internal)));
+
+ return Interface_sendMessage(msg, &ctx->pub.external);
+}
+
+struct ICMP6Generator* ICMP6Generator_new(struct Allocator* alloc)
+{
+ struct ICMP6Generator_pvt* out = Allocator_clone(alloc, (&(struct ICMP6Generator_pvt) {
+ .pub = {
+ .external = {
+ .sendMessage = incoming
+ },
+ .internal = {
+ .sendMessage = outgoing
+ }
+ }
+ }));
+ Identity_set(out);
+ return &out->pub;
+}
View
61 interface/ICMP6Generator.h
@@ -0,0 +1,61 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef ICMP6Generator_H
+#define ICMP6Generator_H
+
+#include "interface/Interface.h"
+#include "wire/Message.h"
+
+#include <stdint.h>
+
+#define ICMP6Generator_MIN_IPV6_MTU 1280
+
+struct ICMP6Generator
+{
+ /** Facing the TUN. */
+ struct Interface external;
+
+ /** Facing the Ducttape. */
+ struct Interface internal;
+};
+
+enum ICMP6Generator_Type
+{
+ ICMP6Generator_Type_NO_ROUTE_TO_HOST,
+ ICMP6Generator_Type_PACKET_TOO_BIG
+ // add more as needed.
+};
+
+/**
+ * Generate an ICMPv6 message.
+ * The message parameter must contain all content which will be beneath the ICMPv6 header
+ * including the MTU in the case of a "packet too big" message.
+ *
+ * @param message a message containing the content. This message must have enough padding
+ * to contain an additional ICMP header and IPv6 header totaling 44 bytes.
+ * @param sourceAddr the IPv6 address which this ICMP message will be said to have come from.
+ * @param destAddr the IPv6 address which this ICMP message will be directed to.
+ * @param type the ICMP message type/code for this message.
+ * @param mtu the MTU value for this message.
+*/
+void ICMP6Generator_generate(struct Message* message,
+ const uint8_t* restrict sourceAddr,
+ const uint8_t* restrict destAddr,
+ enum ICMP6Generator_Type type,
+ uint32_t mtu);
+
+struct ICMP6Generator* ICMP6Generator_new(struct Allocator* alloc);
+
+#endif
View
8 interface/Interface.h
@@ -76,5 +76,13 @@ struct Interface
Interface_CALLBACK(receiveMessage);
};
+static inline uint8_t Interface_sendMessage(struct Message* msg, struct Interface* iface)
+{
+ if (iface->receiveMessage) {
+ return iface->receiveMessage(msg, iface);
+ }
+ return 0;
+}
+
#endif
View
5 interface/InterfaceConnector.c
@@ -19,10 +19,7 @@
static uint8_t transferMessage(struct Message* msg, struct Interface* iface)
{
struct Interface* other = (struct Interface*) iface->receiverContext;
- if (other->sendMessage) {
- return other->sendMessage(msg, other);
- }
- return 0;
+ return other->sendMessage(msg, other);
}
/**
View
94 interface/test/ICMP6Generator_test.c
@@ -0,0 +1,94 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "memory/Allocator.h"
+#include "memory/MallocAllocator.h"
+#include "memory/CanaryAllocator.h"
+#include "crypto/Random.h"
+#include "interface/ICMP6Generator.h"
+#include "wire/Headers.h"
+#include "util/Assert.h"
+#include "util/Bits.h"
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+static void mtuTest(struct Allocator* mainAlloc, struct Random* rand, int messageSize, uint32_t mtu)
+{
+ struct Allocator* alloc = CanaryAllocator_new(Allocator_child(mainAlloc), rand);
+ uint8_t* buff = Allocator_calloc(alloc, messageSize + 64, 1);
+ CanaryAllocator_check(alloc);
+ struct Message* msg = &(struct Message) {
+ .bytes = buff + 64,
+ .length = messageSize,
+ .padding = 64
+ };
+
+ uint8_t* sourceAddr = (uint8_t*) "sourceAddress123";
+ uint8_t* destAddr = (uint8_t*) "destinationAddr1";
+
+ // Fill it with predictable data.
+ for (int i = 0; i < messageSize; i++) {
+ msg->bytes[i] = i & 0xff;
+ }
+ CanaryAllocator_check(alloc);
+ ICMP6Generator_generate(msg, sourceAddr, destAddr, ICMP6Generator_Type_PACKET_TOO_BIG, mtu);
+ CanaryAllocator_check(alloc);
+
+ Assert_always(msg->length <= 1280);
+
+ struct Headers_IP6Header* header = (struct Headers_IP6Header*) msg->bytes;
+ Message_shift(msg, -Headers_IP6Header_SIZE);
+
+ Assert_always(!Bits_memcmp(sourceAddr, header->sourceAddr, 16));
+ Assert_always(!Bits_memcmp(destAddr, header->destinationAddr, 16));
+ Assert_always(Headers_getIpVersion(header) == 6);
+ Assert_always(header->flowLabelLow_be == 0);
+ Assert_always(Endian_bigEndianToHost16(header->payloadLength_be) == msg->length);
+ Assert_always(header->nextHeader == 58); // 58 -> icmp
+ Assert_always(header->hopLimit == 64);
+
+ struct Headers_ICMP6Header* icmp = (struct Headers_ICMP6Header*) msg->bytes;
+ Message_shift(msg, -Headers_ICMP6Header_SIZE);
+
+ Assert_always(icmp->type == 2); // packet too big.
+ Assert_always(icmp->code == 0);
+ Assert_always(icmp->additional == Endian_hostToBigEndian32(mtu));
+
+ Assert_always(msg->length ==
+ MIN(messageSize,
+ ICMP6Generator_MIN_IPV6_MTU
+ - Headers_IP6Header_SIZE
+ - Headers_ICMP6Header_SIZE));
+
+ uint32_t out = 0;
+ for (int i = 0; i < msg->length; i++) {
+ out |= msg->bytes[i] ^ (i & 0xff);
+ }
+ Assert_always(!out);
+
+ Allocator_free(alloc);
+}
+
+int main()
+{
+ struct Allocator* alloc = MallocAllocator_new(20000);
+ struct Random* rand = Random_new(alloc, NULL);
+ mtuTest(alloc, rand, 2048, 1500);
+ mtuTest(alloc, rand, 1500, 1492);
+ mtuTest(alloc, rand, 1492, 1280);
+ mtuTest(alloc, rand, 1280, 1024);
+ mtuTest(alloc, rand, 1492, 1024);
+ mtuTest(alloc, rand, 1024, 512);
+}
View
14 switch/SwitchCore.c
@@ -27,6 +27,12 @@
#include <inttypes.h>
+#define EXPECTED_MTU \
+ (1492 /* PPPoE */ \
+ - Headers_IP4Header_SIZE \
+ - Headers_UDPHeader_SIZE \
+ - 20 /* CryptoAuth in ESTABLISHED state. */ )
+
struct SwitchInterface
{
struct Interface* iface;
@@ -248,12 +254,18 @@ static uint8_t receiveMessage(struct Message* message, struct Interface* iface)
sourceIndex, destIndex, label, targetLabel);
*/
+
+ if (message->length > EXPECTED_MTU)
+ {
+ return Error_OVERSIZE_MESSAGE;
+ }
+
const uint16_t err = sendMessage(&core->interfaces[destIndex], message, sourceIf->core->logger);
if (err) {
Log_debug(sourceIf->core->logger, "Sending packet caused an error. err=%u", err);
header->label_be = Endian_bigEndianToHost64(label);
sendError(sourceIf, message, err, sourceIf->core->logger);
- return Error_NONE;
+ return err;
}
return Error_NONE;
View
9 wire/Headers.h
@@ -339,4 +339,13 @@ struct Headers_UDPHeader {
#define Headers_UDPHeader_SIZE 8
Assert_compileTime(sizeof(struct Headers_UDPHeader) == Headers_UDPHeader_SIZE);
+struct Headers_ICMP6Header {
+ uint8_t type;
+ uint8_t code;
+ uint16_t checksum;
+ uint32_t additional;
+};
+#define Headers_ICMP6Header_SIZE 8
+Assert_compileTime(sizeof(struct Headers_ICMP6Header) == Headers_ICMP6Header_SIZE);
+
#endif
Please sign in to comment.
Something went wrong with that request. Please try again.