/* * 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); } }
int printIPPacket(gpacket_t *msg) { ip_packet_t *ip_pkt; char tmpbuf[MAX_TMPBUF_LEN]; int tos; ip_pkt = (ip_packet_t *)msg->data.data; printf("IP: ----- IP Header -----\n"); printf("IP: Version : %d\n", ip_pkt->ip_version); printf("IP: Header Length : %d Bytes\n", ip_pkt->ip_hdr_len*4); printf("IP: Total Length : %d Bytes\n", ntohs(ip_pkt->ip_pkt_len)); printf("IP: Type of Service: 0x%02X\n", ip_pkt->ip_tos); printf("IP: xxx. .... = 0x%02X (Precedence)\n", IPTOS_PREC(ip_pkt->ip_tos)); tos = IPTOS_TOS(ip_pkt->ip_tos); if (tos == IPTOS_LOWDELAY) printf("IP: ...1 .... = Minimize Delay\n"); else printf("IP: ...0 .... = Normal Delay\n"); if (tos == IPTOS_THROUGHPUT) printf("IP: .... 1... = Maximize Throughput\n"); else printf("IP: .... 0... = Normal Throughput\n"); if (tos == IPTOS_RELIABILITY) printf("IP: .... .1.. = Maximize Reliability\n"); else printf("IP: .... .0.. = Normal Reliability\n"); if (tos == IPTOS_MINCOST) printf("IP: .... ..1. = Minimize Cost\n"); else printf("IP: .... ..0. = Normal Cost\n"); printf("IP: Identification : %d\n", ntohs(ip_pkt->ip_identifier)); printf("IP: Flags : 0x%02X\n", ((ntohs(ip_pkt->ip_frag_off) & ~IP_OFFMASK)>>13)); if ((ntohs(ip_pkt->ip_frag_off) & IP_DF) == IP_DF) printf("IP: .1.. .... = do not fragment\n"); else printf("IP: .0.. .... = can fragment\n"); if ((ntohs(ip_pkt->ip_frag_off) & IP_MF) == IP_MF) printf("IP: ..1. .... = more fragment\n"); else printf("IP: ..0. .... = last fragment\n"); printf("IP: Fragment Offset: %d Bytes\n", (ntohs(ip_pkt->ip_frag_off) & IP_OFFMASK)); printf("IP: Time to Live : %d sec/hops\n", ip_pkt->ip_ttl); printf("IP: Protocol : %d", ip_pkt->ip_prot); printf("IP: Checksum : 0x%X\n", ntohs(ip_pkt->ip_cksum)); printf("IP: Source : %s", IP2Dot(tmpbuf, gNtohl((tmpbuf+20), ip_pkt->ip_src))); printf("IP: Destination : %s", IP2Dot(tmpbuf, gNtohl((tmpbuf+20), ip_pkt->ip_dst))); return ip_pkt->ip_prot; }
void printARPPacket(gpacket_t *msg) { arp_packet_t *apkt; char tmpbuf[MAX_TMPBUF_LEN]; apkt = (arp_packet_t *) msg->data.data; printf(" ARP hardware addr type %x \n", ntohs(apkt->hw_addr_type)); printf(" ARP protocol %x \n", ntohs(apkt->arp_prot)); printf(" ARP hardware addr len %d \n", apkt->hw_addr_len); printf(" ARP protocol len %d \n", apkt->arp_prot_len); printf(" ARP opcode %x \n", ntohs(apkt->arp_opcode)); printf(" ARP src hw addr %s \n", MAC2Colon(tmpbuf, apkt->src_hw_addr)); printf(" ARP src ip addr %s \n", IP2Dot(tmpbuf, gNtohl((uchar *)tmpbuf, apkt->src_ip_addr))); printf(" ARP dst hw addr %s \n", MAC2Colon(tmpbuf, apkt->dst_hw_addr)); printf(" ARP dst ip addr %s \n", IP2Dot(tmpbuf, gNtohl((uchar *)tmpbuf, apkt->dst_ip_addr))); }
/* * check for redirection condition. This function always returns * success. That is no matter whether redirection was sent or not * it returns success! */ int IPCheck4Redirection(gpacket_t *in_pkt) { char tmpbuf[MAX_TMPBUF_LEN]; gpacket_t *cp_pkt; ip_packet_t *ip_pkt = (ip_packet_t *)in_pkt->data.data; // check for redirect condition and send an ICMP back... let the current packet // go as well (check the specification??) if (isInSameNetwork(gNtohl(tmpbuf, ip_pkt->ip_src), in_pkt->frame.nxth_ip_addr) == EXIT_SUCCESS) { verbose(2, "[processIPErrors]:: redirect message sent on packet from %s", IP2Dot(tmpbuf, gNtohl((tmpbuf+20), ip_pkt->ip_src))); cp_pkt = duplicatePacket(in_pkt); ICMPProcessRedirect(cp_pkt, cp_pkt->frame.nxth_ip_addr); } // IP packet is verified to be good. This packet should be // further processed to carry out forwarding. return EXIT_SUCCESS; }
/* * check whether the IP packet has correct checksum and * version number... this router is hard coded for IP version 4! * NOTE: we don't send any ICMP error messages to the source - instead * we silently drop the packet. It seems (should check carefully) that * ICMP does not have a facility to report this kind of condition. * May be this condition is not likely to happen??? */ int IPVerifyPacket(ip_packet_t *ip_pkt) { char tmpbuf[MAX_TMPBUF_LEN]; int hdr_len = ip_pkt->ip_hdr_len; // verify the header checksum if (checksum((void *)ip_pkt, hdr_len *2) != 0) { verbose(2, "[IPVerifyPacket]:: packet from %s failed checksum, packet thrown", IP2Dot(tmpbuf, gNtohl((tmpbuf+20), ip_pkt->ip_src))); return EXIT_FAILURE; } // Check correct IP version if (ip_pkt->ip_version != 4) { verbose(2, "[IPVerifyPacket]:: from %s failed checksum, packet thrown", IP2Dot(tmpbuf, gNtohl((tmpbuf + 20), ip_pkt->ip_src))); return EXIT_FAILURE; } return EXIT_SUCCESS; }
int IPCheck4Errors(gpacket_t *in_pkt) { char tmpbuf[MAX_TMPBUF_LEN]; ip_packet_t *ip_pkt = (ip_packet_t *)in_pkt->data.data; // check for valid version and checksum.. silently drop the packet if not. if (IPVerifyPacket(ip_pkt) == EXIT_FAILURE) return EXIT_FAILURE; // Decrement TTL, if TTL <= 0, send to ICMP module with TTL-expired command // return EXIT_FAILURE if (--ip_pkt->ip_ttl <= 0) { verbose(2, "[processIPErrors]:: TTL expired on packet from %s", IP2Dot(tmpbuf, gNtohl((tmpbuf+20), ip_pkt->ip_src))); ICMPProcessTTLExpired(in_pkt); return EXIT_FAILURE; } return EXIT_SUCCESS; }
/* * 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; }
/* * 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; }
/* * process an IP packet destined to someone else... * ARGUMENT: in_pkt - pointer to incoming packet * * Error processing: Check for conditions that generate ICMP packets. * For example, TTL expired, redirect, mulformed packets, ... * DF set and fragment,.. etc. * * Fragment processing: Check whether fragment is necessary .. condition already checked. * * Forward packet and fragments (could be multicasting) */ int IPProcessForwardingPacket(gpacket_t *in_pkt) { gpacket_t *pkt_frags[MAX_FRAGMENTS]; ip_packet_t *ip_pkt = (ip_packet_t *)in_pkt->data.data; int num_frags, i, need_frag; char tmpbuf[MAX_TMPBUF_LEN]; verbose(2, "[IPProcessForwardingPacket]:: checking for any IP errors.."); // all the validation and ICMP generation, processing is // done in this function... if (IPCheck4Errors(in_pkt) == EXIT_FAILURE) return EXIT_FAILURE; // find the route... if it does not exist, should we send a // ICMP network/host unreachable message -- CHECK?? if (findRouteEntry(route_tbl, gNtohl(tmpbuf, ip_pkt->ip_dst), in_pkt->frame.nxth_ip_addr, &(in_pkt->frame.dst_interface)) == EXIT_FAILURE) return EXIT_FAILURE; // check for redirection?? -- the output interface is already found // by the previous command.. if needed the following routine sends the // redirects but the packet is sent to destination.. // TODO: Check the RFC for conformance?? IPCheck4Redirection(in_pkt); // check for fragmentation -- this should return three conditions: // FRAGS_NONE, FRAGS_ERROR, MORE_FRAGS need_frag = IPCheck4Fragmentation(in_pkt); switch (need_frag) { case FRAGS_NONE: verbose(2, "[IPProcessForwardingPacket]:: sending packet to GNET.."); // compute the checksum before sending out.. the fragmentation routine does this inside it. ip_pkt->ip_cksum = 0; ip_pkt->ip_cksum = htons(checksum((uchar *)ip_pkt, ip_pkt->ip_hdr_len *2)); if (IPSend2Output(in_pkt) == EXIT_FAILURE) { verbose(1, "[IPProcessForwardingPacket]:: WARNING: IPProcessForwardingPacket(): Could not forward packets "); return EXIT_FAILURE; } break; case FRAGS_ERROR: verbose(2, "[IPProcessForwardingPacket]:: unreachable on packet from %s", IP2Dot(tmpbuf, gNtohl((tmpbuf+20), ip_pkt->ip_src))); ICMPProcessFragNeeded(in_pkt); break; case MORE_FRAGS: // fragment processing... num_frags = fragmentIPPacket(in_pkt, pkt_frags); verbose(2, "[IPProcessForwardingPacket]:: IP packet needs fragmentation"); // forward each fragment for (i = 0; i < num_frags; i++) { if (IPSend2Output(pkt_frags[i]) == EXIT_FAILURE) { verbose(1, "[IPProcessForwardingPacket]:: processForwardIPPacket(): Could not forward packets "); return EXIT_FAILURE; } } deallocateFragments(pkt_frags, num_frags); break; default: return EXIT_FAILURE; } return EXIT_SUCCESS; }
/* * 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) { 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); 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) 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) return EXIT_FAILURE; // the outgoing packet should have the interface IP as source COPY_IP(ip_pkt->ip_src, gHtonl(tmpbuf, iface_ip_addr)); 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); IPSend2Output(pkt); verbose(2, "[IPOutgoingPacket]:: IP packet sent to output queue.. "); return EXIT_SUCCESS; }