Пример #1
0
static ssize_t handle_read( const int64 clientsocket ) {
  struct http_data* h = io_getcookie( clientsocket );
  ssize_t l;

  if( ( l = io_tryread( clientsocket, static_inbuf, sizeof static_inbuf ) ) <= 0 ) {
    handle_dead( clientsocket );
    return 0;
  }

  /* If we get the whole request in one packet, handle it without copying */
  if( !array_start( &h->request ) ) {
    if( memchr( static_inbuf, '\n', l ) )
      return http_handle_request( clientsocket, static_inbuf, l );
    h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED;
    array_catb( &h->request, static_inbuf, l );
    return 0;
  }

  h->flag |= STRUCT_HTTP_FLAG_ARRAY_USED;
  array_catb( &h->request, static_inbuf, l );

  if( array_failed( &h->request ) )
    return http_issue_error( clientsocket, CODE_HTTPERROR_500 );

  if( ( array_bytes( &h->request ) > 8192 ) && !accesslist_isblessed( (char*)&h->ip, OT_PERMISSION_MAY_SYNC ) )
     return http_issue_error( clientsocket, CODE_HTTPERROR_500 );

  if( memchr( array_start( &h->request ), '\n', array_bytes( &h->request ) ) )
    return http_handle_request( clientsocket, array_start( &h->request ), array_bytes( &h->request ) );

  return 0;
}
Пример #2
0
static void * livesync_worker( void * args ) {
  struct ot_workstruct ws;
  ot_ip6 in_ip; uint16_t in_port;

  (void)args;
  
  /* Initialize our "thread local storage" */
  ws.inbuf   = ws.request = malloc( LIVESYNC_INCOMING_BUFFSIZE );
  ws.outbuf  = ws.reply   = 0;
  
  memcpy( in_ip, V4mappedprefix, sizeof( V4mappedprefix ) );

  while( 1 ) {
    ws.request_size = socket_recv4(g_socket_in, (char*)ws.inbuf, LIVESYNC_INCOMING_BUFFSIZE, 12+(char*)in_ip, &in_port);

    /* Expect at least tracker id and packet type */
    if( ws.request_size <= (ssize_t)(sizeof( g_tracker_id ) + sizeof( uint32_t )) )
      continue;
    if( !accesslist_isblessed(in_ip, OT_PERMISSION_MAY_LIVESYNC))
      continue;
    if( !memcmp( ws.inbuf, &g_tracker_id, sizeof( g_tracker_id ) ) ) {
      /* TODO: log packet coming from ourselves */
      continue;
    }

    switch( uint32_read_big( sizeof( g_tracker_id ) + (char *)ws.inbuf ) ) {
    case OT_SYNC_PEER:
      livesync_handle_peersync( &ws );
      break;
    default:
      break;
    }
  }

  /* Never returns. */
  return NULL;
}
Пример #3
0
static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws, char *read_ptr ) {
  int               numwant, tmp, scanon;
  unsigned short    port = 0;
  char             *write_ptr;
  ssize_t           len;
  struct http_data *cookie = io_getcookie( sock );

  /* This is to hack around stupid clients that send "announce ?info_hash" */
  if( read_ptr[-1] != '?' ) {
    while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr;
    if( *read_ptr == '\n' ) HTTPERROR_400_PARAM;
    ++read_ptr;
  }

#ifdef WANT_IP_FROM_PROXY
  if( accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_PROXY ) ) {
    ot_ip6 proxied_ip;
    char *fwd = http_header( ws->request, ws->header_size, "x-forwarded-for" );
    if( fwd && scan_ip6( fwd, proxied_ip ) )
      OT_SETIP( &ws->peer, proxied_ip );
    else
      OT_SETIP( &ws->peer, cookie->ip );
  } else
