/protocol-dhcp/src/main/java/org/apache/directory/server/dhcp/service/StoreBasedDhcpService.java

https://github.com/apache/directory-server · Java · 310 lines · 154 code · 59 blank · 97 comment · 22 complexity · 527e0d1245751007c1fc73ef575d85ac MD5 · raw file

  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. */
  20. package org.apache.directory.server.dhcp.service;
  21. import java.net.InetAddress;
  22. import java.net.InetSocketAddress;
  23. import org.apache.directory.server.dhcp.DhcpException;
  24. import org.apache.directory.server.dhcp.messages.DhcpMessage;
  25. import org.apache.directory.server.dhcp.messages.MessageType;
  26. import org.apache.directory.server.dhcp.options.AddressOption;
  27. import org.apache.directory.server.dhcp.options.OptionsField;
  28. import org.apache.directory.server.dhcp.options.dhcp.ClientIdentifier;
  29. import org.apache.directory.server.dhcp.options.dhcp.IpAddressLeaseTime;
  30. import org.apache.directory.server.dhcp.options.dhcp.MaximumDhcpMessageSize;
  31. import org.apache.directory.server.dhcp.options.dhcp.ParameterRequestList;
  32. import org.apache.directory.server.dhcp.options.dhcp.RequestedIpAddress;
  33. import org.apache.directory.server.dhcp.options.dhcp.ServerIdentifier;
  34. import org.apache.directory.server.dhcp.store.DhcpStore;
  35. /**
  36. * A default implementation of the DHCP service. Does the tedious low-level
  37. * chores of handling DHCP messages, but delegates the lease-handling to a
  38. * supplied DhcpStore.
  39. *
  40. * @see org.apache.directory.server.dhcp.store.DhcpStore
  41. * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  42. */
  43. public class StoreBasedDhcpService extends AbstractDhcpService
  44. {
  45. private final DhcpStore dhcpStore;
  46. public StoreBasedDhcpService( DhcpStore dhcpStore )
  47. {
  48. this.dhcpStore = dhcpStore;
  49. }
  50. /**
  51. * Try to get an existing lease. The lease may have been created during
  52. * earlier DHCP negotiations or a recent DHCPDISCOVER.
  53. *
  54. * @param clientAddress
  55. * @param request
  56. * @return
  57. * @throws DhcpException
  58. */
  59. private Lease getExistingLease( InetSocketAddress clientAddress, DhcpMessage request ) throws DhcpException
  60. {
  61. // determine requested lease time
  62. IpAddressLeaseTime requestedLeaseTimeOption = ( IpAddressLeaseTime ) request.getOptions().get(
  63. IpAddressLeaseTime.class );
  64. long requestedLeaseTime = null != requestedLeaseTimeOption ? requestedLeaseTimeOption.getIntValue() * 1000
  65. : -1L;
  66. // try to get the lease (address) requested by the client
  67. InetAddress requestedAddress = null;
  68. AddressOption requestedAddressOption = ( AddressOption ) request.getOptions().get( RequestedIpAddress.class );
  69. if ( null != requestedAddressOption )
  70. {
  71. requestedAddress = requestedAddressOption.getAddress();
  72. }
  73. if ( null == requestedAddress )
  74. {
  75. requestedAddress = request.getCurrentClientAddress();
  76. }
  77. InetAddress selectionBase = determineSelectionBase( clientAddress, request );
  78. Lease lease = dhcpStore.getExistingLease( request.getHardwareAddress(), requestedAddress, selectionBase,
  79. requestedLeaseTime, request.getOptions() );
  80. if ( null == lease )
  81. {
  82. return null;
  83. }
  84. return lease;
  85. }
  86. /**
  87. * Determine a lease to offer in response to a DHCPDISCOVER message.
  88. * <p>
  89. * When a server receives a DHCPDISCOVER message from a client, the server
  90. * chooses a network address for the requesting client. If no address is
  91. * available, the server may choose to report the problem to the system
  92. * administrator. If an address is available, the new address SHOULD be
  93. * chosen as follows:
  94. * <ul>
  95. * <li> The client's current address as recorded in the client's current
  96. * binding, ELSE
  97. * <li> The client's previous address as recorded in the client's (now
  98. * expired or released) binding, if that address is in the server's pool of
  99. * available addresses and not already allocated, ELSE
  100. * <li> The address requested in the 'Requested IP Address' option, if that
  101. * address is valid and not already allocated, ELSE
  102. * <li> A new address allocated from the server's pool of available
  103. * addresses; the address is selected based on the subnet from which the
  104. * message was received (if 'giaddr' is 0) or on the address of the relay
  105. * agent that forwarded the message ('giaddr' when not 0).
  106. * </ul>
  107. *
  108. * @param clientAddress
  109. * @param request
  110. * @return
  111. */
  112. private Lease getLeaseOffer( InetSocketAddress clientAddress, DhcpMessage request ) throws DhcpException
  113. {
  114. // determine requested lease time
  115. IpAddressLeaseTime requestedLeaseTimeOption = ( IpAddressLeaseTime ) request.getOptions().get(
  116. IpAddressLeaseTime.class );
  117. long requestedLeaseTime = null != requestedLeaseTimeOption ? requestedLeaseTimeOption.getIntValue() * 1000
  118. : -1L;
  119. // try to get the lease (address) requested by the client
  120. InetAddress requestedAddress = null;
  121. AddressOption requestedAddressOption = ( AddressOption ) request.getOptions().get( RequestedIpAddress.class );
  122. if ( null != requestedAddressOption )
  123. {
  124. requestedAddress = requestedAddressOption.getAddress();
  125. }
  126. InetAddress selectionBase = determineSelectionBase( clientAddress, request );
  127. return dhcpStore.getLeaseOffer( request.getHardwareAddress(), requestedAddress, selectionBase,
  128. requestedLeaseTime, request.getOptions() );
  129. }
  130. /*
  131. * @see org.apache.directory.server.dhcp.service.AbstractDhcpService#handleRELEASE(java.net.InetSocketAddress,
  132. * java.net.InetSocketAddress,
  133. * org.apache.directory.server.dhcp.messages.DhcpMessage)
  134. */
  135. @Override
  136. protected DhcpMessage handleRELEASE( InetSocketAddress localAddress, InetSocketAddress clientAddress,
  137. DhcpMessage request ) throws DhcpException
  138. {
  139. // check server ident
  140. AddressOption serverIdentOption = ( AddressOption ) request.getOptions().get( ServerIdentifier.class );
  141. if ( null != serverIdentOption && serverIdentOption.getAddress().isAnyLocalAddress() )
  142. {
  143. return null; // not me?! FIXME: handle authoritative server case
  144. }
  145. Lease lease = getExistingLease( clientAddress, request );
  146. DhcpMessage reply = initGeneralReply( localAddress, request );
  147. if ( null == lease )
  148. {
  149. // null lease? send NAK
  150. // FIXME...
  151. reply.setMessageType( MessageType.DHCPNAK );
  152. reply.setCurrentClientAddress( null );
  153. reply.setAssignedClientAddress( null );
  154. reply.setNextServerAddress( null );
  155. }
  156. else
  157. {
  158. dhcpStore.releaseLease( lease );
  159. // lease Ok, send ACK
  160. // FIXME...
  161. reply.getOptions().merge( lease.getOptions() );
  162. reply.setAssignedClientAddress( lease.getClientAddress() );
  163. reply.setNextServerAddress( lease.getNextServerAddress() );
  164. // fix options
  165. OptionsField options = reply.getOptions();
  166. // these options must not be present
  167. options.remove( RequestedIpAddress.class );
  168. options.remove( ParameterRequestList.class );
  169. options.remove( ClientIdentifier.class );
  170. options.remove( MaximumDhcpMessageSize.class );
  171. // these options must be present
  172. options.add( new IpAddressLeaseTime( ( lease.getExpires() - System.currentTimeMillis() ) / 1000L ) );
  173. stripUnwantedOptions( request, options );
  174. }
  175. return reply;
  176. }
  177. /*
  178. * @see org.apache.directory.server.dhcp.service.AbstractDhcpService#handleDISCOVER(java.net.InetSocketAddress,
  179. * org.apache.directory.server.dhcp.messages.DhcpMessage)
  180. */
  181. @Override
  182. protected DhcpMessage handleDISCOVER( InetSocketAddress localAddress, InetSocketAddress clientAddress,
  183. DhcpMessage request ) throws DhcpException
  184. {
  185. Lease lease = getLeaseOffer( clientAddress, request );
  186. // null lease? don't offer one.
  187. if ( null == lease )
  188. {
  189. return null;
  190. }
  191. DhcpMessage reply = initGeneralReply( localAddress, request );
  192. reply.getOptions().merge( lease.getOptions() );
  193. reply.setMessageType( MessageType.DHCPOFFER );
  194. reply.setAssignedClientAddress( lease.getClientAddress() );
  195. reply.setNextServerAddress( lease.getNextServerAddress() );
  196. // fix options
  197. OptionsField options = reply.getOptions();
  198. // these options must not be present
  199. options.remove( RequestedIpAddress.class );
  200. options.remove( ParameterRequestList.class );
  201. options.remove( ClientIdentifier.class );
  202. options.remove( MaximumDhcpMessageSize.class );
  203. // these options must be present
  204. options.add( new IpAddressLeaseTime( ( lease.getExpires() - System.currentTimeMillis() ) / 1000L ) );
  205. stripUnwantedOptions( request, options );
  206. return reply;
  207. }
  208. /*
  209. * @see org.apache.directory.server.dhcp.service.AbstractDhcpService#handleREQUEST(java.net.InetSocketAddress,
  210. * org.apache.directory.server.dhcp.messages.DhcpMessage)
  211. */
  212. @Override
  213. protected DhcpMessage handleREQUEST( InetSocketAddress localAddress, InetSocketAddress clientAddress,
  214. DhcpMessage request ) throws DhcpException
  215. {
  216. // check server ident
  217. AddressOption serverIdentOption = ( AddressOption ) request.getOptions().get( ServerIdentifier.class );
  218. if ( null != serverIdentOption && serverIdentOption.getAddress().isAnyLocalAddress() )
  219. {
  220. return null; // not me?! FIXME: handle authoritative server case
  221. }
  222. Lease lease = getExistingLease( clientAddress, request );
  223. DhcpMessage reply = initGeneralReply( localAddress, request );
  224. if ( null == lease )
  225. {
  226. // null lease? send NAK
  227. reply.setMessageType( MessageType.DHCPNAK );
  228. reply.setCurrentClientAddress( null );
  229. reply.setAssignedClientAddress( null );
  230. reply.setNextServerAddress( null );
  231. }
  232. else
  233. {
  234. // lease Ok, send ACK
  235. reply.getOptions().merge( lease.getOptions() );
  236. reply.setAssignedClientAddress( lease.getClientAddress() );
  237. reply.setNextServerAddress( lease.getNextServerAddress() );
  238. // fix options
  239. OptionsField options = reply.getOptions();
  240. // these options must not be present
  241. options.remove( RequestedIpAddress.class );
  242. options.remove( ParameterRequestList.class );
  243. options.remove( ClientIdentifier.class );
  244. options.remove( MaximumDhcpMessageSize.class );
  245. // these options must be present
  246. options.add( new IpAddressLeaseTime( ( lease.getExpires() - System.currentTimeMillis() ) / 1000L ) );
  247. stripUnwantedOptions( request, options );
  248. }
  249. return reply;
  250. }
  251. }