A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
dhcp-server.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 UPB
3 * Copyright (c) 2017 NITK Surathkal
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 * Author: Radu Lupu <rlupu@elcom.pub.ro>
8 * Ankit Deepak <adadeepak8@gmail.com>
9 * Deepti Rajagopal <deeptir96@gmail.com>
10 *
11 */
12
13#include "dhcp-server.h"
14
15#include "dhcp-header.h"
16
17#include "ns3/assert.h"
18#include "ns3/ipv4-packet-info-tag.h"
19#include "ns3/ipv4.h"
20#include "ns3/log.h"
21#include "ns3/nstime.h"
22#include "ns3/packet.h"
23#include "ns3/simulator.h"
24#include "ns3/socket.h"
25
26#include <algorithm>
27
28namespace ns3
29{
30
31NS_LOG_COMPONENT_DEFINE("DhcpServer");
33
34TypeId
36{
37 static TypeId tid = TypeId("ns3::DhcpServer")
39 .AddConstructor<DhcpServer>()
40 .SetGroupName("Internet-Apps")
41 .AddAttribute("LeaseTime",
42 "Lease for which address will be leased.",
43 TimeValue(Seconds(30)),
46 .AddAttribute("RenewTime",
47 "Time after which client should renew.",
48 TimeValue(Seconds(15)),
51 .AddAttribute("RebindTime",
52 "Time after which client should rebind.",
53 TimeValue(Seconds(25)),
56 .AddAttribute("PoolAddresses",
57 "Pool of addresses to provide on request.",
61 .AddAttribute("FirstAddress",
62 "The First valid address that can be given.",
66 .AddAttribute("LastAddress",
67 "The Last valid address that can be given.",
71 .AddAttribute("PoolMask",
72 "Mask of the pool of addresses.",
76 .AddAttribute("Gateway",
77 "Address of default gateway",
81 return tid;
82}
83
88
93
94void
100
101void
103{
104 NS_LOG_FUNCTION(this);
105
106 NS_ASSERT_MSG(m_minAddress < m_maxAddress, "Invalid Address range");
107
108 Ipv4Address myOwnAddress;
109
110 if (m_socket)
111 {
112 NS_ABORT_MSG("DHCP daemon is not (yet) meant to be started twice or more.");
113 }
114
115 uint32_t addrIndex;
116
117 // add the DHCP local address to the leased addresses list, if it is defined!
118 Ptr<Ipv4> ipv4 = GetNode()->GetObject<Ipv4>();
119 int32_t ifIndex = ipv4->GetInterfaceForPrefix(m_poolAddress, m_poolMask);
120
121 if (ifIndex < 0)
122 {
123 NS_ABORT_MSG("DHCP daemon must be run on the same subnet it is assigning the addresses.");
124 }
125
126 for (addrIndex = 0; addrIndex < ipv4->GetNAddresses(ifIndex); addrIndex++)
127 {
128 if (ipv4->GetAddress(ifIndex, addrIndex).GetLocal().CombineMask(m_poolMask) ==
130 ipv4->GetAddress(ifIndex, addrIndex).GetLocal().Get() >= m_minAddress.Get() &&
131 ipv4->GetAddress(ifIndex, addrIndex).GetLocal().Get() <= m_maxAddress.Get())
132 {
133 // set infinite GRANTED_LEASED_TIME for my address
134
135 myOwnAddress = ipv4->GetAddress(ifIndex, addrIndex).GetLocal();
136 m_leasedAddresses[Address()] = std::make_pair(myOwnAddress, 0xffffffff);
137 break;
138 }
139 }
140
141 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
145 m_socket->BindToNetDevice(ipv4->GetNetDevice(ifIndex));
146 m_socket->Bind(local);
148
149 uint32_t range = m_maxAddress.Get() - m_minAddress.Get() + 1;
150 for (uint32_t searchSeq = 0; searchSeq < range; searchSeq++)
151 {
152 Ipv4Address poolAddress(m_minAddress.Get() + searchSeq);
153 if (poolAddress != myOwnAddress)
154 {
155 NS_LOG_LOGIC("Adding " << poolAddress << " to the pool");
156 m_availableAddresses.push_back(poolAddress);
157 }
158 }
159
162}
163
164void
166{
167 NS_LOG_FUNCTION(this);
168
169 if (m_socket)
170 {
172 }
173
174 m_leasedAddresses.clear();
176}
177
178void
180{
181 NS_LOG_FUNCTION(this);
182
183 // Set up timeout events and release of unsolicited addresses from the list
185 for (i = m_leasedAddresses.begin(); i != m_leasedAddresses.end(); i++)
186 {
187 // update the address state
188 if (i->second.second != 0xffffffff && i->second.second != 0)
189 {
190 i->second.second--;
191 if (i->second.second == 0)
192 {
193 NS_LOG_INFO("Address leased state expired, address removed - "
194 << "chaddr: " << i->first << " IP address " << i->second.first);
195 i->second.second = 0;
196 m_expiredAddresses.push_front(i->first);
197 }
198 }
199 }
201}
202
203void
205{
206 NS_LOG_FUNCTION(this << socket);
207
208 DhcpHeader header;
209 Ptr<Packet> packet = nullptr;
210 Address from;
211 packet = m_socket->RecvFrom(from);
212
214
215 Ipv4PacketInfoTag interfaceInfo;
216 if (!packet->RemovePacketTag(interfaceInfo))
217 {
218 NS_ABORT_MSG("No incoming interface on DHCP message, aborting.");
219 }
220 uint32_t incomingIf = interfaceInfo.GetRecvIf();
221 Ptr<NetDevice> iDev = GetNode()->GetDevice(incomingIf);
222
223 if (packet->RemoveHeader(header) == 0)
224 {
225 return;
226 }
227 if (header.GetType() == DhcpHeader::DHCPDISCOVER)
228 {
229 SendOffer(iDev, header, senderAddr);
230 }
231 if (header.GetType() == DhcpHeader::DHCPREQ && (header.GetReq()).Get() >= m_minAddress.Get() &&
232 (header.GetReq()).Get() <= m_maxAddress.Get())
233 {
234 SendAck(iDev, header, senderAddr);
235 }
236}
237
238void
240{
241 NS_LOG_FUNCTION(this << iDev << header << from);
242
243 DhcpHeader newDhcpHeader;
244 Address sourceChaddr = header.GetChaddr();
245 uint32_t tran = header.GetTran();
246 Ptr<Packet> packet = nullptr;
247 Ipv4Address offeredAddress;
248
249 NS_LOG_INFO("DHCP DISCOVER from: " << from.GetIpv4() << " source port: " << from.GetPort());
250
251 auto iter = m_leasedAddresses.find(sourceChaddr);
252 if (iter != m_leasedAddresses.end())
253 {
254 // We know this client from some time ago
255 if (m_leasedAddresses[sourceChaddr].second != 0 &&
256 m_leasedAddresses[sourceChaddr].second != 0xffffffff)
257 {
258 NS_LOG_LOGIC("This client is sending a DISCOVER but it has still a lease active - "
259 "perhaps it didn't shut down gracefully: "
260 << sourceChaddr);
261 }
262
263 m_expiredAddresses.remove(sourceChaddr);
264 offeredAddress = m_leasedAddresses[sourceChaddr].first;
265 }
266 else
267 {
268 // No previous record of the client, we must find a suitable address and create a record.
269 if (!m_availableAddresses.empty())
270 {
271 // use an address never used before (if there is one)
272 offeredAddress = m_availableAddresses.front();
273 m_availableAddresses.pop_front();
274 }
275 else
276 {
277 // there's still hope: reuse the old ones.
278 if (!m_expiredAddresses.empty())
279 {
280 Address oldestChaddr = m_expiredAddresses.back();
281 m_expiredAddresses.pop_back();
282 offeredAddress = m_leasedAddresses[oldestChaddr].first;
283 m_leasedAddresses.erase(oldestChaddr);
284 }
285 }
286 }
287
288 if (offeredAddress != Ipv4Address())
289 {
290 m_leasedAddresses[sourceChaddr] = std::make_pair(offeredAddress, m_lease.GetSeconds());
291
292 packet = Create<Packet>();
293 newDhcpHeader.ResetOpt();
294 newDhcpHeader.SetType(DhcpHeader::DHCPOFFER);
295 newDhcpHeader.SetChaddr(sourceChaddr);
296 newDhcpHeader.SetYiaddr(offeredAddress);
297
298 Ptr<Ipv4> ipv4 = GetNode()->GetObject<Ipv4>();
299 Ipv4Address myAddress =
300 ipv4->SelectSourceAddress(iDev,
301 offeredAddress,
303
304 newDhcpHeader.SetDhcps(myAddress);
305 newDhcpHeader.SetMask(m_poolMask.Get());
306 newDhcpHeader.SetTran(tran);
307 newDhcpHeader.SetLease(m_lease.GetSeconds());
308 newDhcpHeader.SetRenew(m_renew.GetSeconds());
309 newDhcpHeader.SetRebind(m_rebind.GetSeconds());
310 newDhcpHeader.SetTime();
311 if (m_gateway != Ipv4Address())
312 {
313 newDhcpHeader.SetRouter(m_gateway);
314 }
315 packet->AddHeader(newDhcpHeader);
316
317 if ((m_socket->SendTo(packet,
318 0,
319 InetSocketAddress(Ipv4Address("255.255.255.255"), from.GetPort()))) >=
320 0)
321 {
322 NS_LOG_INFO("DHCP OFFER"
323 << " Offered Address: " << offeredAddress);
324 }
325 else
326 {
327 NS_LOG_INFO("Error while sending DHCP OFFER");
328 }
329 }
330}
331
332void
334{
335 NS_LOG_FUNCTION(this << iDev << header << from);
336
337 DhcpHeader newDhcpHeader;
338 Address sourceChaddr = header.GetChaddr();
339 uint32_t tran = header.GetTran();
340 Ptr<Packet> packet = nullptr;
341 Ipv4Address address = header.GetReq();
342
343 NS_LOG_INFO("DHCP REQUEST from: " << from.GetIpv4() << " source port: " << from.GetPort()
344 << " - refreshed addr: " << address);
345
347 iter = m_leasedAddresses.find(sourceChaddr);
348 if (iter != m_leasedAddresses.end())
349 {
350 // update the lease time of this address - send ACK
351 (iter->second.second) += m_lease.GetSeconds();
352 packet = Create<Packet>();
353 newDhcpHeader.ResetOpt();
354 newDhcpHeader.SetType(DhcpHeader::DHCPACK);
355 newDhcpHeader.SetChaddr(sourceChaddr);
356 newDhcpHeader.SetYiaddr(address);
357 newDhcpHeader.SetTran(tran);
358 newDhcpHeader.SetTime();
359 packet->AddHeader(newDhcpHeader);
360 if (from.GetIpv4() != address)
361 {
362 m_socket->SendTo(packet,
363 0,
364 InetSocketAddress(Ipv4Address("255.255.255.255"), from.GetPort()));
365 }
366 else
367 {
368 m_socket->SendTo(packet, 0, from);
369 }
370 }
371 else
372 {
373 // Deleted or expired lease - send NACK
374 packet = Create<Packet>();
375 newDhcpHeader.ResetOpt();
376 newDhcpHeader.SetType(DhcpHeader::DHCPNACK);
377 newDhcpHeader.SetChaddr(sourceChaddr);
378 newDhcpHeader.SetYiaddr(address);
379 newDhcpHeader.SetTran(tran);
380 newDhcpHeader.SetTime();
381 packet->AddHeader(newDhcpHeader);
382 if (from.GetIpv4() != address)
383 {
384 m_socket->SendTo(packet,
385 0,
386 InetSocketAddress(Ipv4Address("255.255.255.255"), from.GetPort()));
387 }
388 else
389 {
390 m_socket->SendTo(packet, 0, from);
391 }
392 NS_LOG_INFO("IP addr does not exists or released!");
393 }
394}
395
396void
398{
399 NS_LOG_FUNCTION(this << chaddr << addr);
400 Address cleanedCaddr;
401
402 NS_ASSERT_MSG(addr.Get() >= m_minAddress.Get() && addr.Get() <= m_maxAddress.Get(),
403 "Required address is not in the pool " << addr << " is not in [" << m_minAddress
404 << ", " << m_maxAddress << "]");
405
406 // We need to cleanup the type from the stored chaddr, or later we'll fail to compare it.
407 // Moreover, the length is always 16, because chaddr is 16 bytes.
408 uint8_t buffer[Address::MAX_SIZE];
409 std::memset(buffer, 0, Address::MAX_SIZE);
410 uint32_t len = chaddr.CopyTo(buffer);
411 NS_ASSERT_MSG(len <= 16, "DHCP server can not handle a chaddr larger than 16 bytes");
412 cleanedCaddr.CopyFrom(buffer, 16);
413
414 NS_ASSERT_MSG(m_leasedAddresses.find(cleanedCaddr) == m_leasedAddresses.end(),
415 "Client has already an active lease: " << m_leasedAddresses[cleanedCaddr].first);
416
417 auto it = find(m_availableAddresses.begin(), m_availableAddresses.end(), addr);
419 it == m_availableAddresses.end(),
420 "Required address is not available (perhaps it has been already assigned): " << addr);
421
422 m_availableAddresses.remove(addr);
423 m_leasedAddresses[cleanedCaddr] = std::make_pair(addr, 0xffffffff);
424}
425
426} // Namespace ns3
a polymophic address class
Definition address.h:90
uint32_t CopyFrom(const uint8_t *buffer, uint8_t len)
Definition address.cc:95
static constexpr uint32_t MAX_SIZE
The maximum size of a byte buffer which can be stored in an Address instance.
Definition address.h:96
uint32_t CopyTo(uint8_t buffer[MAX_SIZE]) const
Copy the address bytes into a buffer.
Definition address.cc:75
The base class for all ns3 applications.
Definition application.h:51
void DoDispose() override
Destructor implementation.
Ptr< Node > GetNode() const
BOOTP header with DHCP messages.
Definition dhcp-header.h:73
void SetTime()
Set the time when message is sent.
Ipv4Address GetReq() const
Get the IPv4Address requested by the client.
void ResetOpt()
Reset the BOOTP options.
void SetType(uint8_t type)
Set the type of BOOTP and DHCP messages.
@ DHCPACK
Code for DHCP ACK.
@ DHCPOFFER
Code for DHCP Offer.
@ DHCPDISCOVER
Code for DHCP Discover.
@ DHCPREQ
Code for DHCP Request.
@ DHCPNACK
Code for DHCP NACK.
void SetTran(uint32_t tran)
Set the transaction ID.
Address GetChaddr()
Get the Address of the client.
void SetYiaddr(Ipv4Address addr)
Set the IPv4Address of the client.
void SetDhcps(Ipv4Address addr)
Set the DHCP server information.
uint8_t GetType() const
Return the type of DHCP message.
void SetRenew(uint32_t time)
Set the Renewal time of the IPv4Address.
uint32_t GetTran() const
Get the transaction id.
void SetLease(uint32_t time)
Set the lease time of the IPv4Address.
void SetRouter(Ipv4Address addr)
Set the Ipv4Address of gateway to be used.
void SetMask(uint32_t addr)
Set the mask of the IPv4Address.
void SetRebind(uint32_t time)
Set the Rebind time of the IPv4Address.
void SetChaddr(Address addr)
Set the Address of the device.
EventId m_expiredEvent
The Event to trigger TimerHandler.
void StopApplication() override
Application specific shutdown code.
static const int PORT
Port number of DHCP server.
Definition dhcp-server.h:63
AvailableAddress m_availableAddresses
Available addresses to be used (IP addresses)
Time m_rebind
The rebinding time for an address.
Time m_lease
The granted lease time for an address.
Ipv4Mask m_poolMask
The network mask of the pool.
Definition dhcp-server.h:96
Ptr< Socket > m_socket
The socket bound to port 67.
Definition dhcp-server.h:92
ExpiredAddress m_expiredAddresses
Expired addresses to be reused (chaddr of the clients)
void StartApplication() override
Application specific startup code.
void AddStaticDhcpEntry(Address chaddr, Ipv4Address addr)
Add a static entry to the pool.
LeasedAddress m_leasedAddresses
Leased address and their status (cache memory)
Ipv4Address m_minAddress
The first address in the address pool.
Definition dhcp-server.h:94
Ipv4Address m_gateway
The gateway address.
Definition dhcp-server.h:97
static TypeId GetTypeId()
Get the type ID.
Time m_renew
The renewal time for an address.
Ipv4Address m_maxAddress
The last address in the address pool.
Definition dhcp-server.h:95
Ipv4Address m_poolAddress
The network address available to the server.
Definition dhcp-server.h:93
~DhcpServer() override
void TimerHandler()
Modifies the remaining lease time of addresses.
void NetHandler(Ptr< Socket > socket)
Handles incoming packets from the network.
void SendAck(Ptr< NetDevice > iDev, DhcpHeader header, InetSocketAddress from)
Sends DHCP ACK (or NACK) after receiving Request.
std::map< Address, std::pair< Ipv4Address, uint32_t > >::iterator LeasedAddressIter
Leased address iterator - chaddr + IP addr / lease time.
void SendOffer(Ptr< NetDevice > iDev, DhcpHeader header, InetSocketAddress from)
Sends DHCP offer after receiving DHCP Discover.
void DoDispose() override
Destructor implementation.
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
an Inet address class
Ipv4Address GetIpv4() const
static InetSocketAddress ConvertFrom(const Address &address)
Returns an InetSocketAddress which corresponds to the input Address.
Ipv4 addresses are stored in host order in this class.
uint32_t Get() const
Get the host-order 32-bit IP address.
static Ipv4Address GetAny()
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition ipv4.h:69
uint32_t Get() const
Get the host-order 32-bit IP mask.
This class implements Linux struct pktinfo in order to deliver ancillary information to the socket in...
uint32_t GetRecvIf() const
Get the tag's receiving interface.
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition node.cc:138
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:511
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
virtual Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress)=0
Read a single packet from the socket and retrieve the sender address.
virtual bool SetAllowBroadcast(bool allowBroadcast)=0
Configure whether broadcast datagram transmissions are allowed.
void SetRecvPktInfo(bool flag)
Enable/Disable receive packet information to socket.
Definition socket.cc:343
virtual void BindToNetDevice(Ptr< NetDevice > netdevice)
Bind a socket to specific device.
Definition socket.cc:316
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition socket.cc:117
static Ptr< Socket > CreateSocket(Ptr< Node > node, TypeId tid)
This method wraps the creation of sockets that is performed on a given node by a SocketFactory specif...
Definition socket.cc:61
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
virtual int SendTo(Ptr< Packet > p, uint32_t flags, const Address &toAddress)=0
Send data to a specified peer.
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:392
a unique identifier for an interface.
Definition type-id.h:48
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition type-id.cc:872
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Callback< R, Args... > MakeNullCallback()
Definition callback.h:727
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1396
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< const AttributeAccessor > MakeIpv4AddressAccessor(T1 a1)
Ptr< const AttributeChecker > MakeIpv4AddressChecker()
Ptr< const AttributeAccessor > MakeIpv4MaskAccessor(T1 a1)
Ptr< const AttributeChecker > MakeIpv4MaskChecker()
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1416