001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with this 004 * work for additional information regarding copyright ownership. The ASF 005 * licenses this file to you under the Apache License, Version 2.0 (the 006 * "License"); you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 014 * License for the specific language governing permissions and limitations under 015 * the License. 016 * 017 */ 018 019 package org.apache.directory.server.dhcp.service; 020 021 import java.net.InetAddress; 022 import java.net.InetSocketAddress; 023 import java.util.Iterator; 024 025 import org.apache.directory.server.dhcp.DhcpException; 026 import org.apache.directory.server.dhcp.messages.DhcpMessage; 027 import org.apache.directory.server.dhcp.messages.MessageType; 028 import org.apache.directory.server.dhcp.options.DhcpOption; 029 import org.apache.directory.server.dhcp.options.OptionsField; 030 import org.apache.directory.server.dhcp.options.dhcp.ParameterRequestList; 031 import org.apache.directory.server.dhcp.options.dhcp.ServerIdentifier; 032 import org.slf4j.Logger; 033 import org.slf4j.LoggerFactory; 034 035 /** 036 * Abstract implementation of the server-side DHCP protocol. This class just 037 * provides some utility methods and dispatches server-bound messages to handler 038 * methods which can be overridden to provide the functionality. 039 * <p> 040 * Client-bound messages and BOOTP messages are ignored. 041 * 042 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 043 * @version $Rev: 545042 $, $Date: 2007-06-06 22:32:01 -0500 (Mi, 06 Jun 2007) $ 044 * 045 */ 046 public abstract class AbstractDhcpService implements DhcpService { 047 private static final Logger logger = LoggerFactory 048 .getLogger(AbstractDhcpService.class); 049 050 /* 051 * @see org.apache.directory.server.dhcp.DhcpService#getReplyFor(org.apache.directory.server.dhcp.messages.DhcpMessage) 052 */ 053 public final DhcpMessage getReplyFor(InetSocketAddress localAddress, 054 InetSocketAddress clientAddress, DhcpMessage request) 055 throws DhcpException { 056 // ignore messages with an op != REQUEST/REPLY 057 if (request.getOp() != DhcpMessage.OP_BOOTREQUEST 058 && request.getOp() != DhcpMessage.OP_BOOTREPLY) 059 return null; 060 061 // message type option MUST be set - we don't support plain BOOTP. 062 if (null == request.getMessageType()) { 063 logger.warn("Missing message type option - plain BOOTP not supported."); 064 return null; 065 } 066 067 // dispatch based on the message type 068 switch (request.getMessageType().getCode()){ 069 // client-to-server messages 070 case MessageType.CODE_DHCPDISCOVER : 071 return handleDISCOVER(localAddress, clientAddress, request); 072 case MessageType.CODE_DHCPREQUEST : 073 return handleREQUEST(localAddress, clientAddress, request); 074 case MessageType.CODE_DHCPRELEASE : 075 return handleRELEASE(localAddress, clientAddress, request); 076 case MessageType.CODE_DHCPINFORM : 077 return handleINFORM(localAddress, clientAddress, request); 078 079 case MessageType.CODE_DHCPOFFER : 080 return handleOFFER(localAddress, clientAddress, request); 081 082 // server-to-client messages 083 case MessageType.CODE_DHCPDECLINE : 084 case MessageType.CODE_DHCPACK : 085 case MessageType.CODE_DHCPNAK : 086 return null; // just ignore them 087 088 default : 089 return handleUnknownMessage(clientAddress, request); 090 } 091 } 092 093 /** 094 * Handle unknown DHCP message. The default implementation just logs and 095 * ignores it. 096 * 097 * @param clientAddress 098 * @param request the request message 099 * @return DhcpMessage response message or <code>null</code> to ignore (don't reply to) 100 * it. 101 */ 102 protected DhcpMessage handleUnknownMessage(InetSocketAddress clientAddress, 103 DhcpMessage request) { 104 if (logger.isWarnEnabled()) 105 logger.warn("Got unknkown DHCP message: " + request + " from: " 106 + clientAddress); 107 return null; 108 } 109 110 /** 111 * Handle DHCPINFORM message. The default implementation just ignores it. 112 * 113 * @param localAddress 114 * @param clientAddress 115 * @param request the request message 116 * @return DhcpMessage response message or <code>null</code> to ignore (don't reply to) 117 * it. 118 */ 119 protected DhcpMessage handleINFORM(InetSocketAddress localAddress, 120 InetSocketAddress clientAddress, DhcpMessage request) 121 throws DhcpException { 122 if (logger.isDebugEnabled()) 123 logger.debug("Got INFORM message: " + request + " from: " 124 + clientAddress); 125 return null; 126 } 127 128 /** 129 * Handle DHCPRELEASE message. The default implementation just ignores it. 130 * 131 * @param localAddress 132 * @param clientAddress 133 * @param request the request message 134 * @return DhcpMessage response message or <code>null</code> to ignore (don't reply to) 135 * it. 136 */ 137 protected DhcpMessage handleRELEASE(InetSocketAddress localAddress, 138 InetSocketAddress clientAddress, DhcpMessage request) 139 throws DhcpException { 140 if (logger.isDebugEnabled()) 141 logger.debug("Got RELEASE message: " + request + " from: " 142 + clientAddress); 143 return null; 144 } 145 146 /** 147 * Handle DHCPREQUEST message. The default implementation just ignores it. 148 * 149 * @param localAddress 150 * @param clientAddress 151 * @param request the request message 152 * @return DhcpMessage response message or <code>null</code> to ignore (don't reply to) 153 * it. 154 */ 155 protected DhcpMessage handleREQUEST(InetSocketAddress localAddress, 156 InetSocketAddress clientAddress, DhcpMessage request) 157 throws DhcpException { 158 if (logger.isDebugEnabled()) 159 logger.debug("Got REQUEST message: " + request + " from: " 160 + clientAddress); 161 return null; 162 } 163 164 /** 165 * Handle DHCPDISCOVER message. The default implementation just ignores it. 166 * 167 * @param localAddress 168 * @param clientAddress 169 * @param request the request message 170 * @return DhcpMessage response message or <code>null</code> to ignore (don't reply to) 171 * it. 172 * @throws DhcpException 173 */ 174 protected DhcpMessage handleDISCOVER(InetSocketAddress localAddress, 175 InetSocketAddress clientAddress, DhcpMessage request) 176 throws DhcpException { 177 if (logger.isDebugEnabled()) 178 logger.debug("Got DISCOVER message: " + request + " from: " 179 + clientAddress); 180 return null; 181 } 182 183 /** 184 * Handle DHCPOFFER message. The default implementation just ignores it. 185 * 186 * @param localAddress 187 * @param clientAddress 188 * @param request the request message 189 * @return DhcpMessage response message or <code>null</code> to ignore (don't reply to) 190 * it. 191 * @throws DhcpException 192 */ 193 protected DhcpMessage handleOFFER(InetSocketAddress localAddress, 194 InetSocketAddress clientAddress, DhcpMessage request) 195 throws DhcpException { 196 if (logger.isDebugEnabled()) 197 logger 198 .debug("Got OFFER message: " + request + " from: " + clientAddress); 199 return null; 200 } 201 202 /** 203 * Initialize a general DHCP reply message. Sets: 204 * <ul> 205 * <li>op=BOOTREPLY 206 * <li>htype, hlen, xid, flags, giaddr, chaddr like in request message 207 * <li>hops, secs to 0. 208 * <li>server hostname to the hostname appropriate for the interface the 209 * request was received on 210 * <li>the server identifier set to the address of the interface the request 211 * was received on 212 * </ul> 213 * 214 * @param localAddress 215 * @param request 216 * @return DhcpMessage 217 */ 218 protected final DhcpMessage initGeneralReply(InetSocketAddress localAddress, 219 DhcpMessage request) { 220 final DhcpMessage reply = new DhcpMessage(); 221 222 reply.setOp(DhcpMessage.OP_BOOTREPLY); 223 224 reply.setHardwareAddress(request.getHardwareAddress()); 225 reply.setTransactionId(request.getTransactionId()); 226 reply.setFlags(request.getFlags()); 227 reply.setRelayAgentAddress(request.getRelayAgentAddress()); 228 229 // set server hostname 230 reply.setServerHostname(localAddress.getHostName()); 231 232 // set server identifier based on the IF on which we received the packet 233 reply.getOptions().add(new ServerIdentifier(localAddress.getAddress())); 234 235 return reply; 236 } 237 238 /** 239 * Check if an address is the zero-address 240 * 241 * @param addr 242 * @return boolean 243 */ 244 private boolean isZeroAddress(byte[] addr) { 245 for (int i = 0; i < addr.length; i++) 246 if (addr[i] != 0) 247 return false; 248 return true; 249 } 250 251 /** 252 * Determine address on which to base selection. If the relay agent address is 253 * set, we use the relay agent's address, otherwise we use the address we 254 * received the request from. 255 * 256 * @param clientAddress 257 * @param request 258 * @return InetAddress 259 */ 260 protected final InetAddress determineSelectionBase( 261 InetSocketAddress clientAddress, DhcpMessage request) { 262 // FIXME: do we know 263 // a) the interface address over which we received a message (!) 264 // b) the client address (if specified) 265 // c) the relay agent address? 266 267 // if the relay agent address is set, we use it as the selection base 268 if (!isZeroAddress(request.getRelayAgentAddress().getAddress())) 269 return request.getRelayAgentAddress(); 270 271 return clientAddress.getAddress(); 272 } 273 274 /** 275 * Strip options that the client doesn't want, if the ParameterRequestList 276 * option is present. 277 * 278 * @param request 279 * @param options 280 */ 281 protected final void stripUnwantedOptions(DhcpMessage request, 282 OptionsField options) { 283 final ParameterRequestList prl = (ParameterRequestList) request 284 .getOptions().get(ParameterRequestList.class); 285 if (null != prl) { 286 final byte[] list = prl.getData(); 287 for (final Iterator i = options.iterator(); i.hasNext();) { 288 final DhcpOption o = (DhcpOption) i.next(); 289 for (int j = 0; j < list.length; j++) 290 if (list[j] == o.getTag()) 291 continue; 292 i.remove(); 293 } 294 } 295 } 296 }