Example #1
0
  /**
   * Make a new PushRequest object to represent a push packet we read from the network. This is the
   * packet parser.
   *
   * @param guid The GUID that uniquely identifies this Gnutella message
   * @param ttl The message TTL, the number of times it will travel across the Internet
   * @param hops The number of times this Gnutella message has traveled across the Internet
   * @param payload The 26 byte payload
   * @param network The Internet protocol that brought us this message, like 1 N_TCP or 2 N_UDP
   * @return A new PushRequest object with that information
   */
  public PushRequest(byte[] guid, byte ttl, byte hops, byte[] payload, int network)
      throws BadPacketException {

    // Call the Message constructor to save information from the packet header in the Message
    // members this PushRequest inherits
    super(guid, Message.F_PUSH, ttl, hops, payload.length, network);

    // Make sure the payload is at least 26 bytes
    if (payload.length < STANDARD_PAYLOAD_SIZE) {
      ReceivedErrorStat.PUSH_INVALID_PAYLOAD.incrementStat();
      throw new BadPacketException("Payload too small: " + payload.length);
    }

    // Save the payload data
    this.payload = payload;

    // Make sure the port number isn't 0
    if (!NetworkUtils.isValidPort(getPort())) {
      ReceivedErrorStat.PUSH_INVALID_PORT.incrementStat();
      throw new BadPacketException("invalid port");
    }

    // Make sure the IP address doesn't start 0 or 255
    String ip = NetworkUtils.ip2string(payload, 20);
    if (!NetworkUtils.isValidAddress(ip)) {
      ReceivedErrorStat.PUSH_INVALID_ADDRESS.incrementStat();
      throw new BadPacketException("invalid address: " + ip);
    }
  }
Example #2
0
  /**
   * @return whether this RFD supports firewall-to-firewall transfer. For this to be true we need to
   *     have some push proxies, indication that the host supports FWT and we need to know that
   *     hosts' external address.
   */
  public final boolean supportsFWTransfer() {

    if (_host.equals(BOGUS_IP)
        || !NetworkUtils.isValidAddress(_host)
        || NetworkUtils.isPrivateAddress(_host)) return false;

    return _pushAddr == null ? false : _pushAddr.supportsFWTVersion() > 0;
  }
Example #3
0
  /**
   * Creates a new Endpoint instance
   *
   * @param hostBytes IP address of the host (MSB first)
   * @param port The port number for the host
   */
  public Endpoint(byte[] hostBytes, int port) {
    if (!NetworkUtils.isValidPort(port))
      throw new IllegalArgumentException("invalid port: " + port);
    if (!NetworkUtils.isValidAddress(hostBytes))
      throw new IllegalArgumentException("invalid address");

    this.port = port;
    this.hostname = NetworkUtils.ip2string(hostBytes);
  }
