/* * 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 LeaseManager.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.db; import java.io.IOException; import java.net.InetAddress; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class LeaseManager implements IaManager { private static Logger log = LoggerFactory.getLogger(LeaseManager.class); protected abstract void insertDhcpLease(final DhcpLease lease); protected abstract void updateDhcpLease(final DhcpLease lease); protected abstract void deleteDhcpLease(final DhcpLease lease); protected abstract void updateIaOptions(final InetAddress inetAddr, final Collection<DhcpOption> iaOptions); protected abstract void updateIpAddrOptions(final InetAddress inetAddr, final Collection<DhcpOption> ipAddrOptions); protected abstract List<DhcpLease> findDhcpLeasesForIA(final byte[] duid, final byte iatype, final long iaid); protected abstract DhcpLease findDhcpLeaseForInetAddr(final InetAddress inetAddr); protected abstract List<DhcpLease> findExpiredLeases(final byte iatype); /* (non-Javadoc) * @see com.jagornet.dhcpv6.db.IaManager#createIA(com.jagornet.dhcpv6.db.IdentityAssoc) */ public void createIA(IdentityAssoc ia) { if (ia != null) { List<DhcpLease> leases = toDhcpLeases(ia); if ((leases != null) && !leases.isEmpty()) { for (final DhcpLease lease : leases) { insertDhcpLease(lease); } } } } /* (non-Javadoc) * @see com.jagornet.dhcpv6.db.IaManager#updateIA(com.jagornet.dhcpv6.db.IdentityAssoc, java.util.Collection, java.util.Collection, java.util.Collection) */ public void updateIA(IdentityAssoc ia, Collection<? extends IaAddress> addAddrs, Collection<? extends IaAddress> updateAddrs, Collection<? extends IaAddress> delAddrs) { if ((addAddrs != null) && !addAddrs.isEmpty()) { for (IaAddress addAddr : addAddrs) { DhcpLease lease = toDhcpLease(ia, addAddr); insertDhcpLease(lease); } } if ((updateAddrs != null) && !updateAddrs.isEmpty()) { for (IaAddress updateAddr : updateAddrs) { DhcpLease lease = toDhcpLease(ia, updateAddr); updateDhcpLease(lease); } } if ((delAddrs != null) && !delAddrs.isEmpty()) { for (IaAddress delAddr : delAddrs) { DhcpLease lease = toDhcpLease(ia, delAddr); deleteDhcpLease(lease); } } } /* (non-Javadoc) * @see com.jagornet.dhcpv6.db.IaManager#deleteIA(com.jagornet.dhcpv6.db.IdentityAssoc) */ public void deleteIA(IdentityAssoc ia) { if (ia != null) { List<DhcpLease> leases = toDhcpLeases(ia); if ((leases != null) && !leases.isEmpty()) { for (final DhcpLease lease : leases) { deleteDhcpLease(lease); } } } } public List<IdentityAssoc> findExpiredIAs(byte iatype) { List<DhcpLease> leases = findExpiredLeases(iatype); return toIdentityAssocs(leases); } /* (non-Javadoc) * @see com.jagornet.dhcpv6.db.IaManager#findExpiredIaAddresses(byte) */ @Override public List<IaAddress> findExpiredIaAddresses(byte iatype) { List<DhcpLease> leases = findExpiredLeases(iatype); return toIaAddresses(leases); } public void saveDhcpOption(IaAddress iaAddr, com.jagornet.dhcp.option.base.BaseDhcpOption baseOption) { try { byte[] newVal = baseOption.encode().array(); // don't store the option code, start with length to // simplify decoding when retrieving from database if (baseOption.isV4()) { newVal = Arrays.copyOfRange(newVal, 1, newVal.length); } else { newVal = Arrays.copyOfRange(newVal, 2, newVal.length); } // DhcpOption dbOption = iaAddr.getDhcpOption(baseOption.getCode()); DhcpOption dbOption = findIaAddressOption(iaAddr, baseOption); if (dbOption == null) { dbOption = new com.jagornet.dhcp.db.DhcpOption(); dbOption.setCode(baseOption.getCode()); dbOption.setValue(newVal); setDhcpOption(iaAddr, dbOption); } else { if(!Arrays.equals(dbOption.getValue(), newVal)) { dbOption.setValue(newVal); setDhcpOption(iaAddr, dbOption); } } } catch (IOException ex) { log.error("Failed to update binding with option", ex); } } public void deleteDhcpOption(IaAddress iaAddr, com.jagornet.dhcp.option.base.BaseDhcpOption baseOption) { DhcpLease lease = findDhcpLeaseForInetAddr(iaAddr.getIpAddress()); if (lease != null) { Collection<DhcpOption> iaAddrOptions = lease.getIaAddrDhcpOptions(); if (iaAddrOptions != null) { boolean deleted = false; for (DhcpOption iaAddrOption : iaAddrOptions) { if (iaAddrOption.getCode() == baseOption.getCode()) { iaAddrOptions.remove(iaAddrOption); deleted = true; break; } } if (deleted) { updateIpAddrOptions(iaAddr.getIpAddress(), iaAddrOptions); } } } } protected DhcpOption findIaAddressOption(IaAddress iaAddr, com.jagornet.dhcp.option.base.BaseDhcpOption baseOption) { DhcpOption dbOption = null; DhcpLease lease = findDhcpLeaseForInetAddr(iaAddr.getIpAddress()); if (lease != null) { Collection<DhcpOption> iaAddrOptions = lease.getIaAddrDhcpOptions(); if (iaAddrOptions != null) { for (DhcpOption iaAddrOption : iaAddrOptions) { if (iaAddrOption.getCode() == baseOption.getCode()) { dbOption = iaAddrOption; break; } } } } return dbOption; } protected void setDhcpOption(IaAddress iaAddr, DhcpOption option) { iaAddr.setDhcpOption(option); updateIpAddrOptions(iaAddr.getIpAddress(), iaAddr.getDhcpOptions()); } /* (non-Javadoc) * @see com.jagornet.dhcpv6.db.IaManager#findIA(byte[], byte, long) */ public IdentityAssoc findIA(final byte[] duid, final byte iatype, final long iaid) { List<DhcpLease> leases = findDhcpLeasesForIA(duid, iatype, iaid); return toIdentityAssoc(leases); } /* (non-Javadoc) * @see com.jagornet.dhcpv6.db.IaManager#findIA(com.jagornet.dhcpv6.db.IaAddress) */ public IdentityAssoc findIA(IaAddress iaAddress) { return findIA(iaAddress.getIpAddress(), true); } /* (non-Javadoc) * @see com.jagornet.dhcpv6.db.IaManager#findIA(java.net.InetAddress) */ public IdentityAssoc findIA(final InetAddress inetAddr) { return findIA(inetAddr, true); } /** * Find ia. * * @param inetAddr the inet addr * @param allBindings the all bindings * @return the identity assoc */ public IdentityAssoc findIA(final InetAddress inetAddr, boolean allBindings) { IdentityAssoc ia = null; DhcpLease lease = findDhcpLeaseForInetAddr(inetAddr); if (lease != null) { // use a set here, so that if we are getting all bindings, then we don't // include the lease found above again in the returned collection Set<DhcpLease> leases = new LinkedHashSet<DhcpLease>(); leases.add(lease); if (allBindings) { leases.addAll(findDhcpLeasesForIA(lease.getDuid(), lease.getIatype(), lease.getIaid())); } ia = toIdentityAssoc(leases); } return ia; } /* (non-Javadoc) * @see com.jagornet.dhcpv6.db.IaManager#updateIaPrefix(com.jagornet.dhcpv6.db.IaPrefix) */ public void updateIaPrefix(final IaPrefix iaPrefix) { updateIaAddr(iaPrefix); } /* (non-Javadoc) * @see com.jagornet.dhcpv6.db.IaManager#deleteIaPrefix(com.jagornet.dhcpv6.db.IaPrefix) */ public void deleteIaPrefix(IaPrefix iaPrefix) { deleteIaAddr(iaPrefix); } // Conversion methods /** * To identity assoc. * * @param leases the leases * @return the identity assoc */ protected IdentityAssoc toIdentityAssoc(Collection<DhcpLease> leases) { IdentityAssoc ia = null; if ((leases != null) && !leases.isEmpty()) { Iterator<DhcpLease> leaseIter = leases.iterator(); DhcpLease lease = leaseIter.next(); ia = new IdentityAssoc(); ia.setDuid(lease.getDuid()); ia.setIatype(lease.getIatype()); ia.setIaid(lease.getIaid()); ia.setState(lease.getState()); ia.setDhcpOptions(lease.getIaDhcpOptions()); if (lease.getIatype() == IdentityAssoc.PD_TYPE) { List<IaPrefix> iaPrefixes = new ArrayList<IaPrefix>(); iaPrefixes.add(toIaPrefix(lease)); while (leaseIter.hasNext()) { //TODO: should confirm that the duid/iatype/iaid/state still match lease = leaseIter.next(); iaPrefixes.add(toIaPrefix(lease)); } ia.setIaAddresses(iaPrefixes); } else { List<IaAddress> iaAddrs = new ArrayList<IaAddress>(); iaAddrs.add(toIaAddress(lease)); while (leaseIter.hasNext()) { //TODO: should confirm that the duid/iatype/iaid/state still match lease = leaseIter.next(); iaAddrs.add(toIaAddress(lease)); } ia.setIaAddresses(iaAddrs); } } return ia; } protected List<IdentityAssoc> toIdentityAssocs(Collection<DhcpLease> leases) { List<IdentityAssoc> ias = null; if ((leases != null) && !leases.isEmpty()) { ias = new ArrayList<IdentityAssoc>(); // for each lease, create a separate IdentityAssoc for (DhcpLease lease : leases) { Collection<DhcpLease> _leases = new ArrayList<DhcpLease>(); _leases.add(lease); IdentityAssoc ia = toIdentityAssoc(_leases); ias.add(ia); } } return ias; } protected List<IaAddress> toIaAddresses(List<DhcpLease> leases) { List<IaAddress> addrs = null; if (leases != null) { addrs = new ArrayList<IaAddress>(); for (DhcpLease dhcpLease : leases) { addrs.add(this.toIaAddress(dhcpLease)); } } return addrs; } /** * To ia address. * * @param lease the lease * @return the ia address */ protected IaAddress toIaAddress(DhcpLease lease) { IaAddress iaAddr = new IaAddress(); iaAddr.setIpAddress(lease.getIpAddress()); iaAddr.setState(lease.getState()); iaAddr.setStartTime(lease.getStartTime()); iaAddr.setPreferredEndTime(lease.getPreferredEndTime()); iaAddr.setValidEndTime(lease.getValidEndTime()); iaAddr.setDhcpOptions(lease.getIaAddrDhcpOptions()); return iaAddr; } protected List<IaPrefix> toIaPrefixes(List<DhcpLease> leases) { List<IaPrefix> prefixes = null; if (leases != null) { prefixes = new ArrayList<IaPrefix>(); for (DhcpLease dhcpLease : leases) { prefixes.add(toIaPrefix(dhcpLease)); } } return prefixes; } /** * To ia prefix. * * @param lease the lease * @return the ia prefix */ protected IaPrefix toIaPrefix(DhcpLease lease) { IaPrefix iaPrefix = new IaPrefix(); iaPrefix.setIpAddress(lease.getIpAddress()); iaPrefix.setPrefixLength(lease.getPrefixLength()); iaPrefix.setState(lease.getState()); iaPrefix.setStartTime(lease.getStartTime()); iaPrefix.setPreferredEndTime(lease.getPreferredEndTime()); iaPrefix.setValidEndTime(lease.getValidEndTime()); iaPrefix.setDhcpOptions(lease.getIaAddrDhcpOptions()); return iaPrefix; } /** * To dhcp leases. * * @param ia the ia * @return the list */ protected List<DhcpLease> toDhcpLeases(IdentityAssoc ia) { if (ia != null) { Collection<? extends IaAddress> iaAddrs = ia.getIaAddresses(); if ((iaAddrs != null) && !iaAddrs.isEmpty()) { List<DhcpLease> leases = new ArrayList<DhcpLease>(); for (IaAddress iaAddr : iaAddrs) { DhcpLease lease = toDhcpLease(ia, iaAddr); leases.add(lease); } return leases; } else { log.warn("No addresses in lease"); } } return null; } /** * To dhcp lease. * * @param ia the ia * @param iaAddr the ia addr * @return the dhcp lease */ protected DhcpLease toDhcpLease(IdentityAssoc ia, IaAddress iaAddr) { DhcpLease lease = new DhcpLease(); lease.setDuid(ia.getDuid()); lease.setIaid(ia.getIaid()); lease.setIatype(ia.getIatype()); lease.setIpAddress(iaAddr.getIpAddress()); if (iaAddr instanceof IaPrefix) { lease.setPrefixLength(((IaPrefix)iaAddr).getPrefixLength()); } lease.setState(iaAddr.getState()); lease.setStartTime(iaAddr.getStartTime()); lease.setPreferredEndTime(iaAddr.getPreferredEndTime()); lease.setValidEndTime(iaAddr.getValidEndTime()); lease.setIaAddrDhcpOptions(iaAddr.getDhcpOptions()); lease.setIaDhcpOptions(ia.getDhcpOptions()); return lease; } /** * Encode options. * * @param dhcpOptions the dhcp options * @return the byte[] */ protected byte[] encodeOptions(Collection<DhcpOption> dhcpOptions) { if (dhcpOptions != null) { ByteBuffer bb = ByteBuffer.allocate(1024); for (DhcpOption option : dhcpOptions) { bb.putShort((short)option.getCode()); bb.putShort((short)option.getValue().length); bb.put(option.getValue()); } bb.flip(); byte[] b = new byte[bb.limit()]; bb.get(b); return b; } return null; } /** * Decode options. * * @param buf the buf * @return the collection */ protected Collection<DhcpOption> decodeOptions(byte[] buf) { Collection<DhcpOption> options = null; if (buf != null) { ByteBuffer bb = ByteBuffer.wrap(buf); options = new ArrayList<DhcpOption>(); while (bb.hasRemaining()) { DhcpOption option = new DhcpOption(); option.setCode(bb.getShort()); int len = bb.getShort(); byte[] val = new byte[len]; bb.get(val); option.setValue(val); options.add(option); } } return options; } }