/*
* Copyright 2009-2014 Jagornet Technologies, LLC. All Rights Reserved.
*
* This software is the proprietary information of Jagornet Technologies, LLC.
* Use is subject to license terms.
*
*/
/*
* This file DhcpV6MessageHandler.java is part of Jagornet DHCP.
*
* Jagornet DHCP is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Jagornet DHCP is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jagornet DHCP. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.jagornet.dhcp.server.request;
import java.net.InetAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jagornet.dhcp.message.DhcpV6Message;
import com.jagornet.dhcp.message.DhcpV6RelayMessage;
import com.jagornet.dhcp.option.v6.DhcpV6RelayOption;
import com.jagornet.dhcp.util.DhcpConstants;
/**
* Title: DhcpV6MessageHandler
* Description: The main DHCPv6 message handler class.
*
* @author A. Gregory Rabil
*/
public class DhcpV6MessageHandler
{
private static Logger log = LoggerFactory.getLogger(DhcpV6MessageHandler.class);
/**
* - The link to which the client is attached. The server determines
* the link as follows:
* If the server receives the message directly from the client and
* the source address in the IP datagram in which the message was
* received is a link-local address, then the client is on the
* same link to which the interface over which the message was
* received is attached.
* If the server receives the message from a forwarding relay
* agent, then the client is on the same link as the one to which
* the interface, identified by the link-address field in the
* message from the relay agent, is attached.
* If the server receives the message directly from the client and
* the source address in the IP datagram in which the message was
* received is not a link-local address, then the client is on the
* link identified by the source address in the IP datagram (note
* that this situation can occur only if the server has enabled
* the use of unicast message delivery by the client and the
* client has sent a message for which unicast delivery is
* allowed).
*
* @param localAddress the address on the local host which received the message
* @param dhcpMessage the Info-Request or Relay-Forward message to be handled
*
* @return a Reply or Relay-Reply message
*/
//NOTE: this is the magic method where the nio and net implementations come together
public static DhcpV6Message handleMessage(InetAddress localAddress, DhcpV6Message dhcpMessage)
{
DhcpV6Message replyMessage = null;
if (dhcpMessage instanceof DhcpV6RelayMessage) {
if (dhcpMessage.getMessageType() == DhcpConstants.V6MESSAGE_TYPE_RELAY_FORW) {
DhcpV6RelayMessage relayMessage = (DhcpV6RelayMessage) dhcpMessage;
replyMessage = handleRelayForward(relayMessage);
}
else {
log.error("Unsupported message type: " + dhcpMessage.getMessageType());
}
}
else {
log.info("Handling client request on local client link address: " +
localAddress.getHostAddress());
replyMessage = handleClientRequest(localAddress, dhcpMessage);
}
return replyMessage;
}
/**
* Handle relay forward message.
*
* @param relayMessage the Relay-Forward message
*
* @return a Relay-Reply message
*/
private static DhcpV6RelayMessage handleRelayForward(DhcpV6RelayMessage relayMessage)
{
InetAddress linkAddr = relayMessage.getLinkAddress();
log.info("Handling relay forward on link address: " + linkAddr.getHostAddress());
DhcpV6RelayOption relayOption = relayMessage.getRelayOption();
if (relayOption != null) {
DhcpV6Message relayOptionMessage = relayOption.getDhcpMessage();
while (relayOptionMessage != null) {
// check what kind of message is in the option
if (relayOptionMessage instanceof DhcpV6RelayMessage) {
// encapsulated message is another relay message
DhcpV6RelayMessage anotherRelayMessage =
(DhcpV6RelayMessage)relayOptionMessage;
// flip this inner relay_forward into a relay_reply,
// because we reuse the relay message "stack" for the reply
anotherRelayMessage.setMessageType(DhcpConstants.V6MESSAGE_TYPE_RELAY_REPL);
// reset the client link reference
linkAddr = anotherRelayMessage.getLinkAddress();
// reset the current relay option reference to the
// encapsulated relay message's relay option
relayOption = anotherRelayMessage.getRelayOption();
// reset the relayOptionMessage reference to recurse
relayOptionMessage = relayOption.getDhcpMessage();
}
else {
// we've peeled off all the layers of the relay message(s),
// so now go handle the client request
log.info("Handling client request on remote client link address: " +
linkAddr.getHostAddress());
DhcpV6Message replyMessage = handleClientRequest(linkAddr, relayOptionMessage);
if (replyMessage != null) {
// replace the original client request message inside
// the relayed message with the generated Reply message
relayOption.setDhcpMessage(replyMessage);
// flip the outer-most relay_foward into a relay_reply
relayMessage.setMessageType(DhcpConstants.V6MESSAGE_TYPE_RELAY_REPL);
// return the relay message we started with,
// with each relay "layer" flipped from a relay_forward
// to a relay_reply, and the lowest level relayOption
// will contain our Reply for the client request
return relayMessage;
}
relayOptionMessage = null; // done with relayed messages
}
}
}
else {
log.error("Relay message does not contain a relay option");
}
// if we get here, no reply was generated
return null;
}
/**
* Handle client request.
*
* @param linkAddress the link address
* @param dhcpMessage the dhcp message
*
* @return the dhcp message
*/
public static DhcpV6Message handleClientRequest(InetAddress linkAddress, DhcpV6Message dhcpMessage)
{
DhcpV6MessageProcessor processor = null;
switch (dhcpMessage.getMessageType()) {
case DhcpConstants.V6MESSAGE_TYPE_SOLICIT:
processor = new DhcpV6SolicitProcessor(dhcpMessage, linkAddress);
break;
case DhcpConstants.V6MESSAGE_TYPE_REQUEST:
processor = new DhcpV6RequestProcessor(dhcpMessage, linkAddress);
break;
case DhcpConstants.V6MESSAGE_TYPE_CONFIRM:
processor = new DhcpV6ConfirmProcessor(dhcpMessage, linkAddress);
break;
case DhcpConstants.V6MESSAGE_TYPE_RENEW:
processor = new DhcpV6RenewProcessor(dhcpMessage, linkAddress);
break;
case DhcpConstants.V6MESSAGE_TYPE_REBIND:
processor = new DhcpV6RebindProcessor(dhcpMessage, linkAddress);
break;
case DhcpConstants.V6MESSAGE_TYPE_RELEASE:
processor = new DhcpV6ReleaseProcessor(dhcpMessage, linkAddress);
break;
case DhcpConstants.V6MESSAGE_TYPE_DECLINE:
processor = new DhcpV6DeclineProcessor(dhcpMessage, linkAddress);
break;
case DhcpConstants.V6MESSAGE_TYPE_INFO_REQUEST:
processor = new DhcpV6InfoRequestProcessor(dhcpMessage, linkAddress);
break;
default:
log.error("Unknown message type.");
break;
}
if (processor != null) {
return processor.processMessage();
}
else {
log.error("No processor found for message type: " + dhcpMessage.getMessageType());
}
return null;
}
}