Example #4
0
  /**
   * Constructs a new endpoint using the specific hostname & port. If strict is true, this does a
   * DNS lookup against the name, failing if the lookup couldn't complete.
   */
  public Endpoint(String hostname, int port, boolean strict) {
    if (!NetworkUtils.isValidPort(port))
      throw new IllegalArgumentException("invalid port: " + port);
    if (strict && !NetworkUtils.isValidAddress(hostname))
      throw new IllegalArgumentException("invalid address: " + hostname);

    this.hostname = hostname;
    this.port = port;
  }
  public void writeMessageHeaders(OutputStream ostream) throws IOException {
    LOG.debug("writing headers");

    byte[] clientGUID = GUID.fromHexString(UPLOADER.getFileName());
    InetAddress hostAddress = UPLOADER.getNodeAddress();
    int hostPort = UPLOADER.getNodePort();

    if (clientGUID.length != 16
        || hostAddress == null
        || !NetworkUtils.isValidPort(hostPort)
        || !NetworkUtils.isValidAddress(hostAddress)) {
      // send back a 400
      String str = "HTTP/1.1 400 Push Proxy: Bad Request\r\n\r\n";
      ostream.write(str.getBytes());
      ostream.flush();
      debug("PPUS.doUpload(): unknown host.");
      UploadStat.PUSH_PROXY_REQ_BAD.incrementStat();
      return;
    }

    Map params = UPLOADER.getParameters();
    int fileIndex = 0; // default to 0.
    Object index = params.get(P_FILE);
    // set the file index if we know it...
    if (index != null) fileIndex = ((Integer) index).intValue();

    PushRequest push =
        new PushRequest(
            GUID.makeGuid(), (byte) 0, clientGUID, fileIndex, hostAddress.getAddress(), hostPort);
    try {
      RouterService.getMessageRouter().sendPushRequest(push);

    } catch (IOException ioe) {
      // send back a 410
      String str = "HTTP/1.1 410 Push Proxy: Servent not connected\r\n\r\n";
      ostream.write(str.getBytes());
      ostream.flush();
      debug("PPUS.doUpload(): push failed.");
      debug(ioe);
      UploadStat.PUSH_PROXY_REQ_FAILED.incrementStat();
      return;
    }

    UploadStat.PUSH_PROXY_REQ_SUCCESS.incrementStat();

    String str;
    str = "HTTP/1.1 202 Push Proxy: Message Sent\r\n";
    ostream.write(str.getBytes());
    str = "Server: " + CommonUtils.getHttpServer() + "\r\n";
    ostream.write(str.getBytes());
    str = "Content-Type: " + Constants.QUERYREPLY_MIME_TYPE + "\r\n";
    ostream.write(str.getBytes());
    str = "Content-Length: " + BAOS.size() + "\r\n";
    ostream.write(str.getBytes());
    str = "\r\n";
    ostream.write(str.getBytes());
  }
Example #6
0
  /**
   * @return true if I am not a multicast host and have a hash. also, if I am firewalled I must have
   *     at least one push proxy, otherwise my port and address need to be valid.
   */
  public final boolean isAltLocCapable() {
    boolean ret = getSHA1Urn() != null && !_replyToMulticast;

    if (_firewalled) ret = ret && _pushAddr != null && _pushAddr.getProxies().size() > 0;
    else
      ret =
          ret
              && NetworkUtils.isValidPort(_port)
              && !NetworkUtils.isPrivateAddress(_host)
              && NetworkUtils.isValidAddress(_host);

    return ret;
  }
Example #7
0
  /**
   * Make a new PushRequest object for us to send with the given information. This is the packet
   * maker.
   *
   * @param guid For the header, the message GUID that will mark this packet unique
   * @param ttl For the header, the TTL
   * @param clientGUID For the payload, the client ID GUID of the firewalled computer that has the
   *     file and will push open the connection
   * @param index For the payload, the ID number the firewalled computer has assigned the file the
   *     downloading computer wants
   * @param ip For the payload, the downloading computer's IP address the firewalled computer will
   *     push open a connection to
   * @param port For the payload, the downloading computer's port number the firewalled computer
   *     will push open a connection to
   * @param network The Internet protocol this push packet will travel on, like 1 N_TCP or 2 N_UDP,
   *     this is not a part of the packet that's sent
   * @return A new PushRequest object with that information
   */
  public PushRequest(
      byte[] guid, byte ttl, byte[] clientGUID, long index, byte[] ip, int port, int network) {

    // Call the Message constructor to save packet header information
    super(
        guid, // The message GUID
        Message.F_PUSH, // 0x40, this is a push message
        ttl, // The number of times this push will be able to travel between ultrapeers
        (byte) 0, // This push message hasn't traveled any hops yet
        STANDARD_PAYLOAD_SIZE, // The payload length will be 26 bytes
        network); // The Internet protocol we'll use to send, the Message object keeps this
                  // information but it is not part of the packet that's sent

    // Make sure the GUID is 16 bytes, the file id fits in 4 bytes, the IP is 4 bytes, the IP
    // address doesn't start 0 or 255, and the port number fits in 2 bytes
    if (clientGUID.length != 16)
      throw new IllegalArgumentException("invalid guid length: " + clientGUID.length);
    else if ((index & 0xFFFFFFFF00000000l) != 0)
      throw new IllegalArgumentException("invalid index: " + index);
    else if (ip.length != 4) throw new IllegalArgumentException("invalid ip length: " + ip.length);
    else if (!NetworkUtils.isValidAddress(ip))
      throw new IllegalArgumentException("invalid ip " + NetworkUtils.ip2string(ip));
    else if (!NetworkUtils.isValidPort(port))
      throw new IllegalArgumentException("invalid port: " + port);

    /*
     * The 26 byte pong payload has this structure:
     *
     * [client ID GUID]  At  0, 16 bytes  The client ID GUID of the computer that will get this packet and push open a new connection
     * FILE              At 16,  4 bytes  The number the pushing computer has given the file the wanting computer wants
     * IPIPPP            At 20,  6 bytes  The IP address and port number of the wanting computer
     */

    // Compose the 26 byte push payload
    payload = new byte[STANDARD_PAYLOAD_SIZE]; // Make a byte array that can hold 26 bytes
    System.arraycopy(clientGUID, 0, payload, 0, 16); // Copy the client ID GUID into the first 16
    ByteOrder.int2leb((int) index, payload, 16); // 16 bytes into the array, copy the 4 byte file id
    payload[20] = ip[0]; // 20 bytes into the array, copy the 4 bytes of the IP address
    payload[21] = ip[1];
    payload[22] = ip[2];
    payload[23] = ip[3];
    ByteOrder.short2leb(
        (short) port, payload, 24); // 24 bytes into the array, place the 2 byte port number
  }
