-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
622 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.maxmind.db; | ||
|
||
import java.net.InetAddress; | ||
|
||
public class BadVersionException extends Exception { | ||
public BadVersionException(InetAddress ip) { | ||
super("you attempted to use an IPv6 network in an IPv4-only database: " + ip.toString()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
package com.maxmind.db; | ||
|
||
import java.io.IOException; | ||
|
||
import java.util.Iterator; | ||
import java.net.Inet4Address; | ||
import java.net.InetAddress; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
|
||
import java.nio.ByteBuffer; | ||
|
||
public class Networks<T> implements Iterator<DatabaseRecord<T>>{ | ||
private final Reader reader; | ||
private ArrayList<NetworkNode> nodes; | ||
private NetworkNode lastNode; | ||
private boolean skipAliasedNetworks; | ||
private Exception err; | ||
|
||
private ByteBuffer buffer; /* Stores the buffer for Next() calls */ | ||
private Class<T> typeParameterClass; | ||
|
||
/** | ||
* Constructs a Networks instance. | ||
* | ||
* @param Reader the reader object. | ||
*/ | ||
Networks(Reader reader, boolean skipAliasedNetworks) throws ClosedDatabaseException { | ||
this(reader, skipAliasedNetworks, new NetworkNode[]{}); | ||
|
||
} | ||
|
||
Networks(Reader reader, boolean skipAliasedNetworks, NetworkNode[] nodes) throws ClosedDatabaseException{ | ||
this.reader = reader; | ||
this.skipAliasedNetworks = skipAliasedNetworks; | ||
this.nodes = new ArrayList<NetworkNode>(Arrays.asList(nodes)); | ||
this.buffer = reader.getBufferHolder().get(); | ||
} | ||
|
||
/** | ||
* Creates a Networks instance with skipAliasedNetworks set to false. | ||
* @param reader | ||
*/ | ||
Networks(Reader reader) throws ClosedDatabaseException { | ||
this(reader,false); | ||
} | ||
|
||
public Exception getErr() { | ||
return this.err; | ||
} | ||
|
||
public void setDataClass(Class<T> cls){ | ||
this.typeParameterClass = cls; | ||
} | ||
|
||
/** | ||
* Returns the next NetworksItem<T>. You need to set the class using | ||
* prepareForClass before calling next. | ||
* For example, | ||
* networks.prepareForClass(Map.Class); | ||
* Map test = networks.next(); | ||
*/ | ||
@Override | ||
public DatabaseRecord<T> next(){ | ||
if (this.err != null){ | ||
return null; | ||
} | ||
|
||
try{ | ||
T data = this.reader.resolveDataPointer(this.buffer, this.lastNode.pointer, this.typeParameterClass); | ||
|
||
byte[] ip = this.lastNode.ip; | ||
int prefixLength = this.lastNode.prefix; | ||
|
||
// We do this because uses of SkipAliasedNetworks expect the IPv4 networks | ||
// to be returned as IPv4 networks. If we are not skipping aliased | ||
// networks, then the user will get IPv4 networks from the ::FFFF:0:0/96 | ||
// network. | ||
if (this.skipAliasedNetworks && isInIPv4Subtree(ip)){ | ||
ip = Arrays.copyOfRange(ip, 12, ip.length); | ||
prefixLength -= 96; | ||
} | ||
|
||
// If the ip is in ipv6 form, drop the prefix manually as InetAddress converts it to ipv4. | ||
InetAddress ipAddr = InetAddress.getByAddress(ip); | ||
if (ipAddr instanceof Inet4Address && ip.length > 4 && | ||
ip[10] == -1 && ip[11] == -1 && prefixLength > 32) { | ||
prefixLength -= 96; | ||
} | ||
|
||
return new DatabaseRecord<T>(data, InetAddress.getByAddress(ip), prefixLength); | ||
}catch(IOException e){ | ||
this.err = e; | ||
return null; | ||
} | ||
} | ||
|
||
public boolean isInIPv4Subtree(byte[] ip) { | ||
if (ip.length != 16 ){ | ||
return false; | ||
} | ||
for(int i = 0; i < 12; i ++){ | ||
if (ip[i] != 0 ) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
|
||
/* | ||
* Next prepares the next network for reading with the Network method. It | ||
* returns true if there is another network to be processed and false if there | ||
* are no more networks or if there is an error. | ||
*/ | ||
@Override | ||
public boolean hasNext() { | ||
if (this.err != null){ | ||
return false; | ||
} | ||
while(this.nodes.size() > 0){ | ||
// Pop the last one. | ||
NetworkNode node = this.nodes.remove(this.nodes.size() - 1); | ||
|
||
// Next until we don't have data. | ||
while (node.pointer != this.reader.getMetadata().getNodeCount()) { | ||
// This skips IPv4 aliases without hardcoding the networks that the writer | ||
// currently aliases. | ||
if (this.skipAliasedNetworks && this.reader.getIPv4Start() != 0 && | ||
node.pointer == this.reader.getIPv4Start() && !isInIPv4Subtree(node.ip)){ | ||
break; | ||
} | ||
|
||
if (node.pointer > this.reader.getMetadata().getNodeCount() ){ | ||
this.lastNode = node; | ||
return true; | ||
} | ||
|
||
byte[] ipRight = Arrays.copyOf(node.ip, node.ip.length); | ||
if (ipRight.length <= (node.prefix>>3)){ | ||
this.err = new InvalidDatabaseException("Invalid search tree"); | ||
return false; | ||
} | ||
|
||
ipRight[node.prefix>>3] |= 1 << (7 - (node.prefix % 8)); | ||
|
||
try{ | ||
int rightPointer = this.reader.readNode(this.buffer, node.pointer, 1); | ||
node.prefix++; | ||
|
||
this.nodes.add(new NetworkNode(ipRight, node.prefix, rightPointer)); | ||
node.pointer = this.reader.readNode(this.buffer, node.pointer, 0); | ||
}catch(InvalidDatabaseException e){ | ||
this.err = e; | ||
return false; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
public static class NetworkNode{ | ||
public byte[] ip; | ||
public int prefix; | ||
public int pointer; /* The number of the node. */ | ||
public NetworkNode(byte[] ip, int prefix, int pointer){ | ||
this.ip = ip; | ||
this.prefix=prefix; | ||
this.pointer = pointer; | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.