View Javadoc

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  
22  
23  import java.net.InetAddress;
24  import java.net.InetSocketAddress;
25  
26  import org.apache.directory.server.dhcp.DhcpException;
27  import org.apache.directory.server.dhcp.messages.DhcpMessage;
28  import org.apache.directory.server.dhcp.messages.MessageType;
29  import org.apache.directory.server.dhcp.options.AddressOption;
30  import org.apache.directory.server.dhcp.options.OptionsField;
31  import org.apache.directory.server.dhcp.options.dhcp.ClientIdentifier;
32  import org.apache.directory.server.dhcp.options.dhcp.IpAddressLeaseTime;
33  import org.apache.directory.server.dhcp.options.dhcp.MaximumDhcpMessageSize;
34  import org.apache.directory.server.dhcp.options.dhcp.ParameterRequestList;
35  import org.apache.directory.server.dhcp.options.dhcp.RequestedIpAddress;
36  import org.apache.directory.server.dhcp.options.dhcp.ServerIdentifier;
37  import org.apache.directory.server.dhcp.store.DhcpStore;
38  
39  
40  /**
41   * A default implementation of the DHCP service. Does the tedious low-level
42   * chores of handling DHCP messages, but delegates the lease-handling to a
43   * supplied DhcpStore.
44   * 
45   * @see org.apache.directory.server.dhcp.store.DhcpStore
46   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
47   * @version $Rev: 545042 $, $Date: 2007-06-06 22:32:01 -0500 (Mi, 06 Jun 2007) $
48   */
49  public class StoreBasedDhcpService extends AbstractDhcpService
50  {
51      private final DhcpStore dhcpStore;
52  
53  
54      public StoreBasedDhcpService(DhcpStore dhcpStore)
55      {
56          this.dhcpStore = dhcpStore;
57      }
58  
59  
60      /**
61       * Try to get an existing lease. The lease may have been created during
62       * earlier DHCP negotiations or a recent DHCPDISCOVER.
63       * 
64       * @param clientAddress
65       * @param request
66       * @return
67       * @throws DhcpException
68       */
69      private Lease getExistingLease( InetSocketAddress clientAddress, DhcpMessage request ) throws DhcpException
70      {
71          // determine requested lease time
72          IpAddressLeaseTime requestedLeaseTimeOption = ( IpAddressLeaseTime ) request.getOptions().get(
73              IpAddressLeaseTime.class );
74          long requestedLeaseTime = null != requestedLeaseTimeOption ? requestedLeaseTimeOption.getIntValue() * 1000
75              : -1L;
76  
77          // try to get the lease (address) requested by the client
78          InetAddress requestedAddress = null;
79          AddressOption requestedAddressOption = ( AddressOption ) request.getOptions().get( RequestedIpAddress.class );
80          if ( null != requestedAddressOption )
81              requestedAddress = requestedAddressOption.getAddress();
82          if ( null == requestedAddress )
83              requestedAddress = request.getCurrentClientAddress();
84  
85          InetAddress selectionBase = determineSelectionBase( clientAddress, request );
86  
87          Lease lease = dhcpStore.getExistingLease( request.getHardwareAddress(), requestedAddress, selectionBase,
88              requestedLeaseTime, request.getOptions() );
89  
90          if ( null == lease )
91              return null;
92  
93          return lease;
94      }
95  
96  
97      /**
98       * Determine a lease to offer in response to a DHCPDISCOVER message.
99       * <p>
100      * When a server receives a DHCPDISCOVER message from a client, the server
101      * chooses a network address for the requesting client. If no address is
102      * available, the server may choose to report the problem to the system
103      * administrator. If an address is available, the new address SHOULD be
104      * chosen as follows:
105      * <ul>
106      * <li> The client's current address as recorded in the client's current
107      * binding, ELSE
108      * <li> The client's previous address as recorded in the client's (now
109      * expired or released) binding, if that address is in the server's pool of
110      * available addresses and not already allocated, ELSE
111      * <li> The address requested in the 'Requested IP Address' option, if that
112      * address is valid and not already allocated, ELSE
113      * <li> A new address allocated from the server's pool of available
114      * addresses; the address is selected based on the subnet from which the
115      * message was received (if 'giaddr' is 0) or on the address of the relay
116      * agent that forwarded the message ('giaddr' when not 0).
117      * </ul>
118      * 
119      * @param clientAddress
120      * @param request
121      * @return
122      */
123     private Lease getLeaseOffer( InetSocketAddress clientAddress, DhcpMessage request ) throws DhcpException
124     {
125         // determine requested lease time
126         IpAddressLeaseTime requestedLeaseTimeOption = ( IpAddressLeaseTime ) request.getOptions().get(
127             IpAddressLeaseTime.class );
128         long requestedLeaseTime = null != requestedLeaseTimeOption ? requestedLeaseTimeOption.getIntValue() * 1000
129             : -1L;
130 
131         // try to get the lease (address) requested by the client
132         InetAddress requestedAddress = null;
133         AddressOption requestedAddressOption = ( AddressOption ) request.getOptions().get( RequestedIpAddress.class );
134         if ( null != requestedAddressOption )
135             requestedAddress = requestedAddressOption.getAddress();
136 
137         InetAddress selectionBase = determineSelectionBase( clientAddress, request );
138 
139         Lease lease = dhcpStore.getLeaseOffer( request.getHardwareAddress(), requestedAddress, selectionBase,
140             requestedLeaseTime, request.getOptions() );
141 
142         return lease;
143     }
144 
145 
146     /*
147      * @see org.apache.directory.server.dhcp.service.AbstractDhcpService#handleRELEASE(java.net.InetSocketAddress,
148      *      java.net.InetSocketAddress,
149      *      org.apache.directory.server.dhcp.messages.DhcpMessage)
150      */
151     protected DhcpMessage handleRELEASE( InetSocketAddress localAddress, InetSocketAddress clientAddress,
152         DhcpMessage request ) throws DhcpException
153     {
154         // check server ident
155         AddressOption serverIdentOption = ( AddressOption ) request.getOptions().get( ServerIdentifier.class );
156         if ( null != serverIdentOption && serverIdentOption.getAddress().isAnyLocalAddress() )
157             return null; // not me?! FIXME: handle authoritative server case
158 
159         Lease lease = getExistingLease( clientAddress, request );
160 
161         DhcpMessage reply = initGeneralReply( localAddress, request );
162 
163         if ( null == lease )
164         {
165             // null lease? send NAK
166             // FIXME...
167             reply.setMessageType( MessageType.DHCPNAK );
168             reply.setCurrentClientAddress( null );
169             reply.setAssignedClientAddress( null );
170             reply.setNextServerAddress( null );
171         }
172         else
173         {
174             dhcpStore.releaseLease( lease );
175 
176             // lease Ok, send ACK
177             // FIXME...
178             reply.getOptions().merge( lease.getOptions() );
179 
180             reply.setAssignedClientAddress( lease.getClientAddress() );
181             reply.setNextServerAddress( lease.getNextServerAddress() );
182 
183             // fix options
184             OptionsField options = reply.getOptions();
185 
186             // these options must not be present
187             options.remove( RequestedIpAddress.class );
188             options.remove( ParameterRequestList.class );
189             options.remove( ClientIdentifier.class );
190             options.remove( MaximumDhcpMessageSize.class );
191 
192             // these options must be present
193             options.add( new IpAddressLeaseTime( ( lease.getExpires() - System.currentTimeMillis() ) / 1000L ) );
194 
195             stripUnwantedOptions( request, options );
196         }
197         return reply;
198 
199     }
200 
201 
202     /*
203      * @see org.apache.directory.server.dhcp.service.AbstractDhcpService#handleDISCOVER(java.net.InetSocketAddress,
204      *      org.apache.directory.server.dhcp.messages.DhcpMessage)
205      */
206     protected DhcpMessage handleDISCOVER( InetSocketAddress localAddress, InetSocketAddress clientAddress,
207         DhcpMessage request ) throws DhcpException
208     {
209         Lease lease = getLeaseOffer( clientAddress, request );
210 
211         // null lease? don't offer one.
212         if ( null == lease )
213             return null;
214 
215         DhcpMessage reply = initGeneralReply( localAddress, request );
216 
217         reply.getOptions().merge( lease.getOptions() );
218 
219         reply.setMessageType( MessageType.DHCPOFFER );
220 
221         reply.setAssignedClientAddress( lease.getClientAddress() );
222         reply.setNextServerAddress( lease.getNextServerAddress() );
223 
224         // fix options
225         OptionsField options = reply.getOptions();
226 
227         // these options must not be present
228         options.remove( RequestedIpAddress.class );
229         options.remove( ParameterRequestList.class );
230         options.remove( ClientIdentifier.class );
231         options.remove( MaximumDhcpMessageSize.class );
232 
233         // these options must be present
234         options.add( new IpAddressLeaseTime( ( lease.getExpires() - System.currentTimeMillis() ) / 1000L ) );
235 
236         stripUnwantedOptions( request, options );
237 
238         return reply;
239     }
240 
241 
242     /*
243      * @see org.apache.directory.server.dhcp.service.AbstractDhcpService#handleREQUEST(java.net.InetSocketAddress,
244      *      org.apache.directory.server.dhcp.messages.DhcpMessage)
245      */
246     protected DhcpMessage handleREQUEST( InetSocketAddress localAddress, InetSocketAddress clientAddress,
247         DhcpMessage request ) throws DhcpException
248     {
249         // check server ident
250         AddressOption serverIdentOption = ( AddressOption ) request.getOptions().get( ServerIdentifier.class );
251         if ( null != serverIdentOption && serverIdentOption.getAddress().isAnyLocalAddress() )
252             return null; // not me?! FIXME: handle authoritative server case
253 
254         Lease lease = getExistingLease( clientAddress, request );
255 
256         DhcpMessage reply = initGeneralReply( localAddress, request );
257 
258         if ( null == lease )
259         {
260             // null lease? send NAK
261             reply.setMessageType( MessageType.DHCPNAK );
262             reply.setCurrentClientAddress( null );
263             reply.setAssignedClientAddress( null );
264             reply.setNextServerAddress( null );
265         }
266         else
267         {
268             // lease Ok, send ACK
269             reply.getOptions().merge( lease.getOptions() );
270 
271             reply.setAssignedClientAddress( lease.getClientAddress() );
272             reply.setNextServerAddress( lease.getNextServerAddress() );
273 
274             // fix options
275             OptionsField options = reply.getOptions();
276 
277             // these options must not be present
278             options.remove( RequestedIpAddress.class );
279             options.remove( ParameterRequestList.class );
280             options.remove( ClientIdentifier.class );
281             options.remove( MaximumDhcpMessageSize.class );
282 
283             // these options must be present
284             options.add( new IpAddressLeaseTime( ( lease.getExpires() - System.currentTimeMillis() ) / 1000L ) );
285 
286             stripUnwantedOptions( request, options );
287         }
288         return reply;
289     }
290 }