示例#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);
    }
  }
示例#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;
  }
示例#3
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());
  }
示例#5
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);
  }
示例#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;
  }
示例#7
0
  /**
   * Utility method for converting the non-firewalled elements of an AlternateLocationCollection to
   * a smaller set of endpoints.
   */
  private static Set getAsEndpoints(AlternateLocationCollection col) {
    if (col == null || !col.hasAlternateLocations()) return Collections.EMPTY_SET;

    long now = System.currentTimeMillis();
    synchronized (col) {
      Set endpoints = null;
      int i = 0;
      for (Iterator iter = col.iterator(); iter.hasNext() && i < MAX_LOCATIONS; ) {
        Object o = iter.next();
        if (!(o instanceof DirectAltLoc)) continue;
        DirectAltLoc al = (DirectAltLoc) o;
        if (al.canBeSent(AlternateLocation.MESH_RESPONSE)) {
          IpPort host = al.getHost();
          if (!NetworkUtils.isMe(host)) {
            if (endpoints == null) endpoints = new HashSet();

            if (!(host instanceof Endpoint)) host = new Endpoint(host.getAddress(), host.getPort());

            endpoints.add(host);
            i++;
            al.send(now, AlternateLocation.MESH_RESPONSE);
          }
        } else if (!al.canBeSentAny()) iter.remove();
      }
      return endpoints == null ? Collections.EMPTY_SET : endpoints;
    }
  }
示例#8
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
  }
示例#9
0
  /**
   * Express this PushRequest object as text.
   *
   * @return A String like "PushRequest({guid=00FF00FF00FF00FF00FF00FF00FF00FF, ttl=1, hops=1,
   *     priority=1} 1.2.3.4:5)"
   */
  public String toString() {

    // Compose and return the text
    return "PushRequest("
        + super.toString()
        + " "
        + NetworkUtils.ip2string(getIP())
        + ":"
        + getPort()
        + ")";
  }
示例#10
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;
    }
示例#11
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);
  }
示例#12
0
  /** @return whether a push should be sent tho this rfd. */
  public boolean needsPush() {

    // if replying to multicast, do a push.
    if (isReplyToMulticast()) return true;
    // Return true if rfd is private or unreachable
    if (isPrivate()) {
      // Don't do a push for magnets in case you are in a private network.
      // Note to Sam: This doesn't mean that isPrivate should be true.
      if (this instanceof URLRemoteFileDesc) return false;
      else // Otherwise obey push rule for private rfds.
      return true;
    } else if (!NetworkUtils.isValidPort(getPort())) return true;

    // make sure we have some push proxies.
    else return _firewalled && _pushAddr != null;
  }
    public void delegate(final String word, final Socket sock, boolean newThread) {
      boolean localHost = NetworkUtils.isLocalHost(sock);
      boolean drop = false;
      if (localOnly && !localHost) drop = true;
      if (!localOnly && localHost && ConnectionSettings.LOCAL_IS_PRIVATE.getValue()) drop = true;

      if (drop) {
        IOUtils.close(sock);
        return;
      }

      if (blocking && newThread) {
        Runnable r =
            new Runnable() {
              public void run() {
                acceptor.acceptConnection(word, sock);
              }
            };
        ThreadFactory.startThread(r, "IncomingConnection");
      } else acceptor.acceptConnection(word, sock);
    }
示例#14
0
 /**
  * Determines whether or not this host reported a private address.
  *
  * @return <tt>true</tt> if the address for this host is private, otherwise <tt>false</tt>. If the
  *     address is unknown, returns <tt>true</tt>
  *     <p>TODO:: use InetAddress in this class for the host so that we don't have to go through
  *     the process of creating one each time we check it it's a private address
  */
 public final boolean isPrivate() {
   return NetworkUtils.isPrivateAddress(_host);
 }
示例#15
0
 /** @return whether this rfd points to myself. */
 public boolean isMe() {
   return needsPush()
       ? Arrays.equals(_clientGUID, RouterService.getMyGUID())
       : NetworkUtils.isMe(getHost(), getPort());
 }
示例#16
0
 /** Returns an InetAddress representing the given IP address. */
 public static InetAddress getByAddress(byte[] addr) throws UnknownHostException {
   String addrString = NetworkUtils.ip2string(addr);
   return InetAddress.getByName(addrString);
 }
示例#17
0
  public RemoteFileDesc(
      String host,
      int port,
      long index,
      String filename,
      int size,
      int speed,
      boolean chat,
      int quality,
      boolean browseHost,
      Set urns,
      boolean replyToMulticast,
      boolean firewalled,
      String vendor,
      long timestamp,
      long createTime,
      PushEndpoint pe) {

    if (!NetworkUtils.isValidPort(port)) {
      throw new IllegalArgumentException("invalid port: " + port);
    }
    if ((speed & 0xFFFFFFFF00000000L) != 0) {
      throw new IllegalArgumentException("invalid speed: " + speed);
    }
    if (filename == null) {
      throw new NullPointerException("null filename");
    }
    if (filename.equals("")) {
      throw new IllegalArgumentException("cannot accept empty string file name");
    }
    if ((size & 0xFFFFFFFF00000000L) != 0) {
      throw new IllegalArgumentException("invalid size: " + size);
    }
    if ((index & 0xFFFFFFFF00000000L) != 0) {
      throw new IllegalArgumentException("invalid index: " + index);
    }
    if (host == null) {
      throw new NullPointerException("null host");
    }

    _speed = speed;
    _host = host;
    _port = port;
    _index = index;
    _filename = filename;
    _size = size;

    _pushAddr = pe;
    if (pe != null) _clientGUID = pe.getClientGUID();
    else _clientGUID = null;

    _chatEnabled = chat;
    _quality = quality;
    _browseHostEnabled = browseHost;
    _replyToMulticast = replyToMulticast;
    _firewalled = firewalled;
    _vendor = vendor;
    _creationTime = createTime;

    if (urns == null) {
      _urns = Collections.EMPTY_SET;
    } else {
      _urns = Collections.unmodifiableSet(urns);
    }
    _http11 = (!_urns.isEmpty());
  }
  /**
   * 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;
  }