/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
* | |
*/ | |
package org.apache.directory.server.dhcp.service; | |
import java.net.InetAddress; | |
import java.net.InetSocketAddress; | |
import org.apache.directory.server.dhcp.DhcpException; | |
import org.apache.directory.server.dhcp.messages.DhcpMessage; | |
import org.apache.directory.server.dhcp.messages.MessageType; | |
import org.apache.directory.server.dhcp.options.AddressOption; | |
import org.apache.directory.server.dhcp.options.OptionsField; | |
import org.apache.directory.server.dhcp.options.dhcp.ClientIdentifier; | |
import org.apache.directory.server.dhcp.options.dhcp.IpAddressLeaseTime; | |
import org.apache.directory.server.dhcp.options.dhcp.MaximumDhcpMessageSize; | |
import org.apache.directory.server.dhcp.options.dhcp.ParameterRequestList; | |
import org.apache.directory.server.dhcp.options.dhcp.RequestedIpAddress; | |
import org.apache.directory.server.dhcp.options.dhcp.ServerIdentifier; | |
import org.apache.directory.server.dhcp.store.DhcpStore; | |
/** | |
* A default implementation of the DHCP service. Does the tedious low-level | |
* chores of handling DHCP messages, but delegates the lease-handling to a | |
* supplied DhcpStore. | |
* | |
* @see org.apache.directory.server.dhcp.store.DhcpStore | |
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> | |
* @version $Rev: 545042 $, $Date: 2007-06-06 22:32:01 -0500 (Mi, 06 Jun 2007) $ | |
*/ | |
public class StoreBasedDhcpService extends AbstractDhcpService | |
{ | |
private final DhcpStore dhcpStore; | |
public StoreBasedDhcpService(DhcpStore dhcpStore) | |
{ | |
this.dhcpStore = dhcpStore; | |
} | |
/** | |
* Try to get an existing lease. The lease may have been created during | |
* earlier DHCP negotiations or a recent DHCPDISCOVER. | |
* | |
* @param clientAddress | |
* @param request | |
* @return | |
* @throws DhcpException | |
*/ | |
private Lease getExistingLease( InetSocketAddress clientAddress, DhcpMessage request ) throws DhcpException | |
{ | |
// determine requested lease time | |
IpAddressLeaseTime requestedLeaseTimeOption = ( IpAddressLeaseTime ) request.getOptions().get( | |
IpAddressLeaseTime.class ); | |
long requestedLeaseTime = null != requestedLeaseTimeOption ? requestedLeaseTimeOption.getIntValue() * 1000 | |
: -1L; | |
// try to get the lease (address) requested by the client | |
InetAddress requestedAddress = null; | |
AddressOption requestedAddressOption = ( AddressOption ) request.getOptions().get( RequestedIpAddress.class ); | |
if ( null != requestedAddressOption ) | |
requestedAddress = requestedAddressOption.getAddress(); | |
if ( null == requestedAddress ) | |
requestedAddress = request.getCurrentClientAddress(); | |
InetAddress selectionBase = determineSelectionBase( clientAddress, request ); | |
Lease lease = dhcpStore.getExistingLease( request.getHardwareAddress(), requestedAddress, selectionBase, | |
requestedLeaseTime, request.getOptions() ); | |
if ( null == lease ) | |
return null; | |
return lease; | |
} | |
/** | |
* Determine a lease to offer in response to a DHCPDISCOVER message. | |
* <p> | |
* When a server receives a DHCPDISCOVER message from a client, the server | |
* chooses a network address for the requesting client. If no address is | |
* available, the server may choose to report the problem to the system | |
* administrator. If an address is available, the new address SHOULD be | |
* chosen as follows: | |
* <ul> | |
* <li> The client's current address as recorded in the client's current | |
* binding, ELSE | |
* <li> The client's previous address as recorded in the client's (now | |
* expired or released) binding, if that address is in the server's pool of | |
* available addresses and not already allocated, ELSE | |
* <li> The address requested in the 'Requested IP Address' option, if that | |
* address is valid and not already allocated, ELSE | |
* <li> A new address allocated from the server's pool of available | |
* addresses; the address is selected based on the subnet from which the | |
* message was received (if 'giaddr' is 0) or on the address of the relay | |
* agent that forwarded the message ('giaddr' when not 0). | |
* </ul> | |
* | |
* @param clientAddress | |
* @param request | |
* @return | |
*/ | |
private Lease getLeaseOffer( InetSocketAddress clientAddress, DhcpMessage request ) throws DhcpException | |
{ | |
// determine requested lease time | |
IpAddressLeaseTime requestedLeaseTimeOption = ( IpAddressLeaseTime ) request.getOptions().get( | |
IpAddressLeaseTime.class ); | |
long requestedLeaseTime = null != requestedLeaseTimeOption ? requestedLeaseTimeOption.getIntValue() * 1000 | |
: -1L; | |
// try to get the lease (address) requested by the client | |
InetAddress requestedAddress = null; | |
AddressOption requestedAddressOption = ( AddressOption ) request.getOptions().get( RequestedIpAddress.class ); | |
if ( null != requestedAddressOption ) | |
requestedAddress = requestedAddressOption.getAddress(); | |
InetAddress selectionBase = determineSelectionBase( clientAddress, request ); | |
Lease lease = dhcpStore.getLeaseOffer( request.getHardwareAddress(), requestedAddress, selectionBase, | |
requestedLeaseTime, request.getOptions() ); | |
return lease; | |
} | |
/* | |
* @see org.apache.directory.server.dhcp.service.AbstractDhcpService#handleRELEASE(java.net.InetSocketAddress, | |
* java.net.InetSocketAddress, | |
* org.apache.directory.server.dhcp.messages.DhcpMessage) | |
*/ | |
protected DhcpMessage handleRELEASE( InetSocketAddress localAddress, InetSocketAddress clientAddress, | |
DhcpMessage request ) throws DhcpException | |
{ | |
// check server ident | |
AddressOption serverIdentOption = ( AddressOption ) request.getOptions().get( ServerIdentifier.class ); | |
if ( null != serverIdentOption && serverIdentOption.getAddress().isAnyLocalAddress() ) | |
return null; // not me?! FIXME: handle authoritative server case | |
Lease lease = getExistingLease( clientAddress, request ); | |
DhcpMessage reply = initGeneralReply( localAddress, request ); | |
if ( null == lease ) | |
{ | |
// null lease? send NAK | |
// FIXME... | |
reply.setMessageType( MessageType.DHCPNAK ); | |
reply.setCurrentClientAddress( null ); | |
reply.setAssignedClientAddress( null ); | |
reply.setNextServerAddress( null ); | |
} | |
else | |
{ | |
dhcpStore.releaseLease( lease ); | |
// lease Ok, send ACK | |
// FIXME... | |
reply.getOptions().merge( lease.getOptions() ); | |
reply.setAssignedClientAddress( lease.getClientAddress() ); | |
reply.setNextServerAddress( lease.getNextServerAddress() ); | |
// fix options | |
OptionsField options = reply.getOptions(); | |
// these options must not be present | |
options.remove( RequestedIpAddress.class ); | |
options.remove( ParameterRequestList.class ); | |
options.remove( ClientIdentifier.class ); | |
options.remove( MaximumDhcpMessageSize.class ); | |
// these options must be present | |
options.add( new IpAddressLeaseTime( ( lease.getExpires() - System.currentTimeMillis() ) / 1000L ) ); | |
stripUnwantedOptions( request, options ); | |
} | |
return reply; | |
} | |
/* | |
* @see org.apache.directory.server.dhcp.service.AbstractDhcpService#handleDISCOVER(java.net.InetSocketAddress, | |
* org.apache.directory.server.dhcp.messages.DhcpMessage) | |
*/ | |
protected DhcpMessage handleDISCOVER( InetSocketAddress localAddress, InetSocketAddress clientAddress, | |
DhcpMessage request ) throws DhcpException | |
{ | |
Lease lease = getLeaseOffer( clientAddress, request ); | |
// null lease? don't offer one. | |
if ( null == lease ) | |
return null; | |
DhcpMessage reply = initGeneralReply( localAddress, request ); | |
reply.getOptions().merge( lease.getOptions() ); | |
reply.setMessageType( MessageType.DHCPOFFER ); | |
reply.setAssignedClientAddress( lease.getClientAddress() ); | |
reply.setNextServerAddress( lease.getNextServerAddress() ); | |
// fix options | |
OptionsField options = reply.getOptions(); | |
// these options must not be present | |
options.remove( RequestedIpAddress.class ); | |
options.remove( ParameterRequestList.class ); | |
options.remove( ClientIdentifier.class ); | |
options.remove( MaximumDhcpMessageSize.class ); | |
// these options must be present | |
options.add( new IpAddressLeaseTime( ( lease.getExpires() - System.currentTimeMillis() ) / 1000L ) ); | |
stripUnwantedOptions( request, options ); | |
return reply; | |
} | |
/* | |
* @see org.apache.directory.server.dhcp.service.AbstractDhcpService#handleREQUEST(java.net.InetSocketAddress, | |
* org.apache.directory.server.dhcp.messages.DhcpMessage) | |
*/ | |
protected DhcpMessage handleREQUEST( InetSocketAddress localAddress, InetSocketAddress clientAddress, | |
DhcpMessage request ) throws DhcpException | |
{ | |
// check server ident | |
AddressOption serverIdentOption = ( AddressOption ) request.getOptions().get( ServerIdentifier.class ); | |
if ( null != serverIdentOption && serverIdentOption.getAddress().isAnyLocalAddress() ) | |
return null; // not me?! FIXME: handle authoritative server case | |
Lease lease = getExistingLease( clientAddress, request ); | |
DhcpMessage reply = initGeneralReply( localAddress, request ); | |
if ( null == lease ) | |
{ | |
// null lease? send NAK | |
reply.setMessageType( MessageType.DHCPNAK ); | |
reply.setCurrentClientAddress( null ); | |
reply.setAssignedClientAddress( null ); | |
reply.setNextServerAddress( null ); | |
} | |
else | |
{ | |
// lease Ok, send ACK | |
reply.getOptions().merge( lease.getOptions() ); | |
reply.setAssignedClientAddress( lease.getClientAddress() ); | |
reply.setNextServerAddress( lease.getNextServerAddress() ); | |
// fix options | |
OptionsField options = reply.getOptions(); | |
// these options must not be present | |
options.remove( RequestedIpAddress.class ); | |
options.remove( ParameterRequestList.class ); | |
options.remove( ClientIdentifier.class ); | |
options.remove( MaximumDhcpMessageSize.class ); | |
// these options must be present | |
options.add( new IpAddressLeaseTime( ( lease.getExpires() - System.currentTimeMillis() ) / 1000L ) ); | |
stripUnwantedOptions( request, options ); | |
} | |
return reply; | |
} | |
} |