Example #8
0
  /**
   * Constructs a new endpoint. If requireNumeric is true, or strict is false, no DNS lookups are
   * ever involved. If requireNumeric is false or strict is true, a DNS lookup MAY be performed if
   * the hostname is not numeric.
   *
   * <p>To never block, make sure strict is false.
   */
  public Endpoint(String hostAndPort, boolean requireNumeric, boolean strict) {
    final int DEFAULT = 6346;
    int j = hostAndPort.indexOf(":");
    if (j < 0) {
      this.hostname = hostAndPort;
      this.port = DEFAULT;
    } else if (j == 0) {
      throw new IllegalArgumentException();
    } else if (j == (hostAndPort.length() - 1)) {
      this.hostname = hostAndPort.substring(0, j);
      this.port = DEFAULT;
    } else {
      this.hostname = hostAndPort.substring(0, j);
      try {
        this.port = Integer.parseInt(hostAndPort.substring(j + 1));
      } catch (NumberFormatException e) {
        throw new IllegalArgumentException();
      }

      if (!NetworkUtils.isValidPort(getPort())) throw new IllegalArgumentException("invalid port");
    }

    if (requireNumeric) {
      // TODO3: implement with fewer allocations
      String[] numbers = StringUtils.split(hostname, '.');
      if (numbers.length != 4) throw new IllegalArgumentException();
      for (int i = 0; i < numbers.length; i++) {
        try {
          int x = Integer.parseInt(numbers[i]);
          if (x < 0 || x > 255) throw new IllegalArgumentException();
        } catch (NumberFormatException fail) {
          throw new IllegalArgumentException();
        }
      }
    }

    if (strict && !NetworkUtils.isValidAddress(hostname))
      throw new IllegalArgumentException("invalid address: " + hostname);
  }
