Permalink
Browse files

Refactored DIC interface to shift the duty of garbaging invalid peers…

… (state caused by stray packets)

on to the MultiInterface. Added test.
Fixed bugs with OSX TUN handling.
  • Loading branch information...
1 parent 67f1b5b commit cb6e137dace117be0c979f52ddd031a67b95ec89 Caleb James DeLisle committed Dec 9, 2012
View
@@ -1064,3 +1064,18 @@ int CryptoAuth_getState(struct Interface* interface)
return CryptoAuth_ESTABLISHED;
}
}
+
+struct Interface* CryptoAuth_getConnectedInterface(struct Interface* iface)
+{
+ if (iface->sendMessage == sendMessage) {
+ // internal (plaintext side)
+ struct CryptoAuth_Wrapper* wrapper =
+ Identity_cast((struct CryptoAuth_Wrapper*)iface->senderContext);
+ return wrapper->wrappedInterface;
+ } else if (iface->receiveMessage == receiveMessage) {
+ struct CryptoAuth_Wrapper* wrapper =
+ Identity_cast((struct CryptoAuth_Wrapper*)iface->receiverContext);
+ return &wrapper->externalInterface;
+ }
+ return NULL;
+}
View
@@ -167,4 +167,15 @@ void CryptoAuth_reset(struct Interface* iface);
*/
int CryptoAuth_getState(struct Interface* iface);
+/**
+ * Get the interface on the other side of this CryptoAuth session.
+ *
+ * Given a wrapped interface, get the wrapping interface.
+ * given a wrapping interface, get the one which is wrapped.
+ *
+ * @param iface the wrapped or wrapper iface.
+ * @return the opposite.
+ */
+struct Interface* CryptoAuth_getConnectedInterface(struct Interface* iface);
+
#endif
View
@@ -36,6 +36,14 @@ void Random_bytes(struct Random* rand, uint8_t* location, uint64_t count);
void Random_base32(struct Random* rand, uint8_t* output, uint32_t length);
+static inline void Random_longs(struct Random* rand, uint64_t* location, uint64_t count)
+{
+ Random_bytes(rand, (uint8_t*) location, count*8);
+}
+static inline void Random_ints(struct Random* rand, uint32_t* location, uint64_t count)
+{
+ Random_bytes(rand, (uint8_t*) location, count*4);
+}
static inline int16_t Random_int16(struct Random* rand)
{
int16_t ret;
View
@@ -23,6 +23,7 @@
#define CryptoAuth_reset Exports_CryptoAuth_reset
#define CryptoAuth_flushUsers Exports_CryptoAuth_flushUsers
#define CryptoAuth_getState Exports_CryptoAuth_getState
+#define CryptoAuth_getConnectedInterface Exports_CryptoAuth_getConnectedInterface
#include "crypto/CryptoAuth.c"
@@ -21,34 +21,63 @@
#include <stdint.h>
#include <stdbool.h>
+enum InterfaceController_PeerState
+{
+ /** If state is UNAUTHENTICATED, the other node has not sent a single valid packet. */
+ InterfaceController_PeerState_UNAUTHENTICATED = 0,
+
+ /** In state == HANDSHAKE, a valid packet has been received but it could still be a replay. */
+ InterfaceController_PeerState_HANDSHAKE,
+
+ /** In state == ESTABLISHED, we know the node at the other end is authentic. */
+ InterfaceController_PeerState_ESTABLISHED,
+
+ /** If state == UNRESPONSIVE, the peer has not responded to pings in the required timeframe. */
+ InterfaceController_PeerState_UNRESPONSIVE
+};
+
struct InterfaceController
{
/**
* Add a new peer.
* Called from the network interface when it is asked to make a connection or it autoconnects.
+ * If the peer which is connected to becomes unresponsive, IC will *not* remove it but will
+ * set it's state to UNRESPONSIVE and it is the job of the caller to remove the peer by freeing
+ * the allocator which is provided with iface.
*
+ * If a peer is registered and it turns out to have the same cryptographic key as an existing
+ * peer, the existing one will be freed by the IC and the new one will take it's place.
+ * BEWARE: the interface allocator you provide here may be freed by this code!
+ *
+ * @param ic the interface controller.
* @param herPublicKey the public key of the foreign node, NULL if unknown.
- * @param password the password for authenticating with the other node if specified.
+ * @param password the password for authenticating with the other node or NULL if unspecified.
* @param requireAuth true if the other node must authenticate (incoming connection).
- * @param iface an interface which pipes messages to this peer.
- * @param ic the interface controller, a child of the memory allocator for this controller
- * will be used for the endpoint because we want to be able to free a single
- * endpoint without freeing the whole network interface but if the network interface
- * is freed, we would expect all of its children to deregister.
+ * @param iface an interface which pipes messages to/from this peer. The peer will be
+ * deregistered if this allocator is freed.
+ *
* @return 0 if all goes well.
- * InterfaceController_registerInterface_BAD_KEY if the key is not a valid cjdns key.
- * InterfaceController_registerInterface_OUT_OF_SPACE if no space to store the entry.
+ * InterfaceController_registerPeer_OUT_OF_SPACE if there is no space to store the peer.
+ * InterfaceController_registerPeer_BAD_KEY the provided herPublicKey is not valid.
+ * InterfaceController_registerPeer_INTERNAL unspecified error.
*/
- #define InterfaceController_registerPeer_OUT_OF_SPACE -1
+ #define InterfaceController_registerPeer_INTERNAL -3
#define InterfaceController_registerPeer_BAD_KEY -2
+ #define InterfaceController_registerPeer_OUT_OF_SPACE -1
int (* const registerPeer)(struct InterfaceController* ic,
uint8_t herPublicKey[32],
String* password,
bool requireAuth,
struct Interface* iface);
+
+ /** Get the current state of a registered interface. */
+ enum InterfaceController_PeerState (* const getPeerState)(struct Interface* iface);
};
+#define InterfaceController_getPeerState(ic, iface) \
+ ((ic)->getPeerState(iface))
+
#define InterfaceController_registerPeer(ic, herPublicKey, password, requireAuth, iface) \
- (ic)->registerPeer((ic), (herPublicKey), (password), (requireAuth), (iface))
+ ((ic)->registerPeer((ic), (herPublicKey), (password), (requireAuth), (iface)))
#endif
View
@@ -45,6 +45,9 @@ struct Peer
/** The multi-iface containing this peer. */
struct MultiInterface* multiIface;
+ /** The InterfaceController's structure which is used to detect unresponsive peers. */
+ struct InterfaceController_Peer* ifcPeer;
+
Identity
/** Variable size. */
@@ -150,6 +153,7 @@ static inline struct Peer* peerForKey(struct MultiInterface_pvt* mif,
return peer;
}
+/** Incoming from the network interface */
static uint8_t receiveMessage(struct Message* msg, struct Interface* external)
{
struct MultiInterface_pvt* mif =
@@ -163,7 +167,18 @@ static uint8_t receiveMessage(struct Message* msg, struct Interface* external)
// pop the key size and key
Message_shift(msg, -(mif->pub.keySize + 4));
- return p->internalIf.receiveMessage(msg, &p->internalIf);
+ // into the core.
+ uint8_t ret = p->internalIf.receiveMessage(msg, &p->internalIf);
+
+ enum InterfaceController_PeerState state =
+ InterfaceController_getPeerState(mif->ic, &p->internalIf);
+ if (state == InterfaceController_PeerState_UNAUTHENTICATED) {
+ // some random stray packet wandered in to the interface....
+ // This removes all of the state associated with the endpoint.
+ Allocator_free(p->internalIf.allocator);
+ }
+
+ return ret;
}
struct Interface* MultiInterface_ifaceForKey(struct MultiInterface* mIface, void* key)
View
@@ -48,7 +48,12 @@ static void handleEvent(void* vcontext)
}
msg->length = length;
- #ifdef Illumos
+ #ifdef OSX
+ // OSX tags the message with the AF type (AF_INET or AF_INET6) rather than the ethertype.
+ // pop it and scrap it then tag it the same as we do for Illumos.
+ TUNInterface_popMessageType(msg);
+ #endif
+ #if defined(Illumos) || defined(OSX)
// Illumos does not send packet info, it only supports ip4 and ip6 over tun.
uint16_t ethertype = ((msg->bytes[0] >> 4) == 6) ? Ethernet_TYPE_IP6 : Ethernet_TYPE_IP4;
TUNInterface_pushMessageType(msg, ethertype);
View
@@ -178,12 +178,20 @@ struct UDPInterface* UDPInterface_new(struct event_base* base,
context->socket = socket(addrFam, SOCK_DGRAM, 0);
if (context->socket == -1) {
- Except_raise(exHandler, UDPInterface_new_BIND_FAILED, "call to socket() failed.");
+ Except_raise(exHandler,
+ UDPInterface_new_BIND_FAILED,
+ "call to socket() failed [%s]",
+ Errno_getString());
}
if (bindAddr != NULL) {
if (bind(context->socket, (struct sockaddr*) &addr, context->addrLen)) {
- Except_raise(exHandler, UDPInterface_new_BIND_FAILED, "call to bind() failed.");
+ enum Errno err = Errno_get();
+ EVUTIL_CLOSESOCKET(context->socket);
+ Except_raise(exHandler,
+ UDPInterface_new_BIND_FAILED,
+ "call to bind() failed [%s]",
+ Errno_strerror(err));
}
}
@@ -192,7 +200,7 @@ struct UDPInterface* UDPInterface_new(struct event_base* base,
EVUTIL_CLOSESOCKET(context->socket);
Except_raise(exHandler, -1, "Failed to get socket name [%s]", Errno_strerror(err));
}
- Bits_memcpyConst(&context->boundPort_be, &((struct sockaddr_in*)&addr)->sin_port, 2);
+ Bits_memcpyConst(&context->pub.boundPort_be, &((struct sockaddr_in*)&addr)->sin_port, 2);
evutil_make_socket_nonblocking(context->socket);
View
@@ -24,6 +24,9 @@
struct UDPInterface
{
struct Interface generic;
+
+ /** Used for testing. */
+ uint16_t boundPort_be;
};
/**
@@ -53,9 +53,6 @@ struct UDPInterface_pvt
struct MultiInterface* multiIface;
- /** used for testing. */
- uint16_t boundPort_be;
-
Identity
};
@@ -62,6 +62,10 @@ static int registerPeer(struct InterfaceController* ic,
return 0;
}
+static enum InterfaceController_PeerState getPeerState(struct Interface* iface)
+{
+ return InterfaceController_PeerState_HANDSHAKE;
+}
int main()
{
@@ -71,7 +75,8 @@ int main()
// mock interface controller.
struct Context ctx = {
.ic = {
- .registerPeer = registerPeer
+ .registerPeer = registerPeer,
+ .getPeerState = getPeerState
}
};
@@ -64,7 +64,10 @@ static uint8_t receiveMessageTUN(struct Message* msg, struct Interface* iface)
{
receivedMessageTUNCount++;
uint16_t ethertype = TUNInterface_popMessageType(msg);
- Assert_always(ethertype == Ethernet_TYPE_IP4);
+ if (ethertype != Ethernet_TYPE_IP4) {
+ printf("Spurious packet with ethertype [%u]\n", Endian_bigEndianToHost16(ethertype));
+ return 0;
+ }
struct Headers_IP4Header* header = (struct Headers_IP4Header*) msg->bytes;
@@ -113,10 +116,10 @@ int main(int argc, char** argv)
TUNConfigurator_addIp4Address(assignedInterfaceName, testAddrA, 30, logger, NULL);
struct TUNInterface* tun = TUNInterface_new(tunPtr, base, alloc);
- struct UDPInterface* udp = UDPInterface_new(base, "11.0.0.1:5000", alloc, NULL, logger, &ic);
+ struct UDPInterface* udp = UDPInterface_new(base, "0.0.0.0", alloc, NULL, logger, &ic);
struct sockaddr_in sin = { .sin_family = AF_INET };
- sin.sin_port = Endian_hostToBigEndian16(5000);
+ sin.sin_port = udp->boundPort_be;
Bits_memcpy(&sin.sin_addr, testAddrB, 4);
struct Message* msg;
@@ -63,7 +63,10 @@ static uint8_t receiveMessageTUN(struct Message* msg, struct Interface* iface)
{
receivedMessageTUNCount++;
uint16_t ethertype = TUNInterface_popMessageType(msg);
- Assert_always(ethertype == Ethernet_TYPE_IP6);
+ if (ethertype != Ethernet_TYPE_IP6) {
+ printf("Spurious packet with ethertype [%u]\n", Endian_bigEndianToHost16(ethertype));
+ return 0;
+ }
struct Headers_IP6Header* header = (struct Headers_IP6Header*) msg->bytes;
@@ -83,7 +86,7 @@ static uint8_t receiveMessageTUN(struct Message* msg, struct Interface* iface)
static uint8_t receiveMessageUDP(struct Message* msg, struct Interface* iface)
{
if (!receivedMessageTUNCount) {
- // return 0;
+ return 0;
}
// Got the message, test successful.
exit(0);
@@ -112,10 +115,10 @@ int main(int argc, char** argv)
TUNConfigurator_addIp6Address(assignedInterfaceName, testAddrA, 126, logger, NULL);
struct TUNInterface* tun = TUNInterface_new(tunPtr, base, alloc);
- struct UDPInterface* udp = UDPInterface_new(base, "[fd00::1]:5000", alloc, NULL, logger, &ic);
+ struct UDPInterface* udp = UDPInterface_new(base, "[::]", alloc, NULL, logger, &ic);
struct sockaddr_in6 sin = { .sin6_family = AF_INET6 };
- sin.sin6_port = Endian_hostToBigEndian16(5000);
+ sin.sin6_port = udp->boundPort_be;
Bits_memcpy(&sin.sin6_addr, testAddrB, 16);
struct Message* msg;
@@ -91,7 +91,7 @@ int main(int argc, char** argv)
struct sockaddr_in sin = { .sin_family = AF_INET };
- sin.sin_port = ((struct UDPInterface_pvt*) udpA)->boundPort_be;
+ sin.sin_port = udpA->boundPort_be;
uint8_t localHost[] = {127, 0, 0, 1};
Bits_memcpyConst(&sin.sin_addr, localHost, 4);
Oops, something went wrong.

0 comments on commit cb6e137

Please sign in to comment.