X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Modules%2FIPStack%2Fipv6.c;h=7cb8e0a8335b977175c01ddf4fdd8b8574687208;hb=58c7107eb0a5ae254c135f2eaa6263751f1ebe67;hp=9368c3e2614950f42e8f362819a2ba04db93f376;hpb=11e9a26f9aa039eb2b4edcf55c1295e640b5999a;p=tpg%2Facess2.git diff --git a/Modules/IPStack/ipv6.c b/Modules/IPStack/ipv6.c index 9368c3e2..7cb8e0a8 100644 --- a/Modules/IPStack/ipv6.c +++ b/Modules/IPStack/ipv6.c @@ -5,6 +5,7 @@ #include "ipstack.h" #include "link.h" #include "ipv6.h" +#include "firewall.h" // === IMPORTS === extern tInterface *gIP_Interfaces; @@ -12,9 +13,13 @@ extern Uint32 IPv4_Netmask(int FixedBits); // === PROTOTYPES === int IPv6_Initialise(); + int IPv6_RegisterCallback(int ID, tIPCallback Callback); void IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer); tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast); +// === GLOBALS === +tIPCallback gaIPv6_Callbacks[256]; + // === CODE === /** * \brief Initialise the IPv6 handling code @@ -25,6 +30,33 @@ int IPv6_Initialise() return 1; } +/** + * \brief Registers a callback + * \param ID 8-bit packet type ID + * \param Callback Callback function + */ +int IPv6_RegisterCallback(int ID, tIPCallback Callback) +{ + if( ID < 0 || ID > 255 ) return 0; + if( gaIPv6_Callbacks[ID] ) return 0; + gaIPv6_Callbacks[ID] = Callback; + return 1; +} + +/** + * \brief Creates and sends an IPv6 Packet + * \param Iface Interface + * \param Destination Destination IP + * \param Protocol Protocol ID + * \param Length Data Length + * \param Data Packet Data + * \return Boolean Success + */ +int IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, size_t Length, const void *Data) +{ + return 0; +} + /** * \fn void IPv6_int_GetPacket(tInterface *Interface, tMacAddr From, int Length, void *Buffer) * \brief Process an IPv6 Packet @@ -33,9 +65,14 @@ int IPv6_Initialise() * \param Length Packet length * \param Buffer Packet data */ -void IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer) +void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer) { + tInterface *iface; tIPv6Header *hdr = Buffer; + int ret, dataLength; + char *dataPtr; + Uint8 nextHeader; + if(Length < sizeof(tIPv6Header)) return; hdr->Head = ntohl(hdr->Head); @@ -44,6 +81,7 @@ void IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Bu if( hdr->Version != 6 ) return; + #if 1 Log_Debug("IPv6", "hdr = {"); Log_Debug("IPv6", " .Version = %i", hdr->Version ); Log_Debug("IPv6", " .TrafficClass = %i", hdr->TrafficClass ); @@ -54,7 +92,114 @@ void IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Bu Log_Debug("IPv6", " .Source = %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", hdr->Source ); Log_Debug("IPv6", " .Destination = %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", hdr->Destination ); Log_Debug("IPv6", "}"); + #endif + + // No checksum in IPv6 + + // Check Packet length + if( ntohs(hdr->PayloadLength)+sizeof(tIPv6Header) > Length) { + Log_Log("IPv6", "hdr->PayloadLength(%i) > Length(%i)", ntohs(hdr->PayloadLength), Length); + return; + } + + // Process Options + nextHeader = hdr->NextHeader; + dataPtr = hdr->Data; + dataLength = hdr->PayloadLength; + for( ;; ) + { + struct { + Uint8 NextHeader; + Uint8 Length; // In 8-byte chunks, with 0 being 8 bytes long + Uint8 Data[]; + } *optionHdr; + optionHdr = (void*)dataPtr; + // Hop-by-hop options + if(nextHeader == 0) + { + // TODO: Parse the options (actually, RFC2460 doesn't specify any) + } + // Routing Options + else if(nextHeader == 43) + { + // TODO: Routing Header options + } + else + { + break; // Unknown, pass on + } + nextHeader = optionHdr->NextHeader; + dataPtr += (optionHdr->Length + 1) * 8; // 8-octet length (0 = 8 bytes long) + } + + // Get Interface (allowing broadcasts) + iface = IPv6_GetInterface(Adapter, hdr->Destination, 1); + + // Firewall rules + if( iface ) { + // Incoming Packets + ret = IPTables_TestChain("INPUT", + 6, &hdr->Source, &hdr->Destination, + hdr->NextHeader, 0, + hdr->PayloadLength, hdr->Data + ); + } + else { + // Routed packets + ret = IPTables_TestChain("FORWARD", + 6, &hdr->Source, &hdr->Destination, + hdr->NextHeader, 0, + hdr->PayloadLength, hdr->Data + ); + } + switch(ret) + { + // 0 - Allow + case 0: break; + // 1 - Silent Drop + case 1: + Log_Debug("IPv6", "Silently dropping packet"); + return ; + // Unknown, silent drop + default: + return ; + } + + // Routing + if(!iface) + { + #if 0 + tMacAddr to; + tRoute *rt; + + Log_Debug("IPv6", "Route the packet"); + // Drop the packet if the TTL is zero + if( hdr->HopLimit == 0 ) { + Log_Warning("IPv6", "TODO: Sent ICMP-Timeout when TTL exceeded"); + return ; + } + + hdr->HopLimit --; + + rt = IPStack_FindRoute(6, NULL, &hdr->Destination); // Get the route (gets the interface) + to = ICMP6_ResolveHWAddr(rt->Interface, hdr->Destination); // Resolve address + + // Send packet + Log_Log("IPv6", "Forwarding packet"); + Link_SendPacket(rt->Interface->Adapter, IPV6_ETHERNET_ID, to, Length, Buffer); + #endif + + return ; + } + + // Send it on + if( !gaIPv6_Callbacks[hdr->NextHeader] ) { + Log_Log("IPv6", "Unknown Protocol %i", hdr->NextHeader); + return ; + } + + gaIPv6_Callbacks[hdr->NextHeader]( iface, &hdr->Source, hdr->PayloadLength, hdr->Data ); } /** @@ -73,6 +218,7 @@ tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast) for( iface = gIP_Interfaces; iface; iface = iface->Next) { tIPv6 *thisAddr; + // Check for this adapter if( iface->Adapter != Adapter ) continue; @@ -87,6 +233,7 @@ tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast) if( !Broadcast ) continue; // Check for broadcast + // - Check first DWORDs if( iface->SubnetBits > 32 && Address.L[0] != thisAddr->L[0] ) continue; if( iface->SubnetBits > 64 && Address.L[1] != thisAddr->L[1] ) @@ -94,6 +241,7 @@ tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast) if( iface->SubnetBits > 96 && Address.L[2] != thisAddr->L[2] ) continue; + // Check final DWORD j = iface->SubnetBits / 32; i = iface->SubnetBits % 32; netmask = IPv4_Netmask( iface->SubnetBits % 32 );