Example #9
0
    private static Set parseLocations(byte[] locBytes) {
      Set locations = null;
      IPFilter ipFilter = IPFilter.instance();

      if (locBytes.length % 6 == 0) {
        for (int j = 0; j < locBytes.length; j += 6) {
          int port = ByteOrder.ushort2int(ByteOrder.leb2short(locBytes, j + 4));
          if (!NetworkUtils.isValidPort(port)) continue;
          byte[] ip = new byte[4];
          ip[0] = locBytes[j];
          ip[1] = locBytes[j + 1];
          ip[2] = locBytes[j + 2];
          ip[3] = locBytes[j + 3];
          if (!NetworkUtils.isValidAddress(ip)
              || !ipFilter.allow(ip)
              || NetworkUtils.isMe(ip, port)) continue;
          if (locations == null) locations = new HashSet();
          locations.add(new Endpoint(ip, port));
        }
      }
      return locations;
    }
  /**
   * Parses a new ExtendedEndpoint. Strictly validates all data. For example, addresses MUST be in
   * dotted quad format.
   *
   * @param line a single line read from the stream
   * @return the endpoint constructed from the line
   * @exception IOException problem reading from in, e.g., EOF reached prematurely
   * @exception ParseException data not in proper format. Does NOT necessarily set the offset of the
   *     exception properly.
   * @see write
   */
  public static ExtendedEndpoint read(String line) throws ParseException {
    // Break the line into fields.  Skip if badly formatted.  Note that
    // subsequent delimiters are NOT coalesced.
    String[] linea = StringUtils.splitNoCoalesce(line, FIELD_SEPARATOR);
    if (linea.length == 0) throw new ParseException("Empty line", 0);

    // 1. Host and port.  As a dirty trick, we use existing code in Endpoint.
    // Note that we strictly validate the address to work around corrupted
    // gnutella.net files from an earlier version
    boolean pureNumeric;

    String host;
    int port;
    try {
      Endpoint tmp = new Endpoint(linea[0], true); // require numeric.
      host = tmp.getAddress();
      port = tmp.getPort();
      pureNumeric = true;
    } catch (IllegalArgumentException e) {
      // Alright, pure numeric failed -- let's try constructing without
      // numeric & without requiring a DNS lookup.
      try {
        Endpoint tmp = new Endpoint(linea[0], false, false);
        host = tmp.getAddress();
        port = tmp.getPort();
        pureNumeric = false;
      } catch (IllegalArgumentException e2) {
        ParseException e3 =
            new ParseException("Couldn't extract address and port from: " + linea[0], 0);
        e3.initCause(e2);
        throw e3;
      }
    }

    // Build endpoint without any optional data.  (We'll set it if possible
    // later.)
    ExtendedEndpoint ret = new ExtendedEndpoint(host, port, false);

    // 2. Average uptime (optional)
    if (linea.length >= 2) {
      try {
        ret.dailyUptime = Integer.parseInt(linea[1].trim());
      } catch (NumberFormatException e) {
      }
    }

    // 3. Time of pong (optional).  Do NOT use current system tome
    //   if not set.
    ret.timeRecorded = DEFAULT_TIME_RECORDED;
    if (linea.length >= 3) {
      try {
        ret.timeRecorded = Long.parseLong(linea[2].trim());
      } catch (NumberFormatException e) {
      }
    }

    // 4. Time of successful connects (optional)
    if (linea.length >= 4) {
      try {
        String times[] = StringUtils.split(linea[3], LIST_SEPARATOR);
        for (int i = times.length - 1; i >= 0; i--)
          ret.recordConnectionAttempt(ret.connectSuccesses, Long.parseLong(times[i].trim()));
      } catch (NumberFormatException e) {
      }
    }

    // 5. Time of failed connects (optional)
    if (linea.length >= 5) {
      try {
        String times[] = StringUtils.split(linea[4], LIST_SEPARATOR);
        for (int i = times.length - 1; i >= 0; i--)
          ret.recordConnectionAttempt(ret.connectFailures, Long.parseLong(times[i].trim()));
      } catch (NumberFormatException e) {
      }
    }

    // 6. locale of the connection (optional)
    if (linea.length >= 6) {
      ret.setClientLocale(linea[5]);
    }

    // 7. udp-host
    if (linea.length >= 7) {
      try {
        int i = Integer.parseInt(linea[6]);
        if (i >= 0) ret.udpHostCacheFailures = i;
      } catch (NumberFormatException nfe) {
      }
    }

    // validate address if numeric.
    if (pureNumeric && !NetworkUtils.isValidAddress(host))
      throw new ParseException("invalid dotted addr: " + ret, 0);

    // validate that non UHC addresses were numeric.
    if (!ret.isUDPHostCache() && !pureNumeric)
      throw new ParseException("illegal non-UHC endpoint: " + ret, 0);

    return ret;
  }