package com.subgraph.orchid.directory.router;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.subgraph.orchid.RouterDescriptor;
import com.subgraph.orchid.Tor;
import com.subgraph.orchid.crypto.TorPublicKey;
import com.subgraph.orchid.data.BandwidthHistory;
import com.subgraph.orchid.data.HexDigest;
import com.subgraph.orchid.data.IPv4Address;
import com.subgraph.orchid.data.Timestamp;
import com.subgraph.orchid.data.exitpolicy.ExitPolicy;
public class RouterDescriptorImpl implements RouterDescriptor {
private String nickname;
private IPv4Address address;
private int routerPort;
private int directoryPort;
private int averageBandwidth = -1;
private int burstBandwidth = -1;
private int observedBandwidth = -1;
private String platform;
private Timestamp published;
private HexDigest fingerprint;
private boolean hibernating;
private int uptime;
private TorPublicKey onionKey;
private byte[] ntorOnionKey;
private TorPublicKey identityKey;
private ExitPolicy exitPolicy = new ExitPolicy();
private String contact;
private Set<String> familyMembers = Collections.emptySet();
private Set<Integer> linkProtocols = Collections.emptySet();
private Set<Integer> circuitProtocols = Collections.emptySet();
private BandwidthHistory readHistory;
private BandwidthHistory writeHistory;
private boolean eventDNS = false;
private boolean cachesExtraInfo = false;
private boolean hiddenServiceDir = false;
private HexDigest extraInfoDigest = null;
private boolean allowSingleHopExits = false;
private boolean hasValidSignature = false;
private HexDigest descriptorDigest;
private String rawDocumentData;
private long lastListed;
private CacheLocation cacheLocation = CacheLocation.NOT_CACHED;
public void setNickname(String nickname) { this.nickname = nickname; }
public void setAddress(IPv4Address address) { this.address = address; }
public void setRouterPort(int port) { this.routerPort = port; }
void setDirectoryPort(int port) { this.directoryPort = port; }
void setPlatform(String platform) { this.platform = platform; }
void setPublished(Timestamp published) { this.published = published; }
void setFingerprint(HexDigest fingerprint) { this.fingerprint = fingerprint; }
void setHibernating(boolean flag) { this.hibernating = flag; }
void setUptime(int uptime) { this.uptime = uptime; }
public void setOnionKey(TorPublicKey key) { this.onionKey = key; }
void setNtorOnionKey(byte[] key) { this.ntorOnionKey = key; }
void setIdentityKey(TorPublicKey key) { this.identityKey = key; }
void setContact(String contact) { this.contact = contact; }
void setEventDNS() { eventDNS = true; }
void setHiddenServiceDir() { hiddenServiceDir = true; }
void setExtraInfoDigest(HexDigest digest) { this.extraInfoDigest = digest; }
void setCachesExtraInfo() { cachesExtraInfo = true; }
void setAllowSingleHopExits() { allowSingleHopExits = true; }
void setReadHistory(BandwidthHistory history) { this.readHistory= history; }
void setWriteHistory(BandwidthHistory history) { this.writeHistory = history; }
void setValidSignature() { hasValidSignature = true; }
void setDescriptorHash(HexDigest digest) { descriptorDigest = digest; }
void setRawDocumentData(String rawData) { rawDocumentData = rawData; }
void addAcceptRule(String rule) {
exitPolicy.addAcceptRule(rule);
}
void addRejectRule(String rule) {
exitPolicy.addRejectRule(rule);
}
void setBandwidthValues(int average, int burst, int observed) {
this.averageBandwidth = average;
this.burstBandwidth = burst;
this.observedBandwidth = observed;
}
void addFamilyMember(String familyMember) {
if(familyMembers.isEmpty()) {
familyMembers = new HashSet<String>();
}
familyMembers.add(familyMember);
}
void addCircuitProtocolVersion(int version) {
if(circuitProtocols.isEmpty())
circuitProtocols = new HashSet<Integer>();
circuitProtocols.add(version);
}
void addLinkProtocolVersion(int version) {
if(linkProtocols.isEmpty())
linkProtocols = new HashSet<Integer>();
linkProtocols.add(version);
}
public boolean isValidDocument() {
// verify required fields exist, see dirspec.txt section 2.1
return hasValidSignature && (nickname != null) && (address != null) &&
(averageBandwidth != -1) && (routerPort != 0 || directoryPort != 0) &&
(published != null) && (onionKey != null) && (identityKey != null) &&
(descriptorDigest != null);
}
public String getNickname() {
return nickname;
}
public IPv4Address getAddress() {
return address;
}
public int getRouterPort() {
return routerPort;
}
public int getDirectoryPort() {
return directoryPort;
}
public int getAverageBandwidth() {
return averageBandwidth;
}
public int getBurstBandwidth() {
return burstBandwidth;
}
public int getObservedBandwidth() {
return observedBandwidth;
}
public String getPlatform() {
return platform;
}
public HexDigest getFingerprint() {
return fingerprint;
}
public int getUptime() {
return uptime;
}
public TorPublicKey getOnionKey() {
return onionKey;
}
public byte[] getNTorOnionKey() {
return ntorOnionKey;
}
public TorPublicKey getIdentityKey() {
return identityKey;
}
public String getContact() {
return contact;
}
public boolean isHibernating() {
return hibernating;
}
public boolean cachesExtraInfo() {
return cachesExtraInfo;
}
public boolean allowsSingleHopExits() {
return allowSingleHopExits;
}
public Timestamp getPublishedTime() {
return published;
}
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Router Descriptor: (name: ");
builder.append(nickname);
builder.append(" orport=");
builder.append(routerPort);
builder.append(" dirport=");
builder.append(directoryPort);
builder.append(" address=");
builder.append(address);
builder.append(" platform=");
builder.append(platform);
builder.append(" published=");
builder.append(published.getDate());
builder.append(")");
return builder.toString();
}
public void print() {
System.out.println("nickname: "+ nickname +" IP: "+ address +" port: "+ routerPort);
System.out.println("directory port: "+ directoryPort +" platform: "+ platform);
System.out.println("Bandwidth(avg/burst/observed): "+ averageBandwidth +"/"+ burstBandwidth +"/"+ observedBandwidth);
System.out.println("Publication time: "+ published +" Uptime: "+ uptime);
if(fingerprint != null)
System.out.println("Fingerprint: "+ fingerprint);
if(contact != null)
System.out.println("Contact: "+ contact);
}
public boolean exitPolicyAccepts(IPv4Address address, int port) {
return exitPolicy.acceptsDestination(address, port);
}
public boolean exitPolicyAccepts(int port) {
return exitPolicy.acceptsPort(port);
}
public HexDigest getExtraInfoDigest() {
return extraInfoDigest;
}
public boolean isHiddenServiceDirectory() {
return hiddenServiceDir;
}
public Set<String> getFamilyMembers() {
return familyMembers;
}
public boolean supportsEventDNS() {
return eventDNS;
}
public BandwidthHistory getReadHistory() {
return readHistory;
}
public BandwidthHistory getWriteHistory() {
return writeHistory;
}
public boolean isNewerThan(RouterDescriptor other) {
return other.getPublishedTime().isBefore(published);
}
public HexDigest getDescriptorDigest() {
return descriptorDigest;
}
public String getRawDocumentData() {
return rawDocumentData;
}
public ByteBuffer getRawDocumentBytes() {
if(getRawDocumentData() == null) {
return ByteBuffer.allocate(0);
} else {
return ByteBuffer.wrap(getRawDocumentData().getBytes(Tor.getDefaultCharset()));
}
}
public boolean equals(Object o) {
if(!(o instanceof RouterDescriptorImpl))
return false;
final RouterDescriptorImpl other = (RouterDescriptorImpl) o;
if(other.getDescriptorDigest() == null || descriptorDigest == null)
return false;
return other.getDescriptorDigest().equals(descriptorDigest);
}
public int hashCode() {
if(descriptorDigest == null)
return 0;
return descriptorDigest.hashCode();
}
public ExitPolicy getExitPolicy() {
return exitPolicy;
}
public void setLastListed(long timestamp) {
this.lastListed = timestamp;
}
public long getLastListed() {
return lastListed;
}
public void setCacheLocation(CacheLocation location) {
this.cacheLocation = location;
}
public CacheLocation getCacheLocation() {
return cacheLocation;
}
public int getBodyLength() {
return rawDocumentData.length();
}
}