blob: 79248144f8840aa5bae8adc1789274cba4ee7b27 [file] [log] [blame]
/*
* 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 java.util.Iterator;
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.DhcpOption;
import org.apache.directory.server.dhcp.options.OptionsField;
import org.apache.directory.server.dhcp.options.dhcp.ParameterRequestList;
import org.apache.directory.server.dhcp.options.dhcp.ServerIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract implementation of the server-side DHCP protocol. This class just
* provides some utility methods and dispatches server-bound messages to handler
* methods which can be overridden to provide the functionality.
* <p>
* Client-bound messages and BOOTP messages are ignored.
*
* @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 abstract class AbstractDhcpService implements DhcpService {
private static final Logger logger = LoggerFactory
.getLogger(AbstractDhcpService.class);
/*
* @see org.apache.directory.server.dhcp.DhcpService#getReplyFor(org.apache.directory.server.dhcp.messages.DhcpMessage)
*/
public final DhcpMessage getReplyFor(InetSocketAddress localAddress,
InetSocketAddress clientAddress, DhcpMessage request)
throws DhcpException {
// ignore messages with an op != REQUEST/REPLY
if (request.getOp() != DhcpMessage.OP_BOOTREQUEST
&& request.getOp() != DhcpMessage.OP_BOOTREPLY)
return null;
// message type option MUST be set - we don't support plain BOOTP.
if (null == request.getMessageType()) {
logger.warn("Missing message type option - plain BOOTP not supported.");
return null;
}
// dispatch based on the message type
switch (request.getMessageType().getCode()){
// client-to-server messages
case MessageType.CODE_DHCPDISCOVER :
return handleDISCOVER(localAddress, clientAddress, request);
case MessageType.CODE_DHCPREQUEST :
return handleREQUEST(localAddress, clientAddress, request);
case MessageType.CODE_DHCPRELEASE :
return handleRELEASE(localAddress, clientAddress, request);
case MessageType.CODE_DHCPINFORM :
return handleINFORM(localAddress, clientAddress, request);
case MessageType.CODE_DHCPOFFER :
return handleOFFER(localAddress, clientAddress, request);
// server-to-client messages
case MessageType.CODE_DHCPDECLINE :
case MessageType.CODE_DHCPACK :
case MessageType.CODE_DHCPNAK :
return null; // just ignore them
default :
return handleUnknownMessage(clientAddress, request);
}
}
/**
* Handle unknown DHCP message. The default implementation just logs and
* ignores it.
*
* @param clientAddress
* @param request the request message
* @return DhcpMessage response message or <code>null</code> to ignore (don't reply to)
* it.
*/
protected DhcpMessage handleUnknownMessage(InetSocketAddress clientAddress,
DhcpMessage request) {
if (logger.isWarnEnabled())
logger.warn("Got unknkown DHCP message: " + request + " from: "
+ clientAddress);
return null;
}
/**
* Handle DHCPINFORM message. The default implementation just ignores it.
*
* @param localAddress
* @param clientAddress
* @param request the request message
* @return DhcpMessage response message or <code>null</code> to ignore (don't reply to)
* it.
*/
protected DhcpMessage handleINFORM(InetSocketAddress localAddress,
InetSocketAddress clientAddress, DhcpMessage request)
throws DhcpException {
if (logger.isDebugEnabled())
logger.debug("Got INFORM message: " + request + " from: "
+ clientAddress);
return null;
}
/**
* Handle DHCPRELEASE message. The default implementation just ignores it.
*
* @param localAddress
* @param clientAddress
* @param request the request message
* @return DhcpMessage response message or <code>null</code> to ignore (don't reply to)
* it.
*/
protected DhcpMessage handleRELEASE(InetSocketAddress localAddress,
InetSocketAddress clientAddress, DhcpMessage request)
throws DhcpException {
if (logger.isDebugEnabled())
logger.debug("Got RELEASE message: " + request + " from: "
+ clientAddress);
return null;
}
/**
* Handle DHCPREQUEST message. The default implementation just ignores it.
*
* @param localAddress
* @param clientAddress
* @param request the request message
* @return DhcpMessage response message or <code>null</code> to ignore (don't reply to)
* it.
*/
protected DhcpMessage handleREQUEST(InetSocketAddress localAddress,
InetSocketAddress clientAddress, DhcpMessage request)
throws DhcpException {
if (logger.isDebugEnabled())
logger.debug("Got REQUEST message: " + request + " from: "
+ clientAddress);
return null;
}
/**
* Handle DHCPDISCOVER message. The default implementation just ignores it.
*
* @param localAddress
* @param clientAddress
* @param request the request message
* @return DhcpMessage response message or <code>null</code> to ignore (don't reply to)
* it.
* @throws DhcpException
*/
protected DhcpMessage handleDISCOVER(InetSocketAddress localAddress,
InetSocketAddress clientAddress, DhcpMessage request)
throws DhcpException {
if (logger.isDebugEnabled())
logger.debug("Got DISCOVER message: " + request + " from: "
+ clientAddress);
return null;
}
/**
* Handle DHCPOFFER message. The default implementation just ignores it.
*
* @param localAddress
* @param clientAddress
* @param request the request message
* @return DhcpMessage response message or <code>null</code> to ignore (don't reply to)
* it.
* @throws DhcpException
*/
protected DhcpMessage handleOFFER(InetSocketAddress localAddress,
InetSocketAddress clientAddress, DhcpMessage request)
throws DhcpException {
if (logger.isDebugEnabled())
logger
.debug("Got OFFER message: " + request + " from: " + clientAddress);
return null;
}
/**
* Initialize a general DHCP reply message. Sets:
* <ul>
* <li>op=BOOTREPLY
* <li>htype, hlen, xid, flags, giaddr, chaddr like in request message
* <li>hops, secs to 0.
* <li>server hostname to the hostname appropriate for the interface the
* request was received on
* <li>the server identifier set to the address of the interface the request
* was received on
* </ul>
*
* @param localAddress
* @param request
* @return DhcpMessage
*/
protected final DhcpMessage initGeneralReply(InetSocketAddress localAddress,
DhcpMessage request) {
final DhcpMessage reply = new DhcpMessage();
reply.setOp(DhcpMessage.OP_BOOTREPLY);
reply.setHardwareAddress(request.getHardwareAddress());
reply.setTransactionId(request.getTransactionId());
reply.setFlags(request.getFlags());
reply.setRelayAgentAddress(request.getRelayAgentAddress());
// set server hostname
reply.setServerHostname(localAddress.getHostName());
// set server identifier based on the IF on which we received the packet
reply.getOptions().add(new ServerIdentifier(localAddress.getAddress()));
return reply;
}
/**
* Check if an address is the zero-address
*
* @param addr
* @return boolean
*/
private boolean isZeroAddress(byte[] addr) {
for (int i = 0; i < addr.length; i++)
if (addr[i] != 0)
return false;
return true;
}
/**
* Determine address on which to base selection. If the relay agent address is
* set, we use the relay agent's address, otherwise we use the address we
* received the request from.
*
* @param clientAddress
* @param request
* @return InetAddress
*/
protected final InetAddress determineSelectionBase(
InetSocketAddress clientAddress, DhcpMessage request) {
// FIXME: do we know
// a) the interface address over which we received a message (!)
// b) the client address (if specified)
// c) the relay agent address?
// if the relay agent address is set, we use it as the selection base
if (!isZeroAddress(request.getRelayAgentAddress().getAddress()))
return request.getRelayAgentAddress();
return clientAddress.getAddress();
}
/**
* Strip options that the client doesn't want, if the ParameterRequestList
* option is present.
*
* @param request
* @param options
*/
protected final void stripUnwantedOptions(DhcpMessage request,
OptionsField options) {
final ParameterRequestList prl = (ParameterRequestList) request
.getOptions().get(ParameterRequestList.class);
if (null != prl) {
final byte[] list = prl.getData();
for (final Iterator i = options.iterator(); i.hasNext();) {
final DhcpOption o = (DhcpOption) i.next();
for (int j = 0; j < list.length; j++)
if (list[j] == o.getTag())
continue;
i.remove();
}
}
}
}