INET Framework for OMNeT++/OMNEST
inet::DHCPServer Class Reference

Implements a DHCP server. More...

#include <DHCPServer.h>

Inheritance diagram for inet::DHCPServer:
inet::ILifecycle

Public Member Functions

 DHCPServer ()
 
virtual ~DHCPServer ()
 
- Public Member Functions inherited from inet::ILifecycle
virtual ~ILifecycle ()
 

Protected Types

enum  TimerType { START_DHCP }
 
typedef std::map< IPv4Address, DHCPLeaseDHCPLeased
 

Protected Member Functions

virtual int numInitStages () const override
 
virtual void initialize (int stage) override
 
virtual void handleMessage (cMessage *msg) override
 
virtual void openSocket ()
 
virtual DHCPLeasegetLeaseByMac (MACAddress mac)
 
virtual DHCPLeasegetAvailableLease (IPv4Address requestedAddress, MACAddress &clientMAC)
 
virtual void processDHCPMessage (DHCPMessage *packet)
 
virtual void sendOffer (DHCPLease *lease, DHCPMessage *packet)
 
virtual void sendACK (DHCPLease *lease, DHCPMessage *packet)
 
virtual void sendNAK (DHCPMessage *msg)
 
virtual void handleSelfMessages (cMessage *msg)
 
virtual InterfaceEntrychooseInterface ()
 
virtual void sendToUDP (cPacket *msg, int srcPort, const L3Address &destAddr, int destPort)
 
virtual void receiveSignal (cComponent *source, simsignal_t signalID, cObject *obj, cObject *details) override
 
virtual void startApp ()
 
virtual void stopApp ()
 
virtual bool handleOperationStage (LifecycleOperation *operation, int stage, IDoneCallback *doneCallback) override
 Perform one stage of a lifecycle operation. More...
 

Protected Attributes

DHCPLeased leased
 
bool isOperational = false
 
int numSent = 0
 
int numReceived = 0
 
int serverPort = -1
 
int clientPort = -1
 
unsigned int maxNumOfClients = 0
 
unsigned int leaseTime = 0
 
IPv4Address subnetMask
 
IPv4Address gateway
 
IPv4Address ipAddressStart
 
InterfaceEntryie = nullptr
 
UDPSocket socket
 
simtime_t startTime
 
cMessage * startTimer = nullptr
 

Detailed Description

Implements a DHCP server.

See NED file for more details.

Member Typedef Documentation

typedef std::map<IPv4Address, DHCPLease> inet::DHCPServer::DHCPLeased
protected

Member Enumeration Documentation

Enumerator
START_DHCP 
43  {
45  };
Definition: DHCPServer.h:44

Constructor & Destructor Documentation

inet::DHCPServer::DHCPServer ( )
37 {
38  ie = nullptr;
39  startTimer = nullptr;
40 }
cMessage * startTimer
Definition: DHCPServer.h:64
InterfaceEntry * ie
Definition: DHCPServer.h:61
inet::DHCPServer::~DHCPServer ( )
virtual
43 {
44  cancelAndDelete(startTimer);
45 }
cMessage * startTimer
Definition: DHCPServer.h:64

Member Function Documentation

InterfaceEntry * inet::DHCPServer::chooseInterface ( )
protectedvirtual

Referenced by startApp().

101 {
102  IInterfaceTable *ift = getModuleFromPar<IInterfaceTable>(par("interfaceTableModule"), this);
103  const char *interfaceName = par("interface");
104  InterfaceEntry *ie = nullptr;
105 
106  if (strlen(interfaceName) > 0) {
107  ie = ift->getInterfaceByName(interfaceName);
108  if (ie == nullptr)
109  throw cRuntimeError("Interface \"%s\" does not exist", interfaceName);
110  }
111  else {
112  // there should be exactly one non-loopback interface that we want to serve DHCP requests on
113  for (int i = 0; i < ift->getNumInterfaces(); i++) {
114  InterfaceEntry *current = ift->getInterface(i);
115  if (!current->isLoopback()) {
116  if (ie)
117  throw cRuntimeError("Multiple non-loopback interfaces found, please select explicitly which one you want to serve DHCP requests on");
118  ie = current;
119  }
120  }
121  if (!ie)
122  throw cRuntimeError("No non-loopback interface found to be configured via DHCP");
123  }
124 
125  return ie;
126 }
InterfaceEntry * ie
Definition: DHCPServer.h:61
DHCPLease * inet::DHCPServer::getAvailableLease ( IPv4Address  requestedAddress,
MACAddress clientMAC 
)
protectedvirtual

Referenced by processDHCPMessage().

