diff --git a/src/Cedar/CedarType.h b/src/Cedar/CedarType.h index e3124a8c..61f8c5b8 100644 --- a/src/Cedar/CedarType.h +++ b/src/Cedar/CedarType.h @@ -582,6 +582,7 @@ typedef struct IPC_PARAM IPC_PARAM; typedef struct IPC_DHCP_RELEASE_QUEUE IPC_DHCP_RELEASE_QUEUE; typedef struct IPC_MSCHAP_V2_AUTHINFO IPC_MSCHAP_V2_AUTHINFO; typedef struct IPC_SESSION_SHARED_BUFFER_DATA IPC_SESSION_SHARED_BUFFER_DATA; +typedef struct IPC_IPV6_ROUTER_ADVERTISEMENT IPC_IPV6_ROUTER_ADVERTISEMENT; // ============================================================== diff --git a/src/Cedar/IPC.c b/src/Cedar/IPC.c index 47ad93cb..d78524be 100644 --- a/src/Cedar/IPC.c +++ b/src/Cedar/IPC.c @@ -489,6 +489,8 @@ IPC *NewIPC(CEDAR *cedar, char *client_name, char *postfix, char *hubname, char // Create an IPv4 reception queue ipc->IPv4ReceivedQueue = NewQueue(); + IPCIPv6Init(ipc); + return ipc; LABEL_ERROR: @@ -531,6 +533,8 @@ IPC *NewIPCBySock(CEDAR *cedar, SOCK *s, void *mac_address) ipc->FlushList = NewTubeFlushList(); + IPCIPv6Init(ipc); + return ipc; } @@ -610,6 +614,8 @@ void FreeIPC(IPC *ipc) ReleaseSharedBuffer(ipc->IpcSessionSharedBuffer); + IPCIPv6Free(ipc); + Free(ipc); } @@ -1186,7 +1192,7 @@ void IPCProcessArp(IPC *ipc, BLOCK *b) if (CmpIpAddr(&target_ip, &ipc->ClientIPAddress) == 0) { // Create a response since a request for its own IP address have received - if (IsValidUnicastMacAddress(sender_mac)) + if (IsMacUnicast(sender_mac)) { UCHAR tmp[14 + sizeof(ARPV4_HEADER)]; ARPV4_HEADER *arp = (ARPV4_HEADER *)(tmp + 14); @@ -1218,7 +1224,7 @@ void IPCAssociateOnArpTable(IPC *ipc, IP *ip, UCHAR *mac_address) { IPC_ARP *a; // Validate arguments - if (ipc == NULL || ip == NULL || IsValidUnicastIPAddress4(ip) == false || IsValidUnicastMacAddress(mac_address) == false) + if (ipc == NULL || ip == NULL || IsValidUnicastIPAddress4(ip) == false || IsMacUnicast(mac_address) == false) { return; } @@ -1239,7 +1245,7 @@ void IPCAssociateOnArpTable(IPC *ipc, IP *ip, UCHAR *mac_address) } // Search whether there is ARP table entry already - a = IPCSearchArpTable(ipc, ip); + a = IPCSearchArpTable(ipc->ArpTable, ip); if (a == NULL) { // Add to the ARP table @@ -1278,68 +1284,6 @@ void IPCAssociateOnArpTable(IPC *ipc, IP *ip, UCHAR *mac_address) } } -// Identify whether the MAC address is a normal unicast address -bool IsValidUnicastMacAddress(UCHAR *mac) -{ - // Validate arguments - if (mac == NULL) - { - return false; - } - - if (mac[0] & 0x01) - { - return false; - } - - if (IsZero(mac, 6)) - { - return false; - } - - return true; -} - -// Identify whether the IP address is a normal unicast address -bool IsValidUnicastIPAddress4(IP *ip) -{ - UINT i; - // Validate arguments - if (IsIP4(ip) == false) - { - return false; - } - - if (IsZeroIP(ip)) - { - return false; - } - - if (ip->addr[0] >= 224 && ip->addr[0] <= 239) - { - // IPv4 Multicast - return false; - } - - for (i = 0;i < 4;i++) - { - if (ip->addr[i] != 255) - { - return true; - } - } - - return false; -} -bool IsValidUnicastIPAddressUINT4(UINT ip) -{ - IP a; - - UINTToIP(&a, ip); - - return IsValidUnicastIPAddress4(&a); -} - // Interrupt process (This is called periodically) void IPCProcessInterrupts(IPC *ipc) { @@ -1371,6 +1315,7 @@ void IPCProcessL3EventsEx(IPC *ipc, UINT64 now) // Remove old ARP table entries IPCFlushArpTableEx(ipc, now); + IPCIPv6FlushNDTEx(ipc, now); // Receive all the L2 packet while (true) @@ -1390,10 +1335,10 @@ void IPCProcessL3EventsEx(IPC *ipc, UINT64 now) // Confirm the destination MAC address // (Receive if the destination MAC address is the IPC address or a broadcast address) - if (Cmp(dest_mac, ipc->MacAddress, 6) == 0 || dest_mac[0] & 0x01) + if (Cmp(dest_mac, ipc->MacAddress, 6) == 0 || IsMacBroadcast(dest_mac) || IsMacMulticast(dest_mac)) { // If the source MAC address is itselves or invalid address, ignore the packet - if (Cmp(src_mac, ipc->MacAddress, 6) != 0 && IsValidUnicastMacAddress(src_mac)) + if (Cmp(src_mac, ipc->MacAddress, 6) != 0 && !IsMacUnicast(src_mac)) { if (protocol == MAC_PROTO_ARPV4) { @@ -1457,6 +1402,54 @@ void IPCProcessL3EventsEx(IPC *ipc, UINT64 now) } } } + else if (protocol == MAC_PROTO_IPV6) + { + PKT* p = ParsePacketUpToICMPv6(b->Buf, b->Size); + if (p != NULL) + { + IP ip_src, ip_dst; + bool ndtProcessed = false; + + UCHAR* data = Clone(p->L3.IPv6Header, p->L3.IPv6Header->PayloadLength + sizeof(IPV6_HEADER)); + + IPv6AddrToIP(&ip_src, &p->IPv6HeaderPacketInfo.IPv6Header->SrcAddress); + IPv6AddrToIP(&ip_dst, &p->IPv6HeaderPacketInfo.IPv6Header->DestAddress); + + if (p->IPv6HeaderPacketInfo.Protocol == IP_PROTO_ICMPV6) + { + IP icmpHeaderAddr; + // We need to parse the Router Advertisement and Neighbor Advertisement messages + // to build the Neighbor Discovery Table (aka ARP table for IPv6) + switch (p->ICMPv6HeaderPacketInfo.Type) + { + case ICMPV6_TYPE_ROUTER_ADVERTISEMENT: + // We save the router advertisement data for later use + IPCIPv6AddRouterPrefix(ipc, &p->ICMPv6HeaderPacketInfo.OptionList, src_mac, &ip_src); + IPCIPv6AssociateOnNDTEx(ipc, &ip_src, src_mac, true); + IPCIPv6AssociateOnNDTEx(ipc, &ip_src, &p->ICMPv6HeaderPacketInfo.OptionList.SourceLinkLayer, true); + break; + case ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT: + // We save the neighbor advertisements into NDT + IPv6AddrToIP(&icmpHeaderAddr, &p->ICMPv6HeaderPacketInfo.Headers.NeighborAdvertisementHeader->TargetAddress); + IPCIPv6AssociateOnNDTEx(ipc, &icmpHeaderAddr, src_mac, true); + IPCIPv6AssociateOnNDTEx(ipc, &ip_src, src_mac, true); + ndtProcessed = true; + break; + } + } + + // We update the NDT only if we have an entry in it for the IP+Mac + if (!ndtProcessed) + { + IPCIPv6AssociateOnNDT(ipc, &ip_src, src_mac); + } + + /// TODO: should we or not filter Neighbor Advertisements and/or Neighbor Solicitations? + InsertQueue(ipc->IPv6ReceivedQueue, data); + + FreePacket(p); + } + } } } } @@ -1725,7 +1718,7 @@ void IPCSendIPv4Unicast(IPC *ipc, void *data, UINT size, IP *next_ip) return; } - a = IPCSearchArpTable(ipc, next_ip); + a = IPCSearchArpTable(ipc->ArpTable, next_ip); if (a != NULL) { @@ -1789,19 +1782,19 @@ void IPCSendIPv4Unicast(IPC *ipc, void *data, UINT size, IP *next_ip) } // Search the ARP table -IPC_ARP *IPCSearchArpTable(IPC *ipc, IP *ip) +IPC_ARP *IPCSearchArpTable(LIST* arpTable, IP *ip) { IPC_ARP t; IPC_ARP *a; // Validate arguments - if (ipc == NULL || ip == NULL) + if (arpTable == NULL || ip == NULL) { return NULL; } Copy(&t.Ip, ip, sizeof(IP)); - a = Search(ipc->ArpTable, &t); + a = Search(arpTable, &t); return a; } @@ -1944,5 +1937,434 @@ BLOCK *IPCRecvL2(IPC *ipc) return b; } +// IPv6 stuff +// Memory management +void IPCIPv6Init(IPC* ipc) +{ + ipc->IPv6ReceivedQueue = NewQueue(); + // The NDT is basically the same as ARP Table with some slight adjustments + ipc->IPv6NeighborTable = NewList(IPCCmpArpTable); + ipc->IPv6RouterAdvs = NewList(NULL); +} +void IPCIPv6Free(IPC* ipc) +{ + UINT i; + for (i = 0; i < LIST_NUM(ipc->IPv6NeighborTable); i++) + { + IPC_ARP* a = LIST_DATA(ipc->IPv6NeighborTable, i); + IPCFreeARP(a); + } + ReleaseList(ipc->IPv6NeighborTable); + for (i = 0; i < LIST_NUM(ipc->IPv6RouterAdvs); i++) + { + IPC_IPV6_ROUTER_ADVERTISEMENT* ra = LIST_DATA(ipc->IPv6RouterAdvs, i); + Free(ra); + } + + ReleaseList(ipc->IPv6RouterAdvs); + + while (true) + { + BLOCK* b = GetNext(ipc->IPv6ReceivedQueue); + if (b == NULL) + { + break; + } + + FreeBlock(b); + } + + ReleaseQueue(ipc->IPv6ReceivedQueue); +} + +// NDT +void IPCIPv6AssociateOnNDT(IPC* ipc, IP* ip, UCHAR* mac_address) +{ + IPCIPv6AssociateOnNDTEx(ipc, ip, mac_address, false); +} +void IPCIPv6AssociateOnNDTEx(IPC* ipc, IP* ip, UCHAR* mac_address, bool isNeighborAdv) +{ + IPC_ARP* a; + UINT addrType = 0; + if (ipc == NULL || ip == NULL || + IsValidUnicastIPAddress6(ip) == false || + IsMacUnicast(mac_address) == false) + { + return; + } + + addrType = GetIPAddrType6(ip); + + if (addrType != IPV6_ADDR_LOCAL_UNICAST && + addrType != IPV6_ADDR_GLOBAL_UNICAST) + { + return; + } + + if (addrType == IPV6_ADDR_GLOBAL_UNICAST) + { + if (!IPCIPv6CheckUnicastFromRouterPrefix(ipc, ip, NULL)) + { + return; + } + } + + a = IPCSearchArpTable(ipc->IPv6NeighborTable, ip); + + // We create a new entry only if we got a neighbor advertisement + if (a == NULL && isNeighborAdv) + { + a = IPCNewARP(ip, mac_address); + Insert(ipc->IPv6NeighborTable, a); + } + else if (a == NULL) + { + // We skip the NDT association on random packets from unknown locations + return; + } + else + { + Copy(a->MacAddress, mac_address, 6); + + if (a->Resolved == false) + { + a->Resolved = true; + a->GiveupTime = 0; + while (true) + { + BLOCK* b = GetNext(a->PacketQueue); + + if (b == NULL) + { + break; + } + + IPCIPv6SendWithDestMacAddr(ipc, b->Buf, b->Size, a->MacAddress); + + FreeBlock(b); + } + } + + a->ExpireTime = Tick64() + (UINT64)IPC_IPV6_NDT_LIFETIME; + } +} + +void IPCIPv6FlushNDT(IPC* ipc) +{ + IPCIPv6FlushNDTEx(ipc, 0); +} +void IPCIPv6FlushNDTEx(IPC* ipc, UINT64 now) +{ + UINT i; + LIST* o = NULL; + // Validate arguments + if (ipc == NULL) + { + return; + } + if (now == 0) + { + now = Tick64(); + } + + for (i = 0; i < LIST_NUM(ipc->IPv6NeighborTable); i++) + { + IPC_ARP* a = LIST_DATA(ipc->IPv6NeighborTable, i); + bool b = false; + + if (a->Resolved && a->ExpireTime <= now) + { + b = true; + } + else if (a->Resolved == false && a->GiveupTime <= now) + { + b = true; + } + /// TODO: think about adding retransmission as per RFC4861 + + if (b) + { + if (o == NULL) + { + o = NewListFast(NULL); + } + + Add(o, a); + } + } + + if (o != NULL) + { + for (i = 0; i < LIST_NUM(o); i++) + { + IPC_ARP* a = LIST_DATA(o, i); + + IPCFreeARP(a); + + Delete(ipc->IPv6NeighborTable, a); + } + + ReleaseList(o); + } +} + +// RA +void IPCIPv6AddRouterPrefix(IPC* ipc, ICMPV6_OPTION_LIST* recvPrefix, UCHAR* macAddress, IP* ip) +{ + UINT i; + bool foundPrefix = false; + for (i = 0; i < LIST_NUM(ipc->IPv6RouterAdvs); i++) + { + IPC_IPV6_ROUTER_ADVERTISEMENT* existingRA = LIST_DATA(ipc->IPv6RouterAdvs, i); + if (Cmp(&recvPrefix->Prefix->Prefix, &existingRA->RoutedPrefix.ipv6_addr, sizeof(IPV6_ADDR)) == 0) + { + foundPrefix = true; + break; + } + } + + if (!foundPrefix) + { + IPC_IPV6_ROUTER_ADVERTISEMENT* newRA = Malloc(sizeof(IPC_IPV6_ROUTER_ADVERTISEMENT)); + IPv6AddrToIP(&newRA->RoutedPrefix, &recvPrefix->Prefix->Prefix); + IntToSubnetMask6(&newRA->RoutedMask, recvPrefix->Prefix->SubnetLength); + CopyIP(&newRA->RouterAddress, ip); + Copy(newRA->RouterMacAddress, macAddress, 6); + Copy(newRA->RouterLinkLayerAddress, recvPrefix->SourceLinkLayer->Address, 6); + Add(ipc->IPv6RouterAdvs, newRA); + } +} + +bool IPCIPv6CheckUnicastFromRouterPrefix(IPC* ipc, IP* ip, IPC_IPV6_ROUTER_ADVERTISEMENT* matchedRA) +{ + UINT i; + IPC_IPV6_ROUTER_ADVERTISEMENT* matchingRA = NULL; + bool isInPrefix = false; + for (i = 0; i < LIST_NUM(ipc->IPv6RouterAdvs); i++) + { + IPC_IPV6_ROUTER_ADVERTISEMENT* ra = LIST_DATA(ipc->IPv6RouterAdvs, i); + isInPrefix = IsInSameNetwork6(ip, &ra->RoutedPrefix, &ra->RoutedMask); + if (isInPrefix) + { + matchingRA = ra; + break; + } + } + + if (matchedRA != NULL && matchingRA != NULL) + { + Copy(matchedRA, matchingRA, sizeof(IPC_IPV6_ROUTER_ADVERTISEMENT)); + } + + return isInPrefix; +} + +// Send router solicitation and then eventually populate the info from Router Advertisements +void IPCIPv6SendRouterSolicitation(IPC* ipc) +{ + IP senderIP; + IP destIP; + UCHAR destMacAddress[6]; + IPV6_ADDR linkLocal; + BUF *packet; + Zero(&linkLocal, sizeof(IPV6_ADDR)); + + // Generate link local from client's EUI + linkLocal.Value[0] = 0xFE; + linkLocal.Value[1] = 0x80; + WRITE_UINT64(&linkLocal.Value[8], &ipc->IPv6ClientEUI); + + GetAllRouterMulticastAddress6(&destIP); + + // Generate the MAC address from the multicast address + destMacAddress[0] = 0x33; + destMacAddress[1] = 0x33; + WRITE_UINT(&destMacAddress[2], &destIP.ipv6_addr[12]); + + packet = BuildICMPv6RouterSoliciation(senderIP.ipv6_addr, destIP.ipv6_addr, ipc->MacAddress, 0); + + while (LIST_NUM(ipc->IPv6RouterAdvs) == 0) + { + UINT64 giveup_time = Tick64() + (UINT64)(IPC_IPV6_RA_MAX_RETRIES * IPC_IPV6_RA_INTERVAL); + UINT64 timeout_retry = Tick() + (UINT64)IPC_IPV6_RA_INTERVAL; + IPCIPv6SendWithDestMacAddr(ipc, packet->Buf, packet->Size, destMacAddress); + + AddInterrupt(ipc->Interrupt, timeout_retry); + + if (Tick64() >= giveup_time) + { + // We failed to receive any router advertisements + break; + } + + // The processing should populate the received RAs by itself + IPCProcessL3Events(ipc); + } +} + +// Data flow +BLOCK* IPCIPv6Recv(IPC* ipc) +{ + BLOCK* b; + // Validate arguments + if (ipc == NULL) + { + return NULL; + } + + b = GetNext(ipc->IPv6ReceivedQueue); + + return b; +} + +void IPCIPv6Send(IPC* ipc, void* data, UINT size) +{ + IP destAddr; + UINT ipv6Type; + UCHAR destMac[6]; + IPV6_HEADER* header = data; + + IPv6AddrToIP(&destAddr, &header->DestAddress); + + if (IsValidUnicastIPAddress6(&destAddr)) + { + IPCIPv6SendUnicast(ipc, data, size, &destAddr); + return; + } + + // Here we're probably dealing with a multicast packet. But let's check it anyway + ipv6Type = GetIPAddrType6(&destAddr); + if (ipv6Type & IPV6_ADDR_MULTICAST) + { + // Constructing multicast MAC address based on destination IP address, then just fire and forget + destMac[0] = 0x33; + destMac[1] = 0x33; + destMac[2] = destAddr.ipv6_addr[12]; + destMac[3] = destAddr.ipv6_addr[13]; + destMac[4] = destAddr.ipv6_addr[14]; + destMac[5] = destAddr.ipv6_addr[15]; + IPCIPv6SendWithDestMacAddr(ipc, data, size, destMac); + return; + } + else + { + Debug("We got a weird packet with a weird type! %i\n", ipv6Type); + } +} + +void IPCIPv6SendWithDestMacAddr(IPC* ipc, void* data, UINT size, UCHAR* dest_mac_addr) +{ + UCHAR tmp[1514]; + // Validate arguments + if (ipc == NULL || data == NULL || size < 40 || size > 1500 || dest_mac_addr == NULL) + { + return; + } + + // Destination + Copy(tmp + 0, dest_mac_addr, 6); + + // Source + Copy(tmp + 6, ipc->MacAddress, 6); + + // Protocol number + WRITE_USHORT(tmp + 12, MAC_PROTO_IPV6); + + // Data + Copy(tmp + 14, data, size); + + // Send + IPCSendL2(ipc, tmp, size + 14); +} + +void IPCIPv6SendUnicast(IPC* ipc, void* data, UINT size, IP* next_ip) +{ + IPC_ARP* ndtMatch; + UCHAR* destMac = NULL; + IPC_IPV6_ROUTER_ADVERTISEMENT ra; + IPV6_HEADER* header = data; + IP srcIp; + bool isLocal = false; + // First we need to understand if it is a local packet or we should route it through the router + UINT addrType = GetIPAddrType6(next_ip); + + Zero(&ra, sizeof(IPC_IPV6_ROUTER_ADVERTISEMENT)); + IPv6AddrToIP(&srcIp, &header->SrcAddress); + + // Link local is always local =) + if (addrType & IPV6_ADDR_LOCAL_UNICAST) + { + isLocal = true; + } + + // If it matches any received prefix from router advertisements, it's also local + if (!isLocal && IPCIPv6CheckUnicastFromRouterPrefix(ipc, next_ip, &ra)) + { + isLocal = true; + } + + // If it is a global packet, we need to get our source IP prefix to know through which router shall we route + if (!isLocal) + { + if (!IPCIPv6CheckUnicastFromRouterPrefix(ipc, &srcIp, &ra)) + { + // If we didn't find a router for the source IP, let's just try to pick the first router and try to send to it + if (LIST_NUM(ipc->IPv6RouterAdvs) > 0) + { + Copy(&ra, LIST_DATA(ipc->IPv6RouterAdvs, 0), sizeof(IPC_IPV6_ROUTER_ADVERTISEMENT)); + } + else + { + CHAR tmp[MAX_SIZE]; + IPToStr6(tmp, MAX_SIZE, &srcIp); + Debug("We couldn't find a router for the source address of %s! Trying as local.\n", tmp); + isLocal = true; + } + } + + destMac = ra.RouterMacAddress; + if (!IsMacUnicast(destMac) && !IsMacInvalid(ra.RouterMacAddress)) + { + destMac = ra.RouterLinkLayerAddress; + } + } + + // If it is local it should be routed directly through the NDT + if (isLocal) + { + ndtMatch = IPCSearchArpTable(ipc->IPv6NeighborTable, next_ip); + if (ndtMatch == NULL) + { + // Creating a non-matched NDT entry + ndtMatch = IPCNewARP(next_ip, NULL); + Add(ipc->IPv6NeighborTable, ndtMatch); + } + if (ndtMatch->Resolved != true) + { + /// TODO: check if we need to manage NDT manually from here or the client will + /// TODO: send Neighbor Solicitations by itself and we just proxy them + CHAR tmp[MAX_SIZE]; + BLOCK* blk = NewBlock(data, size, 0); + InsertQueue(ndtMatch->PacketQueue, blk); + IPToStr6(tmp, MAX_SIZE, next_ip); + Debug("We can't send the packet because we don't have IP %s in NDT! Need to send Neighbor Solicitation first... Saving for later send.\n", tmp); + + return; + } + destMac = ndtMatch->MacAddress; + } + + if (destMac != NULL && !IsMacInvalid(destMac)) + { + IPCIPv6SendWithDestMacAddr(ipc, data, size, destMac); + } + else + { + CHAR tmp[MAX_SIZE]; + IPToStr6(tmp, MAX_SIZE, next_ip); + Debug("We couldn't deduce the MAC address for unicast address %s, packet dropped.\n", tmp); + /// TODO: think about sending to the all routers broadcast MAC as a last resort + } +} diff --git a/src/Cedar/IPC.h b/src/Cedar/IPC.h index 0aa25b4a..bce2cd93 100644 --- a/src/Cedar/IPC.h +++ b/src/Cedar/IPC.h @@ -24,6 +24,12 @@ #define IPC_LAYER_2 2 #define IPC_LAYER_3 3 +// IPv6 constants +#define IPC_IPV6_NDT_LIFETIME (30 * 1000) // as per REACHABLE_TIME constant of RFC4861 +#define IPC_IPV6_NDT_GIVEUPTIME (3 * 1000) // as per MAX_MULTICAST_SOLICIT * RETRANS_TIMER constants of RFC4861 +#define IPC_IPV6_RA_INTERVAL (4 * 1000) // as per RTR_SOLICITATION_INTERVAL constant of RFC4861 +#define IPC_IPV6_RA_MAX_RETRIES 3 // as per MAX_RTR_SOLICITATIONS constant of RFC4861 + // ARP table entry struct IPC_ARP { @@ -117,6 +123,13 @@ struct IPC SHARED_BUFFER *IpcSessionSharedBuffer; // A shared buffer between IPC and Session IPC_SESSION_SHARED_BUFFER_DATA *IpcSessionShared; // Shared data between IPC and Session UINT Layer; + + // IPv6 stuff + QUEUE* IPv6ReceivedQueue; // IPv6 reception queue + LIST* IPv6NeighborTable; // Neighbor Discovery Table + LIST* IPv6RouterAdvs; // Router offered prefixes + UINT64 IPv6ClientEUI; // The EUI of the client (for the SLAAC autoconf) + UINT64 IPv6ServerEUI; // The EUI of the server (from the RA discovery) }; // MS-CHAPv2 authentication information @@ -129,6 +142,15 @@ struct IPC_MSCHAP_V2_AUTHINFO EAP_CLIENT *MsChapV2_EapClient; // EAP client }; +struct IPC_IPV6_ROUTER_ADVERTISEMENT +{ + IP RoutedPrefix; + IP RoutedMask; + IP RouterAddress; + UCHAR RouterMacAddress[6]; + UCHAR RouterLinkLayerAddress[6]; +}; + IPC *NewIPC(CEDAR *cedar, char *client_name, char *postfix, char *hubname, char *username, char *password, UINT *error_code, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, char *client_hostname, char *crypt_name, @@ -151,15 +173,15 @@ IPC_ARP *IPCNewARP(IP *ip, UCHAR *mac_address); void IPCFreeARP(IPC_ARP *a); int IPCCmpArpTable(void *p1, void *p2); void IPCSendIPv4Unicast(IPC *ipc, void *data, UINT size, IP *next_ip); -IPC_ARP *IPCSearchArpTable(IPC *ipc, IP *ip); +IPC_ARP *IPCSearchArpTable(LIST* arpTable, IP *ip); void IPCSendIPv4WithDestMacAddr(IPC *ipc, void *data, UINT size, UCHAR *dest_mac_addr); void IPCFlushArpTable(IPC *ipc); void IPCFlushArpTableEx(IPC *ipc, UINT64 now); void IPCProcessArp(IPC *ipc, BLOCK *b); void IPCAssociateOnArpTable(IPC *ipc, IP *ip, UCHAR *mac_address); -bool IsValidUnicastMacAddress(UCHAR *mac); -bool IsValidUnicastIPAddress4(IP *ip); -bool IsValidUnicastIPAddressUINT4(UINT ip); + + + DHCPV4_DATA *IPCSendDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt, UINT expecting_code, UINT timeout, TUBE *discon_poll_tube); BUF *IPCBuildDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt); BUF *IPCBuildDhcpRequestOptions(IPC *ipc, DHCP_OPTION_LIST *opt); @@ -171,6 +193,25 @@ IPC_ASYNC *NewIPCAsync(CEDAR *cedar, IPC_PARAM *param, SOCK_EVENT *sock_event); void IPCAsyncThreadProc(THREAD *thread, void *param); void FreeIPCAsync(IPC_ASYNC *a); +// IPv6 stuff +// Memory management +void IPCIPv6Init(IPC* ipc); +void IPCIPv6Free(IPC* ipc); +// NDT +void IPCIPv6AssociateOnNDT(IPC* ipc, IP* ip, UCHAR* mac_address); +void IPCIPv6AssociateOnNDTEx(IPC* ipc, IP* ip, UCHAR* mac_address, bool isNeighborAdv); +void IPCIPv6FlushNDT(IPC* ipc); +void IPCIPv6FlushNDTEx(IPC* ipc, UINT64 now); +// RA +void IPCIPv6AddRouterPrefix(IPC* ipc, ICMPV6_OPTION_LIST* recvPrefix, UCHAR* macAddress, IP* ip); +bool IPCIPv6CheckUnicastFromRouterPrefix(IPC* ipc, IP* ip, IPC_IPV6_ROUTER_ADVERTISEMENT* matchedRA); +void IPCIPv6SendRouterSolicitation(IPC* ipc); +// Data flow +BLOCK* IPCIPv6Recv(IPC* ipc); +void IPCIPv6Send(IPC* ipc, void* data, UINT size); +void IPCIPv6SendWithDestMacAddr(IPC* ipc, void* data, UINT size, UCHAR* dest_mac_addr); +void IPCIPv6SendUnicast(IPC* ipc, void* data, UINT size, IP* next_ip); + bool ParseAndExtractMsChapV2InfoFromPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *password); #endif // IPC_H diff --git a/src/Cedar/Virtual.c b/src/Cedar/Virtual.c index 1cac3370..26a27922 100644 --- a/src/Cedar/Virtual.c +++ b/src/Cedar/Virtual.c @@ -8220,46 +8220,6 @@ void FreeArpWaitTable(VH *v) ReleaseList(v->ArpWaitTable); } -// Check whether the MAC address is valid -bool IsMacInvalid(UCHAR *mac) -{ - UINT i; - // Validate arguments - if (mac == NULL) - { - return false; - } - - for (i = 0;i < 6;i++) - { - if (mac[i] != 0x00) - { - return false; - } - } - return true; -} - -// Check whether the MAC address is a broadcast address -bool IsMacBroadcast(UCHAR *mac) -{ - UINT i; - // Validate arguments - if (mac == NULL) - { - return false; - } - - for (i = 0;i < 6;i++) - { - if (mac[i] != 0xff) - { - return false; - } - } - return true; -} - // Insert an entry in the ARP table void InsertArpTable(VH *v, UCHAR *mac, UINT ip) { diff --git a/src/Cedar/Virtual.h b/src/Cedar/Virtual.h index 80c71463..5577e1ad 100644 --- a/src/Cedar/Virtual.h +++ b/src/Cedar/Virtual.h @@ -409,8 +409,6 @@ ARP_ENTRY *SearchArpTable(VH *v, UINT ip); void RefreshArpTable(VH *v); void PollingArpTable(VH *v); void InsertArpTable(VH *v, UCHAR *mac, UINT ip); -bool IsMacBroadcast(UCHAR *mac); -bool IsMacInvalid(UCHAR *mac); void InitArpWaitTable(VH *v); void FreeArpWaitTable(VH *v); int CompareArpWaitTable(void *p1, void *p2); diff --git a/src/Mayaqua/Network.c b/src/Mayaqua/Network.c index 14c1f325..47babba3 100644 --- a/src/Mayaqua/Network.c +++ b/src/Mayaqua/Network.c @@ -7375,6 +7375,175 @@ void CopyIP(IP *dst, IP *src) Copy(dst, src, sizeof(IP)); } +// Utility functions about IP and MAC address types +// Identify whether the IP address is a normal unicast address +bool IsValidUnicastIPAddress4(IP* ip) +{ + UINT i; + // Validate arguments + if (IsIP4(ip) == false) + { + return false; + } + + if (IsZeroIP(ip)) + { + return false; + } + + if (ip->addr[0] >= 224 && ip->addr[0] <= 239) + { + // IPv4 Multicast + return false; + } + + + /// TODO: this is kinda incorrect, but for the correct parsing we need the netmask anyway + for (i = 0; i < 4; i++) + { + if (ip->addr[i] != 255) + { + return true; + } + } + + return false; +} +bool IsValidUnicastIPAddressUINT4(UINT ip) +{ + IP a; + + UINTToIP(&a, ip); + + return IsValidUnicastIPAddress4(&a); +} + +bool IsValidUnicastIPAddress6(IP* ip) +{ + UINT ipv6Type; + + if (!IsIP6(ip)) + { + return false; + } + + if (IsZeroIP(ip)) + { + return false; + } + + ipv6Type = GetIPAddrType6(ip); + + if (!(ipv6Type & IPV6_ADDR_LOCAL_UNICAST) && + !(ipv6Type & IPV6_ADDR_GLOBAL_UNICAST)) + { + return false; + } + + return true; +} + +// Check whether the MAC address is valid +bool IsMacInvalid(UCHAR* mac) +{ + UINT i; + // Validate arguments + if (mac == NULL) + { + return false; + } + + for (i = 0; i < 6; i++) + { + if (mac[i] != 0x00) + { + return false; + } + } + return true; +} + +// Check whether the MAC address is a broadcast address +bool IsMacBroadcast(UCHAR* mac) +{ + UINT i; + // Validate arguments + if (mac == NULL) + { + return false; + } + + for (i = 0; i < 6; i++) + { + if (mac[i] != 0xff) + { + return false; + } + } + return true; +} + +// Check wether the MAC address is an IPv4 multicast or an IPv6 multicast +bool IsMacMulticast(UCHAR* mac) +{ + // Validate arguments + if (mac == NULL) + { + return false; + } + + if (mac[0] == 0x01 && + mac[1] == 0x00 && + mac[2] == 0x5e) + { + // Multicast IPv4 and other IANA multicasts + return true; + } + + if (mac[0] == 0x01) + { + // That's not a really reserved for multicast range, but it seems like anything with 0x01 is used as multicast anyway + // Remove or specify if it causes problems + return true; + } + + if (mac[0] == 0x33 && + mac[1] == 0x33) + { + // Multicast IPv6 + return true; + } + + return false; +} + +// Check wether the MAC address is a unicast one +bool IsMacUnicast(UCHAR* mac) +{ + // Validate arguments + if (mac == NULL) + { + return false; + } + + if (IsMacInvalid(mac)) + { + return false; + } + + if (IsMacBroadcast(mac)) + { + return false; + } + + if (IsMacMulticast(mac)) + { + return false; + } + + return true; +} + // Get the number of clients connected from the specified IP address UINT GetNumIpClient(IP *ip) { diff --git a/src/Mayaqua/Network.h b/src/Mayaqua/Network.h index b99f179a..22529f23 100644 --- a/src/Mayaqua/Network.h +++ b/src/Mayaqua/Network.h @@ -1302,6 +1302,15 @@ void IPAnd4(IP *dst, IP *a, IP *b); bool IsInSameNetwork4(IP *a1, IP *a2, IP *subnet); bool IsInSameNetwork4Standard(IP *a1, IP *a2); +// Utility functions about IP and MAC address types +bool IsValidUnicastIPAddress4(IP* ip); +bool IsValidUnicastIPAddressUINT4(UINT ip); +bool IsValidUnicastIPAddress6(IP* ip); +bool IsMacUnicast(UCHAR* mac); +bool IsMacBroadcast(UCHAR* mac); +bool IsMacMulticast(UCHAR* mac); +bool IsMacInvalid(UCHAR* mac); + bool ParseIpAndSubnetMask4(char *src, UINT *ip, UINT *mask); bool ParseIpAndSubnetMask46(char *src, IP *ip, IP *mask); bool ParseIpAndMask4(char *src, UINT *ip, UINT *mask); diff --git a/src/Mayaqua/TcpIp.c b/src/Mayaqua/TcpIp.c index efdd96a0..95d5257d 100644 --- a/src/Mayaqua/TcpIp.c +++ b/src/Mayaqua/TcpIp.c @@ -889,6 +889,44 @@ BUF *BuildICMPv6NeighborSoliciation(IPV6_ADDR *src_ip, IPV6_ADDR *target_ip, UCH return ret; } +BUF *BuildICMPv6RouterSoliciation(IPV6_ADDR* src_ip, IPV6_ADDR* target_ip, UCHAR* my_mac_address, UINT id) +{ + ICMPV6_OPTION_LIST opt; + ICMPV6_OPTION_LINK_LAYER link; + ICMPV6_ROUTER_SOLICIATION_HEADER header; + BUF *b; + BUF *b2; + BUF *ret; + + if (src_ip == NULL || target_ip == NULL || my_mac_address == NULL) + { + return NULL; + } + + Zero(&link, sizeof(link)); + Copy(link.Address, my_mac_address, 6); + + Zero(&opt, sizeof(opt)); + opt.SourceLinkLayer = &link; + + b = BuildICMPv6Options(&opt); + + Zero(&header, sizeof(header)); + + b2 = NewBuf(); + + WriteBuf(b2, &header, sizeof(header)); + WriteBufBuf(b2, b); + + ret = BuildICMPv6(src_ip, target_ip, 255, + ICMPV6_TYPE_ROUTER_SOLICIATION, 0, b2->Buf, b2->Size, id); + + FreeBuf(b); + FreeBuf(b2); + + return ret; +} + // Get the next header number from the queue UCHAR IPv6GetNextHeaderFromQueue(QUEUE *q) { @@ -1452,6 +1490,12 @@ PKT *ClonePacket(PKT *p, bool copy_data) return ret; } +// Parse the packet but without data layer except for ICMP +PKT* ParsePacketUpToICMPv6(UCHAR* buf, UINT size) +{ + return ParsePacketEx5(buf, size, false, 0, true, true, false, true); +} + // Parse the contents of the packet PKT *ParsePacket(UCHAR *buf, UINT size) { @@ -1469,7 +1513,11 @@ PKT *ParsePacketEx3(UCHAR *buf, UINT size, bool no_l3, UINT vlan_type_id, bool b { return ParsePacketEx4(buf, size, no_l3, vlan_type_id, bridge_id_as_mac_address, false, false); } -PKT *ParsePacketEx4(UCHAR *buf, UINT size, bool no_l3, UINT vlan_type_id, bool bridge_id_as_mac_address, bool no_http, bool correct_checksum) +PKT* ParsePacketEx4(UCHAR* buf, UINT size, bool no_l3, UINT vlan_type_id, bool bridge_id_as_mac_address, bool no_http, bool correct_checksum) +{ + return ParsePacketEx5(buf, size, no_l3, vlan_type_id, bridge_id_as_mac_address, no_http, correct_checksum, false); +} +PKT* ParsePacketEx5(UCHAR* buf, UINT size, bool no_l3, UINT vlan_type_id, bool bridge_id_as_mac_address, bool no_http, bool correct_checksum, bool no_l3_l4_except_icmpv6) { PKT *p; USHORT vlan_type_id_16; @@ -1559,7 +1607,7 @@ PKT *ParsePacketEx4(UCHAR *buf, UINT size, bool no_l3, UINT vlan_type_id, bool b } // Do parse - if (ParsePacketL2Ex(p, buf, size, no_l3) == false) + if (ParsePacketL2Ex(p, buf, size, no_l3, no_l3_l4_except_icmpv6) == false) { // Parsing failure FreePacket(p); @@ -1929,7 +1977,7 @@ HTTPLOG *ParseHttpAccessLog(PKT *pkt) // Layer-2 parsing -bool ParsePacketL2Ex(PKT *p, UCHAR *buf, UINT size, bool no_l3) +bool ParsePacketL2Ex(PKT *p, UCHAR *buf, UINT size, bool no_l3, bool no_l3_l4_except_icmpv6) { UINT i; bool b1, b2; @@ -1994,7 +2042,7 @@ bool ParsePacketL2Ex(PKT *p, UCHAR *buf, UINT size, bool no_l3) switch (type_id_16) { case MAC_PROTO_ARPV4: // ARPv4 - if (no_l3) + if (no_l3 || no_l3_l4_except_icmpv6) { return true; } @@ -2002,7 +2050,7 @@ bool ParsePacketL2Ex(PKT *p, UCHAR *buf, UINT size, bool no_l3) return ParsePacketARPv4(p, buf, size); case MAC_PROTO_IPV4: // IPv4 - if (no_l3) + if (no_l3 || no_l3_l4_except_icmpv6) { return true; } @@ -2015,7 +2063,7 @@ bool ParsePacketL2Ex(PKT *p, UCHAR *buf, UINT size, bool no_l3) return true; } - return ParsePacketIPv6(p, buf, size); + return ParsePacketIPv6(p, buf, size, no_l3_l4_except_icmpv6); default: // Unknown if (type_id_16 == p->VlanTypeID) @@ -2538,7 +2586,7 @@ void CloneICMPv6Options(ICMPV6_OPTION_LIST *dst, ICMPV6_OPTION_LIST *src) } // IPv6 parsing -bool ParsePacketIPv6(PKT *p, UCHAR *buf, UINT size) +bool ParsePacketIPv6(PKT *p, UCHAR *buf, UINT size, bool no_l3_l4_except_icmpv6) { // Validate arguments if (p == NULL || buf == NULL) @@ -2585,9 +2633,17 @@ bool ParsePacketIPv6(PKT *p, UCHAR *buf, UINT size) } case IP_PROTO_TCP: // TCP + if (no_l3_l4_except_icmpv6) + { + return true; + } return ParseTCP(p, buf, size); case IP_PROTO_UDP: // UDP + if (no_l3_l4_except_icmpv6) + { + return true; + } return ParseUDP(p, buf, size); default: // Unknown diff --git a/src/Mayaqua/TcpIp.h b/src/Mayaqua/TcpIp.h index 8ff4f385..89ca3a95 100644 --- a/src/Mayaqua/TcpIp.h +++ b/src/Mayaqua/TcpIp.h @@ -745,6 +745,8 @@ PKT *ParsePacketEx(UCHAR *buf, UINT size, bool no_l3); PKT *ParsePacketEx2(UCHAR *buf, UINT size, bool no_l3, UINT vlan_type_id); PKT *ParsePacketEx3(UCHAR *buf, UINT size, bool no_l3, UINT vlan_type_id, bool bridge_id_as_mac_address); PKT *ParsePacketEx4(UCHAR *buf, UINT size, bool no_l3, UINT vlan_type_id, bool bridge_id_as_mac_address, bool no_http, bool correct_checksum); +PKT* ParsePacketEx5(UCHAR* buf, UINT size, bool no_l3, UINT vlan_type_id, bool bridge_id_as_mac_address, bool no_http, bool correct_checksum, bool no_l3_l4_except_icmpv6); +PKT* ParsePacketUpToICMPv6(UCHAR* buf, UINT size); void FreePacket(PKT *p); void FreePacketWithData(PKT *p); void FreePacketIPv4(PKT *p); @@ -754,7 +756,7 @@ void FreePacketUDPv4(PKT *p); void FreePacketTCPv4(PKT *p); void FreePacketICMPv4(PKT *p); void FreePacketDHCPv4(PKT *p); -bool ParsePacketL2Ex(PKT *p, UCHAR *buf, UINT size, bool no_l3); +bool ParsePacketL2Ex(PKT *p, UCHAR *buf, UINT size, bool no_l3, bool no_l3_l4_except_icmpv6); bool ParsePacketARPv4(PKT *p, UCHAR *buf, UINT size); bool ParsePacketIPv4(PKT *p, UCHAR *buf, UINT size); bool ParsePacketBPDU(PKT *p, UCHAR *buf, UINT size); @@ -770,7 +772,7 @@ void FreeClonePacket(PKT *p); void CorrectChecksum(PKT *p); -bool ParsePacketIPv6(PKT *p, UCHAR *buf, UINT size); +bool ParsePacketIPv6(PKT *p, UCHAR *buf, UINT size, bool no_l3_l4_except_icmpv6); bool ParsePacketIPv6Header(IPV6_HEADER_PACKET_INFO *info, UCHAR *buf, UINT size); bool ParseIPv6ExtHeader(IPV6_HEADER_PACKET_INFO *info, UCHAR next_header, UCHAR *buf, UINT size); bool ParseICMPv6Options(ICMPV6_OPTION_LIST *o, UCHAR *buf, UINT size); @@ -786,6 +788,7 @@ BUF *BuildIPv6PacketHeader(IPV6_HEADER_PACKET_INFO *info, UINT *bytes_before_pay UCHAR IPv6GetNextHeaderFromQueue(QUEUE *q); void BuildAndAddIPv6PacketOptionHeader(BUF *b, IPV6_OPTION_HEADER *opt, UCHAR next_header, UINT size); BUF *BuildICMPv6NeighborSoliciation(IPV6_ADDR *src_ip, IPV6_ADDR *target_ip, UCHAR *my_mac_address, UINT id); +BUF *BuildICMPv6RouterSoliciation(IPV6_ADDR* src_ip, IPV6_ADDR* target_ip, UCHAR* my_mac_address, UINT id); BUF *BuildICMPv6(IPV6_ADDR *src_ip, IPV6_ADDR *dest_ip, UCHAR hop_limit, UCHAR type, UCHAR code, void *data, UINT size, UINT id); bool VLanRemoveTag(void **packet_data, UINT *packet_size, UINT vlan_id, UINT vlan_tpid);