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#include <limits>
28
29namespace ns3
30{
31
32NS_LOG_COMPONENT_DEFINE("DhcpServer");
34
37{
38 static TypeId tid = TypeId("ns3::DhcpServer")
40 .AddConstructor<DhcpServer>()
41 .SetGroupName("Internet-Apps")
42 .AddAttribute("LeaseTime",
43 "Lease for which address will be leased.",
44 TimeValue(Seconds(30)),
47 .AddAttribute("RenewTime",
48 "Time after which client should renew.",
49 TimeValue(Seconds(15)),
52 .AddAttribute("RebindTime",
53 "Time after which client should rebind.",
54 TimeValue(Seconds(25)),
57 .AddAttribute("PoolAddresses",
58 "Pool of addresses to provide on request.",
62 .AddAttribute("FirstAddress",
63 "The First valid address that can be given.",
67 .AddAttribute("LastAddress",
68 "The Last valid address that can be given.",
72 .AddAttribute("PoolMask",
73 "Mask of the pool of addresses.",
77 .AddAttribute("Gateway",
78 "Address of default gateway",
82 return tid;
83}
84
89
94
95void
101
102void
104{
105 NS_LOG_FUNCTION(this);
106
107 NS_ASSERT_MSG(m_minAddress < m_maxAddress, "Invalid Address range");
108
109 Ipv4Address myOwnAddress;
110
111 if (m_socket)
112 {
113 NS_ABORT_MSG("DHCP daemon is not (yet) meant to be started twice or more.");
114 }
115
116 uint32_t addrIndex;
117
118 // add the DHCP local address to the leased addresses list, if it is defined!
119 Ptr<Ipv4> ipv4 = GetNode()->GetObject<Ipv4>();
120 int32_t ifIndex = ipv4->GetInterfaceForPrefix(m_poolAddress, m_poolMask);
121
122 if (ifIndex < 0)
123 {
124 NS_ABORT_MSG("DHCP daemon must be run on the same subnet it is assigning the addresses.");
125 }
126
127 for (addrIndex = 0; addrIndex < ipv4->GetNAddresses(ifIndex); addrIndex++)
128 {
129 if (ipv4->GetAddress(ifIndex, addrIndex).GetLocal().CombineMask(m_poolMask) ==
131 ipv4->GetAddress(ifIndex, addrIndex).GetLocal().Get() >= m_minAddress.Get() &&
132 ipv4->GetAddress(ifIndex, addrIndex).GetLocal().Get() <= m_maxAddress.Get())
133 {
134 // set infinite GRANTED_LEASED_TIME for my address
135
136 myOwnAddress = ipv4->GetAddress(ifIndex, addrIndex).GetLocal();
137 DhcpChaddr null = {};
138 m_leasedAddresses[null] = std::make_pair(myOwnAddress, PERMANENT_LEASE);
139 break;
140 }
141 }
142
143 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
146 m_socket->SetAllowBroadcast(true);
147 m_socket->BindToNetDevice(ipv4->GetNetDevice(ifIndex));
148 m_socket->Bind(local);
149 m_socket->SetRecvPktInfo(true);
150
151 uint32_t range = m_maxAddress.Get() - m_minAddress.Get() + 1;
152 for (uint32_t searchSeq = 0; searchSeq < range; searchSeq++)
153 {
154 Ipv4Address poolAddress(m_minAddress.Get() + searchSeq);
155 if (poolAddress != myOwnAddress)
156 {
157 NS_LOG_LOGIC("Adding " << poolAddress << " to the pool");
158 m_availableAddresses.push_back(poolAddress);
159 }
160 }
161
162 m_socket->SetRecvCallback(MakeCallback(&DhcpServer::NetHandler, this));
164}
165
166void
168{
169 NS_LOG_FUNCTION(this);
170
171 if (m_socket)
172 {
173 m_socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
174 }
175
176 m_leasedAddresses.clear();
177 m_expiredEvent.Cancel();
178}
179
180void
182{
183 NS_LOG_FUNCTION(this);
184
185 // Set up timeout events and release of unsolicited addresses from the list
186 for (auto [k, v] : m_leasedAddresses)
187 {
188 // update the address state
189 if (v.second != PERMANENT_LEASE && v.second != 0)
190 {
191 v.second--;
192 if (v.second == 0)
193 {
194 NS_LOG_INFO("Address leased state expired, address removed - "
195 << "chaddr: " << DhcpChaddrToString(k) << " IP address " << v.first);
196 v.second = 0;
197 m_expiredAddresses.push_front(k);
198 }
199 }
200 }
202}
203
204void
206{
207 NS_LOG_FUNCTION(this << socket);
208
209 DhcpHeader header;
210 Ptr<Packet> packet = nullptr;
211 Address from;
212 packet = m_socket->RecvFrom(from);
213
215
216 Ipv4PacketInfoTag interfaceInfo;
217 if (!packet->RemovePacketTag(interfaceInfo))
218 {
219 NS_ABORT_MSG("No incoming interface on DHCP message, aborting.");
220 }
221 uint32_t incomingIf = interfaceInfo.GetRecvIf();
222 Ptr<NetDevice> iDev = GetNode()->GetDevice(incomingIf);
223
224 if (packet->RemoveHeader(header) == 0)
225 {
226 return;
227 }
228 if (header.GetType() == DhcpHeader::DHCPDISCOVER)
229 {
230 SendOffer(iDev, header, senderAddr);
231 }
232 if (header.GetType() == DhcpHeader::DHCPREQ && (header.GetReq()).Get() >= m_minAddress.Get() &&
233 (header.GetReq()).Get() <= m_maxAddress.Get())
234 {
235 SendAck(iDev, header, senderAddr);
236 }
237}
238
239void
241{
242 NS_LOG_FUNCTION(this << iDev << header << from);
243
244 DhcpHeader newDhcpHeader;
245 DhcpChaddr sourceChaddr = header.GetChaddr();
246 uint32_t tran = header.GetTran();
247 Ptr<Packet> packet = nullptr;
248 Ipv4Address offeredAddress;
249
250 NS_LOG_INFO("DHCP DISCOVER from: " << from.GetIpv4() << " source port: " << from.GetPort());
251
252 auto iter = m_leasedAddresses.find(sourceChaddr);
253 if (iter != m_leasedAddresses.end())
254 {
255 // We know this client from some time ago
256 if (m_leasedAddresses[sourceChaddr].second != 0 &&
258 {
259 NS_LOG_LOGIC("This client is sending a DISCOVER but it has still a lease active - "
260 "perhaps it didn't shut down gracefully: "
261 << DhcpChaddrToString(sourceChaddr));
262 }
263
264 m_expiredAddresses.remove(sourceChaddr);
265 offeredAddress = m_leasedAddresses[sourceChaddr].first;
266 }
267 else
268 {
269 // No previous record of the client, we must find a suitable address and create a record.
270 if (!m_availableAddresses.empty())
271 {
272 // use an address never used before (if there is one)
273 offeredAddress = m_availableAddresses.front();
274 m_availableAddresses.pop_front();
275 }
276 else
277 {
278 // there's still hope: reuse the old ones.
279 if (!m_expiredAddresses.empty())
280 {
281 DhcpChaddr oldestChaddr = m_expiredAddresses.back();
282 m_expiredAddresses.pop_back();
283 offeredAddress = m_leasedAddresses[oldestChaddr].first;
284 m_leasedAddresses.erase(oldestChaddr);
285 }
286 }
287 }
288
289 if (offeredAddress != Ipv4Address())
290 {
291 m_leasedAddresses[sourceChaddr] = std::make_pair(offeredAddress, m_lease.GetSeconds());
292
293 packet = Create<Packet>();
294 newDhcpHeader.ResetOpt();
295 newDhcpHeader.SetType(DhcpHeader::DHCPOFFER);
296 newDhcpHeader.SetChaddr(sourceChaddr);
297 newDhcpHeader.SetYiaddr(offeredAddress);
298
299 Ptr<Ipv4> ipv4 = GetNode()->GetObject<Ipv4>();
300 Ipv4Address myAddress =
301 ipv4->SelectSourceAddress(iDev,
302 offeredAddress,
304
305 newDhcpHeader.SetDhcps(myAddress);
306 newDhcpHeader.SetMask(m_poolMask.Get());
307 newDhcpHeader.SetTran(tran);
308 newDhcpHeader.SetLease(m_lease.GetSeconds());
309 newDhcpHeader.SetRenew(m_renew.GetSeconds());
310 newDhcpHeader.SetRebind(m_rebind.GetSeconds());
311 newDhcpHeader.SetTime();
312 if (m_gateway != Ipv4Address())
313 {
314 newDhcpHeader.SetRouter(m_gateway);
315 }
316 packet->AddHeader(newDhcpHeader);
317
318 if ((m_socket->SendTo(packet,
319 0,
320 InetSocketAddress(Ipv4Address("255.255.255.255"), from.GetPort()))) >=
321 0)
322 {
323 NS_LOG_INFO("DHCP OFFER 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 DhcpChaddr 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
346 auto iter = m_leasedAddresses.find(sourceChaddr);
347 if (iter != m_leasedAddresses.end())
348 {
349 // update the lease time of this address - send ACK
350 (iter->second.second) += m_lease.GetSeconds();
351 packet = Create<Packet>();
352 newDhcpHeader.ResetOpt();
353 newDhcpHeader.SetType(DhcpHeader::DHCPACK);
354 newDhcpHeader.SetChaddr(sourceChaddr);
355 newDhcpHeader.SetYiaddr(address);
356 newDhcpHeader.SetTran(tran);
357 newDhcpHeader.SetTime();
358 packet->AddHeader(newDhcpHeader);
359 if (from.GetIpv4() != address)
360 {
361 m_socket->SendTo(packet,
362 0,
363 InetSocketAddress(Ipv4Address("255.255.255.255"), from.GetPort()));
364 }
365 else
366 {
367 m_socket->SendTo(packet, 0, from);
368 }
369 }
370 else
371 {
372 // Deleted or expired lease - send NACK
373 packet = Create<Packet>();
374 newDhcpHeader.ResetOpt();
375 newDhcpHeader.SetType(DhcpHeader::DHCPNACK);
376 newDhcpHeader.SetChaddr(sourceChaddr);
377 newDhcpHeader.SetYiaddr(address);
378 newDhcpHeader.SetTran(tran);
379 newDhcpHeader.SetTime();
380 packet->AddHeader(newDhcpHeader);
381 if (from.GetIpv4() != address)
382 {
383 m_socket->SendTo(packet,
384 0,
385 InetSocketAddress(Ipv4Address("255.255.255.255"), from.GetPort()));
386 }
387 else
388 {
389 m_socket->SendTo(packet, 0, from);
390 }
391 NS_LOG_INFO("IP addr does not exists or released!");
392 }
393}
394
395void
397{
398 NS_LOG_FUNCTION(this << macAddr << addr);
399 DhcpChaddr chAddr{};
400
401 NS_ASSERT_MSG(addr.Get() >= m_minAddress.Get() && addr.Get() <= m_maxAddress.Get(),
402 "Required address is not in the pool " << addr << " is not in [" << m_minAddress
403 << ", " << m_maxAddress << "]");
404 NS_ASSERT_MSG(macAddr.GetLength() <= 16,
405 "DHCP server can not handle a chaddr larger than 16 bytes");
406 macAddr.CopyTo(chAddr.data());
407
409 "Client has already an active lease: " << m_leasedAddresses[chAddr].first);
410
411 auto it = find(m_availableAddresses.begin(), m_availableAddresses.end(), addr);
413 it == m_availableAddresses.end(),
414 "Required address is not available (perhaps it has been already assigned): " << addr);
415
416 m_availableAddresses.remove(addr);
417 NS_LOG_INFO("Added a static lease for " << DhcpChaddrToString(chAddr) << " -> " << addr);
418 m_leasedAddresses[chAddr] = std::make_pair(addr, PERMANENT_LEASE);
419}
420
421} // Namespace ns3
uint32_t v
a polymophic address class
Definition address.h:111
uint8_t GetLength() const
Get the length of the underlying address.
Definition address.cc:88
uint32_t CopyTo(uint8_t buffer[MAX_SIZE]) const
Copy the address bytes into a buffer.
Definition address.cc:96
void DoDispose() override
Destructor implementation.
Ptr< Node > GetNode() const
BOOTP header with DHCP messages.
Definition dhcp-header.h:99
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.
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.
DhcpChaddr GetChaddr()
Get the Address of the client.
void SetRebind(uint32_t time)
Set the Rebind time of the IPv4Address.
void SetChaddr(DhcpChaddr addr)
Set the Chaddress of the device.
Implements the functionality of a DHCP server.
Definition dhcp-server.h:38
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:64
AvailableAddress m_availableAddresses
Available addresses to be used (IP addresses).
void AddStaticDhcpEntry(Address macAddr, Ipv4Address addr)
Add a static entry to the pool.
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:97
Ptr< Socket > m_socket
The socket bound to port 67.
Definition dhcp-server.h:93
ExpiredAddress m_expiredAddresses
Expired addresses to be reused (chaddr of the clients).
void StartApplication() override
Application specific startup code.
static constexpr uint32_t PERMANENT_LEASE
The maximum representable lease time means permanent lease.
LeasedAddress m_leasedAddresses
Leased address and their status (cache memory).
Ipv4Address m_minAddress
The first address in the address pool.
Definition dhcp-server.h:95
Ipv4Address m_gateway
The gateway address.
Definition dhcp-server.h:98
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:96
Ipv4Address m_poolAddress
The network address available to the server.
Definition dhcp-server.h:94
~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.
void SendOffer(Ptr< NetDevice > iDev, DhcpHeader header, InetSocketAddress from)
Sends DHCP offer after receiving DHCP Discover.
void DoDispose() override
Destructor implementation.
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()
AttributeValue implementation for Ipv4Address.
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition ipv4.h:69
AttributeValue implementation for Ipv4Mask.
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.
Definition ptr.h:67
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:561
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
AttributeValue implementation for Time.
Definition nstime.h:1456
a unique identifier for an interface.
Definition type-id.h:49
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
DhcpHeader classes declaration.
#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
Ptr< const AttributeAccessor > MakeIpv4AddressAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeIpv4AddressChecker()
Ptr< const AttributeAccessor > MakeIpv4MaskAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeIpv4MaskChecker()
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1457
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1477
Callback< R, Args... > MakeNullCallback()
Definition callback.h:727
std::array< uint8_t, 16 > DhcpChaddr
This is the Chaddr field, which is 16 bytes long.
Definition dhcp-header.h:44
std::string DhcpChaddrToString(const DhcpChaddr &chaddr)
Function to pretty-print a Chaddr.
#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:439
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1369
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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