458 {
459  int beginAddr = ipAddressStart.getInt(); // the first address that we might use
460 
461  // try to allocate the requested address if that address is valid and not already allocated
462  if (!requestedAddress.isUnspecified()) { // valid
463  if (leased.find(requestedAddress) != leased.end() && !leased[requestedAddress].leased) // not already leased (allocated)
464  return &leased[requestedAddress];
465 
466  // lease does not exist, create it
467  leased[requestedAddress] = DHCPLease();
468  leased[requestedAddress].ip = requestedAddress;
469  leased[requestedAddress].gateway = gateway;
470  leased[requestedAddress].subnetMask = subnetMask;
471 
472  return &leased[requestedAddress];
473  }
474 
475  // allocate new address from server's pool of available addresses
476  for (unsigned int i = 0; i < maxNumOfClients; i++) {
477  IPv4Address ip(beginAddr + i);
478  if (leased.find(ip) != leased.end()) {
479  // lease exists but not allocated (e.g. expired or released)
480  if (!leased[ip].leased)
481  return &(leased[ip]);
482  }
483  else {
484  // there is no expired lease so we create a new one
485  leased[ip] = DHCPLease();
486  leased[ip].ip = ip;
487  leased[ip].gateway = gateway;
488  leased[ip].subnetMask = subnetMask;
489  return &(leased[ip]);
490  }
491  }
492  // no lease available
493  return nullptr;
494 }
IPv4Address gateway
Definition: DHCPServer.h:58
IPv4Address ipAddressStart
Definition: DHCPServer.h:59
IPv4Address subnetMask
Definition: DHCPServer.h:57
DHCPLeased leased
Definition: DHCPServer.h:46
uint32 getInt() const
Returns the address as an int.
Definition: IPv4Address.h:197
unsigned int maxNumOfClients
Definition: DHCPServer.h:55
DHCPLease * inet::DHCPServer::getLeaseByMac ( MACAddress  mac)
protectedvirtual

Referenced by processDHCPMessage().

443 {
444  for (auto & elem : leased) {
445  // lease exist
446  if (elem.second.mac == mac) {
447  EV_DETAIL << "Found lease for MAC " << mac << "." << endl;
448  return &(elem.second);
449  }
450  }
451  EV_DETAIL << "Lease not found for MAC " << mac << "." << endl;
452 
453  // lease does not exist
454  return nullptr;
455 }
DHCPLeased leased
Definition: DHCPServer.h:46
void inet::DHCPServer::handleMessage ( cMessage *  msg)
overrideprotectedvirtual
129 {
130  DHCPMessage *dhcpPacket = dynamic_cast<DHCPMessage *>(msg);
131  if (msg->isSelfMessage()) {
132  handleSelfMessages(msg);
133  }
134  else if (dhcpPacket)
135  processDHCPMessage(dhcpPacket);
136  else {
137  // note: unknown packets are likely ICMP errors in response to DHCP messages we sent out; just ignore them
138  EV_WARN << "Unknown packet '" << msg->getName() << "', discarding it." << endl;
139  delete msg;
140  }
141 }
virtual void processDHCPMessage(DHCPMessage *packet)
Definition: DHCPServer.cc:152
virtual void handleSelfMessages(cMessage *msg)
Definition: DHCPServer.cc:143
bool inet::DHCPServer::handleOperationStage ( LifecycleOperation operation,
int  stage,
IDoneCallback doneCallback 
)
overrideprotectedvirtual

Perform one stage of a lifecycle operation.

Processing may be done entirely within this method, or may be a longer process that involves nonzero simulation time or several events, and is triggered by this method call.

Return value: true = "done"; false = "not yet done, will invoke doneCallback when done"

Implements inet::ILifecycle.

537 {
538  Enter_Method_Silent();
539  if (dynamic_cast<NodeStartOperation *>(operation)) {
541  startApp();
542  isOperational = true;
543  }
544  }
545  else if (dynamic_cast<NodeShutdownOperation *>(operation)) {
547  stopApp();
548  isOperational = false;
549  }
550  }
551  else if (dynamic_cast<NodeCrashOperation *>(operation)) {
553  stopApp();
554  isOperational = false;
555  }
556  }
557  else
558  throw cRuntimeError("Unsupported lifecycle operation '%s'", operation->getClassName());
559  return true;
560 }
bool isOperational
Definition: DHCPServer.h:48
Stage
Definition: NodeOperations.h:71
Stage
Definition: NodeOperations.h:126
Stage
Definition: NodeOperations.h:46
virtual void startApp()
Definition: DHCPServer.cc:505
virtual void stopApp()
Definition: DHCPServer.cc:528
Definition: NodeOperations.h:127
void inet::DHCPServer::handleSelfMessages ( cMessage *  msg)
protectedvirtual