#endif
  OT_SETIP( &ws->peer, cookie->ip );

  ws->peer_id = NULL;
  ws->hash = NULL;

  OT_SETPORT( &ws->peer, &port );
  OT_PEERFLAG( &ws->peer ) = 0;
  numwant = 50;
  scanon = 1;

  while( scanon ) {
    switch( scan_find_keywords(keywords_announce, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) {
    case -2: scanon = 0; break;   /* TERMINATOR */
    case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */
    case -3: scan_urlencoded_skipvalue( &read_ptr ); break;
    case 1: /* matched "port" */
      len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE );
      if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM;
      port = htons( tmp ); OT_SETPORT( &ws->peer, &port );
      break;
    case 2: /* matched "left" */
      if( ( len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM;
      if( scan_fixed_int( write_ptr, len, &tmp ) ) tmp = 0;
      if( !tmp ) OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_SEEDING;
      break;
    case 3: /* matched "event" */
      switch( scan_find_keywords( keywords_announce_event, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) {
        case -1: HTTPERROR_400_PARAM;
        case  1: /* matched "completed" */
          OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED;
          break;
        case  2: /* matched "stopped" */
          OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED;
          break;
        default:
          break;
      }
      break;
    case 4: /* matched "numwant" */
      len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE );
      if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &numwant ) ) HTTPERROR_400_PARAM;
      if( numwant < 0 ) numwant = 50;
      if( numwant > 200 ) numwant = 200;
      break;
    case 5: /* matched "compact" */
      len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE );
      if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) ) HTTPERROR_400_PARAM;
      if( !tmp ) HTTPERROR_400_COMPACT;
      break;
    case 6: /* matched "info_hash" */
      if( ws->hash ) HTTPERROR_400_DOUBLEHASH;
      /* ignore this, when we have less than 20 bytes */
      if( scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM;
        ws->hash = (ot_hash*)write_ptr;
      break;
#ifdef WANT_IP_FROM_QUERY_STRING
    case  7: /* matched "ip" */
      {
        char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply+16;
        len = scan_urlencoded_query( &read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE );
        tmp_buf2[len] = 0;
        if( ( len <= 0 ) || !scan_ip6( tmp_buf2, tmp_buf1 ) ) HTTPERROR_400_PARAM;
        OT_SETIP( &ws->peer, tmp_buf1 );
      }
      break;
#endif
#ifdef WANT_FULLLOG_NETWORKS
      case 8: /* matched "lognet" */
      {
        //if( accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_STAT ) ) {
          char *tmp_buf = ws->reply;
          ot_net net;
          signed short parsed, bits;

          len = scan_urlencoded_query( &read_ptr, tmp_buf, SCAN_SEARCHPATH_VALUE );
          tmp_buf[len] = 0;
          if( len <= 0 ) HTTPERROR_400_PARAM;
          if( *tmp_buf == '-' ) {
            loglist_reset( );
            return ws->reply_size = sprintf( ws->reply, "Successfully removed.\n" );
          }
          parsed = scan_ip6( tmp_buf, net.address );
          if( !parsed ) HTTPERROR_400_PARAM;
          if( tmp_buf[parsed++] != '/' )
            bits = 128;
          else {
            parsed = scan_short( tmp_buf + parsed, &bits );
            if( !parsed ) HTTPERROR_400_PARAM; 
            if( ip6_isv4mapped( net.address ) )
              bits += 96;
          }
          net.bits = bits;
          loglist_add_network( &net );
          return ws->reply_size = sprintf( ws->reply, "Successfully added.\n" );
        //}
      }
#endif
        break;
      case 9: /* matched "peer_id" */
        /* ignore this, when we have less than 20 bytes */
        if( scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM;
        ws->peer_id = write_ptr;
        break;
    }
  }

#ifdef WANT_LOG_NUMWANT
  numwants[numwant]++;
