use of net.i2p.data.DataFormatException in project i2p.i2p by i2p.
the class I2PDatagramDissector method loadI2PDatagram.
/**
* Load an I2P repliable datagram into the dissector.
* Does NOT verify the signature.
*
* Format is:
* <ol>
* <li>Destination (387+ bytes)
* <li>Signature (40+ bytes, type and length as implied by signing key type in the Destination)
* <li>Payload
* </ol>
*
* For DSA_SHA1 Destinations, the signature is of the SHA-256 Hash of the payload.
*
* As of 0.9.14, for non-DSA_SHA1 Destinations, the signature is of the payload itself.
*
* @param dgram non-null I2P repliable datagram to be loaded
*
* @throws DataFormatException If there's an error in the datagram format
*/
public void loadI2PDatagram(byte[] dgram) throws DataFormatException {
// set invalid(very important!)
this.valid = false;
if (dgram.length < MIN_DGRAM_SIZE)
throw new DataFormatException("repliable datagram too small: " + dgram.length);
ByteArrayInputStream dgStream = new ByteArrayInputStream(dgram);
try {
// read destination
rxDest = Destination.create(dgStream);
SigType type = rxDest.getSigningPublicKey().getType();
if (type == null)
throw new DataFormatException("unsupported sig type");
rxSign = new Signature(type);
// read signature
rxSign.readBytes(dgStream);
// read payload
rxPayloadLen = dgStream.read(rxPayload);
// calculate the hash of the payload
if (type == SigType.DSA_SHA1) {
if (rxHash == null)
rxHash = new byte[Hash.HASH_LENGTH];
// non-caching
hashGen.calculateHash(rxPayload, 0, rxPayloadLen, rxHash, 0);
// assert this.hashGen.calculateHash(this.extractPayload()).equals(this.rxHash);
} else {
rxHash = null;
}
} catch (IOException e) {
// log.error("Error loading datagram", e);
throw new DataFormatException("Error loading datagram", e);
// } catch(AssertionError e) {
// Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PDatagramDissector.class);
// log.error("Assertion failed!", e);
}
// _log.debug("Datagram payload size: " + rxPayloadLen + "; content:\n"
// + HexDump.dump(rxPayload, 0, rxPayloadLen));
}
use of net.i2p.data.DataFormatException in project i2p.i2p by i2p.
the class I2PDatagramMaker method makeI2PDatagram.
/**
* Make a repliable I2P datagram containing the specified payload.
*
* Format is:
* <ol>
* <li>Destination (387+ bytes)
* <li>Signature (40+ bytes, type and length as implied by signing key type in the Destination)
* <li>Payload
* </ol>
*
* Maximum datagram size is 32768, so maximum payload size is 32341, or less for
* non-DSA_SHA1 destinations. Practical maximum is a few KB less due to
* ElGamal/AES overhead. 10 KB or less is recommended for best results.
*
* For DSA_SHA1 Destinations, the signature is of the SHA-256 Hash of the payload.
*
* As of 0.9.14, for non-DSA_SHA1 Destinations, the signature is of the payload itself.
*
* @param payload non-null Bytes to be contained in the I2P datagram.
* @return null on error
* @throws IllegalArgumentException if payload is too big
* @throws IllegalStateException if Destination signature type unsupported
*/
public byte[] makeI2PDatagram(byte[] payload) {
sxDGram.reset();
try {
sxDGram.write(sxDestBytes);
SigType type = sxPrivKey.getType();
if (type == null)
throw new IllegalStateException("Unsupported sig type");
Signature sig;
if (type == SigType.DSA_SHA1) {
byte[] hash = SimpleByteCache.acquire(Hash.HASH_LENGTH);
// non-caching
hashGen.calculateHash(payload, 0, payload.length, hash, 0);
sig = dsaEng.sign(hash, sxPrivKey);
SimpleByteCache.release(hash);
} else {
sig = dsaEng.sign(payload, sxPrivKey);
}
sig.writeBytes(sxDGram);
sxDGram.write(payload);
if (sxDGram.size() > DGRAM_BUFSIZE)
throw new IllegalArgumentException("Too big");
return sxDGram.toByteArray();
} catch (IOException e) {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PDatagramMaker.class);
log.error("Caught IOException", e);
return null;
} catch (DataFormatException e) {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PDatagramMaker.class);
log.error("Caught DataFormatException", e);
return null;
}
}
use of net.i2p.data.DataFormatException in project i2p.i2p by i2p.
the class MessagePayloadMessageHandler method handleMessage.
public void handleMessage(I2CPMessage message, I2PSessionImpl session) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Handle message " + message + " for session " + session);
try {
MessagePayloadMessage msg = (MessagePayloadMessage) message;
long id = msg.getMessageId();
decryptPayload(msg, session);
session.addNewMessage(msg);
// (needs router version saving support in SetDateMessageHandler)
if (!session.getFastReceive()) {
ReceiveMessageEndMessage m = new ReceiveMessageEndMessage();
m.setMessageId(id);
m.setSessionId(msg.getSessionId());
session.sendMessage(m);
}
} catch (DataFormatException dfe) {
session.propogateError("Error handling a new payload message", dfe);
} catch (I2PSessionException ise) {
session.propogateError("Error handling a new payload message", ise);
}
}
use of net.i2p.data.DataFormatException in project i2p.i2p by i2p.
the class Daemon method update.
/**
* @param knownNames only non-null if router book is a text file
* @param publishedNS only non-null if we have a published address book
* @since 0.9.33 split out from above
*/
private static void update(NamingService router, Set<String> knownNames, NamingService publishedNS, AddressBook addressbook, Iterator<Map.Entry<String, HostTxtEntry>> iter, Log log) {
long start = System.currentTimeMillis();
int old = 0, nnew = 0, invalid = 0, conflict = 0, total = 0;
int deleted = 0;
while (iter.hasNext()) {
Map.Entry<String, HostTxtEntry> entry = iter.next();
total++;
// may be null for 'remove' entries
String key = entry.getKey();
boolean isKnown;
// NOT set for text file NamingService
Destination oldDest;
if (knownNames != null) {
oldDest = null;
isKnown = key != null ? knownNames.contains(key) : null;
} else {
oldDest = key != null ? router.lookup(key) : null;
isKnown = oldDest != null;
}
try {
HostTxtEntry he = entry.getValue();
Properties hprops = he.getProps();
boolean mustValidate = MUST_VALIDATE || hprops != null;
String action = hprops != null ? hprops.getProperty(HostTxtEntry.PROP_ACTION) : null;
if (key == null && !he.hasValidRemoveSig()) {
if (log != null) {
log.append("Bad signature of action " + action + " for key " + hprops.getProperty(HostTxtEntry.PROP_NAME) + ". From: " + addressbook.getLocation());
}
invalid++;
} else if (key != null && mustValidate && !he.hasValidSig()) {
if (log != null) {
log.append("Bad signature of action " + action + " for key " + key + ". From: " + addressbook.getLocation());
}
invalid++;
} else if (action != null || !isKnown) {
if (key != null && AddressBook.isValidKey(key)) {
Destination dest = new Destination(he.getDest());
Properties props = new OrderedProperties();
props.setProperty("s", addressbook.getLocation());
boolean allowExistingKeyInPublished = false;
if (mustValidate) {
// sig checked above
props.setProperty("v", "true");
}
if (hprops != null) {
// merge in all the received properties
for (Map.Entry<Object, Object> e : hprops.entrySet()) {
// Add prefix to indicate received property
props.setProperty(RCVD_PROP_PREFIX + e.getKey(), (String) e.getValue());
}
}
if (action != null) {
// Must handle isKnown in each case.
if (action.equals(HostTxtEntry.ACTION_ADDDEST)) {
// Add an alternate destination (new crypto) for existing hostname
// Requires new NamingService support if the key exists
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
if (polddest != null) {
Destination pod = new Destination(polddest);
List<Destination> pod2 = router.lookupAll(key);
if (pod2 == null) {
// check inner sig anyway
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
} else if (pod2.contains(dest)) {
// we knew it before, with the same dest
old++;
continue;
} else if (pod2.contains(pod)) {
// checks out, so verify the inner sig
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
// TODO Requires NamingService support
// if (isTextFile), do we replace or not? check sigType.isAvailable()
boolean success = router.addDestination(key, dest, props);
if (log != null) {
if (success)
log.append("Additional address for " + key + " added to address book. From: " + addressbook.getLocation());
else
log.append("Failed to add additional address for " + key + " From: " + addressbook.getLocation());
}
// ditto
if (publishedNS != null) {
// FIXME this fails, no support in SFNS
success = publishedNS.addDestination(key, dest, props);
if (log != null && !success)
log.append("Add to published address book " + publishedNS.getName() + " failed for " + key);
}
nnew++;
continue;
} else {
// mismatch, disallow
logMismatch(log, action, key, pod2, he.getDest(), addressbook);
invalid++;
continue;
}
} else {
logMissing(log, action, key, addressbook);
invalid++;
continue;
}
} else if (action.equals(HostTxtEntry.ACTION_ADDNAME)) {
// Add an alias for an existing hostname, same dest
if (isKnown) {
// could be same or different dest
old++;
continue;
}
String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
if (poldname != null) {
List<Destination> pod = router.lookupAll(poldname);
if (pod == null) {
// we didn't have the old one, so we'll add the new one
} else if (pod.contains(dest)) {
// checks out, so we'll add the new one
} else {
// mismatch, disallow
logMismatch(log, action, key, pod, he.getDest(), addressbook);
invalid++;
continue;
}
} else {
logMissing(log, action, key, addressbook);
invalid++;
continue;
}
} else if (action.equals(HostTxtEntry.ACTION_ADDSUBDOMAIN)) {
// add a subdomain with verification
if (isKnown) {
old++;
continue;
}
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
if (polddest != null && poldname != null) {
// check for valid subdomain
if (!AddressBook.isValidKey(poldname) || key.indexOf('.' + poldname) <= 0) {
if (log != null)
log.append("Action: " + action + " failed because" + " old name " + poldname + " is invalid" + ". From: " + addressbook.getLocation());
invalid++;
continue;
}
Destination pod = new Destination(polddest);
List<Destination> pod2 = router.lookupAll(poldname);
if (pod2 == null) {
// check inner sig anyway
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
} else if (pod2.contains(pod)) {
// checks out, so verify the inner sig
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
} else {
// mismatch, disallow
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
continue;
}
} else {
logMissing(log, action, key, addressbook);
invalid++;
continue;
}
} else if (action.equals(HostTxtEntry.ACTION_CHANGEDEST)) {
// change destination on an existing entry
// This removes all previous destinations under that hostname,
// is this what we want?
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
if (polddest != null) {
Destination pod = new Destination(polddest);
List<Destination> pod2 = router.lookupAll(key);
if (pod2 == null) {
// check inner sig anyway
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
} else if (pod2.contains(dest)) {
// we already have the new dest
old++;
continue;
} else if (pod2.contains(pod)) {
// checks out, so verify the inner sig
if (!he.hasValidInnerSig()) {
logInner(log, action, key, addressbook);
invalid++;
continue;
}
if (log != null) {
if (pod2.size() == 1)
log.append("Changing destination for " + key + ". From: " + addressbook.getLocation());
else
log.append("Replacing " + pod2.size() + " destinations for " + key + ". From: " + addressbook.getLocation());
}
allowExistingKeyInPublished = true;
props.setProperty("m", Long.toString(I2PAppContext.getGlobalContext().clock().now()));
} else {
// mismatch, disallow
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
continue;
}
} else {
logMissing(log, action, key, addressbook);
invalid++;
continue;
}
} else if (action.equals(HostTxtEntry.ACTION_CHANGENAME)) {
// is this what we want?
if (isKnown) {
old++;
continue;
}
String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
if (poldname != null) {
List<Destination> pod = router.lookupAll(poldname);
if (pod == null) {
// we didn't have the old name
} else if (pod.contains(dest)) {
// checks out, so we'll delete it
if (knownNames != null)
knownNames.remove(poldname);
boolean success = router.remove(poldname, dest);
if (success)
deleted++;
if (log != null) {
if (success)
log.append("Removed: " + poldname + " to be replaced with " + key + ". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + poldname + " to be replaced with " + key + ". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (publishedNS != null) {
success = publishedNS.remove(poldname, dest);
if (log != null && !success)
log.append("Remove from published address book " + publishedNS.getName() + " failed for " + poldname);
}
} else {
// mismatch, disallow
logMismatch(log, action, key, pod, he.getDest(), addressbook);
continue;
}
} else {
logMissing(log, action, key, addressbook);
invalid++;
continue;
}
} else if (action.equals(HostTxtEntry.ACTION_REMOVE) || action.equals(HostTxtEntry.ACTION_REMOVEALL)) {
// w/o name=dest handled below
if (log != null)
log.append("Action: " + action + " with name=dest invalid" + ". From: " + addressbook.getLocation());
invalid++;
continue;
} else if (action.equals(HostTxtEntry.ACTION_UPDATE)) {
if (isKnown) {
allowExistingKeyInPublished = true;
props.setProperty("m", Long.toString(I2PAppContext.getGlobalContext().clock().now()));
}
} else {
if (log != null)
log.append("Action: " + action + " unrecognized" + ". From: " + addressbook.getLocation());
invalid++;
continue;
}
}
// action != null
boolean success = router.put(key, dest, props);
if (log != null) {
if (success)
log.append("New address " + key + " added to address book. From: " + addressbook.getLocation());
else
log.append("Save to naming service " + router + " failed for new key " + key);
}
// now update the published addressbook
if (publishedNS != null) {
if (allowExistingKeyInPublished)
success = publishedNS.put(key, dest, props);
else
success = publishedNS.putIfAbsent(key, dest, props);
if (log != null && !success) {
log.append("Save to published address book " + publishedNS.getName() + " failed for new key " + key);
}
}
if (knownNames != null) {
// keep track for later dup check
knownNames.add(key);
}
nnew++;
} else if (key == null) {
// isKnown is false
if (action != null) {
// Process commands. hprops is non-null.
if (action.equals(HostTxtEntry.ACTION_REMOVE)) {
// delete this entry
String polddest = hprops.getProperty(HostTxtEntry.PROP_DEST);
String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME);
if (polddest != null && poldname != null) {
Destination pod = new Destination(polddest);
List<Destination> pod2 = router.lookupAll(poldname);
if (pod2 != null && pod2.contains(pod)) {
if (knownNames != null && pod2.size() == 1)
knownNames.remove(poldname);
boolean success = router.remove(poldname, pod);
if (success)
deleted++;
if (log != null) {
if (success)
log.append("Removed: " + poldname + " as requested" + ". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + poldname + " as requested" + ". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (publishedNS != null) {
success = publishedNS.remove(poldname, pod);
if (log != null && !success)
log.append("Remove from published address book " + publishedNS.getName() + " failed for " + poldname);
}
} else if (pod2 != null) {
// mismatch, disallow
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
} else {
old++;
}
} else {
logMissing(log, action, "delete", addressbook);
invalid++;
}
} else if (action.equals(HostTxtEntry.ACTION_REMOVEALL)) {
// delete all entries with this destination
String polddest = hprops.getProperty(HostTxtEntry.PROP_DEST);
// oldname is optional, but nice because not all books support reverse lookup
if (polddest != null) {
Destination pod = new Destination(polddest);
String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME);
if (poldname != null) {
List<Destination> pod2 = router.lookupAll(poldname);
if (pod2 != null && pod2.contains(pod)) {
if (knownNames != null)
knownNames.remove(poldname);
boolean success = router.remove(poldname, pod);
if (success)
deleted++;
if (log != null) {
if (success)
log.append("Removed: " + poldname + " as requested" + ". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + poldname + " as requested" + ". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (publishedNS != null) {
success = publishedNS.remove(poldname, pod);
if (log != null && !success)
log.append("Remove from published address book " + publishedNS.getName() + " failed for " + poldname);
}
} else if (pod2 != null) {
// mismatch, disallow
logMismatch(log, action, key, pod2, polddest, addressbook);
invalid++;
} else {
old++;
}
}
// reverse lookup, delete all
List<String> revs = router.reverseLookupAll(pod);
if (revs != null) {
for (String rev : revs) {
if (knownNames != null)
knownNames.remove(rev);
boolean success = router.remove(rev, pod);
if (success)
deleted++;
if (log != null) {
if (success)
log.append("Removed: " + rev + " as requested" + ". From: " + addressbook.getLocation());
else
log.append("Remove failed for: " + rev + " as requested" + ". From: " + addressbook.getLocation());
}
// now update the published addressbook
if (publishedNS != null) {
success = publishedNS.remove(rev, pod);
if (log != null && !success)
log.append("Remove from published address book " + publishedNS.getName() + " failed for " + rev);
}
}
}
} else {
logMissing(log, action, "delete", addressbook);
invalid++;
}
} else {
if (log != null)
log.append("Action: " + action + " w/o name=dest unrecognized" + ". From: " + addressbook.getLocation());
invalid++;
}
continue;
} else {
if (log != null)
log.append("No action in command line" + ". From: " + addressbook.getLocation());
invalid++;
continue;
}
} else if (log != null) {
log.append("Bad hostname " + key + ". From: " + addressbook.getLocation());
invalid++;
}
/**
**
* } else if (false && DEBUG && log != null) {
* // lookup the conflict if we haven't yet (O(n**2) for text file)
* if (isTextFile)
* oldDest = router.lookup(key);
* if (oldDest != null && !oldDest.toBase64().equals(entry.getValue())) {
* log.append("Conflict for " + key + ". From: "
* + addressbook.getLocation()
* + ". Destination in remote address book is "
* + entry.getValue());
* conflict++;
* } else {
* old++;
* }
***
*/
} else {
old++;
}
} catch (DataFormatException dfe) {
if (log != null)
log.append("Invalid b64 for " + key + " From: " + addressbook.getLocation());
invalid++;
}
}
// entries
if (DEBUG && log != null && total > 0) {
log.append("Merge of " + addressbook.getLocation() + " into " + router + " took " + (System.currentTimeMillis() - start) + " ms with " + total + " total, " + nnew + " new, " + old + " old, " + deleted + " deleted, " + invalid + " invalid, " + conflict + " conflicts");
}
}
use of net.i2p.data.DataFormatException in project i2p.i2p by i2p.
the class BlockfileNamingService method writeLongStringUTF8.
/**
* Same as DataHelper.writeStringUTF8, except that
* strings up to 4K bytes are allowed.
* Format is: one-byte length + data, or 0xff + two-byte length + data
*
* @param out stream to write string
* @param string to write out: null strings are valid, but strings of excess length will
* cause a DataFormatException to be thrown
* @throws DataFormatException if the string is not valid
* @throws IOException if there is an IO error writing the string
*/
private static void writeLongStringUTF8(ByteArrayOutputStream out, String string) throws DataFormatException, IOException {
if (string == null) {
out.write(0);
} else {
byte[] raw = string.getBytes("UTF-8");
int len = raw.length;
if (len >= 255) {
if (len > MAX_VALUE_LENGTH)
throw new DataFormatException(MAX_VALUE_LENGTH + " max, but this is " + len + " [" + string + "]");
out.write(0xff);
DataHelper.writeLong(out, 2, len);
} else {
out.write(len);
}
out.write(raw);
}
}
Aggregations