package be.neutrinet.ispng.vpn.ip; import be.neutrinet.ispng.VPN; import com.googlecode.ipv6.IPv6Network; import com.googlecode.ipv6.IPv6NetworkMask; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.table.TableUtils; import org.apache.log4j.Logger; import java.sql.SQLException; import java.util.Iterator; import java.util.List; /** * Subnet allocator, slab like * Known to be inefficient * <p> * Created by wannes on 11/15/14. */ public class IPSubnets { public static Dao<IPSubnet, String> dao; static { Class cls = IPSubnet.class; try { dao = DaoManager.createDao(VPN.cs, cls); TableUtils.createTableIfNotExists(VPN.cs, cls); createPoolSubnets(); } catch (SQLException ex) { Logger.getLogger(cls).error("Failed to create DAO", ex); } } private static void createPoolSubnets() { try { IPv6Network pool = IPv6Network.fromString(VPN.cfg.getProperty("vpn.ipv6.pool.subnet")); List<IPSubnet> subnet = dao.queryForEq("subnet", pool.toString()); if (subnet.size() != 1) { IPSubnet rootSubnet = new IPSubnet(); rootSubnet.ipVersion = 6; rootSubnet.prefix = pool.getNetmask().asPrefixLength(); rootSubnet.subAllocate = true; rootSubnet.subnet = pool.toString(); dao.create(rootSubnet); } } catch (SQLException ex) { Logger.getLogger(IPSubnets.class).error("Failed to check for root subnet", ex); } } /** * @param prefix IP prefix * @param ipVersion IGNORED ATM * @return */ public static IPSubnet allocate(int prefix, boolean allowSubAllocation, int ipVersion) { if (prefix < 4 || prefix > 64) throw new IllegalArgumentException("Can only allocate subnet from /4 to /64"); // check for range to alloc from try { QueryBuilder<IPSubnet, String> qb = dao.queryBuilder(); qb.where().eq("prefix", prefix - 1).and().eq("subAllocate", true); for (Iterator<IPSubnet> it = qb.iterator(); ; ) { IPSubnet parent = null; if (!it.hasNext()) { if (prefix != 4) { parent = allocate(prefix - 1, true, 6); if (parent == null) return null; } else return null; } else parent = it.next(); List<IPSubnet> siblings = dao.queryForEq("parentId", parent.id); IPv6Network ipv6Network = IPv6Network.fromString(parent.subnet); for (Iterator<IPv6Network> ite = ipv6Network.split(IPv6NetworkMask.fromPrefixLength(prefix)); ite.hasNext(); ) { IPv6Network n = ite.next(); if (siblings.stream().filter(no -> no.subnet.equals(n.toString())).count() != 0) { continue; } else { IPSubnet ns = new IPSubnet(); ns.ipVersion = 6; ns.parentId = parent.id; ns.prefix = prefix; ns.subnet = n.toString(); ns.subAllocate = allowSubAllocation; dao.create(ns); return ns; } } } } catch (SQLException ex) { Logger.getLogger(IPSubnets.class).error("Failed to alloc subnet", ex); } return null; } }