Referenced by handleMessage().

144 {
145  if (msg->getKind() == START_DHCP) {
146  openSocket();
147  }
148  else
149  throw cRuntimeError("Unknown selfmessage type!");
150 }
virtual void openSocket()
Definition: DHCPServer.cc:75
Definition: DHCPServer.h:44
void inet::DHCPServer::initialize ( int  stage)
overrideprotectedvirtual
48 {
49  if (stage == INITSTAGE_LOCAL) {
50  startTimer = new cMessage("Start DHCP server", START_DHCP);
51  startTime = par("startTime");
52  }
53  else if (stage == INITSTAGE_APPLICATION_LAYER) {
54  numSent = 0;
55  numReceived = 0;
56  WATCH(numSent);
57  WATCH(numReceived);
58  WATCH_MAP(leased);
59 
60  // DHCP UDP ports
61  clientPort = 68; // client
62  serverPort = 67; // server
63 
64  cModule *host = getContainingNode(this);
65  host->subscribe(NF_INTERFACE_DELETED, this);
66 
67  NodeStatus *nodeStatus = dynamic_cast<NodeStatus *>(host->getSubmodule("status"));
68  isOperational = (!nodeStatus) || nodeStatus->getState() == NodeStatus::UP;
69 
70  if (isOperational)
71  startApp();
72  }
73 }
bool isOperational
Definition: DHCPServer.h:48
simtime_t startTime
Definition: DHCPServer.h:63
int numReceived
Definition: DHCPServer.h:50
int numSent
Definition: DHCPServer.h:49
int serverPort
Definition: DHCPServer.h:51
Local initializations.
Definition: InitStages.h:35
cModule * getContainingNode(const cModule *from)
Find the node containing the given module.
Definition: ModuleAccess.cc:65
DHCPLeased leased
Definition: DHCPServer.h:46
Definition: DHCPServer.h:44
virtual void startApp()
Definition: DHCPServer.cc:505
int clientPort
Definition: DHCPServer.h:52
cMessage * startTimer
Definition: DHCPServer.h:64
simsignal_t NF_INTERFACE_DELETED
Definition: NotifierConsts.cc:49
Initialization of applications.
Definition: InitStages.h:106
Definition: NodeStatus.h:40
virtual int inet::DHCPServer::numInitStages ( ) const
inlineoverrideprotectedvirtual
67 { return NUM_INIT_STAGES; }
The number of initialization stages.
Definition: InitStages.h:116
void inet::DHCPServer::openSocket ( )
protectedvirtual

Referenced by handleSelfMessages().

76 {
77  if (!ie)
78  throw cRuntimeError("Interface to listen does not exist. aborting");
79  socket.setOutputGate(gate("udpOut"));
81  socket.setBroadcast(true);
82  EV_INFO << "DHCP server bound to port " << serverPort << endl;
83 }
void setOutputGate(cGate *toUdp)
Sets the gate on which to send to UDP.
Definition: UDPSocket.h:110
void setBroadcast(bool broadcast)
Set the Broadcast option on the UDP socket.
Definition: UDPSocket.cc:121
int serverPort
Definition: DHCPServer.h:51
InterfaceEntry * ie
Definition: DHCPServer.h:61
UDPSocket socket
Definition: DHCPServer.h:62
void bind(int localPort)
Bind the socket to a local port number.
Definition: UDPSocket.cc:53
void inet::DHCPServer::processDHCPMessage ( DHCPMessage packet)
protectedvirtual

Referenced by handleMessage().