#endif

  /* XXX DEBUG
  stats_issue_event( EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ws->reply );
  */

  /* Scanned whole query string */
  if( !ws->hash )
    return ws->reply_size = sprintf( ws->reply, "d14:failure reason80:Your client forgot to send your torrent's info_hash. Please upgrade your client.e" );

  if( OT_PEERFLAG( &ws->peer ) & PEER_FLAG_STOPPED )
    ws->reply_size = remove_peer_from_torrent( FLAG_TCP, ws );
  else
    ws->reply_size = add_peer_to_torrent_and_return_peers( FLAG_TCP, ws, numwant );

  stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, ws->reply_size);
  return ws->reply_size;
}
Пример #4
0
static ssize_t http_handle_stats( const int64 sock, struct ot_workstruct *ws, char *read_ptr ) {
static const ot_keywords keywords_main[] =
  { { "mode", 1 }, {"format", 2 }, { NULL, -3 } };
static const ot_keywords keywords_mode[] =
  { { "peer", TASK_STATS_PEERS }, { "conn", TASK_STATS_CONNS }, { "scrp", TASK_STATS_SCRAPE }, { "udp4", TASK_STATS_UDP }, { "tcp4", TASK_STATS_TCP },
    { "busy", TASK_STATS_BUSY_NETWORKS }, { "torr", TASK_STATS_TORRENTS }, { "fscr", TASK_STATS_FULLSCRAPE },
    { "s24s", TASK_STATS_SLASH24S }, { "tpbs", TASK_STATS_TPB }, { "herr", TASK_STATS_HTTPERRORS }, { "completed", TASK_STATS_COMPLETED },
    { "top100", TASK_STATS_TOP100 }, { "top10", TASK_STATS_TOP10 }, { "renew", TASK_STATS_RENEW }, { "syncs", TASK_STATS_SYNCS }, { "version", TASK_STATS_VERSION },
    { "everything", TASK_STATS_EVERYTHING }, { "statedump", TASK_FULLSCRAPE_TRACKERSTATE }, { "fulllog", TASK_STATS_FULLLOG },
    { "woodpeckers", TASK_STATS_WOODPECKERS},
#ifdef WANT_LOG_NUMWANT
    { "numwants", TASK_STATS_NUMWANTS},
#endif
    { NULL, -3 } };
static const ot_keywords keywords_format[] =
  { { "bin", TASK_FULLSCRAPE_TPB_BINARY }, { "ben", TASK_FULLSCRAPE }, { "url", TASK_FULLSCRAPE_TPB_URLENCODED },
    { "txt", TASK_FULLSCRAPE_TPB_ASCII }, { NULL, -3 } };

  int mode = TASK_STATS_PEERS, scanon = 1, format = 0;

#ifdef WANT_RESTRICT_STATS
  struct http_data *cookie = io_getcookie( sock );

  if( !cookie || !accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_STAT ) )
    HTTPERROR_403_IP;
#endif

  while( scanon ) {
    switch( scan_find_keywords( keywords_main, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) {
    case -2: scanon = 0; break;   /* TERMINATOR */
    case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */
    case -3: scan_urlencoded_skipvalue( &read_ptr ); break;
    case  1: /* matched "mode" */
      if( ( mode = scan_find_keywords( keywords_mode, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM;
      break;
    case  2: /* matched "format" */
      if( ( format = scan_find_keywords( keywords_format, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM;
      break;
    }
  }

#ifdef WANT_FULLSCRAPE
  if( mode == TASK_FULLSCRAPE_TRACKERSTATE ) {
    format = mode; mode = TASK_STATS_TPB;
  }

  if( mode == TASK_STATS_TPB ) {
    struct http_data* cookie = io_getcookie( sock );
    tai6464 t;
#ifdef WANT_COMPRESSION_GZIP
    ws->request[ws->request_size] = 0;
#ifdef WANT_COMPRESSION_GZIP_ALWAYS
    if( strstr( read_ptr - 1, "gzip" ) ) {
#endif
      cookie->flag |= STRUCT_HTTP_FLAG_GZIP;
      format |= TASK_FLAG_GZIP;
#ifdef WANT_COMPRESSION_GZIP_ALWAYS
    }
#endif
#endif
    /* Pass this task to the worker thread */
    cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK;

    /* Clients waiting for us should not easily timeout */
    taia_uint( &t, 0 ); io_timeout( sock, t );
    fullscrape_deliver( sock, format );
    io_dontwantread( sock );
    return ws->reply_size = -2;
  }
#endif

  /* default format for now */
  if( ( mode & TASK_CLASS_MASK ) == TASK_STATS ) {
    tai6464 t;
    /* Complex stats also include expensive memory debugging tools */
    taia_uint( &t, 0 ); io_timeout( sock, t );
    stats_deliver( sock, mode );
    return ws->reply_size = -2;
  }

  /* Simple stats can be answerred immediately */
  return ws->reply_size = return_stats_for_tracker( ws->reply, mode, 0 );
}