Package com.subgraph.orchid.directory.router

Source Code of com.subgraph.orchid.directory.router.RouterDescriptorParser

package com.subgraph.orchid.directory.router;

import com.subgraph.orchid.RouterDescriptor;
import com.subgraph.orchid.TorParsingException;
import com.subgraph.orchid.crypto.TorSignature;
import com.subgraph.orchid.data.BandwidthHistory;
import com.subgraph.orchid.data.Timestamp;
import com.subgraph.orchid.directory.parsing.BasicDocumentParsingResult;
import com.subgraph.orchid.directory.parsing.DocumentFieldParser;
import com.subgraph.orchid.directory.parsing.DocumentParser;
import com.subgraph.orchid.directory.parsing.DocumentParsingHandler;
import com.subgraph.orchid.directory.parsing.DocumentParsingResult;
import com.subgraph.orchid.directory.parsing.DocumentParsingResultHandler;

public class RouterDescriptorParser implements DocumentParser<RouterDescriptor> {
  private final DocumentFieldParser fieldParser;
  private final boolean verifySignatures;
 
  private RouterDescriptorImpl currentDescriptor;
  private DocumentParsingResultHandler<RouterDescriptor> resultHandler;
 
  public RouterDescriptorParser(DocumentFieldParser fieldParser, boolean verifySignatures) {
    this.fieldParser = fieldParser;
    this.fieldParser.setHandler(createParsingHandler());
    this.fieldParser.setRecognizeOpt();
    this.verifySignatures = verifySignatures;
  }
 
  private DocumentParsingHandler createParsingHandler() {
    return new DocumentParsingHandler() {
      public void endOfDocument() {
      }
      public void parseKeywordLine() {
        processKeywordLine();       
      }
    };
  }
 
  private void processKeywordLine() {
    final RouterDescriptorKeyword keyword = RouterDescriptorKeyword.findKeyword(fieldParser.getCurrentKeyword());
    /*
     * dirspec.txt (1.2)
     * When interpreting a Document, software MUST ignore any KeywordLine that
     * starts with a keyword it doesn't recognize;
     */
    if(!keyword.equals(RouterDescriptorKeyword.UNKNOWN_KEYWORD))
      processKeyword(keyword)
  }
 
  private void startNewDescriptor() {
    fieldParser.resetRawDocument();
    fieldParser.startSignedEntity();
    currentDescriptor = new RouterDescriptorImpl();
  }
 
  public boolean parse(DocumentParsingResultHandler<RouterDescriptor> resultHandler) {
    this.resultHandler = resultHandler;
    startNewDescriptor();
    try {
      fieldParser.processDocument();
      return true;
    } catch(TorParsingException e) {
      resultHandler.parsingError(e.getMessage());
      return false;
    }
  }
 
  public DocumentParsingResult<RouterDescriptor> parse() {
    final BasicDocumentParsingResult<RouterDescriptor> result = new BasicDocumentParsingResult<RouterDescriptor>();
    parse(result);
    return result;
  }

  private void processKeyword(RouterDescriptorKeyword keyword) {
    fieldParser.verifyExpectedArgumentCount(keyword.getKeyword(), keyword.getArgumentCount());

    switch(keyword) {
    case ROUTER:
      processRouter();
      return;
    case BANDWIDTH:
      processBandwidth();
      break;
    case PLATFORM:
      currentDescriptor.setPlatform(fieldParser.parseConcatenatedString());
      break;
    case PUBLISHED:
      currentDescriptor.setPublished(fieldParser.parseTimestamp());
      break;
    case FINGERPRINT:
      currentDescriptor.setFingerprint(fieldParser.parseFingerprint());
      break;
    case HIBERNATING:
      currentDescriptor.setHibernating(fieldParser.parseBoolean());
      break;
    case UPTIME:
      currentDescriptor.setUptime(fieldParser.parseInteger());
      break;
    case ONION_KEY:
      currentDescriptor.setOnionKey(fieldParser.parsePublicKey());
      break;
    case NTOR_ONION_KEY:
      currentDescriptor.setNtorOnionKey(fieldParser.parseNtorPublicKey());
      break;
    case SIGNING_KEY:
      currentDescriptor.setIdentityKey(fieldParser.parsePublicKey());
      break;     
    case ROUTER_SIGNATURE:
      processSignature();
      break;
    case ACCEPT:
      currentDescriptor.addAcceptRule(fieldParser.parseString());
      break;
    case REJECT:
      currentDescriptor.addRejectRule(fieldParser.parseString());
      break;
    case CONTACT:
      currentDescriptor.setContact(fieldParser.parseConcatenatedString());
      break;
    case FAMILY:
      while(fieldParser.argumentsRemaining() > 0)
        currentDescriptor.addFamilyMember(fieldParser.parseString());
      break;
    case EVENTDNS:
      if(fieldParser.parseBoolean())
        currentDescriptor.setEventDNS();
      break;   
    case PROTOCOLS:
      processProtocols();
      break;     
    case CACHES_EXTRA_INFO:
      currentDescriptor.setCachesExtraInfo();
      break;     
    case HIDDEN_SERVICE_DIR:
      currentDescriptor.setHiddenServiceDir();
      break;     
    case ALLOW_SINGLE_HOP_EXITS:
      currentDescriptor.setAllowSingleHopExits();
      break;
    case EXTRA_INFO_DIGEST:
      currentDescriptor.setExtraInfoDigest(fieldParser.parseHexDigest());
      break;   
    case READ_HISTORY:
      currentDescriptor.setReadHistory(parseHistory());
      break;
    case WRITE_HISTORY:
      currentDescriptor.setWriteHistory(parseHistory());
      break;
    default:
      break;
    }
  }
 