153 {
154  ASSERT(isOperational && ie != nullptr);
155 
156  // check that the packet arrived on the interface we are supposed to serve
157  UDPDataIndication *ctrl = check_and_cast<UDPDataIndication *>(packet->removeControlInfo());
158  int inputInterfaceId = ctrl->getInterfaceId();
159  delete ctrl;
160  if (inputInterfaceId != ie->getInterfaceId()) {
161  EV_WARN << "DHCP message arrived on a different interface, dropping\n";
162  delete packet;
163  return;
164  }
165 
166  // check the OP code
167  if (packet->getOp() == BOOTREQUEST) {
168  int messageType = packet->getOptions().getMessageType();
169 
170  if (messageType == DHCPDISCOVER) { // RFC 2131, 4.3.1
171  EV_INFO << "DHCPDISCOVER arrived. Handling it." << endl;
172 
173  DHCPLease *lease = getLeaseByMac(packet->getChaddr());
174  if (!lease) {
175  // MAC not registered, create offering a new lease to the client
176  lease = getAvailableLease(packet->getOptions().getRequestedIp(), packet->getChaddr());
177  if (lease != nullptr) {
178  // std::cout << "MAC: " << packet->getChaddr() << " ----> IP: " << lease->ip << endl;
179  lease->mac = packet->getChaddr();
180  lease->xid = packet->getXid();
181  //lease->parameterRequestList = packet->getOptions().get(PARAM_LIST); TODO: !!
182  lease->leased = true; // TODO
183  sendOffer(lease, packet);
184  }
185  else
186  EV_ERROR << "No lease available. Ignoring discover." << endl;
187  }
188  else {
189  // MAC already exist, offering the same lease
190  lease->xid = packet->getXid();
191  //lease->parameterRequestList = packet->getOptions().get(PARAM_LIST); // TODO: !!
192  sendOffer(lease, packet);
193  }
194  }
195  else if (messageType == DHCPREQUEST) { // RFC 2131, 4.3.2
196  EV_INFO << "DHCPREQUEST arrived. Handling it." << endl;
197 
198  // check if the request was in response of an offering
199  if (packet->getOptions().getServerIdentifier() == ie->ipv4Data()->getIPAddress()) {
200  // the REQUEST is in response to an offering (because SERVER_ID is filled)
201  // otherwise the msg is a request to extend an existing lease (e. g. INIT-REBOOT)
202 
203  DHCPLease *lease = getLeaseByMac(packet->getChaddr());
204  if (lease != nullptr) {
205  if (lease->ip != packet->getOptions().getRequestedIp()) {
206  EV_ERROR << "The 'requested IP address' must be filled in with the 'yiaddr' value from the chosen DHCPOFFER." << endl;
207  sendNAK(packet);
208  }
209  else {
210  EV_INFO << "From now " << lease->ip << " is leased to " << lease->mac << "." << endl;
211  lease->xid = packet->getXid();
212  lease->leaseTime = leaseTime;
213  lease->leased = true;
214 
215  // TODO: final check before ACK (it is not necessary but recommended)
216  sendACK(lease, packet);
217 
218  // TODO: update the display string to inform how many clients are assigned
219  }
220  }
221  else {
222  EV_ERROR << "There is no available lease for " << packet->getChaddr() << ". Probably, the client missed to send DHCPDISCOVER before DHCPREQUEST." << endl;
223  sendNAK(packet);
224  }
225  }
226  else {
227  if (packet->getCiaddr().isUnspecified()) { // init-reboot
228  // std::cout << "init-reboot" << endl;
229  IPv4Address requestedAddress = packet->getOptions().getRequestedIp();
230  auto it = leased.find(requestedAddress);
231  if (it == leased.end()) {
232  // if DHCP server has no record of the requested IP, then it must remain silent
233  // and may output a warning to the network admin
234  EV_WARN << "DHCP server has no record of IP " << requestedAddress << "." << endl;
235  }
236  else if (IPv4Address::maskedAddrAreEqual(requestedAddress, it->second.ip, subnetMask)) { // on the same network
237  DHCPLease *lease = &it->second;
238  EV_INFO << "Initialization with known IP address (INIT-REBOOT) " << lease->ip << " on " << lease->mac << " was successful." << endl;
239  lease->xid = packet->getXid();
240  lease->leaseTime = leaseTime;
241  lease->leased = true;
242 
243  // TODO: final check before ACK (it is not necessary but recommended)
244  sendACK(lease, packet);
245  }
246  else {
247  EV_ERROR << "The requested IP address is incorrect, or is on the wrong network." << endl;
248  sendNAK(packet);
249  }
250  }
251  else { // renewing or rebinding: in this case ciaddr must be filled in with client's IP address
252  auto it = leased.find(packet->getCiaddr());
253  DHCPLease *lease = &it->second;
254  if (it != leased.end()) {
255  EV_INFO << "Request for renewal/rebinding IP " << lease->ip << " to " << lease->mac << "." << endl;
256  lease->xid = packet->getXid();
257  lease->leaseTime = leaseTime;
258  lease->leased = true;
259 
260  // unicast ACK to ciaddr
261  sendACK(lease, packet);
262  }
263  else {
264  EV_ERROR << "Renewal/rebinding process failed: requested IP address " << packet->getCiaddr() << " not found in the server's database!" << endl;
265  sendNAK(packet);
266  }
267  }
268  }
269  }
270  else
271  EV_WARN << "BOOTREQUEST arrived, but DHCP message type is unknown. Dropping it." << endl;
272  }
273  else {
274  EV_WARN << "Message opcode is unknown. This DHCP server only handles BOOTREQUEST messages. Dropping it." << endl;
275  }
276 
277  EV_DEBUG << "Deleting " << packet << "." << endl;
278  delete packet;
279 
280  numReceived++;
281 }
IPv4InterfaceData * ipv4Data() const
Definition: InterfaceEntry.h:221
static bool maskedAddrAreEqual(const IPv4Address &addr1, const IPv4Address &addr2, const IPv4Address &netmask)
Test if the masked addresses (ie the mask is applied to addr1 and addr2) are equal.
Definition: IPv4Address.cc:260
int getInterfaceId() const
Definition: InterfaceEntry.h:185
virtual DHCPLease * getLeaseByMac(MACAddress mac)
Definition: DHCPServer.cc:442
bool isOperational
Definition: DHCPServer.h:48
virtual DHCPLease * getAvailableLease(IPv4Address requestedAddress, MACAddress &clientMAC)
Definition: DHCPServer.cc:457
Definition: DHCPMessage_m.h:72
int numReceived
Definition: DHCPServer.h:50
virtual void sendNAK(DHCPMessage *msg)
Definition: DHCPServer.cc:283
unsigned int leaseTime
Definition: DHCPServer.h:56
IPv4Address subnetMask
Definition: DHCPServer.h:57
DHCPLeased leased
Definition: DHCPServer.h:46
IPv4Address getIPAddress() const
Definition: IPv4InterfaceData.h:177
Definition: DHCPMessage_m.h:74
Definition: DHCPMessage_m.h:50
virtual void sendACK(DHCPLease *lease, DHCPMessage *packet)
Definition: DHCPServer.cc:311
virtual void sendOffer(DHCPLease *lease, DHCPMessage *packet)
Definition: DHCPServer.cc:376
MACAddress mac
Definition: DHCPLease.h:36
InterfaceEntry * ie
Definition: DHCPServer.h:61
void inet::DHCPServer::receiveSignal ( cComponent *  source,
simsignal_t  signalID,
cObject *  obj,
cObject *  details 
)
overrideprotectedvirtual
86 {
87  Enter_Method_Silent();
88 
89  if (signalID == NF_INTERFACE_DELETED) {
90  if (isOperational) {
91  InterfaceEntry *nie = check_and_cast<InterfaceEntry *>(obj);
92  if (ie == nie)
93  throw cRuntimeError("Reacting to interface deletions is not implemented in this module");
94  }
95  }
96  else
97  throw cRuntimeError("Unexpected signal: %s", getSignalName(signalID));
98 }
bool isOperational
Definition: DHCPServer.h:48
InterfaceEntry * ie
Definition: DHCPServer.h:61
simsignal_t NF_INTERFACE_DELETED
Definition: NotifierConsts.cc:49
void inet::DHCPServer::sendACK ( DHCPLease lease,
DHCPMessage packet 
)
protectedvirtual

