001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 package org.apache.directory.server.dhcp.store; 021 022 023 import java.net.InetAddress; 024 import java.util.Map; 025 026 import org.apache.directory.server.dhcp.DhcpException; 027 import org.apache.directory.server.dhcp.messages.HardwareAddress; 028 import org.apache.directory.server.dhcp.options.OptionsField; 029 import org.apache.directory.server.dhcp.options.vendor.HostName; 030 import org.apache.directory.server.dhcp.options.vendor.SubnetMask; 031 import org.apache.directory.server.dhcp.service.Lease; 032 import org.slf4j.Logger; 033 import org.slf4j.LoggerFactory; 034 035 036 /** 037 * Abstract base implementation of a {@link DhcpStore}. 038 * 039 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 040 * @version $Rev: 545042 $, $Date: 2007-06-06 22:32:01 -0500 (Mi, 06 Jun 2007) $ 041 */ 042 public abstract class AbstractDhcpStore implements DhcpStore 043 { 044 private static final Logger logger = LoggerFactory.getLogger( AbstractDhcpStore.class ); 045 046 047 /* 048 * @see org.apache.directory.server.dhcp.service.DhcpStore#getLeaseOffer(org.apache.directory.server.dhcp.messages.HardwareAddress, 049 * java.net.InetAddress, java.net.InetAddress, long, 050 * org.apache.directory.server.dhcp.options.OptionsField) 051 */ 052 public Lease getLeaseOffer( HardwareAddress hardwareAddress, InetAddress requestedAddress, 053 InetAddress selectionBase, long requestedLeaseTime, OptionsField options ) throws DhcpException 054 { 055 Subnet subnet = findSubnet( selectionBase ); 056 if ( null == subnet ) 057 { 058 logger.warn( "Don't know anything about the sbnet containing " + selectionBase ); 059 return null; 060 } 061 062 // try to find existing lease 063 Lease lease = null; 064 lease = findExistingLease( hardwareAddress, lease ); 065 if ( null != lease ) 066 return lease; 067 068 Host host = null; 069 host = findDesignatedHost( hardwareAddress ); 070 if ( null != host ) 071 { 072 // make sure that the host is actually within the subnet. Depending 073 // on the way the DhcpStore configuration is implemented, it is not 074 // possible to violate this condition, but we can't be sure. 075 if ( !subnet.contains( host.getAddress() ) ) 076 { 077 logger.warn( "Host " + host + " is not within the subnet for which an address is requested" ); 078 } 079 else 080 { 081 // build properties map 082 Map properties = getProperties( subnet ); 083 properties.putAll( getProperties( host ) ); 084 085 // build lease 086 lease = new Lease(); 087 lease.setAcquired( System.currentTimeMillis() ); 088 089 long leaseTime = determineLeaseTime( requestedLeaseTime, properties ); 090 091 lease.setExpires( System.currentTimeMillis() + leaseTime ); 092 093 lease.setHardwareAddress( hardwareAddress ); 094 lease.setState( Lease.STATE_NEW ); 095 lease.setClientAddress( host.getAddress() ); 096 097 // set lease options 098 OptionsField o = lease.getOptions(); 099 100 // set (client) host name 101 o.add( new HostName( host.getName() ) ); 102 103 // add subnet settings 104 o.add( new SubnetMask( subnet.getNetmask() ) ); 105 o.merge( subnet.getOptions() ); 106 107 // add the host's options. they override existing 108 // subnet options as they take the precedence. 109 o.merge( host.getOptions() ); 110 } 111 } 112 113 if ( null == lease ) 114 { 115 // FIXME: use selection base to find a lease in a pool. 116 } 117 118 // update the lease state 119 if ( null != lease && lease.getState() != Lease.STATE_ACTIVE ) 120 { 121 lease.setState( Lease.STATE_OFFERED ); 122 updateLease( lease ); 123 } 124 125 return lease; 126 } 127 128 129 /* 130 * @see org.apache.directory.server.dhcp.store.DhcpStore#getExistingLease(org.apache.directory.server.dhcp.messages.HardwareAddress, 131 * java.net.InetAddress, java.net.InetAddress, long, 132 * org.apache.directory.server.dhcp.options.OptionsField) 133 */ 134 public Lease getExistingLease( HardwareAddress hardwareAddress, InetAddress requestedAddress, 135 InetAddress selectionBase, long requestedLeaseTime, OptionsField options ) throws DhcpException 136 { 137 // try to find existing lease. if we don't find a lease based on the 138 // client's 139 // hardware address, we send a NAK. 140 Lease lease = null; 141 lease = findExistingLease( hardwareAddress, lease ); 142 if ( null == lease ) 143 return null; 144 145 // check whether the notions of the client address match 146 if ( !lease.getClientAddress().equals( requestedAddress ) ) 147 { 148 logger.warn( "Requested address " + requestedAddress + " for " + hardwareAddress 149 + " doesn't match existing lease " + lease ); 150 return null; 151 } 152 153 // check whether addresses and subnet match 154 Subnet subnet = findSubnet( selectionBase ); 155 if ( null == subnet ) 156 { 157 logger.warn( "No subnet found for existing lease " + lease ); 158 return null; 159 } 160 if ( !subnet.contains( lease.getClientAddress() ) ) 161 { 162 logger.warn( "Client with existing lease " + lease + " is on wrong subnet " + subnet ); 163 return null; 164 } 165 if ( !subnet.isInRange( lease.getClientAddress() ) ) 166 { 167 logger.warn( "Client with existing lease " + lease + " is out of valid range for subnet " + subnet ); 168 return null; 169 } 170 171 // build properties map 172 Map properties = getProperties( subnet ); 173 174 // update lease options 175 OptionsField o = lease.getOptions(); 176 o.clear(); 177 178 // add subnet settings 179 o.add( new SubnetMask( subnet.getNetmask() ) ); 180 o.merge( subnet.getOptions() ); 181 182 // check whether there is a designated host. 183 Host host = findDesignatedHost( hardwareAddress ); 184 if ( null != host ) 185 { 186 // check whether the host matches the address (using a fixed 187 // host address is mandatory). 188 if ( host.getAddress() != null && !host.getAddress().equals( lease.getClientAddress() ) ) 189 { 190 logger.warn( "Existing fixed address for " + hardwareAddress + " conflicts with existing lease " 191 + lease ); 192 return null; 193 } 194 195 properties.putAll( getProperties( host ) ); 196 197 // set (client) host name 198 o.add( new HostName( host.getName() ) ); 199 200 // add the host's options 201 o.merge( host.getOptions() ); 202 } 203 204 // update other lease fields 205 long leaseTime = determineLeaseTime( requestedLeaseTime, properties ); 206 lease.setExpires( System.currentTimeMillis() + leaseTime ); 207 lease.setHardwareAddress( hardwareAddress ); 208 209 // update the lease state 210 if ( lease.getState() != Lease.STATE_ACTIVE ) 211 { 212 lease.setState( Lease.STATE_ACTIVE ); 213 updateLease( lease ); 214 } 215 216 // store information about the lease 217 updateLease( lease ); 218 219 return lease; 220 } 221 222 223 /** 224 * Determine the lease time based on the time requested by the client, the 225 * properties and a global default. 226 * 227 * @param requestedLeaseTime 228 * @param properties 229 * @return long 230 */ 231 private long determineLeaseTime( long requestedLeaseTime, Map properties ) 232 { 233 // built-in default 234 long leaseTime = 1000L * 3600; 235 Integer propMaxLeaseTime = ( Integer ) properties.get( DhcpConfigElement.PROPERTY_MAX_LEASE_TIME ); 236 if ( null != propMaxLeaseTime ) 237 if ( requestedLeaseTime > 0 ) 238 leaseTime = Math.min( propMaxLeaseTime.intValue() * 1000L, requestedLeaseTime ); 239 else 240 leaseTime = propMaxLeaseTime.intValue() * 1000L; 241 return leaseTime; 242 } 243 244 245 /* 246 * @see org.apache.directory.server.dhcp.store.DhcpStore#releaseLease(org.apache.directory.server.dhcp.service.Lease) 247 */ 248 public void releaseLease( Lease lease ) 249 { 250 lease.setState( Lease.STATE_RELEASED ); 251 updateLease( lease ); 252 } 253 254 255 /** 256 * Update the (possibly changed) lease in the store. 257 * 258 * @param lease 259 */ 260 protected abstract void updateLease( Lease lease ); 261 262 263 /** 264 * Return a list of all options applicable to the given config element. List 265 * list must contain the options specified for the element and all parent 266 * elements in an aggregated fashion. For instance, the options for a host 267 * must include the global default options, the options of classes the host 268 * is a member of, the host's group options and the host's options. 269 * 270 * @param element 271 * @return OptionsField 272 */ 273 protected abstract OptionsField getOptions( DhcpConfigElement element ); 274 275 276 /** 277 * Return a list of all options applicable to the given config element. List 278 * list must contain the options specified for the element and all parent 279 * elements in an aggregated fashion. For instance, the options for a host 280 * must include the global default options, the options of classes the host 281 * is a member of, the host's group options and the host's options. 282 * 283 * @param element 284 * @return Map 285 */ 286 protected abstract Map getProperties( DhcpConfigElement element ); 287 288 289 /** 290 * Find an existing lease in the store. 291 * 292 * @param hardwareAddress 293 * @param existingLease 294 * @return Map 295 */ 296 protected abstract Lease findExistingLease( HardwareAddress hardwareAddress, Lease existingLease ); 297 298 299 /** 300 * Find a host to with the explicitely designated hardware address. 301 * 302 * @param hardwareAddress 303 * @return Host 304 * @throws DhcpException 305 */ 306 protected abstract Host findDesignatedHost( HardwareAddress hardwareAddress ) throws DhcpException; 307 308 309 /** 310 * Find the subnet definition matching the given address. 311 * 312 * @param clientAddress 313 * @return Subnet 314 */ 315 protected abstract Subnet findSubnet( InetAddress clientAddress ); 316 }