  private BandwidthHistory parseHistory() {
    final Timestamp ts = fieldParser.parseTimestamp();
    final String nsec = fieldParser.parseString();
    fieldParser.parseString();
    final int interval = fieldParser.parseInteger(nsec.substring(1));
    final BandwidthHistory history = new BandwidthHistory(ts, interval);
    if(fieldParser.argumentsRemaining() == 0)
      return history;
    final String[] samples = fieldParser.parseString().split(",");
    for(String s: samples)
      history.addSample(fieldParser.parseInteger(s));
    return history;
  }
 
  private void processRouter() {
    currentDescriptor.setNickname(fieldParser.parseNickname());
    currentDescriptor.setAddress(fieldParser.parseAddress());
    currentDescriptor.setRouterPort(fieldParser.parsePort());
    /* 2.1 SOCKSPort is deprecated and should always be 0 */
    fieldParser.parsePort();
    currentDescriptor.setDirectoryPort(fieldParser.parsePort());
  }
 
  private boolean verifyCurrentDescriptor(TorSignature signature) {
    if(verifySignatures && !fieldParser.verifySignedEntity(currentDescriptor.getIdentityKey(), signature)) {
      resultHandler.documentInvalid(currentDescriptor, "Signature failed.");
      fieldParser.logWarn("Signature failed for router: " + currentDescriptor.getNickname());
      return false;
    }
    currentDescriptor.setValidSignature();
    if(!currentDescriptor.isValidDocument()) {
      resultHandler.documentInvalid(currentDescriptor, "Router data invalid");
      fieldParser.logWarn("Router data invalid for router: " + currentDescriptor.getNickname());
    }
    return currentDescriptor.isValidDocument();
  }
 
  private void processBandwidth() {
    final int average = fieldParser.parseInteger();
    final int burst = fieldParser.parseInteger();
    final int observed = fieldParser.parseInteger();
    currentDescriptor.setBandwidthValues(average, burst, observed);
  }
 
  private void processProtocols() {
    String kw = fieldParser.parseString();
    if(!kw.equals("Link"))
      throw new TorParsingException("Expected 'Link' token in protocol line got: " + kw);
    while(true) {
      kw = fieldParser.parseString();
      if(kw.equals("Circuit"))
        break;
      currentDescriptor.addLinkProtocolVersion(fieldParser.parseInteger(kw));
    }
    while(fieldParser.argumentsRemaining() > 0)
      currentDescriptor.addCircuitProtocolVersion(fieldParser.parseInteger());
   
  }
 
  private void processSignature() {
    fieldParser.endSignedEntity();
    currentDescriptor.setDescriptorHash(fieldParser.getSignatureMessageDigest().getHexDigest());
    final TorSignature signature = fieldParser.parseSignature();
    currentDescriptor.setRawDocumentData(fieldParser.getRawDocument());
   
    if(verifyCurrentDescriptor(signature))
      resultHandler.documentParsed(currentDescriptor);
    startNewDescriptor();
  }
}
TOP

Related Classes of com.subgraph.orchid.directory.router.RouterDescriptorParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.