Referenced by processDHCPMessage().

312 {
313  EV_INFO << "Sending the ACK to " << lease->mac << "." << endl;
314 
315  DHCPMessage *ack = new DHCPMessage("DHCPACK");
316  ack->setOp(BOOTREPLY);
317  ack->setByteLength(308); // DHCP ACK packet size
318  ack->setHtype(1); // ethernet
319  ack->setHlen(6); // hardware address length (6 octets)
320  ack->setHops(0);
321  ack->setXid(lease->xid); // transaction id;
322  ack->setSecs(0); // 0 seconds from transaction started
323  ack->setBroadcast(false);
324  ack->setCiaddr(lease->ip); // client IP addr.
325  ack->setYiaddr(lease->ip); // client IP addr.
326 
327  ack->setChaddr(lease->mac); // client MAC address
328  ack->setSname(""); // no server name given
329  ack->setFile(""); // no file given
330  ack->getOptions().setMessageType(DHCPACK);
331 
332  // add the lease options
333  ack->getOptions().setSubnetMask(lease->subnetMask);
334  ack->getOptions().setRenewalTime(leaseTime * 0.5); // RFC 4.4.5
335  ack->getOptions().setRebindingTime(leaseTime * 0.875);
336  ack->getOptions().setLeaseTime(leaseTime);
337  ack->getOptions().setRouterArraySize(1);
338  ack->getOptions().setRouter(0, lease->gateway);
339  ack->getOptions().setDnsArraySize(1);
340  ack->getOptions().setDns(0, lease->dns);
341 
342  // add the server ID as the RFC says
343  ack->getOptions().setServerIdentifier(ie->ipv4Data()->getIPAddress());
344 
345  // register the lease time
346  lease->leaseTime = simTime();
347 
348  /* RFC 2131, 4.1
349  * If the 'giaddr' field in a DHCP message from a client is non-zero,
350  * the server sends any return messages to the 'DHCP server' port on the
351  * BOOTP relay agent whose address appears in 'giaddr'. If the 'giaddr'
352  * field is zero and the 'ciaddr' field is nonzero, then the server
353  * unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'.
354  * If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is
355  * set, then the server broadcasts DHCPOFFER and DHCPACK messages to
356  * 0xffffffff. If the broadcast bit is not set and 'giaddr' is zero and
357  * 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK
358  * messages to the client's hardware address and 'yiaddr' address.
359  */
360  IPv4Address destAddr;
361  if (!packet->getGiaddr().isUnspecified())
362  destAddr = packet->getGiaddr();
363  else if (!packet->getCiaddr().isUnspecified())
364  destAddr = packet->getCiaddr();
365  else if (packet->getBroadcast())
366  destAddr = IPv4Address::ALLONES_ADDRESS;
367  else {
368  // TODO should send it to client's hardware address and yiaddr address, but the application can not set the destination MACAddress.
369  // destAddr = lease->ip;
370  destAddr = IPv4Address::ALLONES_ADDRESS;
371  }
372 
373  sendToUDP(ack, serverPort, destAddr, clientPort);
374 }
IPv4InterfaceData * ipv4Data() const
Definition: InterfaceEntry.h:221
unsigned int leaseTime
Definition: DHCPServer.h:56
Definition: DHCPMessage_m.h:76
int serverPort
Definition: DHCPServer.h:51
Definition: DHCPMessage_m.h:51
IPv4Address getIPAddress() const
Definition: IPv4InterfaceData.h:177
int clientPort
Definition: DHCPServer.h:52
InterfaceEntry * ie
Definition: DHCPServer.h:61
static const IPv4Address ALLONES_ADDRESS
255.255.255.255
Definition: IPv4Address.h:105
virtual void sendToUDP(cPacket *msg, int srcPort, const L3Address &destAddr, int destPort)
Definition: DHCPServer.cc:496
void inet::DHCPServer::sendNAK ( DHCPMessage msg)
protectedvirtual

