/* * Checks if two IP addresses are on the same network * returns: EXIT_FAILURE if not and EXIT_SUCCESS if they are */ int isInSameNetwork(uchar *ip_addr1, uchar *ip_addr2) { char tmpbuf[MAX_TMPBUF_LEN]; int i, j; uchar net1[4], net2[4]; for (i = 0; i < MAX_ROUTES; i++) { if (route_tbl[i].is_empty == TRUE) continue; // TODO: Could there be a bug here? What about default routes with 0.0.0.0?? for (j = 0; j < 4; j++) { net1[j] = ip_addr1[j] & route_tbl[i].netmask[j]; net2[j] = ip_addr2[j] & route_tbl[i].netmask[j]; } if (COMPARE_IP(net1, net2) == 0) { verbose(2, "[isInSameNetwork]:: IPs %s and %s are on the same network %s", IP2Dot(tmpbuf, ip_addr1), IP2Dot((tmpbuf+20), ip_addr2), IP2Dot((tmpbuf+40), route_tbl[i].network)); return EXIT_SUCCESS; } } verbose(2, "[isInSameNetwork]:: IPs %s and %s are not on the same network", IP2Dot(tmpbuf, ip_addr1), IP2Dot((tmpbuf+20), ip_addr2)); return EXIT_FAILURE; }
/* * IPIncomingPacket: Process incoming IP packet. * The IP packet can be destined to the local router (for example route updates). * Or it could be a packet meant for forwarding: either unicast or multicast/broadcast. * This is a wrapper routine that calls the appropriate subroutine to take * the appropriate function. */ void IPIncomingPacket(gpacket_t *in_pkt) { char tmpbuf[MAX_TMPBUF_LEN]; // get a pointer to the IP packet ip_packet_t *ip_pkt = (ip_packet_t *)&in_pkt->data.data; uchar bcast_ip[] = IP_BCAST_ADDR; // Is this IP packet for me?? if (IPCheckPacket4Me(in_pkt)) { verbose(2, "[IPIncomingPacket]:: got IP packet destined to this router"); IPProcessMyPacket(in_pkt); } else if (COMPARE_IP(gNtohl(tmpbuf, ip_pkt->ip_dst), bcast_ip) == 0) { // TODO: rudimentary 'broadcast IP address' check verbose(2, "[IPIncomingPacket]:: not repeat broadcast (final destination %s), packet thrown", IP2Dot(tmpbuf, gNtohl((tmpbuf+20), ip_pkt->ip_dst))); IPProcessBcastPacket(in_pkt); } else { // Destinated to someone else verbose(2, "[IPIncomingPacket]:: got IP packet destined to someone else"); IPProcessForwardingPacket(in_pkt); } }
/* Returns 1 if one of the interfaces has the given IP */ int hasInterface(uchar *ip) { uchar interfaces[MAX_INTERFACES][4]; int numInterfaces = getInterfaces(interfaces); int i; for (i = 0; i < numInterfaces; i++) { if (!COMPARE_IP(interfaces[i], ip)) return 1; } return 0; }
/* * lookup the given ip_addr in the ARP cache. * copy the MAC address in mac_addr and return TRUE * otherwise return FALSE -- mac_addr is undefined in this case. */ int lookupARPCache(uchar *ip_addr, uchar *mac_addr) { int key; key = getARPCacheKey(ip_addr); if ((arp_cache[key].is_empty == FALSE) && (COMPARE_IP(arp_cache[key].ip_addr, ip_addr) == 0)) { COPY_MAC(mac_addr, arp_cache[key].mac_addr); return TRUE; } return FALSE; }
/* * Delete ARP entry with the given IP address */ void ARPDeleteEntry(char *ip_addr) { int i; for (i = 0; i < MAX_ARP; i++) { if ( (ARPtable[i].is_empty == FALSE) && (COMPARE_IP(ARPtable[i].ip_addr, ip_addr)) == 0) { ARPtable[i].is_empty = TRUE; verbose(2, "[ARPDeleteEntry]:: arp entry #%d deleted", i); } } return; }
/* * Find an ARP entry matching the supplied IP address in the ARP table * ARGUMENTS: uchar *ip_addr: IP address to look up * uchar *mac_addr: returned MAC address corresponding to the IP * The MAC is only set when the return status is EXIT_SUCCESS. If error, * the MAC address (mac_addr) is undefined. */ int ARPFindEntry(uchar *ip_addr, uchar *mac_addr) { int i; char tmpbuf[MAX_TMPBUF_LEN]; for (i = 0; i < MAX_ARP; i++) { if(ARPtable[i].is_empty == FALSE && COMPARE_IP(ARPtable[i].ip_addr, ip_addr) == 0) { // found IP address - copy the MAC address COPY_MAC(mac_addr, ARPtable[i].mac_addr); verbose(2, "[ARPFindEntry]:: found ARP entry #%d for IP %s", i, IP2Dot(tmpbuf, ip_addr)); return EXIT_SUCCESS; } } verbose(2, "[ARPFindEntry]:: failed to find ARP entry for IP %s", IP2Dot(tmpbuf, ip_addr)); return EXIT_FAILURE; }
/* * add an entry to the ARP table * ARGUMENTS: uchar *ip_addr - the IP address (4 bytes) * uchar *mac_addr - the MAC address (6 bytes) * RETURNS: Nothing */ void ARPAddEntry(uchar *ip_addr, uchar *mac_addr) { int i; int empty_slot = MAX_ARP; char tmpbuf[MAX_TMPBUF_LEN]; for (i = 0; i < MAX_ARP; i++) { if ((ARPtable[i].is_empty == FALSE) && (COMPARE_IP(ARPtable[i].ip_addr, ip_addr) == 0)) { // update entry COPY_IP(ARPtable[i].ip_addr, ip_addr); COPY_MAC(ARPtable[i].mac_addr, mac_addr); verbose(2, "[ARPAddEntry]:: updated ARP table entry #%d: IP %s = MAC %s", i, IP2Dot(tmpbuf, ip_addr), MAC2Colon(tmpbuf+20, mac_addr)); return; } if (ARPtable[i].is_empty == TRUE) empty_slot = i; } if (empty_slot == MAX_ARP) { // ARP table full.. do the replacement // use the FIFO strategy: table replace index is the FIFO pointer empty_slot = tbl_replace_indx; tbl_replace_indx = (tbl_replace_indx + 1) % MAX_ARP; } // add new entry or overwrite the replaced entry ARPtable[empty_slot].is_empty = FALSE; COPY_IP(ARPtable[empty_slot].ip_addr, ip_addr); COPY_MAC(ARPtable[empty_slot].mac_addr, mac_addr); verbose(2, "[ARPAddEntry]:: updated ARP table entry #%d: IP %s = MAC %s", empty_slot, IP2Dot(tmpbuf, ip_addr), MAC2Colon(tmpbuf+20, mac_addr)); return; }
/* * get a packet from the ARP buffer * ARGUMENTS: out_pkt - pointer at which packet matching message is to be copied * nexthop - pointer to dest. IP address to search for * RETURNS: The function returns EXIT_SUCCESS if packet was found and copied, * or EXIT_FAILURE if it was not found. */ int ARPGetBuffer(gpacket_t **out_pkt, uchar *nexthop) { int i; char tmpbuf[MAX_TMPBUF_LEN]; // Search for packet in buffer for (i = 0; i < MAX_ARP_BUFFERS; i++) { if (ARPbuffer[i].is_empty == TRUE) continue; if (COMPARE_IP(ARPbuffer[i].wait_msg->frame.nxth_ip_addr, nexthop) == 0) { // match found *out_pkt = ARPbuffer[i].wait_msg; ARPbuffer[i].is_empty = TRUE; verbose(2, "[ARPGetBuffer]:: found packet matching nexthop %s at entry %d", IP2Dot(tmpbuf, nexthop), i); return EXIT_SUCCESS; } } verbose(2, "[ARPGetBuffer]:: no match for nexthop %s", IP2Dot(tmpbuf, nexthop)); return EXIT_FAILURE; }
/* * IPCheckPacket4Me: Return TRUE if the packet is meant for me. Otherwise return FALSE. * Check against all possible IPs I have to determine whether this packet * is meant for me. */ int IPCheckPacket4Me(gpacket_t *in_pkt) { ip_packet_t *ip_pkt = (ip_packet_t *)&in_pkt->data.data; char tmpbuf[MAX_TMPBUF_LEN]; int count, i; uchar iface_ip[MAX_MTU][4]; uchar pkt_ip[4]; COPY_IP(pkt_ip, gNtohl(tmpbuf, ip_pkt->ip_dst)); verbose(2, "[IPCheckPacket4Me]:: looking for IP %s ", IP2Dot(tmpbuf, pkt_ip)); if ((count = findAllInterfaceIPs(MTU_tbl, iface_ip)) > 0) { for (i = 0; i < count; i++) { if (COMPARE_IP(iface_ip[i], pkt_ip) == 0) { verbose(2, "[IPCheckPacket4Me]:: found a matching IP.. for %s ", IP2Dot(tmpbuf, pkt_ip)); return TRUE; } } return FALSE; } else return FALSE; }
/* * ARPProcess: Process a received ARP packet... from remote nodes. If it is * a reply for a ARP request sent from the local node, use it * to update the local ARP cache. Flush (dequeue, process, and send) any packets * that are buffered for ARP processing that match the ARP reply. * If it a request, send a reply.. no need to record any state here. */ void ARPProcess(gpacket_t *pkt) { char tmpbuf[MAX_TMPBUF_LEN]; arp_packet_t *apkt = (arp_packet_t *) pkt->data.data; // check packet is ethernet and addresses of IP type.. otherwise throw away if ((ntohs(apkt->hw_addr_type) != ETHERNET_PROTOCOL) || (ntohs(apkt->arp_prot) != IP_PROTOCOL)) { verbose(2, "[ARPProcess]:: unknown hwtype or protocol, dropping ARP packet"); return; } verbose(2, "[ARPProcess]:: adding sender of received packet to ARP table"); ARPAddEntry(gNtohl((uchar *)tmpbuf, apkt->src_ip_addr), apkt->src_hw_addr); // Check it's actually destined to us,if not throw packet if (COMPARE_IP(apkt->dst_ip_addr, gHtonl((uchar *)tmpbuf, pkt->frame.src_ip_addr)) != 0) { verbose(2, "[APRProcess]:: packet has a frame source (after ntohl) %s ...", IP2Dot(tmpbuf, gNtohl((uchar *)tmpbuf, pkt->frame.src_ip_addr))); verbose(2, "[APRProcess]:: packet destined for %s, dropping", IP2Dot(tmpbuf, gNtohl((uchar *)tmpbuf, apkt->dst_ip_addr))); return; } // We have a valid ARP packet, lets process it now. // If it's a REQUEST, send a reply back if (ntohs(apkt->arp_opcode) == ARP_REQUEST) { apkt->arp_opcode = htons(ARP_REPLY); COPY_MAC(apkt->src_hw_addr, pkt->frame.src_hw_addr); COPY_MAC(apkt->dst_hw_addr, pkt->data.header.src); COPY_IP(apkt->dst_ip_addr, apkt->src_ip_addr); COPY_IP(apkt->src_ip_addr, gHtonl((uchar *)tmpbuf, pkt->frame.src_ip_addr)); verbose(2, "[ARPProcess]:: packet was ARP REQUEST, sending ARP REPLY packet"); // prepare for sending. Set some parameters that is going to be used // by the GNET adapter... pkt->frame.dst_interface = pkt->frame.src_interface; COPY_MAC(pkt->data.header.dst, pkt->data.header.src); COPY_MAC(pkt->data.header.src, pkt->frame.src_hw_addr); COPY_IP(pkt->frame.nxth_ip_addr, gNtohl((uchar *)tmpbuf, apkt->dst_ip_addr)); pkt->frame.arp_valid = TRUE; pkt->data.header.prot = htons(ARP_PROTOCOL); ARPSend2Output(pkt); } else if (ntohs(apkt->arp_opcode) == ARP_REPLY) { // Flush buffer of any packets waiting for the incoming ARP.. verbose(2, "[ARPProcess]:: packet was ARP REPLY... "); ARPFlushBuffer(gNtohl((uchar *)tmpbuf, apkt->src_ip_addr), apkt->src_hw_addr); verbose(2, "[ARPProcess]:: flushed the ARP buffer ... "); } else verbose(2, "[ARPProcess]:: unknown ARP type"); return; }
int process_rx_packet(uint8_t *pu8Packet, uint32_t u32Len) { ARP_PACKET *arp = (ARP_PACKET *)pu8Packet; IP_PACKET *ip = (IP_PACKET *)pu8Packet; UDP_PACKET *udp = (UDP_PACKET *)pu8Packet; if (pu8Packet[0] == 0xFF) { /* this is a broadcast packet */ /* * We manage the ARP reply process here. * In the following code, if we have received a ARP request, * we send ARP reply immediately. */ if ((!COMPARE_IP(arp->au8TargetIP, g_au8IpAddr)) && (arp->u16Type == SWAP16(PROTOCOL_ARP)) && (arp->u16Operation == SWAP16(ARP_REQUEST))) { arp_reply(arp->su8SenderIP, arp->au8SenderHA); } return 0; } else { /* this is a multicast or unicast packet */ /* * This is a unicast packet to us. */ if ((ip->u8Prot == IP_PRO_TCP) && (!COMPARE_IP(ip->au8DestIP, g_au8IpAddr))) { // write me: process TCP packets here return 0; } if ((ip->u8Prot == IP_PRO_UDP) && (udp->u16SrcPort == SWAP16(67))) { // This is a DHCP packet... s_u32PktRdy = u32Len; memcpy(au8RxBuf, pu8Packet, u32Len); return 0; } if ((ip->u8Prot == IP_PRO_UDP) && (!COMPARE_IP(ip->au8DestIP, g_au8IpAddr))) { // write me: process UDP packets here return 0; } /* * Check ICMP Echo Request packet - * if matched, we reply it right here */ if ((ip->u8Prot == IP_PRO_ICMP) && (!COMPARE_IP(ip->au8DestIP, g_au8IpAddr)) && (pu8Packet[34] == 0x08)) { IP_PACKET *tx_ip; /* duplicate packet then modify it */ memcpy((char *)&au8TxBuf[0], (char *)&pu8Packet[0], u32Len); tx_ip = (IP_PACKET *)&au8TxBuf[0]; memcpy((char *)tx_ip->au8DestMac, (char *)ip->au8SrcMac, 6); memcpy((char *)tx_ip->au8SrcMac, (char *)g_au8MacAddr, 6); tx_ip->u16Type = SWAP16(PROTOCOL_IP); tx_ip->u8VerHLen = 0x45; /* fixed value, do not change it */ tx_ip->u8ToS = 0; /* no special priority */ tx_ip->u16TLen = SWAP16(60); tx_ip->u16ID = SWAP16(s_u16IpPacketId); tx_ip->u16Frag = 0; tx_ip->u8TTL = 64; tx_ip->u8Prot = IP_PRO_ICMP; tx_ip->u16HdrChksum = 0; memcpy((char *)tx_ip->au8SrcIP, (char *)g_au8IpAddr, 4); memcpy((char *)tx_ip->au8DestIP, (char *)ip->au8SrcIP, 4); tx_ip->u16HdrChksum = ~chksum((uint16_t *)&tx_ip->u8VerHLen, 10); /* 20 bytes */ s_u16IpPacketId++; /* ICMP reply */ au8TxBuf[34] = 0; /* ICMP checksum */ au8TxBuf[36] = 0; au8TxBuf[37] = 0; *(uint16_t *)&au8TxBuf[36] = ~chksum((uint16_t *)&au8TxBuf[34], (u32Len - 34) / 2); EMAC_SendPkt(au8TxBuf, u32Len); return 0; } } return 0; }
/* * this function processes the IP packets that are reinjected into the * IP layer by ICMP, UDP, and other higher-layers. * There can be two scenarios. The packet can be a reply for an original * query OR it can be a new one. The processing performed by this function depends * on the packet type.. * IMPORTANT: src_prot is the source protocol number. */ int IPOutgoingPacket(gpacket_t *pkt, uchar *dst_ip, int size, int newflag, int src_prot) { ip_packet_t *ip_pkt = (ip_packet_t *)pkt->data.data; ushort cksum; char tmpbuf[MAX_TMPBUF_LEN]; uchar iface_ip_addr[4]; int status; ip_pkt->ip_ttl = 64; // set TTL to default value ip_pkt->ip_cksum = 0; // reset the checksum field ip_pkt->ip_prot = src_prot; // set the protocol field if (newflag == 0) { //if broadcast packet we set the address for 255.255.255.255 if(pkt->frame.bcast == TRUE) { //set ip to find route eg. 192.168.2.255 COPY_IP(ip_pkt->ip_dst, gHtonl(tmpbuf, dst_ip)); // find the nexthop and interface and fill them in the "meta" frame // NOTE: the packet itself is not modified by this lookup! if (findRouteEntry(route_tbl, gNtohl(tmpbuf, ip_pkt->ip_dst), pkt->frame.nxth_ip_addr, &(pkt->frame.dst_interface)) == EXIT_FAILURE) return EXIT_FAILURE; //find interface IP if ((status = findInterfaceIP(MTU_tbl, pkt->frame.dst_interface, iface_ip_addr)) == EXIT_FAILURE) { error("[IPOutgoingPacket]:: couldn't find interface "); return EXIT_FAILURE; } // the outgoing packet should have the interface IP as source COPY_IP(ip_pkt->ip_src, gHtonl(tmpbuf, iface_ip_addr)); //set broadcast IP = 255.255.255.255 uchar bcast_ip[] = IP_BCAST_ADDR; COPY_IP(ip_pkt->ip_dst, gHtonl(tmpbuf, bcast_ip)); } else { COPY_IP(ip_pkt->ip_dst, ip_pkt->ip_src); // set dst to original src COPY_IP(ip_pkt->ip_src, gHtonl(tmpbuf, pkt->frame.src_ip_addr)); // set src to me // find the nexthop and interface and fill them in the "meta" frame // NOTE: the packet itself is not modified by this lookup! if (findRouteEntry(route_tbl, gNtohl(tmpbuf, ip_pkt->ip_dst), pkt->frame.nxth_ip_addr, &(pkt->frame.dst_interface)) == EXIT_FAILURE) return EXIT_FAILURE; } } else if (newflag == 1) { // non REPLY PACKET -- this is a new packet; set all fields ip_pkt->ip_version = 4; ip_pkt->ip_hdr_len = 5; ip_pkt->ip_tos = 0; ip_pkt->ip_identifier = IP_OFFMASK & random(); RESET_DF_BITS(ip_pkt->ip_frag_off); RESET_MF_BITS(ip_pkt->ip_frag_off); ip_pkt->ip_frag_off = 0; COPY_IP(ip_pkt->ip_dst, gHtonl(tmpbuf, dst_ip)); ip_pkt->ip_pkt_len = htons(size + ip_pkt->ip_hdr_len * 4); //printGPacket(pkt, 3, "IP_ROUTINE"); //for debug verbose(2, "[IPOutgoingPacket]:: lookup next hop "); // find the nexthop and interface and fill them in the "meta" frame // NOTE: the packet itself is not modified by this lookup! if (findRouteEntry(route_tbl, gNtohl(tmpbuf, ip_pkt->ip_dst), pkt->frame.nxth_ip_addr, &(pkt->frame.dst_interface)) == EXIT_FAILURE) { error("[IPOutgoingPacket]:: couldn't find route entry "); return EXIT_FAILURE; } verbose(2, "[IPOutgoingPacket]:: lookup MTU of nexthop"); // lookup the IP address of the destination interface.. if ((status = findInterfaceIP(MTU_tbl, pkt->frame.dst_interface, iface_ip_addr)) == EXIT_FAILURE) { error("[IPOutgoingPacket]:: couldn't find interface "); return EXIT_FAILURE; } // the outgoing packet should have the interface IP as source COPY_IP(ip_pkt->ip_src, gHtonl(tmpbuf, iface_ip_addr)); //if broadcast packet we set the address for 255.255.255.255 if(pkt->frame.bcast == TRUE) { //set broadcast IP = uchar bcast_ip[] = IP_BCAST_ADDR; COPY_IP(ip_pkt->ip_dst, gHtonl(tmpbuf, bcast_ip)); } verbose(2, "[IPOutgoingPacket]:: almost one processing the IP header."); } else { error("[IPOutgoingPacket]:: unknown outgoing packet action.. packet discarded "); return EXIT_FAILURE; } // compute the new checksum cksum = checksum((uchar *)ip_pkt, ip_pkt->ip_hdr_len*2); ip_pkt->ip_cksum = htons(cksum); pkt->data.header.prot = htons(IP_PROTOCOL); //FOR DEBUG if(src_prot == OSPF_PROTOCOL) //specific modifications for OSPF_PROTOCOL { ospfhdr_t *ospfhdr = (ospfhdr_t *)((uchar *)ip_pkt + ip_pkt->ip_hdr_len*4); if (ospfhdr->type == OSPF_LINK_STATUS_UPDATE && (COMPARE_IP(ospfhdr->ip_src, gHtonl(tmpbuf, iface_ip_addr))) == 0) { printGPacket(pkt, 3, "IP_ROUTINE"); verbose(2,"[DEBUG] Retransmission of LSA pkt, not broadcasting\n"); //return EXIT_SUCCESS; } } IPSend2Output(pkt); verbose(2, "[IPOutgoingPacket]:: IP packet sent to output queue.. "); return EXIT_SUCCESS; }