From 71f73e92b44e0b6c3b8674df189579f27662389d Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Fri, 7 Jul 2017 23:21:20 +0200 Subject: [PATCH] internet-apps: DHCPv4 application Special thanks to: - Radu Lupu - Ankit Deepak - Deepti Rajagopal - Mohit P. Tahiliani --- .gitignore | 2 + AUTHORS | 2 + src/internet-apps/doc/internet-apps.rst | 85 +++- src/internet-apps/examples/dhcp-example.cc | 162 +++++++ src/internet-apps/examples/wscript | 8 + src/internet-apps/helper/dhcp-helper.cc | 220 +++++++++ src/internet-apps/helper/dhcp-helper.h | 118 +++++ src/internet-apps/model/dhcp-client.cc | 506 ++++++++++++++++++++ src/internet-apps/model/dhcp-client.h | 195 ++++++++ src/internet-apps/model/dhcp-header.cc | 517 +++++++++++++++++++++ src/internet-apps/model/dhcp-header.h | 322 +++++++++++++ src/internet-apps/model/dhcp-server.cc | 421 +++++++++++++++++ src/internet-apps/model/dhcp-server.h | 147 ++++++ src/internet-apps/test/dhcp-test.cc | 162 +++++++ src/internet-apps/wscript | 15 + src/internet/doc/ipv4.rst | 83 ++++ src/internet/doc/ipv6.rst | 2 +- 17 files changed, 2955 insertions(+), 12 deletions(-) create mode 100644 src/internet-apps/examples/dhcp-example.cc create mode 100644 src/internet-apps/examples/wscript create mode 100644 src/internet-apps/helper/dhcp-helper.cc create mode 100644 src/internet-apps/helper/dhcp-helper.h create mode 100644 src/internet-apps/model/dhcp-client.cc create mode 100644 src/internet-apps/model/dhcp-client.h create mode 100644 src/internet-apps/model/dhcp-header.cc create mode 100644 src/internet-apps/model/dhcp-header.h create mode 100644 src/internet-apps/model/dhcp-server.cc create mode 100644 src/internet-apps/model/dhcp-server.h create mode 100644 src/internet-apps/test/dhcp-test.cc diff --git a/.gitignore b/.gitignore index 5165012ca..1ac66b755 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ TAGS build-dir/ build/ +/.cproject +/.project diff --git a/AUTHORS b/AUTHORS index e937ee6a5..7799cc7b4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -99,6 +99,7 @@ Björn Lichtblau (lichtbla@informatik.hu-berlin.de) Timo Lindhorst (tlnd@online.de) Erwan Livolant (erwan.livolant@inria.fr) Andrea Lupia (alupia@dimes.unical.it) +Radu Lupu Keith Ma (keith.nwsuaf@gmail.com) Federico Maguolo (maguolof@dei.unipd.it) Antti Makela (zarhan@cc.hut.fi) @@ -144,6 +145,7 @@ Ovidiu Poncea (ovidiu.poncea@cs.pub.ro) Vikas Pushkar (vikaskupushkar@gmail.com) Andrea Ranieri (andreran@uno.it) Bruno Ranieri (Yrrsinn@googlemail.com) +Deepti Rajagopal Varun Reddy (varunamarreddy@gmail.com) Ken Renard (kenneth.renard@arl.army.mil) Manuel Requena (mrequena@cttc.es) diff --git a/src/internet-apps/doc/internet-apps.rst b/src/internet-apps/doc/internet-apps.rst index a2776507a..722266163 100644 --- a/src/internet-apps/doc/internet-apps.rst +++ b/src/internet-apps/doc/internet-apps.rst @@ -14,16 +14,18 @@ The goal of this module is to hold all the Internet-specific applications, and most notably some very specific applications (e.g., ping) or daemons (e.g., radvd). Other non-Internet-specific applications such as packet generators are contained in other modules. -Model Description -***************** - The source code for the new module lives in the directory ``src/internet-apps``. Each application has its own goals, limitations and scope, which are briefly explained in the following. +All the applications are extensively used in the top-level ``examples`` +directories. The users are encouraged to check the scripts therein to have a +clear overview of the various options and usage tricks. + + V4Ping -====== +****** This app mimics a "ping" (ICMP Echo) using IPv4. The application allows the following attributes to be set: @@ -36,7 +38,7 @@ following attributes to be set: Moreover, the user can access the measured rtt value (as a Traced Source). Ping6 -===== +***** This app mimics a "ping" (ICMP Echo) using IPv6. The application allows the following attributes to be set: @@ -48,16 +50,77 @@ following attributes to be set: * Max number of packets to send Radvd -===== +***** This app mimics a "RADVD" daemon. I.e., the daemon responsible for IPv6 routers advertisements. All the IPv6 routers should have a RADVD daemon installed. The configuration of the Radvd application mimics the one of the radvd Linux program. -Examples and use -**************** +DHCPv4 +****** + +The |ns3| implementation of Dynamic Host Configuration Protocol (DHCP) +follows the specifications of :rfc:`2131` and :rfc:`2132`. + +The source code for DHCP is located in ``src/internet-apps/model`` and consists of the +following 6 files: + +* dhcp-server.h, +* dhcp-server.cc, +* dhcp-client.h, +* dhcp-client.cc, +* dhcp-header.h and +* dhcp-header.cc + +Helpers +======= + +The following two files have been added to ``src/internet-apps/helper`` for DHCP: + +* dhcp-helper.h and +* dhcp-helper.cc + +Tests +===== +The tests for DHCP can be found at ``src/internet-apps/test/dhcp-test.cc`` + +Examples +======== +The examples for DHCP can be found at ``src/internet-apps/examples/dhcp-example.cc`` + + +Scope and Limitations +===================== + +The server should be provided with a network address, mask and a range of address +for the pool. One client application can be installed on only one netdevice in a +node, and can configure address for only that netdevice. + +The following five basic DHCP messages are supported: + +* DHCP DISCOVER +* DHCP OFFER +* DHCP REQUEST +* DHCP ACK +* DHCP NACK + +Also, the following eight options of BootP are supported: + +* 1 (Mask) +* 50 (Requested Address) +* 51 (Address Lease Time) +* 53 (DHCP message type) +* 54 (DHCP server identifier) +* 58 (Address renew time) +* 59 (Address rebind time) +* 255 (end) + +The client identifier option (61) can be implemented in near future. + +In the current implementation, a DHCP client can obtain IPv4 address dynamically +from the DHCP server, and can renew it within a lease time period. + +Multiple DHCP servers can be configured, but the implementation does not support +the use of a DHCP Relay yet. -All the applications are extensively used in the top-level ``examples`` -directories. The users are encouraged to check the scripts therein to have a -clear overview of the various options and usage tricks. diff --git a/src/internet-apps/examples/dhcp-example.cc b/src/internet-apps/examples/dhcp-example.cc new file mode 100644 index 000000000..1516aea31 --- /dev/null +++ b/src/internet-apps/examples/dhcp-example.cc @@ -0,0 +1,162 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 UPB + * Copyright (c) 2017 NITK Surathkal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Radu Lupu + * Ankit Deepak + * Deepti Rajagopal + * + */ + +#include +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/internet-apps-module.h" +#include "ns3/csma-module.h" +#include "ns3/internet-module.h" +#include "ns3/point-to-point-module.h" +#include "ns3/applications-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("DhcpExample"); + +int +main (int argc, char *argv[]) +{ + CommandLine cmd; + + bool verbose = false; + bool tracing = false; + cmd.AddValue ("verbose", "turn on the logs", verbose); + cmd.AddValue ("tracing", "turn on the tracing", tracing); + + cmd.Parse (argc, argv); + + // GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true)); + + if (verbose) + { + LogComponentEnable ("DhcpServer", LOG_LEVEL_ALL); + LogComponentEnable ("DhcpClient", LOG_LEVEL_ALL); + LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO); + LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO); + } + + Time stopTime = Seconds (20); + + NS_LOG_INFO ("Create nodes."); + NodeContainer nodes; + NodeContainer router; + nodes.Create (3); + router.Create (2); + + NodeContainer net (nodes, router); + + NS_LOG_INFO ("Create channels."); + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", StringValue ("5Mbps")); + csma.SetChannelAttribute ("Delay", StringValue ("2ms")); + csma.SetDeviceAttribute ("Mtu", UintegerValue (1500)); + NetDeviceContainer devNet = csma.Install (net); + + NodeContainer p2pNodes; + p2pNodes.Add (net.Get (4)); + p2pNodes.Create (1); + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NetDeviceContainer p2pDevices; + p2pDevices = pointToPoint.Install (p2pNodes); + + InternetStackHelper tcpip; + tcpip.Install (nodes); + tcpip.Install (router); + tcpip.Install (p2pNodes.Get (1)); + + Ipv4AddressHelper address; + address.SetBase ("172.30.1.0", "255.255.255.0"); + Ipv4InterfaceContainer p2pInterfaces; + p2pInterfaces = address.Assign (p2pDevices); + + // manually add a routing entry because we don't want to add a dynamic routing + Ipv4StaticRoutingHelper ipv4RoutingHelper; + Ptr ipv4Ptr = p2pNodes.Get (1)->GetObject (); + Ptr staticRoutingA = ipv4RoutingHelper.GetStaticRouting (ipv4Ptr); + staticRoutingA->AddNetworkRouteTo (Ipv4Address ("172.30.0.0"), Ipv4Mask ("/24"), + Ipv4Address ("172.30.1.1"), 1); + + NS_LOG_INFO ("Setup the IP addresses and create DHCP applications."); + DhcpHelper dhcpHelper; + + // The router must have a fixed IP. + Ipv4InterfaceContainer fixedNodes = dhcpHelper.InstallFixedAddress (devNet.Get (4), Ipv4Address ("172.30.0.17"), Ipv4Mask ("/24")); + // Not really necessary, IP forwarding is enabled by default in IPv4. + fixedNodes.Get (0).first->SetAttribute ("IpForward", BooleanValue (true)); + + // DHCP server + ApplicationContainer dhcpServerApp = dhcpHelper.InstallDhcpServer (devNet.Get (3), Ipv4Address ("172.30.0.12"), + Ipv4Address ("172.30.0.0"), Ipv4Mask ("/24"), + Ipv4Address ("172.30.0.10"), Ipv4Address ("172.30.0.15"), + Ipv4Address ("172.30.0.17")); + + // This is just to show how it can be done. + DynamicCast (dhcpServerApp.Get (0))->AddStaticDhcpEntry (devNet.Get (2)->GetAddress (), Ipv4Address ("172.30.0.14")); + + dhcpServerApp.Start (Seconds (0.0)); + dhcpServerApp.Stop (stopTime); + + // DHCP clients + NetDeviceContainer dhcpClientNetDevs; + dhcpClientNetDevs.Add (devNet.Get (0)); + dhcpClientNetDevs.Add (devNet.Get (1)); + dhcpClientNetDevs.Add (devNet.Get (2)); + + ApplicationContainer dhcpClients = dhcpHelper.InstallDhcpClient (dhcpClientNetDevs); + dhcpClients.Start (Seconds (1.0)); + dhcpClients.Stop (stopTime); + + UdpEchoServerHelper echoServer (9); + + ApplicationContainer serverApps = echoServer.Install (p2pNodes.Get (1)); + serverApps.Start (Seconds (0.0)); + serverApps.Stop (stopTime); + + UdpEchoClientHelper echoClient (p2pInterfaces.GetAddress (1), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (100)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = echoClient.Install (nodes.Get (1)); + clientApps.Start (Seconds (10.0)); + clientApps.Stop (stopTime); + + Simulator::Stop (stopTime + Seconds (10.0)); + + if (tracing) + { + csma.EnablePcapAll ("dhcp-csma"); + pointToPoint.EnablePcapAll ("dhcp-p2p"); + } + + NS_LOG_INFO ("Run Simulation."); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); +} diff --git a/src/internet-apps/examples/wscript b/src/internet-apps/examples/wscript new file mode 100644 index 000000000..fcf3fee0a --- /dev/null +++ b/src/internet-apps/examples/wscript @@ -0,0 +1,8 @@ +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + if not bld.env['ENABLE_EXAMPLES']: + return; + + obj = bld.create_ns3_program('dhcp-example', ['internet', 'internet-apps', 'csma', 'point-to-point', 'applications']) + obj.source = 'dhcp-example.cc' diff --git a/src/internet-apps/helper/dhcp-helper.cc b/src/internet-apps/helper/dhcp-helper.cc new file mode 100644 index 000000000..5860644f8 --- /dev/null +++ b/src/internet-apps/helper/dhcp-helper.cc @@ -0,0 +1,220 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 UPB + * Copyright (c) 2017 NITK Surathkal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Radu Lupu + * Ankit Deepak + * Deepti Rajagopal + * + */ + +#include "dhcp-helper.h" +#include "ns3/dhcp-server.h" +#include "ns3/dhcp-client.h" +#include "ns3/uinteger.h" +#include "ns3/names.h" +#include "ns3/ipv4.h" +#include "ns3/loopback-net-device.h" +#include "ns3/traffic-control-layer.h" +#include "ns3/traffic-control-helper.h" +#include "ns3/log.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("DhcpHelper"); + +DhcpHelper::DhcpHelper () +{ + m_clientFactory.SetTypeId (DhcpClient::GetTypeId ()); + m_serverFactory.SetTypeId (DhcpServer::GetTypeId ()); +} + +void DhcpHelper::SetClientAttribute ( + std::string name, + const AttributeValue &value) +{ + m_clientFactory.Set (name, value); +} + +void DhcpHelper::SetServerAttribute ( + std::string name, + const AttributeValue &value) +{ + m_serverFactory.Set (name, value); +} + +ApplicationContainer DhcpHelper::InstallDhcpClient (Ptr netDevice) const +{ + return ApplicationContainer (InstallDhcpClientPriv (netDevice)); +} + +ApplicationContainer DhcpHelper::InstallDhcpClient (NetDeviceContainer netDevices) const +{ + ApplicationContainer apps; + for (NetDeviceContainer::Iterator i = netDevices.Begin (); i != netDevices.End (); ++i) + { + apps.Add (InstallDhcpClientPriv (*i)); + } + return apps; +} + +Ptr DhcpHelper::InstallDhcpClientPriv (Ptr netDevice) const +{ + Ptr node = netDevice->GetNode (); + NS_ASSERT_MSG (node != 0, "DhcpClientHelper: NetDevice is not not associated with any node -> fail"); + + Ptr ipv4 = node->GetObject (); + NS_ASSERT_MSG (ipv4, "DhcpHelper: NetDevice is associated" + " with a node without IPv4 stack installed -> fail " + "(maybe need to use InternetStackHelper?)"); + + int32_t interface = ipv4->GetInterfaceForDevice (netDevice); + if (interface == -1) + { + interface = ipv4->AddInterface (netDevice); + } + NS_ASSERT_MSG (interface >= 0, "DhcpHelper: Interface index not found"); + + ipv4->SetMetric (interface, 1); + ipv4->SetUp (interface); + + // Install the default traffic control configuration if the traffic + // control layer has been aggregated, if this is not + // a loopback interface, and there is no queue disc installed already + Ptr tc = node->GetObject (); + if (tc && DynamicCast (netDevice) == 0 && tc->GetRootQueueDiscOnDevice (netDevice) == 0) + { + NS_LOG_LOGIC ("DhcpHelper - Installing default traffic control configuration"); + TrafficControlHelper tcHelper = TrafficControlHelper::Default (); + tcHelper.Install (netDevice); + } + + Ptr app = DynamicCast (m_clientFactory.Create ()); + app->SetDhcpClientNetDevice (netDevice); + node->AddApplication (app); + + return app; +} + +ApplicationContainer DhcpHelper::InstallDhcpServer (Ptr netDevice, Ipv4Address serverAddr, + Ipv4Address poolAddr, Ipv4Mask poolMask, + Ipv4Address minAddr, Ipv4Address maxAddr, + Ipv4Address gateway) +{ + m_serverFactory.Set ("PoolAddresses", Ipv4AddressValue (poolAddr)); + m_serverFactory.Set ("PoolMask", Ipv4MaskValue (poolMask)); + m_serverFactory.Set ("FirstAddress", Ipv4AddressValue (minAddr)); + m_serverFactory.Set ("LastAddress", Ipv4AddressValue (maxAddr)); + m_serverFactory.Set ("Gateway", Ipv4AddressValue (gateway)); + + Ptr node = netDevice->GetNode (); + NS_ASSERT_MSG (node != 0, "DhcpHelper: NetDevice is not not associated with any node -> fail"); + + Ptr ipv4 = node->GetObject (); + NS_ASSERT_MSG (ipv4, "DhcpHelper: NetDevice is associated" + " with a node without IPv4 stack installed -> fail " + "(maybe need to use InternetStackHelper?)"); + + int32_t interface = ipv4->GetInterfaceForDevice (netDevice); + if (interface == -1) + { + interface = ipv4->AddInterface (netDevice); + } + NS_ASSERT_MSG (interface >= 0, "DhcpHelper: Interface index not found"); + + Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (serverAddr, poolMask); + ipv4->AddAddress (interface, ipv4Addr); + ipv4->SetMetric (interface, 1); + ipv4->SetUp (interface); + + // Install the default traffic control configuration if the traffic + // control layer has been aggregated, if this is not + // a loopback interface, and there is no queue disc installed already + Ptr tc = node->GetObject (); + if (tc && DynamicCast (netDevice) == 0 && tc->GetRootQueueDiscOnDevice (netDevice) == 0) + { + NS_LOG_LOGIC ("DhcpHelper - Installing default traffic control configuration"); + TrafficControlHelper tcHelper = TrafficControlHelper::Default (); + tcHelper.Install (netDevice); + } + + // check that the already fixed addresses are not in conflict with the pool + std::list::iterator iter; + for (iter=m_fixedAddresses.begin (); iter!=m_fixedAddresses.end (); iter ++) + { + if (iter->Get () >= minAddr.Get () && iter->Get () <= maxAddr.Get ()) + { + NS_ABORT_MSG ("DhcpHelper: Fixed address can not conflict with a pool: " << *iter << " is in [" << minAddr << ", " << maxAddr << "]"); + } + } + m_addressPools.push_back (std::make_pair (minAddr, maxAddr)); + + Ptr app = m_serverFactory.Create (); + node->AddApplication (app); + return ApplicationContainer (app); +} + +Ipv4InterfaceContainer DhcpHelper::InstallFixedAddress (Ptr netDevice, Ipv4Address addr, Ipv4Mask mask) +{ + Ipv4InterfaceContainer retval; + + Ptr node = netDevice->GetNode (); + NS_ASSERT_MSG (node != 0, "DhcpHelper: NetDevice is not not associated with any node -> fail"); + + Ptr ipv4 = node->GetObject (); + NS_ASSERT_MSG (ipv4, "DhcpHelper: NetDevice is associated" + " with a node without IPv4 stack installed -> fail " + "(maybe need to use InternetStackHelper?)"); + + int32_t interface = ipv4->GetInterfaceForDevice (netDevice); + if (interface == -1) + { + interface = ipv4->AddInterface (netDevice); + } + NS_ASSERT_MSG (interface >= 0, "DhcpHelper: Interface index not found"); + + Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (addr, mask); + ipv4->AddAddress (interface, ipv4Addr); + ipv4->SetMetric (interface, 1); + ipv4->SetUp (interface); + retval.Add (ipv4, interface); + + // Install the default traffic control configuration if the traffic + // control layer has been aggregated, if this is not + // a loopback interface, and there is no queue disc installed already + Ptr tc = node->GetObject (); + if (tc && DynamicCast (netDevice) == 0 && tc->GetRootQueueDiscOnDevice (netDevice) == 0) + { + NS_LOG_LOGIC ("DhcpHelper - Installing default traffic control configuration"); + TrafficControlHelper tcHelper = TrafficControlHelper::Default (); + tcHelper.Install (netDevice); + } + + // check that the already fixed addresses are not in conflict with the pool + std::list >::iterator iter; + for (iter=m_addressPools.begin (); iter!=m_addressPools.end (); iter ++) + { + if (addr.Get () >= iter->first.Get () && addr.Get () <= iter->second.Get ()) + { + NS_ABORT_MSG ("DhcpHelper: Fixed address can not conflict with a pool: " << addr << " is in [" << iter->first << ", " << iter->second << "]"); + } + } + m_fixedAddresses.push_back (addr); + return retval; +} + +} // namespace ns3 diff --git a/src/internet-apps/helper/dhcp-helper.h b/src/internet-apps/helper/dhcp-helper.h new file mode 100644 index 000000000..7fbbe171c --- /dev/null +++ b/src/internet-apps/helper/dhcp-helper.h @@ -0,0 +1,118 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 UPB + * Copyright (c) 2017 NITK Surathkal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Radu Lupu + * Ankit Deepak + * Deepti Rajagopal + * + */ + +#ifndef DHCP_HELPER_H +#define DHCP_HELPER_H + +#include +#include "ns3/application-container.h" +#include "ns3/net-device-container.h" +#include "ns3/object-factory.h" +#include "ns3/ipv4-address.h" +#include "ns3/ipv4-interface-container.h" + +namespace ns3 { + +/** + * \ingroup dhcp + * + * \class DhcpHelper + * \brief The helper class used to configure and install DHCP applications on nodes + */ +class DhcpHelper +{ +public: + DhcpHelper (); + + /** + * \brief Set DHCP client attributes + * \param name Name of the attribute + * \param value Value to be set + */ + void SetClientAttribute (std::string name, const AttributeValue &value); + + /** + * \brief Set DHCP server attributes + * \param name Name of the attribute + * \param value Value to be set + */ + void SetServerAttribute (std::string name, const AttributeValue &value); + + /** + * \brief Install DHCP client of a nodes / NetDevice + * \param netDevice The NetDevice on which DHCP client application has to be installed + * \return The application container with DHCP client installed + */ + ApplicationContainer InstallDhcpClient (Ptr netDevice) const; + + /** + * \brief Install DHCP client of a set of nodes / NetDevices + * \param netDevices The NetDevices on which DHCP client application has to be installed + * \return The application container with DHCP client installed + */ + ApplicationContainer InstallDhcpClient (NetDeviceContainer netDevices) const; + + /** + * \brief Install DHCP server of a node / NetDevice + * + * Note: the server address must be coherent with the pool address, because + * DHCP relays are not yet supported. + * + * \param netDevice The NetDevice on which DHCP server application has to be installed + * \param serverAddr The Ipv4Address of the server + * \param poolAddr The Ipv4Address (network part) of the allocated pool + * \param poolMask The mask of the allocated pool + * \param minAddr The lower bound of the Ipv4Address pool + * \param maxAddr The upper bound of the Ipv4Address pool + * \param gateway The Ipv4Address of default gateway (optional) + * \return The application container with DHCP server installed + */ + ApplicationContainer InstallDhcpServer (Ptr netDevice, Ipv4Address serverAddr, + Ipv4Address poolAddr, Ipv4Mask poolMask, + Ipv4Address minAddr, Ipv4Address maxAddr, + Ipv4Address gateway = Ipv4Address ()); + /** + * \brief Assign a fixed IP addresses to a net device. + * \param netDevice The NetDevice on which the address has to be installed + * \param serverAddr The Ipv4Address + * \param poolMask The network mask + */ + Ipv4InterfaceContainer InstallFixedAddress (Ptr netDevice, Ipv4Address addr, Ipv4Mask mask); + +private: + /** + * \brief Function to install DHCP client on a node + * \param node The node on which DHCP client application has to be installed + * \return The pointer to the installed DHCP client + */ + Ptr InstallDhcpClientPriv (Ptr netDevice) const; + ObjectFactory m_clientFactory; //!< DHCP client factory + ObjectFactory m_serverFactory; //!< DHCP server factory + std::list m_fixedAddresses; //!< list of fixed addresses already allocated. + std::list< std::pair > m_addressPools; //!< list of address pools. +}; + +} // namespace ns3 + +#endif /* DHCP_HELPER_H */ diff --git a/src/internet-apps/model/dhcp-client.cc b/src/internet-apps/model/dhcp-client.cc new file mode 100644 index 000000000..ee2accfbb --- /dev/null +++ b/src/internet-apps/model/dhcp-client.cc @@ -0,0 +1,506 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 UPB + * Copyright (c) 2017 NITK Surathkal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Radu Lupu + * Ankit Deepak + * Deepti Rajagopal + * + * + */ + +#include +#include +#include + +#include "ns3/ipv4.h" +#include "ns3/log.h" +#include "ns3/double.h" +#include "ns3/ipv4-address.h" +#include "ns3/nstime.h" +#include "ns3/inet-socket-address.h" +#include "ns3/socket.h" +#include "ns3/simulator.h" +#include "ns3/socket-factory.h" +#include "ns3/packet.h" +#include "ns3/ipv4-static-routing-helper.h" +#include "ns3/uinteger.h" +#include "ns3/random-variable-stream.h" +#include "ns3/pointer.h" +#include "ns3/string.h" +#include "ns3/ipv4-routing-table-entry.h" +#include "dhcp-client.h" +#include "dhcp-header.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("DhcpClient"); +NS_OBJECT_ENSURE_REGISTERED (DhcpClient); + +TypeId +DhcpClient::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::DhcpClient") + .SetParent () + .AddConstructor () + .SetGroupName ("Internet-Apps") + .AddAttribute ("RTRS", "Time for retransmission of Discover message", + TimeValue (Seconds (5)), + MakeTimeAccessor (&DhcpClient::m_rtrs), + MakeTimeChecker ()) + .AddAttribute ("Collect", "Time for which offer collection starts", + TimeValue (Seconds (5)), + MakeTimeAccessor (&DhcpClient::m_collect), + MakeTimeChecker ()) + .AddAttribute ("ReRequest", "Time after which request will be resent to next server", + TimeValue (Seconds (10)), + MakeTimeAccessor (&DhcpClient::m_nextoffer), + MakeTimeChecker ()) + .AddAttribute ("Transactions", + "The possible value of transaction numbers ", + StringValue ("ns3::UniformRandomVariable[Min=0.0|Max=1000000.0]"), + MakePointerAccessor (&DhcpClient::m_ran), + MakePointerChecker ()) + .AddTraceSource ("NewLease", + "Get a NewLease", + MakeTraceSourceAccessor (&DhcpClient::m_newLease), + "ns3::Ipv4Address::TracedCallback") + .AddTraceSource ("ExpireLease", + "A lease expires", + MakeTraceSourceAccessor (&DhcpClient::m_expiry), + "ns3::Ipv4Address::TracedCallback"); + return tid; +} + +DhcpClient::DhcpClient () +{ + NS_LOG_FUNCTION_NOARGS (); + m_server = Ipv4Address::GetAny (); + m_socket = 0; + m_refreshEvent = EventId (); + m_requestEvent = EventId (); + m_discoverEvent = EventId (); + m_rebindEvent = EventId (); + m_nextOfferEvent = EventId (); + m_timeout = EventId (); +} + +DhcpClient::DhcpClient (Ptr netDevice) +{ + NS_LOG_FUNCTION_NOARGS (); + m_device = netDevice; + m_server = Ipv4Address::GetAny (); + m_socket = 0; + m_refreshEvent = EventId (); + m_requestEvent = EventId (); + m_discoverEvent = EventId (); + m_rebindEvent = EventId (); + m_nextOfferEvent = EventId (); + m_timeout = EventId (); +} + +DhcpClient::~DhcpClient () +{ + NS_LOG_FUNCTION_NOARGS (); +} + +Ptr DhcpClient::GetDhcpClientNetDevice (void) +{ + return m_device; +} + + +void DhcpClient::SetDhcpClientNetDevice (Ptr netDevice) +{ + m_device = netDevice; +} + +Ipv4Address DhcpClient::GetDhcpServer (void) +{ + return m_server; +} + +void +DhcpClient::DoDispose (void) +{ + NS_LOG_FUNCTION (this); + + m_device = 0; + + Application::DoDispose (); +} + +int64_t +DhcpClient::AssignStreams (int64_t stream) +{ + NS_LOG_FUNCTION (this << stream); + m_ran->SetStream (stream); + return 1; +} + +void +DhcpClient::StartApplication (void) +{ + NS_LOG_FUNCTION (this); + + m_remoteAddress = Ipv4Address ("255.255.255.255"); + m_myAddress = Ipv4Address ("0.0.0.0"); + m_gateway = Ipv4Address ("0.0.0.0"); + Ptr ipv4 = GetNode ()->GetObject (); + uint32_t ifIndex = ipv4->GetInterfaceForDevice (m_device); + + // We need to cleanup the type from the stored chaddr, or later we'll fail to compare it. + // Moreover, the length is always 16, because chaddr is 16 bytes. + Address myAddress = m_device->GetAddress (); + NS_LOG_INFO ("My address is " << myAddress); + uint8_t addr[Address::MAX_SIZE]; + std::memset (addr, 0, Address::MAX_SIZE); + uint32_t len = myAddress.CopyTo (addr); + NS_ASSERT_MSG (len <= 16, "DHCP client can not handle a chaddr larger than 16 bytes"); + m_chaddr.CopyFrom (addr, 16); + NS_LOG_INFO ("My m_chaddr is " << m_chaddr); + + bool found = false; + for (uint32_t i = 0; i < ipv4->GetNAddresses (ifIndex); i++) + { + if (ipv4->GetAddress (ifIndex, i).GetLocal () == m_myAddress) + { + found = true; + } + } + if (!found) + { + ipv4->AddAddress (ifIndex, Ipv4InterfaceAddress (Ipv4Address ("0.0.0.0"),Ipv4Mask ("/0"))); + } + if (m_socket == 0) + { + TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); + m_socket = Socket::CreateSocket (GetNode (), tid); + InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 68); + m_socket->SetAllowBroadcast (true); + m_socket->Bind (local); + m_socket->BindToNetDevice (m_device); + } + m_socket->SetRecvCallback (MakeCallback (&DhcpClient::NetHandler, this)); + + m_device->AddLinkChangeCallback (MakeCallback (&DhcpClient::LinkStateHandler, this)); + Boot (); + +} + +void +DhcpClient::StopApplication () +{ + NS_LOG_FUNCTION (this); + + Simulator::Remove (m_discoverEvent); + Simulator::Remove (m_requestEvent); + Simulator::Remove (m_rebindEvent); + Simulator::Remove (m_refreshEvent); + Simulator::Remove (m_timeout); + Simulator::Remove (m_nextOfferEvent); + Ptr ipv4 = GetNode ()->GetObject (); + + int32_t ifIndex = ipv4->GetInterfaceForDevice (m_device); + for (uint32_t i = 0; i < ipv4->GetNAddresses (ifIndex); i++) + { + if (ipv4->GetAddress (ifIndex,i).GetLocal () == m_myAddress) + { + ipv4->RemoveAddress (ifIndex, i); + break; + } + } + + m_socket->SetRecvCallback (MakeNullCallback > ()); + m_socket->Close (); +} + +void DhcpClient::LinkStateHandler (void) +{ + NS_LOG_FUNCTION (this); + + if (m_device->IsLinkUp ()) + { + NS_LOG_INFO ("Link up at " << Simulator::Now ().As (Time::S)); + m_socket->SetRecvCallback (MakeCallback (&DhcpClient::NetHandler, this)); + StartApplication (); + } + else + { + NS_LOG_INFO ("Link down at " << Simulator::Now ().As (Time::S)); //reinitialization + Simulator::Remove (m_refreshEvent); //stop refresh timer!!!! + Simulator::Remove (m_rebindEvent); + Simulator::Remove (m_timeout); + m_socket->SetRecvCallback (MakeNullCallback > ()); //stop receiving on this socket !!! + + Ptr ipv4MN = GetNode ()->GetObject (); + int32_t ifIndex = ipv4MN->GetInterfaceForDevice (m_device); + + for (uint32_t i = 0; i < ipv4MN->GetNAddresses (ifIndex); i++) + { + if (ipv4MN->GetAddress (ifIndex,i).GetLocal () == m_myAddress) + { + ipv4MN->RemoveAddress (ifIndex, i); + break; + } + } + + Ipv4StaticRoutingHelper ipv4RoutingHelper; + Ptr staticRouting = ipv4RoutingHelper.GetStaticRouting (ipv4MN); + uint32_t i; + for (i = 0; i < staticRouting->GetNRoutes (); i++) + { + if (staticRouting->GetRoute (i).GetGateway () == m_gateway) + { + staticRouting->RemoveRoute (i); + break; + } + } + } +} + +void DhcpClient::NetHandler (Ptr socket) +{ + NS_LOG_FUNCTION (this << socket); + + Address from; + Ptr packet = m_socket->RecvFrom (from); + DhcpHeader header; + if (packet->RemoveHeader (header) == 0) + { + return; + } + if (header.GetChaddr () != m_chaddr) + { + return; + } + if (m_state == WAIT_OFFER && header.GetType () == DhcpHeader::DHCPOFFER) + { + OfferHandler (header); + } + if (m_state == WAIT_ACK && header.GetType () == DhcpHeader::DHCPACK) + { + Simulator::Remove (m_nextOfferEvent); + AcceptAck (header,from); + } + if (m_state == WAIT_ACK && header.GetType () == DhcpHeader::DHCPNACK) + { + Simulator::Remove (m_nextOfferEvent); + Boot (); + } +} + +void DhcpClient::Boot (void) +{ + NS_LOG_FUNCTION (this); + + DhcpHeader header; + Ptr packet; + packet = Create (); + header.ResetOpt (); + m_tran = (uint32_t) (m_ran->GetValue ()); + header.SetTran (m_tran); + header.SetType (DhcpHeader::DHCPDISCOVER); + header.SetTime (); + header.SetChaddr (m_chaddr); + packet->AddHeader (header); + + if ((m_socket->SendTo (packet, 0, InetSocketAddress (Ipv4Address ("255.255.255.255"), DHCP_PEER_PORT))) >= 0) + { + NS_LOG_INFO ("DHCP DISCOVER sent" ); + } + else + { + NS_LOG_INFO ("Error while sending DHCP DISCOVER to " << m_remoteAddress); + } + m_state = WAIT_OFFER; + m_offered = false; + m_discoverEvent = Simulator::Schedule (m_rtrs, &DhcpClient::Boot, this); +} + +void DhcpClient::OfferHandler (DhcpHeader header) +{ + NS_LOG_FUNCTION (this << header); + + m_offerList.push_back (header); + if (m_offered == false) + { + Simulator::Remove (m_discoverEvent); + m_offered = true; + Simulator::Schedule (m_collect, &DhcpClient::Select, this); + } +} + +void DhcpClient::Select (void) +{ + NS_LOG_FUNCTION (this); + + if (m_offerList.empty ()) + { + Boot (); + return; + } + + DhcpHeader header = m_offerList.front (); + m_offerList.pop_front (); + m_lease = Time (Seconds (header.GetLease ())); + m_renew = Time (Seconds (header.GetRenew ())); + m_rebind = Time (Seconds (header.GetRebind ())); + m_offeredAddress = header.GetYiaddr (); + m_myMask = Ipv4Mask (header.GetMask ()); + m_server = header.GetDhcps (); + m_gateway = header.GetRouter (); + m_offerList.clear (); + m_offered = false; + Request (); +} + +void DhcpClient::Request (void) +{ + NS_LOG_FUNCTION (this); + + DhcpHeader header; + Ptr packet; + if (m_state != REFRESH_LEASE) + { + packet = Create (); + header.ResetOpt (); + header.SetType (DhcpHeader::DHCPREQ); + header.SetTime (); + header.SetTran (m_tran); + header.SetReq (m_offeredAddress); + header.SetChaddr (m_chaddr); + packet->AddHeader (header); + m_socket->SendTo (packet, 0, InetSocketAddress (Ipv4Address ("255.255.255.255"), DHCP_PEER_PORT)); + m_state = WAIT_ACK; + m_nextOfferEvent = Simulator::Schedule (m_nextoffer, &DhcpClient::Select, this); + } + else + { + uint32_t addr = m_myAddress.Get (); + packet = Create ((uint8_t*)&addr, sizeof(addr)); + header.ResetOpt (); + m_tran = (uint32_t) (m_ran->GetValue ()); + header.SetTran (m_tran); + header.SetTime (); + header.SetType (DhcpHeader::DHCPREQ); + header.SetReq (m_myAddress); + m_offeredAddress = m_myAddress; + header.SetChaddr (m_chaddr); + packet->AddHeader (header); + if ((m_socket->SendTo (packet, 0, InetSocketAddress (m_remoteAddress, DHCP_PEER_PORT))) >= 0) + { + NS_LOG_INFO ("DHCP REQUEST sent"); + } + else + { + NS_LOG_INFO ("Error while sending DHCP REQ to " << m_remoteAddress); + } + m_state = WAIT_ACK; + } +} + +void DhcpClient::AcceptAck (DhcpHeader header, Address from) +{ + NS_LOG_FUNCTION (this << header << from); + + Simulator::Remove (m_rebindEvent); + Simulator::Remove (m_refreshEvent); + Simulator::Remove (m_timeout); + NS_LOG_INFO ("DHCP ACK received"); + Ptr ipv4 = GetNode ()->GetObject (); + int32_t ifIndex = ipv4->GetInterfaceForDevice (m_device); + + for (uint32_t i = 0; i < ipv4->GetNAddresses (ifIndex); i++) + { + if (ipv4->GetAddress (ifIndex,i).GetLocal () == m_myAddress) + { + NS_LOG_LOGIC ("Got a new address, removing old one: " << m_myAddress); + ipv4->RemoveAddress (ifIndex, i); + break; + } + } + + ipv4->AddAddress (ifIndex, Ipv4InterfaceAddress (m_offeredAddress, m_myMask)); + ipv4->SetUp (ifIndex); + + InetSocketAddress remote = InetSocketAddress (InetSocketAddress::ConvertFrom (from).GetIpv4 (), DHCP_PEER_PORT); + m_socket->Connect (remote); + if (m_myAddress != m_offeredAddress) + { + m_newLease (m_offeredAddress); + if (m_myAddress != Ipv4Address ("0.0.0.0")) + { + m_expiry (m_myAddress); + } + } + m_myAddress = m_offeredAddress; + Ipv4StaticRoutingHelper ipv4RoutingHelper; + Ptr staticRouting = ipv4RoutingHelper.GetStaticRouting (ipv4); + if (m_gateway == Ipv4Address ("0.0.0.0")) + { + m_gateway = InetSocketAddress::ConvertFrom (from).GetIpv4 (); + } + + staticRouting->SetDefaultRoute (m_gateway, ifIndex, 0); + + m_remoteAddress = InetSocketAddress::ConvertFrom (from).GetIpv4 (); + NS_LOG_INFO ("Current DHCP Server is " << m_remoteAddress); + + m_offerList.clear (); + m_refreshEvent = Simulator::Schedule (m_renew, &DhcpClient::Request, this); + m_rebindEvent = Simulator::Schedule (m_rebind, &DhcpClient::Request, this); + m_timeout = Simulator::Schedule (m_lease, &DhcpClient::RemoveAndStart, this); + m_state = REFRESH_LEASE; +} + +void DhcpClient::RemoveAndStart () +{ + NS_LOG_FUNCTION (this); + + Simulator::Remove (m_nextOfferEvent); + Simulator::Remove (m_refreshEvent); + Simulator::Remove (m_rebindEvent); + Simulator::Remove (m_timeout); + + Ptr ipv4MN = GetNode ()->GetObject (); + int32_t ifIndex = ipv4MN->GetInterfaceForDevice (m_device); + + for (uint32_t i = 0; i < ipv4MN->GetNAddresses (ifIndex); i++) + { + if (ipv4MN->GetAddress (ifIndex,i).GetLocal () == m_myAddress) + { + ipv4MN->RemoveAddress (ifIndex, i); + break; + } + } + m_expiry (m_myAddress); + Ipv4StaticRoutingHelper ipv4RoutingHelper; + Ptr staticRouting = ipv4RoutingHelper.GetStaticRouting (ipv4MN); + uint32_t i; + for (i = 0; i < staticRouting->GetNRoutes (); i++) + { + if (staticRouting->GetRoute (i).GetGateway () == m_gateway) + { + staticRouting->RemoveRoute (i); + break; + } + } + StartApplication (); +} + +} // Namespace ns3 diff --git a/src/internet-apps/model/dhcp-client.h b/src/internet-apps/model/dhcp-client.h new file mode 100644 index 000000000..7c1552391 --- /dev/null +++ b/src/internet-apps/model/dhcp-client.h @@ -0,0 +1,195 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 UPB + * Copyright (c) 2017 NITK Surathkal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Radu Lupu + * Ankit Deepak + * Deepti Rajagopal + * + */ + +#ifndef DHCP_CLIENT_H +#define DHCP_CLIENT_H + +#include "ns3/application.h" +#include "ns3/event-id.h" +#include "ns3/ptr.h" +#include "ns3/ipv4-address.h" +#include "ns3/random-variable-stream.h" +#include "ns3/traced-value.h" +#include "dhcp-header.h" +#include + +namespace ns3 { + +class Socket; +class Packet; + +/** + * \ingroup dhcp + * + * \class DhcpClient + * \brief Implements the functionality of a DHCP client + */ +class DhcpClient : public Application +{ +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId + GetTypeId (void); + + DhcpClient (); + virtual ~DhcpClient (); + + /** + * \brief Constructor + * \param netDevice the NetDevice DHCP should work on + */ + DhcpClient (Ptr netDevice); + + /** + * \brief Get the the NetDevice DHCP should work on + * \return the NetDevice DHCP should work on + */ + Ptr GetDhcpClientNetDevice (void); + + /** + * \brief Set the NetDevice DHCP should work on + * \param netDevice the NetDevice DHCP should work on + */ + void SetDhcpClientNetDevice (Ptr netDevice); + + /** + * \brief Get the IPv4Address of current DHCP server + * \return Ipv4Address of current DHCP server + */ + Ipv4Address GetDhcpServer (void); + + /** + * Assign a fixed random variable stream number to the random variables + * used by this model. Return the number of streams (possibly zero) that + * have been assigned. + * + * \param stream First stream index to use + * \return the number of stream indices assigned by this model + */ + int64_t AssignStreams (int64_t stream); + +protected: + virtual void DoDispose (void); + +private: + enum States + { + WAIT_OFFER = 1, //!< State of a client that waits for the offer + REFRESH_LEASE = 2, //!< State of a client that needs to refresh the lease + WAIT_ACK = 9 //!< State of a client that waits for acknowledgment + }; + + static const int DHCP_PEER_PORT = 67; //!< DHCP server port + + /* + * \brief Starts the DHCP client application + */ + virtual void StartApplication (void); + + /* + * \brief Stops the DHCP client application + */ + virtual void StopApplication (void); + + /* + * \brief Handles changes in LinkState + */ + void LinkStateHandler (void); + + /* + * \brief Handles incoming packets from the network + * \param socket Socket bound to port 68 of the DHCP client + */ + void NetHandler (Ptr socket); + + /* + * \brief Sends DHCP DISCOVER and changes the client state to WAIT_OFFER + */ + void Boot (void); + + /* + * \brief Stores DHCP offers in m_offerList + * \param header DhcpHeader of the DHCP OFFER message + */ + void OfferHandler (DhcpHeader header); + + /* + * \brief Selects an OFFER from m_offerList + */ + void Select (void); + + /* + * \brief Sends the DHCP REQUEST message and changes the client state to WAIT_ACK + */ + void Request (void); + + /* + * \brief Receives the DHCP ACK and configures IP address of the client. + * It also triggers the timeout, renew and rebind events. + * \param header DhcpHeader of the DHCP ACK message + * \param from Address of DHCP server that sent the DHCP ACK + */ + void AcceptAck (DhcpHeader header, Address from); + + /* + * \brief Remove the current DHCP information and restart the process + */ + void RemoveAndStart (); + + uint8_t m_state; //!< State of the DHCP client + Ptr m_device; //!< NetDevice pointer + Ptr m_socket; //!< Socket for remote communication + Ipv4Address m_remoteAddress; //!< Initially set to 255.255.255.255 to start DHCP + Ipv4Address m_offeredAddress; //!< Address offered to the client + Ipv4Address m_myAddress; //!< Address assigned to the client + Address m_chaddr; //!< chaddr of the interface (stored as an Address for convenience). + Ipv4Mask m_myMask; //!< Mask of the address assigned + Ipv4Address m_server; //!< Address of the DHCP server + Ipv4Address m_gateway; //!< Address of the gateway + EventId m_requestEvent; //!< Address refresh event + EventId m_discoverEvent; //!< Message retransmission event + EventId m_refreshEvent; //!< Message refresh event + EventId m_rebindEvent; //!< Message rebind event + EventId m_nextOfferEvent; //!< Message next offer event + EventId m_timeout; //!< The timeout period + Time m_lease; //!< Store the lease time of address + Time m_renew; //!< Store the renew time of address + Time m_rebind; //!< Store the rebind time of address + Time m_nextoffer; //!< Time to try the next offer (if request gets no reply) + Ptr m_ran; //!< Uniform random variable for transaction ID + Time m_rtrs; //!< Defining the time for retransmission + Time m_collect; //!< Time for which client should collect offers + bool m_offered; //!< Specify if the client has got any offer + std::list m_offerList; //!< Stores all the offers given to the client + uint32_t m_tran; //!< Stores the current transaction number to be used + TracedCallback m_newLease;//!< Trace of new lease + TracedCallback m_expiry; //!< Trace of lease expire +}; + +} // namespace ns3 + +#endif /* DHCP_CLIENT_H */ diff --git a/src/internet-apps/model/dhcp-header.cc b/src/internet-apps/model/dhcp-header.cc new file mode 100644 index 000000000..892d3cbb6 --- /dev/null +++ b/src/internet-apps/model/dhcp-header.cc @@ -0,0 +1,517 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 UPB + * Copyright (c) 2017 NITK Surathkal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Radu Lupu + * Ankit Deepak + * Deepti Rajagopal + * + */ + +#include "ns3/assert.h" +#include "ns3/log.h" +#include "ns3/header.h" +#include "ns3/simulator.h" +#include "dhcp-header.h" +#include "ns3/address-utils.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("DhcpHeader"); +NS_OBJECT_ENSURE_REGISTERED (DhcpHeader); + +DhcpHeader::DhcpHeader () +{ + m_hType = 1; + m_hLen = 6; + m_xid = 0; + m_secs = 0; + m_hops = 0; + m_flags = 0; + Ipv4Address addr = Ipv4Address ("0.0.0.0"); + m_yiAddr = addr; + m_ciAddr = addr; + m_siAddr = addr; + m_giAddr = addr; + m_dhcps = addr; + m_req = addr; + m_route = addr; + m_len = 240; + + uint32_t i; + + for (i = 0; i < 64; i++) + { + m_sname[i] = 0; + } + for (i = 0; i < 128; i++) + { + m_file[i] = 0; + } + m_magic_cookie[0] = 99; + m_magic_cookie[1] = 130; + m_magic_cookie[2] = 83; + m_magic_cookie[3] = 99; +} + +DhcpHeader::~DhcpHeader () +{ +} + +void DhcpHeader::SetType (uint8_t type) +{ + if (m_opt[OP_MSGTYPE] == false) + { + m_len += 3; + m_opt[OP_MSGTYPE] = true; + } + m_op = type; + m_bootp = (m_op == 0||m_op == 2) ? 1 : 2; +} + +uint8_t DhcpHeader::GetType (void) const +{ + return m_op; +} + +void DhcpHeader::SetHWType (uint8_t htype, uint8_t hlen) +{ + m_hType = htype; + m_hLen = hlen; +} + +void DhcpHeader::SetTran (uint32_t tran) +{ + m_xid = tran; +} + +uint32_t DhcpHeader::GetTran (void) const +{ + return m_xid; +} + +void DhcpHeader::SetTime () +{ + m_secs = (uint16_t) Simulator::Now ().GetSeconds (); +} + +void DhcpHeader::SetChaddr (Address addr) +{ + std::memset (m_chaddr, 0, 16); + NS_ASSERT_MSG (addr.GetLength () <= 16, "Address length too big"); + addr.CopyTo (m_chaddr); +} + +void DhcpHeader::SetChaddr (uint8_t* addr, uint8_t len) +{ + std::memset (m_chaddr, 0, 16); + NS_ASSERT_MSG (len <= 16, "Address length too big"); + std::memcpy (m_chaddr, addr, len); +} + +Address DhcpHeader::GetChaddr () +{ + Address addr; + addr.CopyFrom (m_chaddr, 16); + return addr; +} + +void DhcpHeader::SetYiaddr (Ipv4Address addr) +{ + m_yiAddr = addr; +} + +Ipv4Address DhcpHeader::GetYiaddr (void) const +{ + return m_yiAddr; +} + +void DhcpHeader::SetDhcps (Ipv4Address addr) +{ + if (m_opt[OP_SERVID] == false) + { + m_len += 6; + m_opt[OP_SERVID] = true; + } + m_dhcps = addr; +} + +Ipv4Address DhcpHeader::GetDhcps (void) const +{ + return m_dhcps; +} + +void DhcpHeader::SetReq (Ipv4Address addr) +{ + if (m_opt[OP_ADDREQ] == false) + { + m_len += 6; + m_opt[OP_ADDREQ] = true; + } + m_req = addr; +} + +Ipv4Address DhcpHeader::GetReq (void) const +{ + return m_req; +} + +void DhcpHeader::SetMask (uint32_t addr) +{ + if (m_opt[OP_MASK] == false) + { + m_len += 6; + m_opt[OP_MASK] = true; + } + m_mask = addr; +} + +uint32_t DhcpHeader::GetMask (void) const +{ + return m_mask; +} + +void DhcpHeader::SetRouter (Ipv4Address addr) +{ + if (m_opt[OP_ROUTE] == false) + { + m_len += 6; + m_opt[OP_ROUTE] = true; + } + m_route = addr; +} + +Ipv4Address DhcpHeader::GetRouter (void) const +{ + return m_route; +} + +void DhcpHeader::SetLease (uint32_t time) +{ + if (m_opt[OP_LEASE] == false) + { + m_len += 6; + m_opt[OP_LEASE] = true; + } + m_lease = time; +} + +uint32_t DhcpHeader::GetLease (void) const +{ + return m_lease; +} + +void DhcpHeader::SetRenew (uint32_t time) +{ + if (m_opt[OP_RENEW] == false) + { + m_len += 6; + m_opt[OP_RENEW] = true; + } + m_renew = time; +} + +uint32_t DhcpHeader::GetRenew (void) const +{ + return m_renew; +} + +void DhcpHeader::SetRebind (uint32_t time) +{ + if (m_opt[OP_REBIND] == false) + { + m_len += 6; + m_opt[OP_REBIND] = true; + } + m_rebind = time; +} + +uint32_t DhcpHeader::GetRebind (void) const +{ + return m_rebind; +} + +void DhcpHeader::ResetOpt () +{ + m_len = 241; + int i; + for (i = 0; i < OP_END; i++) + { + m_opt[i] = false; + } +} + +uint32_t DhcpHeader::GetSerializedSize (void) const +{ + return m_len; +} + +TypeId DhcpHeader::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::DhcpHeader") + .SetParent
() + .SetGroupName ("Internet-Apps") + .AddConstructor () + ; + return tid; +} + +TypeId DhcpHeader::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void DhcpHeader::Print (std::ostream &os) const +{ + os << "(type=" << m_op << ")"; +} + +void +DhcpHeader::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + i.WriteU8 (m_bootp); + i.WriteU8 (m_hType); + i.WriteU8 (m_hLen); + i.WriteU8 (m_hops); + i.WriteU32 (m_xid); + i.WriteHtonU16 (m_secs); + i.WriteU16 ( m_flags); + WriteTo (i, m_ciAddr); + WriteTo (i, m_yiAddr); + WriteTo (i, m_siAddr); + WriteTo (i, m_giAddr); + i.Write (m_chaddr, 16); + i.Write (m_sname,64); + i.Write (m_file,128); + i.Write (m_magic_cookie,4); + if (m_opt[OP_MASK]) + { + i.WriteU8 (OP_MASK); + i.WriteU8 (4); + i.WriteHtonU32 (m_mask); + } + if (m_opt[OP_MSGTYPE]) + { + i.WriteU8 (OP_MSGTYPE); + i.WriteU8 (1); + i.WriteU8 ((m_op + 1)); + } + if (m_opt[OP_ADDREQ]) + { + i.WriteU8 (OP_ADDREQ); + i.WriteU8 (4); + WriteTo (i, m_req); + } + if (m_opt[OP_SERVID]) + { + i.WriteU8 (OP_SERVID); + i.WriteU8 (4); + WriteTo (i, m_dhcps); + } + if (m_opt[OP_ROUTE]) + { + i.WriteU8 (OP_ROUTE); + i.WriteU8 (4); + WriteTo (i, m_route); + } + if (m_opt[OP_LEASE]) + { + i.WriteU8 (OP_LEASE); + i.WriteU8 (4); + i.WriteHtonU32 (m_lease); + } + if (m_opt[OP_RENEW]) + { + i.WriteU8 (OP_RENEW); + i.WriteU8 (4); + i.WriteHtonU32 (m_renew); + } + if (m_opt[OP_REBIND]) + { + i.WriteU8 (OP_REBIND); + i.WriteU8 (4); + i.WriteHtonU32 (m_rebind); + } + i.WriteU8 (OP_END); +} + +uint32_t DhcpHeader::Deserialize (Buffer::Iterator start) +{ + uint32_t len, clen = start.GetSize (); + if (clen < 240) + { + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + Buffer::Iterator i = start; + m_bootp = i.ReadU8 (); + m_hType = i.ReadU8 (); + m_hLen = i.ReadU8 (); + m_hops = i.ReadU8 (); + m_xid = i.ReadU32 (); + m_secs = i.ReadNtohU16 (); + m_flags = i.ReadU16 (); + ReadFrom (i, m_ciAddr); + ReadFrom (i, m_yiAddr); + ReadFrom (i, m_siAddr); + ReadFrom (i, m_giAddr); + i.Read (m_chaddr, 16); + i.Read (m_sname, 64); + i.Read (m_file, 128); + i.Read (m_magic_cookie, 4); + if ( m_magic_cookie[0] != 99 || m_magic_cookie[1] != 130 || m_magic_cookie[2] != 83 || m_magic_cookie[3] != 99) + { + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + len = 240; + uint8_t option; + bool loop = true; + do + { + if (len + 1 <= clen) + { + option = i.ReadU8 (); + len += 1; + } + else + { + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + switch (option) + { + case OP_MASK: + if (len + 5 < clen) + { + i.ReadU8 (); + m_mask = i.ReadNtohU32 (); + len += 5; + } + else + { + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + break; + case OP_ROUTE: + if (len + 5 < clen) + { + i.ReadU8 (); + ReadFrom (i, m_route); + len += 5; + } + else + { + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + break; + case OP_MSGTYPE: + if (len + 2 < clen) + { + i.ReadU8 (); + m_op = (i.ReadU8 () - 1); + len += 2; + } + else + { + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + break; + case OP_SERVID: + if (len + 5 < clen) + { + i.ReadU8 (); + ReadFrom (i, m_dhcps); + len += 5; + } + else + { + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + break; + case OP_ADDREQ: + if (len + 5 < clen) + { + i.ReadU8 (); + ReadFrom (i, m_req); + len += 5; + } + else + { + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + break; + case OP_LEASE: + if (len + 5 < clen) + { + i.ReadU8 (); + m_lease = i.ReadNtohU32 (); + len += 5; + } + else + { + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + break; + case OP_RENEW: + if (len + 5 < clen) + { + i.ReadU8 (); + m_renew = i.ReadNtohU32 (); + len += 5; + } + else + { + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + break; + case OP_REBIND: + if (len + 5 < clen) + { + i.ReadU8 (); + m_rebind = i.ReadNtohU32 (); + len += 5; + } + else + { + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + break; + case OP_END: + loop = false; + break; + default: + NS_LOG_WARN ("Malformed Packet"); + return 0; + } + } + while (loop); + + m_len = len; + return m_len; +} + +} // namespace ns3 diff --git a/src/internet-apps/model/dhcp-header.h b/src/internet-apps/model/dhcp-header.h new file mode 100644 index 000000000..0b8b0356c --- /dev/null +++ b/src/internet-apps/model/dhcp-header.h @@ -0,0 +1,322 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 UPB + * Copyright (c) 2017 NITK Surathkal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Radu Lupu + * Ankit Deepak + * Deepti Rajagopal + * + */ + +#ifndef DHCP_HEADER_H +#define DHCP_HEADER_H + +#include "ns3/header.h" +#include +#include + +namespace ns3 { + +/** + * \ingroup internet-apps + * \defgroup dhcp DHCPv4 Client and Server + */ + +/** + * \ingroup dhcp + * + * \class DhcpHeader + * \brief BOOTP header with DHCP messages supports the following options: + * Subnet Mask (1), Address Request (50), Refresh Lease Time (51), + * DHCP Message Type (53), DHCP Server ID (54), Renew Time (58), + * Rebind Time (59) and End (255) of BOOTP + + \verbatim + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | op (1) | htype (1) | hlen (1) | hops (1) | + +---------------+---------------+---------------+---------------+ + | xid (4) | + +-------------------------------+-------------------------------+ + | secs (2) | flags (2) | + +-------------------------------+-------------------------------+ + | ciaddr (4) | + +---------------------------------------------------------------+ + | yiaddr (4) | + +---------------------------------------------------------------+ + | siaddr (4) | + +---------------------------------------------------------------+ + | giaddr (4) | + +---------------------------------------------------------------+ + | | + | chaddr (16) | + | | + | | + +---------------------------------------------------------------+ + | | + | sname (64) | + +---------------------------------------------------------------+ + | | + | file (128) | + +---------------------------------------------------------------+ + | | + | options (variable) | + +---------------------------------------------------------------+ + \endverbatim + + */ +class DhcpHeader : public Header +{ +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + /** + * \brief Constructor + */ + DhcpHeader (); + + /** + * \brief Destructor + */ + ~DhcpHeader (); + + enum Options + { + OP_MASK = 1, //!< BOOTP Option 1: Address Mask + OP_ROUTE = 3, //!< BOOTP Option 3: Router Option + OP_ADDREQ = 50, //!< BOOTP Option 50: Requested Address + OP_LEASE = 51, //!< BOOTP Option 51: Address Lease Time + OP_MSGTYPE = 53, //!< BOOTP Option 53: DHCP Message Type + OP_SERVID = 54, //!< BOOTP Option 54: Server Identifier + OP_RENEW = 58, //!< BOOTP Option 58: Address Renewal Time + OP_REBIND = 59, //!< BOOTP Option 59: Address Rebind Time + OP_END = 255 //!< BOOTP Option 255: END + }; + + enum Messages + { + DHCPDISCOVER = 0, //!< Code for DHCP Discover + DHCPOFFER = 1, //!< Code for DHCP Offer + DHCPREQ = 2, //!< Code for DHCP Request + DHCPACK = 4, //!< Code for DHCP ACK + DHCPNACK = 5 //!< Code for DHCP NACK + }; + + /** + * \brief Set the type of BOOTP and DHCP messages + * \param type The type of message + */ + void SetType (uint8_t type); + + /** + * \brief Return the type of DHCP message + * \return The type of message + */ + uint8_t GetType (void) const; + + /** + * \brief Set the hardware information + * \param htype Hardware type + * \param hlen Hardware length + */ + void SetHWType (uint8_t htype, uint8_t hlen); + + /** + * \brief Set the transaction ID + * \param tran The transaction number + */ + void SetTran (uint32_t tran); + + /** + * \brief Get the transaction id + * \return The transaction id + */ + uint32_t GetTran (void) const; + + /** + * \brief Set the time when message is sent + */ + void SetTime (); + + /** + * \brief Set the Address of the device. + * + * Only the relevant bits are considered (i.e., not the type and length) + * + * \param addr Address of the device + */ + void SetChaddr (Address addr); + + /** + * \brief Set the Address of the device + * \param addr Address of the device + * \param len Address length + */ + void SetChaddr (uint8_t* addr, uint8_t len); + + /** + * \brief Get the Address of the client. + * + * Note: the address is always 16-bytes long. + * + * \return Address of the client + */ + Address GetChaddr (void); + + /** + * \brief Set the IPv4Address of the client + * \param addr The client Ipv4Address + */ + void SetYiaddr (Ipv4Address addr); + + /** + * \brief Get the IPv4Address of the client + * \return IPv4Address of the client + */ + Ipv4Address GetYiaddr (void) const; + + /** + * \brief Set the DHCP server information + * \param addr IPv4Address of the server + */ + void SetDhcps (Ipv4Address addr); + + /** + * \brief Get the information about the DHCP server + * \return IPv4Address of DHCP server + */ + Ipv4Address GetDhcps (void) const; + + /** + * \brief Set the Ipv4Address requested by the client + * \param addr Ipv4Address requested by the client + */ + void SetReq (Ipv4Address addr); + + /** + * \brief Get the IPv4Address requested by the client + * \return IPv4Address requested by the client + */ + Ipv4Address GetReq (void) const; + + /** + * \brief Set the mask of the IPv4Address + * \param addr 32 bit mask + */ + void SetMask (uint32_t addr); + + /** + * \brief Return the mask of the network + * \return 32 bit mask + */ + uint32_t GetMask (void) const; + + /** + * \brief Set the Ipv4Address of gateway to be used + * \param addr The Ipv4Address of the gateway + */ + void SetRouter (Ipv4Address addr); + + /** + * \brief Return the Ipv4Address of gateway to be used + * \return The Ipv4Address of the gateway + */ + Ipv4Address GetRouter (void) const; + + /** + * \brief Set the lease time of the IPv4Address + * \param time 32 bit time + */ + void SetLease (uint32_t time); + + /** + * \brief Return the lease time of the IPv4Address + * \return 32 bit time + */ + uint32_t GetLease (void) const; + + /** + * \brief Set the Renewal time of the IPv4Address + * \param time 32 bit time + */ + void SetRenew (uint32_t time); + + /** + * \brief Return the Renewal time of the address + * \return 32 bit time + */ + uint32_t GetRenew (void) const; + + /** + * \brief Set the Rebind time of the IPv4Address + * \param time 32 bit time + */ + void SetRebind (uint32_t time); + + /** + * \brief Return the Rebind time of the address + * \return 32 bit time + */ + uint32_t GetRebind (void) const; + + /** + * \brief Reset the BOOTP options + */ + void ResetOpt (); + +private: + virtual TypeId GetInstanceTypeId (void) const; + virtual void Print (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + + uint8_t m_op; //!< The DHCP Message type + uint8_t m_bootp; //!< The BOOTP Message type + uint8_t m_hType; //!< The hardware type + uint8_t m_hLen; //!< The hardware length + uint8_t m_hops; //!< The number of hops covered by the message + uint32_t m_xid; //!< The transaction number + uint32_t m_mask; //!< The mask of the network + uint32_t m_len; //!< The length of the header + uint16_t m_secs; //!< Seconds elapsed + uint16_t m_flags; //!< BOOTP flags + uint8_t m_chaddr[16]; //!< The address identifier + Ipv4Address m_yiAddr; //!< Your (client) IP address + Ipv4Address m_ciAddr; //!< The IP address of the client + Ipv4Address m_siAddr; //!< Next Server IP address + Ipv4Address m_giAddr; //!< Relay Agent IP address + Ipv4Address m_dhcps; //!< DHCP server IP address + Ipv4Address m_req; //!< Requested Address + Ipv4Address m_route; //!< Router Option Address + uint8_t m_sname[64]; //!< Server name (Padded for now) + uint8_t m_file[128]; //!< File name (Padded for now) + uint8_t m_magic_cookie[4]; //!< DHCP Magic Cookie + uint32_t m_lease; //!< The lease time of the address + uint32_t m_renew; //!< The renewal time for the client + uint32_t m_rebind; //!< The rebinding time for the client + bool m_opt[255]; //!< BOOTP option list +}; + +} // namespace ns3 + +#endif /* DHCP_HEADER_H */ diff --git a/src/internet-apps/model/dhcp-server.cc b/src/internet-apps/model/dhcp-server.cc new file mode 100644 index 000000000..b4671fb0a --- /dev/null +++ b/src/internet-apps/model/dhcp-server.cc @@ -0,0 +1,421 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 UPB + * Copyright (c) 2017 NITK Surathkal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Radu Lupu + * Ankit Deepak + * Deepti Rajagopal + * + */ + +#include "ns3/log.h" +#include "ns3/assert.h" +#include "ns3/ipv4-address.h" +#include "ns3/nstime.h" +#include "ns3/inet-socket-address.h" +#include "ns3/ipv4-packet-info-tag.h" +#include "ns3/socket.h" +#include "ns3/simulator.h" +#include "ns3/socket-factory.h" +#include "ns3/packet.h" +#include "ns3/uinteger.h" +#include "ns3/config.h" +#include "dhcp-server.h" +#include "dhcp-header.h" +#include "ns3/ipv4.h" +#include + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("DhcpServer"); +NS_OBJECT_ENSURE_REGISTERED (DhcpServer); + +TypeId +DhcpServer::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::DhcpServer") + .SetParent () + .AddConstructor () + .SetGroupName ("Internet-Apps") + .AddAttribute ("LeaseTime", + "Lease for which address will be leased.", + TimeValue (Seconds (30)), + MakeTimeAccessor (&DhcpServer::m_lease), + MakeTimeChecker ()) + .AddAttribute ("RenewTime", + "Time after which client should renew.", + TimeValue (Seconds (15)), + MakeTimeAccessor (&DhcpServer::m_renew), + MakeTimeChecker ()) + .AddAttribute ("RebindTime", + "Time after which client should rebind.", + TimeValue (Seconds (25)), + MakeTimeAccessor (&DhcpServer::m_rebind), + MakeTimeChecker ()) + .AddAttribute ("PoolAddresses", + "Pool of addresses to provide on request.", + Ipv4AddressValue (), + MakeIpv4AddressAccessor (&DhcpServer::m_poolAddress), + MakeIpv4AddressChecker ()) + .AddAttribute ("FirstAddress", + "The First valid address that can be given.", + Ipv4AddressValue (), + MakeIpv4AddressAccessor (&DhcpServer::m_minAddress), + MakeIpv4AddressChecker ()) + .AddAttribute ("LastAddress", + "The Last valid address that can be given.", + Ipv4AddressValue (), + MakeIpv4AddressAccessor (&DhcpServer::m_maxAddress), + MakeIpv4AddressChecker ()) + .AddAttribute ("PoolMask", + "Mask of the pool of addresses.", + Ipv4MaskValue (), + MakeIpv4MaskAccessor (&DhcpServer::m_poolMask), + MakeIpv4MaskChecker ()) + .AddAttribute ("Gateway", + "Address of default gateway", + Ipv4AddressValue (), + MakeIpv4AddressAccessor (&DhcpServer::m_gateway), + MakeIpv4AddressChecker ()) + ; + return tid; +} + +DhcpServer::DhcpServer () +{ + NS_LOG_FUNCTION (this); +} + +DhcpServer::~DhcpServer () +{ + NS_LOG_FUNCTION (this); +} + +void +DhcpServer::DoDispose (void) +{ + NS_LOG_FUNCTION (this); + Application::DoDispose (); +} + +void DhcpServer::StartApplication (void) +{ + NS_LOG_FUNCTION (this); + + NS_ASSERT_MSG (m_minAddress < m_maxAddress,"Invalid Address range"); + + Ipv4Address myOwnAddress; + + if (m_socket) + { + NS_ABORT_MSG ("DHCP daemon is not (yet) meant to be started twice or more."); + } + + uint32_t addrIndex; + + //add the DHCP local address to the leased addresses list, if it is defined! + Ptr ipv4 = GetNode ()->GetObject (); + int32_t ifIndex = ipv4->GetInterfaceForPrefix (m_poolAddress, m_poolMask); + + if (ifIndex < 0) + { + NS_ABORT_MSG ("DHCP daemon must be run on the same subnet it is assigning the addresses."); + } + + for (addrIndex = 0; addrIndex < ipv4->GetNAddresses (ifIndex); addrIndex++) + { + if (ipv4->GetAddress (ifIndex, addrIndex).GetLocal ().CombineMask (m_poolMask) == m_poolAddress && + ipv4->GetAddress (ifIndex, addrIndex).GetLocal ().Get () >= m_minAddress.Get () && + ipv4->GetAddress (ifIndex, addrIndex).GetLocal ().Get () <= m_maxAddress.Get ()) + { + // set infinite GRANTED_LEASED_TIME for my address + + myOwnAddress = ipv4->GetAddress (ifIndex, addrIndex).GetLocal (); + m_leasedAddresses[Address ()] = std::make_pair (myOwnAddress, 0xffffffff); + break; + } + } + + TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); + m_socket = Socket::CreateSocket (GetNode (), tid); + InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), PORT); + m_socket->SetAllowBroadcast (true); + m_socket->Bind (local); + m_socket->BindToNetDevice (ipv4->GetNetDevice (ifIndex)); + m_socket->SetRecvPktInfo (true); + + uint32_t range = m_maxAddress.Get () - m_minAddress.Get () + 1; + for (uint32_t searchSeq = 0; searchSeq < range; searchSeq ++) + { + Ipv4Address poolAddress = Ipv4Address (m_minAddress.Get () + searchSeq); + if (poolAddress != myOwnAddress) + { + NS_LOG_LOGIC ("Adding " << poolAddress << " to the pool"); + m_availableAddresses.push_back (poolAddress); + } + } + + m_socket->SetRecvCallback (MakeCallback (&DhcpServer::NetHandler, this)); + m_expiredEvent = Simulator::Schedule (Seconds (1), &DhcpServer::TimerHandler, this); +} + +void DhcpServer::StopApplication () +{ + NS_LOG_FUNCTION (this); + + if (m_socket != 0) + { + m_socket->SetRecvCallback (MakeNullCallback > ()); + } + + m_leasedAddresses.clear (); + Simulator::Remove (m_expiredEvent); +} + +void DhcpServer::TimerHandler () +{ + NS_LOG_FUNCTION (this); + + // Set up timeout events and release of unsolicited addresses from the list + LeasedAddressIter i; + for (i = m_leasedAddresses.begin (); i != m_leasedAddresses.end (); i++) + { + // update the address state + if (i->second.second != 0xffffffff && i->second.second != 0) + { + i->second.second--; + if (i->second.second == 0) + { + NS_LOG_INFO ("Address leased state expired, address removed - " << + "chaddr: " << i->first << + "IP address " << i->second.first); + i->second.second = 0; + m_expiredAddresses.push_front (i->first); + } + } + } + m_expiredEvent = Simulator::Schedule (Seconds (1), &DhcpServer::TimerHandler, this); +} + +void DhcpServer::NetHandler (Ptr socket) +{ + NS_LOG_FUNCTION (this << socket); + + DhcpHeader header; + Ptr packet = 0; + Address from; + packet = m_socket->RecvFrom (from); + + InetSocketAddress senderAddr = InetSocketAddress::ConvertFrom (from); + + Ipv4PacketInfoTag interfaceInfo; + if (!packet->RemovePacketTag (interfaceInfo)) + { + NS_ABORT_MSG ("No incoming interface on DHCP message, aborting."); + } + uint32_t incomingIf = interfaceInfo.GetRecvIf (); + Ptr iDev = GetNode ()->GetDevice (incomingIf); + + if (packet->RemoveHeader (header) == 0) + { + return; + } + if (header.GetType () == DhcpHeader::DHCPDISCOVER) + { + SendOffer (iDev, header, senderAddr); + } + if (header.GetType () == DhcpHeader::DHCPREQ && (header.GetReq ()).Get () >= m_minAddress.Get () && (header.GetReq ()).Get () <= m_maxAddress.Get ()) + { + SendAck (iDev, header, senderAddr); + } +} + +void DhcpServer::SendOffer (Ptr iDev, DhcpHeader header, InetSocketAddress from) +{ + NS_LOG_FUNCTION (this << iDev << header << from); + + DhcpHeader newDhcpHeader; + Address sourceChaddr = header.GetChaddr (); + uint32_t tran = header.GetTran (); + Ptr packet = 0; + bool found = false; + Ipv4Address offeredAddress; + + NS_LOG_INFO ("DHCP DISCOVER from: " << from.GetIpv4 () << " source port: " << from.GetPort ()); + + LeasedAddressIter iter = m_leasedAddresses.find (sourceChaddr); + if (iter != m_leasedAddresses.end ()) + { + // We know this client from some time ago + if (m_leasedAddresses[sourceChaddr].second != 0 && m_leasedAddresses[sourceChaddr].second != 0xffffffff) + { + NS_LOG_LOGIC ("This client is sending a DISCOVER but it has still a lease active - perhaps it didn't shut down gracefully: " << sourceChaddr); + } + + m_expiredAddresses.remove (sourceChaddr); + offeredAddress = m_leasedAddresses[sourceChaddr].first; + + } + else + { + // No previous record of the client, we must find a suitable address and create a record. + if (!m_availableAddresses.empty ()) + { + // use an address never used before (if there is one) + found = true; + offeredAddress = m_availableAddresses.front (); + m_availableAddresses.pop_front (); + } + else + { + // there's still hope: reuse the old ones. + if (!m_expiredAddresses.empty ()) + { + Address oldestChaddr = m_expiredAddresses.back (); + m_expiredAddresses.pop_back (); + offeredAddress = m_leasedAddresses[oldestChaddr].first; + m_leasedAddresses.erase (oldestChaddr); + found = true; + } + } + } + + if (offeredAddress != Ipv4Address ()) + { + m_leasedAddresses[sourceChaddr] = std::make_pair (offeredAddress, m_lease.GetSeconds ()); + + packet = Create (); + newDhcpHeader.ResetOpt (); + newDhcpHeader.SetType (DhcpHeader::DHCPOFFER); + newDhcpHeader.SetChaddr (sourceChaddr); + newDhcpHeader.SetYiaddr (offeredAddress); + + Ptr ipv4 = GetNode ()->GetObject (); + Ipv4Address myAddress = ipv4->SelectSourceAddress (iDev, offeredAddress, Ipv4InterfaceAddress::InterfaceAddressScope_e::GLOBAL); + + newDhcpHeader.SetDhcps (myAddress); + newDhcpHeader.SetMask (m_poolMask.Get ()); + newDhcpHeader.SetTran (tran); + newDhcpHeader.SetLease (m_lease.GetSeconds ()); + newDhcpHeader.SetRenew (m_renew.GetSeconds ()); + newDhcpHeader.SetRebind (m_rebind.GetSeconds ()); + newDhcpHeader.SetTime (); + if (m_gateway != Ipv4Address ()) + { + newDhcpHeader.SetRouter (m_gateway); + } + packet->AddHeader (newDhcpHeader); + + if ((m_socket->SendTo (packet, 0, InetSocketAddress (Ipv4Address ("255.255.255.255"), from.GetPort ()))) >= 0) + { + NS_LOG_INFO ("DHCP OFFER" << " Offered Address: " << offeredAddress); + } + else + { + NS_LOG_INFO ("Error while sending DHCP OFFER"); + } + } +} + +void DhcpServer::SendAck (Ptr iDev, DhcpHeader header, InetSocketAddress from) +{ + NS_LOG_FUNCTION (this << iDev << header << from); + + DhcpHeader newDhcpHeader; + Address sourceChaddr = header.GetChaddr (); + uint32_t tran = header.GetTran (); + Ptr packet = 0; + Ipv4Address address = header.GetReq (); + + NS_LOG_INFO ("DHCP REQUEST from: " << from.GetIpv4 () << + " source port: " << from.GetPort () << + " - refreshed addr: " << address); + + LeasedAddressIter iter; + iter = m_leasedAddresses.find (sourceChaddr); + if (iter != m_leasedAddresses.end ()) + { + // update the lease time of this address - send ACK + (iter->second.second) += m_lease.GetSeconds (); + packet = Create (); + newDhcpHeader.ResetOpt (); + newDhcpHeader.SetType (DhcpHeader::DHCPACK); + newDhcpHeader.SetChaddr (sourceChaddr); + newDhcpHeader.SetYiaddr (address); + newDhcpHeader.SetTran (tran); + newDhcpHeader.SetTime (); + packet->AddHeader (newDhcpHeader); + if (from.GetIpv4 () != address) + { + m_socket->SendTo (packet, 0, InetSocketAddress (Ipv4Address ("255.255.255.255"), from.GetPort ())); + } + else + { + m_socket->SendTo (packet, 0, from); + } + } + else + { + // Deleted or expired lease - send NACK + packet = Create (); + newDhcpHeader.ResetOpt (); + newDhcpHeader.SetType (DhcpHeader::DHCPNACK); + newDhcpHeader.SetChaddr (sourceChaddr); + newDhcpHeader.SetYiaddr (address); + newDhcpHeader.SetTran (tran); + newDhcpHeader.SetTime (); + packet->AddHeader (newDhcpHeader); + if (from.GetIpv4 () != address) + { + m_socket->SendTo (packet, 0, InetSocketAddress (Ipv4Address ("255.255.255.255"), from.GetPort ())); + } + else + { + m_socket->SendTo (packet, 0, from); + } + NS_LOG_INFO ("IP addr does not exists or released!"); + } +} + +void DhcpServer::AddStaticDhcpEntry (Address chaddr, Ipv4Address addr) +{ + NS_LOG_FUNCTION (this << chaddr << addr); + Address cleanedCaddr; + + NS_ASSERT_MSG (addr.Get () >= m_minAddress.Get () && addr.Get () <= m_maxAddress.Get (), + "Required address is not in the pool " << addr << " is not in [" << m_minAddress << ", " << m_maxAddress << "]"); + + // We need to cleanup the type from the stored chaddr, or later we'll fail to compare it. + // Moreover, the length is always 16, because chaddr is 16 bytes. + uint8_t buffer[Address::MAX_SIZE]; + std::memset (buffer, 0, Address::MAX_SIZE); + uint32_t len = chaddr.CopyTo (buffer); + NS_ASSERT_MSG (len <= 16, "DHCP server can not handle a chaddr larger than 16 bytes"); + cleanedCaddr.CopyFrom (buffer, 16); + + NS_ASSERT_MSG (m_leasedAddresses.find (cleanedCaddr) == m_leasedAddresses.end (), + "Client has already an active lease: " << m_leasedAddresses[cleanedCaddr].first); + + AvailableAddress::iterator it = find (m_availableAddresses.begin (), m_availableAddresses.end (), addr); + NS_ASSERT_MSG (it == m_availableAddresses.end (), + "Required address is not available (perhaps it has been already assigned): " << addr); + + m_availableAddresses.remove (addr); + m_leasedAddresses[cleanedCaddr] = std::make_pair (addr, 0xffffffff); +} + +} // Namespace ns3 diff --git a/src/internet-apps/model/dhcp-server.h b/src/internet-apps/model/dhcp-server.h new file mode 100644 index 000000000..c9a3c5dec --- /dev/null +++ b/src/internet-apps/model/dhcp-server.h @@ -0,0 +1,147 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 UPB + * Copyright (c) 2017 NITK Surathkal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Radu Lupu + * Ankit Deepak + * Deepti Rajagopal + * + */ + +#ifndef DHCP_SERVER_H +#define DHCP_SERVER_H + +#include "ns3/application.h" +#include "ns3/event-id.h" +#include "ns3/ptr.h" +#include "ns3/address.h" +#include "ns3/traced-value.h" +#include "ns3/inet-socket-address.h" +#include "dhcp-header.h" +#include + +namespace ns3 { + +class Socket; +class Packet; + +/** + * \ingroup dhcp + * + * \class DhcpServer + * \brief Implements the functionality of a DHCP server + */ +class DhcpServer : public Application +{ +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + DhcpServer (); + virtual ~DhcpServer (); + + /** + * \brief Add a static entry to the pool. + * + * \param chaddr The client chaddr. + * \param addr The address to handle to the client. + */ + void AddStaticDhcpEntry (Address chaddr, Ipv4Address addr); + + +protected: + virtual void DoDispose (void); + +private: + static const int PORT = 67; //!< Port number of DHCP server + + /* + * \brief Handles incoming packets from the network + * \param socket Socket bound to port 67 of the DHCP server + */ + void NetHandler (Ptr socket); + + /* + * \brief Sends DHCP offer after receiving DHCP Discover + * \param iDev incoming NetDevice + * \param header DHCP header of the received message + * \param from Address of the DHCP client + */ + void SendOffer (Ptr iDev, DhcpHeader header, InetSocketAddress from); + + /* + * \brief Sends DHCP ACK (or NACK) after receiving Request + * \param iDev incoming NetDevice + * \param header DHCP header of the received message + * \param from Address of the DHCP client + */ + void SendAck (Ptr iDev, DhcpHeader header, InetSocketAddress from); + + /* + * \brief Modifies the remaining lease time of addresses + */ + void TimerHandler (void); + + /* + * \brief Starts the DHCP Server application + */ + virtual void StartApplication (void); + + /* + * \brief Stops the DHCP client application + */ + virtual void StopApplication (void); + + Ptr m_socket; //!< The socket bound to port 67 + Ipv4Address m_poolAddress; //!< The network address available to the server + Ipv4Address m_minAddress; //!< The first address in the address pool + Ipv4Address m_maxAddress; //!< The last address in the address pool + Ipv4Mask m_poolMask; //!< The network mask of the pool + Ipv4Address m_gateway; //!< The gateway address + + /// Leased address container - chaddr + IP addr / lease time + typedef std::map > LeasedAddress; + /// Leased address iterator - chaddr + IP addr / lease time + typedef std::map >::iterator LeasedAddressIter; + /// Leased address const iterator - chaddr + IP addr / lease time + typedef std::map >::const_iterator LeasedAddressCIter; + + /// Expired address container - chaddr + typedef std::list
ExpiredAddress; + /// Expired address iterator - chaddr + typedef std::list
::iterator ExpiredAddressIter; + /// Expired address const iterator - chaddr + typedef std::list
::const_iterator ExpiredAddressCIter; + + /// Available address container - IP addr + typedef std::list AvailableAddress; + + LeasedAddress m_leasedAddresses; //!< Leased address and their status (cache memory) + ExpiredAddress m_expiredAddresses; //!< Expired addresses to be reused (chaddr of the clients) + AvailableAddress m_availableAddresses; //!< Available addresses to be used (IP addresses) + Time m_lease; //!< The granted lease time for an address + Time m_renew; //!< The renewal time for an address + Time m_rebind; //!< The rebinding time for an address + EventId m_expiredEvent; //!< The Event to trigger TimerHandler +}; + +} // namespace ns3 + +#endif /* DHCP_SERVER_H */ diff --git a/src/internet-apps/test/dhcp-test.cc b/src/internet-apps/test/dhcp-test.cc new file mode 100644 index 000000000..619088a86 --- /dev/null +++ b/src/internet-apps/test/dhcp-test.cc @@ -0,0 +1,162 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2017 NITK Surathkal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: Ankit Deepak + * Deepti Rajagopal + * + */ + +#include "ns3/data-rate.h" +#include "ns3/simple-net-device.h" +#include "ns3/simple-net-device-helper.h" +#include "ns3/internet-stack-helper.h" +#include "ns3/ipv4-address-helper.h" +#include "ns3/dhcp-client.h" +#include "ns3/dhcp-server.h" +#include "ns3/dhcp-helper.h" +#include "ns3/test.h" + +using namespace ns3; + +/** + * \ingroup dhcp + * \defgroup dhcp-test DHCP module tests + */ + + +/** + * \ingroup dhcp-test + * \ingroup tests + * + * \brief DHCP basic tests + */ +class DhcpTestCase : public TestCase +{ +public: + DhcpTestCase (); + virtual ~DhcpTestCase (); + /** + * Triggered by an address lease on a client. + * \param newAddress The leased address. + */ + void LeaseObtained (std::string context, const Ipv4Address& newAddress); +private: + virtual void DoRun (void); + Ipv4Address m_leasedAddress[3]; //!< Address given to the nodes +}; + +DhcpTestCase::DhcpTestCase () + : TestCase ("Dhcp test case ") +{ +} + +DhcpTestCase::~DhcpTestCase () +{ +} + +void +DhcpTestCase::LeaseObtained (std::string context, const Ipv4Address& newAddress) +{ + uint8_t numericalContext = std::stoi (context, nullptr, 10); + + if (numericalContext >=0 && numericalContext <=2) + { + m_leasedAddress[numericalContext] = newAddress; + } +} + +void +DhcpTestCase::DoRun (void) +{ + /*Set up devices*/ + NodeContainer nodes; + NodeContainer routers; + nodes.Create (3); + routers.Create (1); + + NodeContainer net (routers, nodes); + + SimpleNetDeviceHelper simpleNetDevice; + simpleNetDevice.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); + simpleNetDevice.SetDeviceAttribute ("DataRate", DataRateValue (DataRate ("5Mbps"))); + NetDeviceContainer devNet = simpleNetDevice.Install (net); + + InternetStackHelper tcpip; + tcpip.Install (routers); + tcpip.Install (nodes); + + DhcpHelper dhcpHelper; + + ApplicationContainer dhcpServerApp = dhcpHelper.InstallDhcpServer (devNet.Get (0), Ipv4Address ("172.30.0.12"), + Ipv4Address ("172.30.0.0"), Ipv4Mask ("/24"), + Ipv4Address ("172.30.0.10"), Ipv4Address ("172.30.0.15"), + Ipv4Address ("172.30.0.17")); + dhcpServerApp.Start (Seconds (0.0)); + dhcpServerApp.Stop (Seconds (20.0)); + + DynamicCast (dhcpServerApp.Get (0))->AddStaticDhcpEntry (devNet.Get (3)->GetAddress (), Ipv4Address ("172.30.0.14")); + + NetDeviceContainer dhcpClientNetDevs; + dhcpClientNetDevs.Add (devNet.Get (1)); + dhcpClientNetDevs.Add (devNet.Get (2)); + dhcpClientNetDevs.Add (devNet.Get (3)); + + ApplicationContainer dhcpClientApps = dhcpHelper.InstallDhcpClient (dhcpClientNetDevs); + dhcpClientApps.Start (Seconds (1.0)); + dhcpClientApps.Stop (Seconds (20.0)); + + + dhcpClientApps.Get(0)->TraceConnect ("NewLease", "0", MakeCallback(&DhcpTestCase::LeaseObtained, this)); + dhcpClientApps.Get(1)->TraceConnect ("NewLease", "1", MakeCallback(&DhcpTestCase::LeaseObtained, this)); + dhcpClientApps.Get(2)->TraceConnect ("NewLease", "2", MakeCallback(&DhcpTestCase::LeaseObtained, this)); + + Simulator::Stop (Seconds (21.0)); + + Simulator::Run (); + + NS_TEST_ASSERT_MSG_EQ (m_leasedAddress[0], Ipv4Address ("172.30.0.10"), + m_leasedAddress[0] << " instead of " << "172.30.0.10"); + + NS_TEST_ASSERT_MSG_EQ (m_leasedAddress[1], Ipv4Address ("172.30.0.11"), + m_leasedAddress[1] << " instead of " << "172.30.0.11"); + + NS_TEST_ASSERT_MSG_EQ (m_leasedAddress[2], Ipv4Address ("172.30.0.14"), + m_leasedAddress[2] << " instead of " << "172.30.0.14"); + + Simulator::Destroy (); +} + +/** + * \ingroup dhcp-test + * \ingroup tests + * + * \brief DHCP TestSuite + */ +class DhcpTestSuite : public TestSuite +{ +public: + DhcpTestSuite (); +}; + +DhcpTestSuite::DhcpTestSuite () + : TestSuite ("dhcp", UNIT) +{ + AddTestCase (new DhcpTestCase, TestCase::QUICK); +} + +static DhcpTestSuite dhcpTestSuite; //!< Static variable for test initialization + diff --git a/src/internet-apps/wscript b/src/internet-apps/wscript index 0a3eebde4..67cc642e3 100644 --- a/src/internet-apps/wscript +++ b/src/internet-apps/wscript @@ -14,9 +14,18 @@ def build(bld): 'model/radvd-prefix.cc', 'model/radvd.cc', 'model/v4ping.cc', + 'model/dhcp-header.cc', + 'model/dhcp-server.cc', + 'model/dhcp-client.cc', 'helper/ping6-helper.cc', 'helper/radvd-helper.cc', 'helper/v4ping-helper.cc', + 'helper/dhcp-helper.cc', + ] + + applications_test = bld.create_ns3_module_test_library('internet-apps') + applications_test.source = [ + 'test/dhcp-test.cc', ] headers = bld(features='ns3header') @@ -27,11 +36,17 @@ def build(bld): 'model/radvd-interface.h', 'model/radvd-prefix.h', 'model/v4ping.h', + 'model/dhcp-header.h', + 'model/dhcp-server.h', + 'model/dhcp-client.h', 'helper/ping6-helper.h', 'helper/v4ping-helper.h', 'helper/radvd-helper.h', + 'helper/dhcp-helper.h', ] + if (bld.env['ENABLE_EXAMPLES']): + bld.recurse('examples') bld.ns3_python_bindings() diff --git a/src/internet/doc/ipv4.rst b/src/internet/doc/ipv4.rst index c240589d3..590456fb3 100644 --- a/src/internet/doc/ipv4.rst +++ b/src/internet/doc/ipv4.rst @@ -11,6 +11,89 @@ IPv4 ---- +This chapter describes the |ns3| IPv4 address assignment and basic components tracking. + +IPv4 addresses assignment +************************* + +In order to use IPv4 on a network, the first thing to do is assigning IPv4 addresses. + +Any IPv4-enabled |ns3| node will have at least one NetDevice: the :cpp:class:`ns3::LoopbackNetDevice`. +The loopback device address is ``127.0.0.1``. +All the other NetDevices will have one (or more) IPv4 addresses. + +Note that, as today, |ns3| does not have a NAT module, and it does not follows the rules about +filtering private addresses (:rfc:`1918`): 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16. +These addresses are routed as any other address. This behaviour could change in the future. + +IPv4 global addresses can be: + +* manually assigned +* assigned though DHCP + +|ns3| can use both methods, and it's quite important to understand the implications of both. + +Manually assigned IPv4 adddresses ++++++++++++++++++++++++++++++++++ + +This is probably the easiest and most used method. As an example: + +:: + + Ptr n0 = CreateObject (); + Ptr n1 = CreateObject (); + NodeContainer net (n0, n1); + CsmaHelper csma; + NetDeviceContainer ndc = csma.Install (net); + + NS_LOG_INFO ("Assign IPv4 Addresses."); + Ipv4AddressHelper ipv4; + ipv4.SetBase (Ipv4Address ("192.168.1.0"), NetMask ("/24")); + Ipv4InterfaceContainer ic = ipv4.Assign (ndc); + +This method will add two global IPv4 addresses to the nodes. + +Note that the addesses are assigned in sequence. As a consequence, the first Node / NetDevice +will have "192.168.1.1", the second "192.168.1.2" and so on. + +It is possible to repeat the above to assign more than one address to a node. +However, due to the :cpp:class:`Ipv4AddressHelper` singleton nature, one should first assign all the +adddresses of a network, then change the network base (``SetBase``), then do a new assignment. + +Alternatively, it is possible to assign a specific address to a node: + +:: + + Ptr n0 = CreateObject (); + NodeContainer net (n0); + CsmaHelper csma; + NetDeviceContainer ndc = csma.Install (net); + + NS_LOG_INFO ("Specifically Assign an IPv4 Address."); + Ipv4AddressHelper ipv4; + Ptr device = ndc.Get (0); + Ptr node = device->GetNode (); + Ptr ipv4proto = node->GetObject (); + int32_t ifIndex = 0; + ifIndex = ipv4proto->GetInterfaceForDevice (device); + Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("192.168.1.42"), NetMask ("/24")); + ipv4proto->AddAddress (ifIndex, ipv4Addr); + + +DHCP assigned IPv4 adddresses ++++++++++++++++++++++++++++++ + +DHCP is available in the internet-apps module. In order to use DHCP you have to have a +:cpp:class:`DhcpServer` application in a node (the DHC server node) and a :cpp:class:`DhcpClient` application in +each of the nodes. Note that it not necessary that all the nodes in a subnet use DHCP. Some +nodes can have static addresses. + +All the DHCP setup is performed though the :cpp:class:`DhcpHelper` class. A complete example is in +``src/internet-apps/examples/dhcp-example.cc``. + +Further info about the DHCP functionalities can be found in the ``internet-apps`` model documentation. + + Tracing in the IPv4 Stack ************************* diff --git a/src/internet/doc/ipv6.rst b/src/internet/doc/ipv6.rst index d0e01e6ff..96de60390 100644 --- a/src/internet/doc/ipv6.rst +++ b/src/internet/doc/ipv6.rst @@ -161,7 +161,7 @@ Note that the global addesses will be derived from the MAC address. As a consequ to have addresses similar to ``2001:db8::200:ff:fe00:1``. It is possible to repeat the above to assign more than one global address to a node. -However, due to the ``Ipv6AddressHelper`` singleton nature, one should first assign all the +However, due to the :cpp:class:`Ipv6AddressHelper` singleton nature, one should first assign all the adddresses of a network, then change the network base (``SetBase``), then do a new assignment. Alternatively, it is possible to assign a specific address to a node: