/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** * Copyright (c) 2017 Alexander Afanasyev * * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program. * If not, see . */ #include "simple-router.hpp" #include "core/utils.hpp" #include namespace simple_router { ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // IMPLEMENT THIS METHOD void SimpleRouter::sendArpReply(const uint32_t &src_ip, const uint32_t &dest_ip, const Buffer &src_mac, const Buffer &dest_mac, std::string ifName){ Buffer* req_packet = new Buffer(sizeof(ethernet_hdr) + sizeof(arp_hdr)); unsigned char *data = req_packet->data(); // ethernet FF:FF:FF:FF:FF:FF,注意均为大端 ethernet_hdr *ethernet = (ethernet_hdr *)data; memcpy(ethernet->ether_shost, src_mac.data(), sizeof(src_mac.size())); memcpy(ethernet->ether_dhost, dest_mac.data(), sizeof(dest_mac.size())); ethernet->ether_type = htons(ethertype_arp); // arp arp_hdr *arp = (arp_hdr *)(data + sizeof(ethernet_hdr)); arp->arp_hrd = htons(arp_hrd_ethernet); // 0x0001 arp->arp_pro = htons(ethertype_ip); // 0x0800 arp->arp_hln = 0x06; arp->arp_pln = 0x04; arp->arp_op = htons(arp_op_reply); memcpy(arp->arp_sha, src_mac.data(), ETHER_ADDR_LEN); arp->arp_sip = src_ip; memcpy(arp->arp_tha, dest_mac.data(), ETHER_ADDR_LEN); arp->arp_tip = dest_ip; std::cout<<"send to "<data(); ethernet_hdr *eth = (ethernet_hdr*)data; ip_hdr *ip = (ip_hdr *)(data + sizeof(ethernet_hdr)); memcpy(eth->ether_shost, (interface->addr).data(), ETHER_ADDR_LEN); memcpy(eth->ether_dhost, dst_mac.data(), ETHER_ADDR_LEN); ip->ip_ttl--; ip->ip_sum = 0; ip->ip_sum = cksum(ip, sizeof(ip_hdr)); sendPacket(*forward_pkt, interface->name); std::cout<<"send ipv4 to:" <ip_dst)<<" via: "<name<data(); ethernet_hdr *eth = (ethernet_hdr*)data; ip_hdr *ip = (ip_hdr *)(data + sizeof(ethernet_hdr)); icmp_hdr *icmp = (icmp_hdr *)(data + sizeof(ethernet_hdr) + sizeof(ip_hdr)); ethernet_hdr *origin_eth = (ethernet_hdr *)(packet.data()); ip_hdr *origin_ip = (ip_hdr *)(packet.data() + sizeof(ethernet_hdr)); // 修改以太帧 memcpy(eth->ether_dhost, origin_eth->ether_shost, ETHER_ADDR_LEN); memcpy(eth->ether_shost, origin_eth->ether_dhost, ETHER_ADDR_LEN); // 修改IPv4 ip->ip_id = 0; ip->ip_ttl = 0x40; ip->ip_dst = origin_ip->ip_src; ip->ip_src = origin_ip->ip_dst; ip->ip_sum = 0; ip->ip_sum = cksum((uint8_t*)ip, sizeof(ip_hdr)); // 修改ICMP icmp->icmp_code = 0x00; icmp->icmp_type = 0x00; icmp->icmp_sum = 0; int icmp_length = packet.size() - sizeof(ip_hdr) - sizeof(ethernet_hdr); icmp->icmp_sum = cksum((uint8_t *)icmp, icmp_length); sendPacket(*reply_pkt, ifName); std::cout<<"send icmp to:" <ip_dst)<ether_type); Buffer src_mac(ETHER_ADDR_LEN); memcpy(src_mac.data(), ethernet->ether_dhost, ETHER_ADDR_LEN); Buffer dst_mac(ETHER_ADDR_LEN); memcpy(dst_mac.data(), ethernet->ether_shost, ETHER_ADDR_LEN); // arp if (eth_type == ethertype_arp) { arp_hdr *arp = (arp_hdr *)(data + sizeof(ethernet_hdr)); uint16_t arp_type = ntohs(arp->arp_op); // 如果是arp request if (arp_type == arp_op_request){ if (arp->arp_tip == iface->ip){ std::cout << "receive arp request from " << ipToString(arp->arp_sip) << std::endl; sendArpReply(arp->arp_tip, arp->arp_sip, iface->addr, src_mac, inIface); } } // 如果是arp reply else if (arp_type == arp_op_reply){ std::cout << "receive arp reply from " << macToString(src_mac) << std::endl; // if not exists in arp cache, update if (!m_arp.lookup(arp->arp_sip)){ auto request = m_arp.insertArpEntry(dst_mac, arp->arp_sip); if (!request)return; // handle pending packets for (auto &pending_packet:request->packets){ handlePacket(pending_packet.packet, pending_packet.iface); } m_arp.removeRequest(request); } } } //ipv4 else if (eth_type == ethertype_ip){ ip_hdr *ip = (ip_hdr *)(data + sizeof(ethernet_hdr)); std::cout << "receive ipv4 from " << ipToString(ip->ip_src) << std::endl; // cksum uint16_t sum = cksum(ip, sizeof(ip_hdr)); if (sum != 0xffff){ std::cerr << "cksum error" << std::endl; return; } // if destination is router if (findIfaceByIp(ip->ip_dst)){ // if protocol is icmp if (ip->ip_p == ip_protocol_icmp) { ip_hdr *origin_ip = (ip_hdr *)(packet.data() + sizeof(ethernet_hdr)); uint32_t src_ip = origin_ip->ip_src; auto entry = m_arp.lookup(src_ip); if(!entry){ m_arp.queueRequest(src_ip, packet, inIface); return; } sendICMP(packet, inIface); } // if protocol is not icmp (e.g. tcp or udp) else{ ip_hdr *origin_ip = (ip_hdr *)(packet.data() + sizeof(ethernet_hdr)); uint32_t src_ip = origin_ip->ip_src; auto entry = m_arp.lookup(src_ip); if(!entry){ m_arp.queueRequest(src_ip, packet, inIface); return; } sendICMPt3(PendingPacket({packet, inIface}), 3, 3); } } // if destination is not router else{ // if time out, send ICMP type3 if (ip->ip_ttl == 1){ ip_hdr *origin_ip = (ip_hdr *)(packet.data() + sizeof(ethernet_hdr)); uint32_t src_ip = origin_ip->ip_src; auto entry = m_arp.lookup(src_ip); if(!entry){ m_arp.queueRequest(src_ip, packet, inIface); return; } sendICMPt3(PendingPacket({packet, inIface}), 11, 0); } // if not timeout, forward packet else { RoutingTableEntry forwardEntry = m_routingTable.lookup(ip->ip_dst); std::string outInterfaceName = forwardEntry.ifName; const Interface * outInterface = findIfaceByName(outInterfaceName); auto arpEntry = m_arp.lookup(ip->ip_dst); if (!arpEntry) { m_arp.queueRequest(ip->ip_dst, packet, inIface); return; } sendIpv4(packet, outInterface, arpEntry->mac); } } } } void SimpleRouter::sendICMPt3(const PendingPacket &pendingPacket, uint8_t type, uint8_t code){ std::cout<<"send icmp t3" <data(); // get MAC ip_hdr *origin_ip = (ip_hdr *)(packet.data() + sizeof(ethernet_hdr)); uint32_t dest_ip = origin_ip->ip_src; auto entry = m_arp.lookup(dest_ip); Buffer mac = Buffer(entry->mac); // ethernet ethernet_hdr *ethernet = (ethernet_hdr *)data; memcpy(ethernet->ether_shost, If->addr.data(), ETHER_ADDR_LEN); memcpy(ethernet->ether_dhost, mac.data(), ETHER_ADDR_LEN); ethernet->ether_type = htons(ethertype_ip); // ipv4 ip_hdr *ip = (ip_hdr *)(data + sizeof(ethernet_hdr)); ip->ip_v = 0x04; ip->ip_hl = 0x05; ip->ip_tos = 0x00; ip->ip_len = htons(sizeof(icmp_t3_hdr) + sizeof(ip_hdr)); ip->ip_id = (uint16_t)rand(); ip->ip_off = htons(IP_DF); ip->ip_ttl = 0x40; // 64 ip->ip_p = ip_protocol_icmp; ip->ip_sum = 0; ip->ip_src = If->ip; ip->ip_dst = origin_ip->ip_src; ip->ip_sum = cksum((const void *)ip, sizeof(ip_hdr)); // icmp type 3 icmp_t3_hdr *icmp = (icmp_t3_hdr *)(data + sizeof(ethernet_hdr) + sizeof(ip_hdr)); icmp->icmp_type = type; icmp->icmp_code = code; icmp->icmp_sum = 0; icmp->unused = 0; icmp->next_mtu = 0; memcpy(icmp->data, origin_ip, ICMP_DATA_SIZE); icmp->icmp_sum = cksum((const void *)icmp, sizeof(icmp_t3_hdr)); sendPacket(*send_packet, IfName); } void SimpleRouter::sendICMPt3NonExisting(const PendingPacket &pendingPacket, uint8_t type, uint8_t code){ auto packet = pendingPacket.packet; std::string IfName = pendingPacket.iface; const Interface* If = findIfaceByName(IfName); Buffer *send_packet = new Buffer(sizeof(ethernet_hdr) + sizeof(ip_hdr) + sizeof(icmp_t3_hdr)); uint8_t *data = send_packet->data(); // get MAC ip_hdr *origin_ip = (ip_hdr *)(packet.data() + sizeof(ethernet_hdr)); uint32_t dest_ip = origin_ip->ip_src; std::cerr << "Unreachable Host:"<ip_dst) <mac; // ethernet ethernet_hdr *ethernet = (ethernet_hdr *)data; memcpy(ethernet->ether_shost, If->addr.data(), ETHER_ADDR_LEN); memcpy(ethernet->ether_dhost, mac.data(), ETHER_ADDR_LEN); ethernet->ether_type = htons(ethertype_ip); // ipv4 ip_hdr *ip = (ip_hdr *)(data + sizeof(ethernet_hdr)); ip->ip_v = 0x04; ip->ip_hl = 0x05; ip->ip_tos = 0x00; ip->ip_len = htons(sizeof(icmp_t3_hdr) + sizeof(ip_hdr)); ip->ip_id = (uint16_t)rand(); ip->ip_off = htons(IP_DF); ip->ip_ttl = 0x40; // 64 ip->ip_p = ip_protocol_icmp; ip->ip_sum = 0; ip->ip_src = If->ip; ip->ip_dst = origin_ip->ip_src; ip->ip_sum = cksum((const void *)ip, sizeof(ip_hdr)); // icmp type 3 icmp_t3_hdr *icmp = (icmp_t3_hdr *)(data + sizeof(ethernet_hdr) + sizeof(ip_hdr)); icmp->icmp_type = type; icmp->icmp_code = code; icmp->icmp_sum = 0; icmp->unused = 0; icmp->next_mtu = 0; memcpy(icmp->data, origin_ip, ICMP_DATA_SIZE); icmp->icmp_sum = cksum((const void *)icmp, sizeof(icmp_t3_hdr)); if(!entry) m_arp.queueRequestWithoutLock(origin_ip->ip_src, *send_packet, IfName); else sendPacket(*send_packet, IfName); } void SimpleRouter::sendArpRequest(const uint32_t &dest_ip){ std::cout<<"send arp request to "<data(); // get interface / addr / ip std::string ifName = m_routingTable.lookup(dest_ip).ifName; const Interface *If = findIfaceByName(ifName); Buffer IfAddr = If->addr; uint32_t IfIp = If->ip; // ethernet FF:FF:FF:FF:FF:FF,注意均为大端 ethernet_hdr *ethernet = (ethernet_hdr *)data; memcpy(ethernet->ether_shost, IfAddr.data(), sizeof(IfAddr.size())); memset(ethernet->ether_dhost, 0xff, sizeof(ethernet->ether_shost)); ethernet->ether_type = htons(ethertype_arp); // arp arp_hdr *arp = (arp_hdr *)(data + sizeof(ethernet_hdr)); arp->arp_hrd = htons(arp_hrd_ethernet); // 0x0001 arp->arp_pro = htons(ethertype_ip); // 0x0800 arp->arp_hln = 0x06; arp->arp_pln = 0x04; arp->arp_op = htons(arp_op_request); memcpy(arp->arp_sha, IfAddr.data(), ETHER_ADDR_LEN); arp->arp_sip = IfIp; memset(arp->arp_tha, 0xff, ETHER_ADDR_LEN); arp->arp_tip = dest_ip; sendPacket(*req_packet, ifName); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // You should not need to touch the rest of this code. SimpleRouter::SimpleRouter() : m_arp(*this) { } void SimpleRouter::sendPacket(const Buffer& packet, const std::string& outIface) { m_pox->begin_sendPacket(packet, outIface); } bool SimpleRouter::loadRoutingTable(const std::string& rtConfig) { return m_routingTable.load(rtConfig); } void SimpleRouter::loadIfconfig(const std::string& ifconfig) { std::ifstream iff(ifconfig.c_str()); std::string line; while (std::getline(iff, line)) { std::istringstream ifLine(line); std::string iface, ip; ifLine >> iface >> ip; in_addr ip_addr; if (inet_aton(ip.c_str(), &ip_addr) == 0) { throw std::runtime_error("Invalid IP address `" + ip + "` for interface `" + iface + "`"); } m_ifNameToIpMap[iface] = ip_addr.s_addr; } } void SimpleRouter::printIfaces(std::ostream& os) { if (m_ifaces.empty()) { os << " Interface list empty " << std::endl; return; } for (const auto& iface : m_ifaces) { os << iface << "\n"; } os.flush(); } const Interface* SimpleRouter::findIfaceByIp(uint32_t ip) const { auto iface = std::find_if(m_ifaces.begin(), m_ifaces.end(), [ip] (const Interface& iface) { return iface.ip == ip; }); if (iface == m_ifaces.end()) { return nullptr; } return &*iface; } const Interface* SimpleRouter::findIfaceByMac(const Buffer& mac) const { auto iface = std::find_if(m_ifaces.begin(), m_ifaces.end(), [mac] (const Interface& iface) { return iface.addr == mac; }); if (iface == m_ifaces.end()) { return nullptr; } return &*iface; } const Interface* SimpleRouter::findIfaceByName(const std::string& name) const { auto iface = std::find_if(m_ifaces.begin(), m_ifaces.end(), [name] (const Interface& iface) { return iface.name == name; }); if (iface == m_ifaces.end()) { return nullptr; } return &*iface; } void SimpleRouter::reset(const pox::Ifaces& ports) { std::cerr << "Resetting SimpleRouter with " << ports.size() << " ports" << std::endl; m_arp.clear(); m_ifaces.clear(); for (const auto& iface : ports) { auto ip = m_ifNameToIpMap.find(iface.name); if (ip == m_ifNameToIpMap.end()) { std::cerr << "IP_CONFIG missing information about interface `" + iface.name + "`. Skipping it" << std::endl; continue; } m_ifaces.insert(Interface(iface.name, iface.mac, ip->second)); } printIfaces(std::cerr); } } // namespace simple_router {