Referenced by processDHCPMessage().

284 {
285  // EV_INFO << "Sending NAK to " << lease->mac << "." << endl;
286  DHCPMessage *nak = new DHCPMessage("DHCPNAK");
287  nak->setOp(BOOTREPLY);
288  nak->setByteLength(308); // DHCPNAK packet size
289  nak->setHtype(1); // ethernet
290  nak->setHlen(6); // hardware address length (6 octets)
291  nak->setHops(0);
292  nak->setXid(msg->getXid()); // transaction id from client
293  nak->setSecs(0); // 0 seconds from transaction started.
294  nak->setBroadcast(msg->getBroadcast());
295  nak->setGiaddr(msg->getGiaddr()); // next server IP
296  nak->setChaddr(msg->getChaddr());
297  nak->getOptions().setServerIdentifier(ie->ipv4Data()->getIPAddress());
298  nak->getOptions().setMessageType(DHCPNAK);
299 
300  /* RFC 2131, 4.1
301  *
302  * In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK
303  * messages to 0xffffffff.
304  */
305  IPv4Address destAddr = IPv4Address::ALLONES_ADDRESS;
306  if (!msg->getGiaddr().isUnspecified())
307  destAddr = msg->getGiaddr();
308  sendToUDP(nak, serverPort, destAddr, clientPort);
309 }
IPv4InterfaceData * ipv4Data() const
Definition: InterfaceEntry.h:221
int serverPort
Definition: DHCPServer.h:51
Definition: DHCPMessage_m.h:51
Definition: DHCPMessage_m.h:77
IPv4Address getIPAddress() const
Definition: IPv4InterfaceData.h:177
int clientPort
Definition: DHCPServer.h:52
InterfaceEntry * ie
Definition: DHCPServer.h:61
static const IPv4Address ALLONES_ADDRESS
255.255.255.255
Definition: IPv4Address.h:105
virtual void sendToUDP(cPacket *msg, int srcPort, const L3Address &destAddr, int destPort)
Definition: DHCPServer.cc:496
void inet::DHCPServer::sendOffer ( DHCPLease lease,
DHCPMessage packet 
)
protectedvirtual

Referenced by processDHCPMessage().

377 {
378  EV_INFO << "Offering " << *lease << endl;
379 
380  DHCPMessage *offer = new DHCPMessage("DHCPOFFER");
381  offer->setOp(BOOTREPLY);
382  offer->setByteLength(308); // DHCP OFFER packet size
383  offer->setHtype(1); // ethernet
384  offer->setHlen(6); // hardware address lenght (6 octets)
385  offer->setHops(0);
386  offer->setXid(lease->xid); // transaction id
387  offer->setSecs(0); // 0 seconds from transaction started
388  offer->setBroadcast(false); // unicast
389 
390  offer->setYiaddr(lease->ip); // ip offered.
391  offer->setGiaddr(lease->gateway); // next server ip
392 
393  offer->setChaddr(lease->mac); // client mac address
394  offer->setSname(""); // no server name given
395  offer->setFile(""); // no file given
396  offer->getOptions().setMessageType(DHCPOFFER);
397 
398  // add the offer options
399  offer->getOptions().setSubnetMask(lease->subnetMask);
400  offer->getOptions().setRenewalTime(leaseTime * 0.5); // RFC 4.4.5
401  offer->getOptions().setRebindingTime(leaseTime * 0.875);
402  offer->getOptions().setLeaseTime(leaseTime);
403  offer->getOptions().setRouterArraySize(1);
404  offer->getOptions().setRouter(0, lease->gateway);
405  offer->getOptions().setDnsArraySize(1);
406  offer->getOptions().setDns(0, lease->dns);
407 
408  // add the server_id as the RFC says
409  offer->getOptions().setServerIdentifier(ie->ipv4Data()->getIPAddress());
410 
411  // register the offering time // todo: ?
412  lease->leaseTime = simTime();
413 
414  /* RFC 2131, 4.1
415  * If the 'giaddr' field in a DHCP message from a client is non-zero,
416  * the server sends any return messages to the 'DHCP server' port on the
417  * BOOTP relay agent whose address appears in 'giaddr'. If the 'giaddr'
418  * field is zero and the 'ciaddr' field is nonzero, then the server
419  * unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'.
420  * If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is
421  * set, then the server broadcasts DHCPOFFER and DHCPACK messages to
422  * 0xffffffff. If the broadcast bit is not set and 'giaddr' is zero and
423  * 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK
424  * messages to the client's hardware address and 'yiaddr' address.
425  */
426  IPv4Address destAddr;
427  if (!packet->getGiaddr().isUnspecified())
428  destAddr = packet->getGiaddr();
429  else if (!packet->getCiaddr().isUnspecified())
430  destAddr = packet->getCiaddr();
431  else if (packet->getBroadcast())
432  destAddr = IPv4Address::ALLONES_ADDRESS;
433  else {
434  // TODO should send it to client's hardware address and yiaddr address, but the application can not set the destination MACAddress.
435  // destAddr = lease->ip;
436  destAddr = IPv4Address::ALLONES_ADDRESS;
437  }
438 
439  sendToUDP(offer, serverPort, destAddr, clientPort);
440 }
IPv4InterfaceData * ipv4Data() const
Definition: InterfaceEntry.h:221
unsigned int leaseTime
Definition: DHCPServer.h:56
int serverPort
Definition: DHCPServer.h:51
Definition: DHCPMessage_m.h:51
IPv4Address getIPAddress() const
Definition: IPv4InterfaceData.h:177
int clientPort
Definition: DHCPServer.h:52
InterfaceEntry * ie
Definition: DHCPServer.h:61
Definition: DHCPMessage_m.h:73
static const IPv4Address ALLONES_ADDRESS
255.255.255.255
Definition: IPv4Address.h:105
virtual void sendToUDP(cPacket *msg, int srcPort, const L3Address &destAddr, int destPort)
Definition: DHCPServer.cc:496
void inet::DHCPServer::sendToUDP ( cPacket *  msg,
int  srcPort,
const L3Address destAddr,
int  destPort 
)
protectedvirtual

Referenced by sendACK(), sendNAK(), and sendOffer().

497 {
498  EV_INFO << "Sending packet: " << msg << "." << endl;
499  numSent++;
500  UDPSocket::SendOptions options;
501  options.outInterfaceId = ie->getInterfaceId();
502  socket.sendTo(msg, destAddr, destPort, &options);
503 }
int getInterfaceId() const
Definition: InterfaceEntry.h:185
void sendTo(cPacket *msg, L3Address destAddr, int destPort, const SendOptions *options=nullptr)
Sends a data packet to the given address and port.
Definition: UDPSocket.cc:88
int numSent
Definition: DHCPServer.h:49
InterfaceEntry * ie
Definition: DHCPServer.h:61
UDPSocket socket
Definition: DHCPServer.h:62
void inet::DHCPServer::startApp ( )
protectedvirtual

Referenced by handleOperationStage(), and initialize().

506 {
507  maxNumOfClients = par("maxNumClients");
508  leaseTime = par("leaseTime");
509 
510  simtime_t start = std::max(startTime, simTime());
511  ie = chooseInterface();
512  IPv4InterfaceData *ipv4data = ie->ipv4Data();
513  if (ipv4data == nullptr)
514  throw cRuntimeError("interface %s is not configured for IPv4", ie->getFullName());
515  const char *gatewayStr = par("gateway").stringValue();
516  gateway = *gatewayStr ? L3AddressResolver().resolve(gatewayStr, L3AddressResolver::ADDR_IPv4).toIPv4() : ipv4data->getIPAddress();
517  subnetMask = ipv4data->getNetmask();
518  long numReservedAddresses = par("numReservedAddresses").longValue();
519  uint32_t networkStartAddress = ipv4data->getIPAddress().getInt() & ipv4data->getNetmask().getInt();
520  ipAddressStart = IPv4Address(networkStartAddress + numReservedAddresses);
521  if (!IPv4Address::maskedAddrAreEqual(ipv4data->getIPAddress(), ipAddressStart, subnetMask))
522  throw cRuntimeError("The numReservedAddresses parameter larger than address range");
523  if (!IPv4Address::maskedAddrAreEqual(ipv4data->getIPAddress(), IPv4Address(ipAddressStart.getInt() + maxNumOfClients - 1), subnetMask))
524  throw cRuntimeError("Not enough IP addresses in subnet for %d clients", maxNumOfClients);
525  scheduleAt(start, startTimer);
526 }
IPv4InterfaceData * ipv4Data() const
Definition: InterfaceEntry.h:221
static bool maskedAddrAreEqual(const IPv4Address &addr1, const IPv4Address &addr2, const IPv4Address &netmask)
Test if the masked addresses (ie the mask is applied to addr1 and addr2) are equal.
Definition: IPv4Address.cc:260
IPv4Address gateway
Definition: DHCPServer.h:58
virtual InterfaceEntry * chooseInterface()
Definition: DHCPServer.cc:100
IPv4Address ipAddressStart
Definition: DHCPServer.h:59
simtime_t startTime
Definition: DHCPServer.h:63
unsigned int leaseTime
Definition: DHCPServer.h:56
double max(double a, double b)
Returns the greater of the given parameters.
Definition: INETMath.h:161
IPv4Address subnetMask
Definition: DHCPServer.h:57
uint32 getInt() const
Returns the address as an int.
Definition: IPv4Address.h:197
Definition: L3AddressResolver.h:80
unsigned int maxNumOfClients
Definition: DHCPServer.h:55
cMessage * startTimer
Definition: DHCPServer.h:64
InterfaceEntry * ie
Definition: DHCPServer.h:61
void inet::DHCPServer::stopApp ( )
protectedvirtual

Referenced by handleOperationStage().

529 {
530  leased.clear();
531  ie = nullptr;
532  cancelEvent(startTimer);
533  // socket.close(); TODO:
534 }
DHCPLeased leased
Definition: DHCPServer.h:46
cMessage * startTimer
Definition: DHCPServer.h:64
InterfaceEntry * ie
Definition: DHCPServer.h:61

Member Data Documentation

int inet::DHCPServer::clientPort = -1
protected
IPv4Address inet::DHCPServer::gateway
protected

Referenced by getAvailableLease(), and startApp().

IPv4Address inet::DHCPServer::ipAddressStart
protected

Referenced by getAvailableLease(), and startApp().

bool inet::DHCPServer::isOperational = false
protected
DHCPLeased inet::DHCPServer::leased
protected
unsigned int inet::DHCPServer::leaseTime = 0
protected
unsigned int inet::DHCPServer::maxNumOfClients = 0
protected

Referenced by getAvailableLease(), and startApp().

int inet::DHCPServer::numReceived = 0
protected

Referenced by initialize(), and processDHCPMessage().

int inet::DHCPServer::numSent = 0
protected

Referenced by initialize(), and sendToUDP().

int inet::DHCPServer::serverPort = -1
protected
UDPSocket inet::DHCPServer::socket
protected

Referenced by openSocket(), and sendToUDP().

simtime_t inet::DHCPServer::startTime
protected

Referenced by initialize(), and startApp().

cMessage* inet::DHCPServer::startTimer = nullptr
protected
IPv4Address inet::DHCPServer::subnetMask
protected

The documentation for this class was generated from the following files: