LINUX.ORG.RU

transmission-daemon, вскрытие


0

1

Имеется исходник: transmission-1.93.tar.xz

Задача: найти участок кода, в котором обрабатывается приходящее на 9091 порт сообщение (rpc-server.c обрабатывает как я понял) и добавить условие - если пакет пришел не с 192.168.0.1(клиент на моём компе), то запретить удаление чужих раздач (связка transmission-daemon - transmission-remoute.NET).

Я рассуждаю так: Если это демон, значит где-то должен быть цикл, в котором обрабатываются все приходящие сообщения, но вот найти его я не могу! Комментариев в коде почти нет. Какова структуры программы, взаимодействие модулей, логика, иерархия и вообще, как в этом разобраться!?

Опытные юниксоиды, подскажите, как вы раскуриваете такой код? Нифигаж нипанятно! :dash1

Если это демон, значит где-то должен быть цикл, в котором обрабатываются все приходящие сообщения

Нет, с чего бы это? Мб просто по событию вызывается функция обработки.

Комментариев в коде почти нет. Какова структуры программы, взаимодействие модулей, логика, иерархия и вообще, как в этом разобраться!?

Это опенсорц, детка (с)

Опытные юниксоиды, подскажите, как вы раскуриваете такой код? Нифигаж нипанятно! :dash1

Попробуй написать разрабам на мыльце, мб ответят.

Zhbert ★★★★★
()

как вы раскуриваете такой код? Нифигаж нипанятно!

Вот дизасмить бинарник - это хардкор даже с IDA, а когда есть исходник, его вполне можно разобрать, делая пометки на бумаге. Конечно на это требуется время, прямо пропорциональное размеру исходника.

m0rph ★★★★★
()
Ответ на: комментарий от m0rph

Ок, тогда подскажите: как искать описание используемых функций?

Или vi и 'egrep -iran' это совсем не интсрумент мазахиста, а я совсем разжирел на своих ide'шечках?

kuzyara
() автор топика
Ответ на: комментарий от kuzyara

ну так и используй свои иде, не?

anonymous
()

может проще на фаерволе прикрыть?

true_admin ★★★★★
()
Ответ на: комментарий от kuzyara

kuzyara

Ок, тогда подскажите: как искать описание используемых функций?

Если комментариев нет, можно только предполагать. Процесс этот долгий и творческий, лучше конечно быть практиком в предметной области. Иногда бывает удобным загрузка проекта в среду разработки, которая умеет навигацию по коду, т.к. помогает построить связи что откуда вызывается. Только во многих случаях для этого придется весьма попотеть, т.к. файлы проекта могут быть разбросаны по разным директориям, будут отсутствовать символы, определяемые на стадии конфигурирования и т.п.

m0rph ★★★★★
()

Transmission использует libevent, так что начинайте смотреть от него.

Sorcerer ★★★★★
()
Ответ на: комментарий от Zhbert

Комментариев в коде почти нет. Какова структуры программы, взаимодействие модулей, логика, иерархия и вообще, как в этом разобраться!?


Это опенсорц, детка (с)

Причем каждый читающий код, ругается «нет комментов». Перечитывает, понимает, и не пишет их.

gordio
()
Ответ на: комментарий от gordio

Причем каждый читающий код, ругается «нет комментов». Перечитывает, понимает, и не пишет их.

Ага, есть такое дело. Я в своих поделках тоже не пишу =)

Zhbert ★★★★★
()

если пакет пришел не с 192.168.0.1
то запретить удаление чужих раздач

это ты уже хочешь Policy в transmission-daemon там есть хоть намек в коде на разграничение доступа? нет? начинай писать.

bhfq ★★★★★
()
Ответ на: комментарий от bhfq

Продолжаю разбор. Как сказал Sorcerer, копаем libevent, вот код trevent.c :

/*
 * $Id: trevent.c 9992 2010-01-22 03:39:21Z charles $
 */

#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <signal.h>

#include <event.h>

#include "transmission.h"
#include "net.h"
#include "session.h"

#ifdef WIN32

#include <WinSock2.h>

static int
pgpipe( int handles[2] )
{
        SOCKET s;
        struct sockaddr_in serv_addr;
        int len = sizeof( serv_addr );

        handles[0] = handles[1] = INVALID_SOCKET;

        if ( ( s = socket( AF_INET, SOCK_STREAM, 0 ) ) == INVALID_SOCKET )
        {
/*              ereport(LOG, (errmsg_internal("pgpipe failed to create socket: %ui", WSAGetLastError()))); */
                return -1;
        }

        memset( &serv_addr, 0, sizeof( serv_addr ) );
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(0);
        serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
        if (bind(s, (SOCKADDR *) & serv_addr, len) == SOCKET_ERROR)
        {
/*              ereport(LOG, (errmsg_internal("pgpipe failed to bind: %ui", WSAGetLastError()))); */
                closesocket(s);
                return -1;
        }
        if (listen(s, 1) == SOCKET_ERROR)
        {
/*              ereport(LOG, (errmsg_internal("pgpipe failed to listen: %ui", WSAGetLastError()))); */
                closesocket(s);
                return -1;
        }
        if (getsockname(s, (SOCKADDR *) & serv_addr, &len) == SOCKET_ERROR)
        {
/*              ereport(LOG, (errmsg_internal("pgpipe failed to getsockname: %ui", WSAGetLastError()))); */
                closesocket(s);
                return -1;
        }
        if ((handles[1] = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
        {
/*              ereport(LOG, (errmsg_internal("pgpipe failed to create socket 2: %ui", WSAGetLastError()))); */
                closesocket(s);
                return -1;
        }

        if (connect(handles[1], (SOCKADDR *) & serv_addr, len) == SOCKET_ERROR)
        {
/*              ereport(LOG, (errmsg_internal("pgpipe failed to connect socket: %ui", WSAGetLastError()))); */
                closesocket(s);
                return -1;
        }
        if ((handles[0] = accept(s, (SOCKADDR *) & serv_addr, &len)) == INVALID_SOCKET)
        {
/*              ereport(LOG, (errmsg_internal("pgpipe failed to accept socket: %ui", WSAGetLastError()))); */
                closesocket(handles[1]);
                handles[1] = INVALID_SOCKET;
                closesocket(s);
                return -1;
        }
        closesocket(s);
        return 0;
}

static int
piperead( int s, char *buf, int len )
{
        int ret = recv(s, buf, len, 0);

        if (ret < 0 && WSAGetLastError() == WSAECONNRESET)
                /* EOF on the pipe! (win32 socket based implementation) */
                ret = 0;
        return ret;
}

#define pipe(a) pgpipe(a)
#define pipewrite(a,b,c) send(a,(char*)b,c,0)

#else
#define piperead(a,b,c) read(a,b,c)
#define pipewrite(a,b,c) write(a,b,c)
#endif

#include <unistd.h>

#include <event.h>

#include "transmission.h"
#include "platform.h"
#include "trevent.h"
#include "utils.h"

/***
****
***/

typedef struct tr_event_handle
{
    uint8_t      die;
    int          fds[2];
    tr_lock *    lock;
    tr_session *  session;
    tr_thread *  thread;
    struct event_base * base;
    struct event pipeEvent;
}
tr_event_handle;

struct tr_run_data
{
    void    ( *func )( void * );
    void *  user_data;
};

#define dbgmsg( ... ) \
    do { \
        if( tr_deepLoggingIsActive( ) ) \
            tr_deepLog( __FILE__, __LINE__, "event", __VA_ARGS__ ); \
    } while( 0 )

static void
readFromPipe( int    fd,
              short  eventType,
              void * veh )
{
    char              ch;
    int               ret;
    tr_event_handle * eh = veh;

    dbgmsg( "readFromPipe: eventType is %hd", eventType );

    /* read the command type */
    ch = '\0';
    do
    {
        ret = piperead( fd, &ch, 1 );
    }
    while( !eh->die && ret < 0 && errno == EAGAIN );

    dbgmsg( "command is [%c], ret is %d, errno is %d", ch, ret, (int)errno );

    switch( ch )
    {
        case 'r': /* run in libevent thread */
        {
            struct tr_run_data data;
            const size_t       nwant = sizeof( data );
            const ssize_t      ngot = piperead( fd, &data, nwant );
            if( !eh->die && ( ngot == (ssize_t)nwant ) )
            {
                dbgmsg( "invoking function in libevent thread" );
                ( data.func )( data.user_data );
            }
            break;
        }

        case '\0': /* eof */
        {
            dbgmsg( "pipe eof reached... removing event listener" );
            event_del( &eh->pipeEvent );
            break;
        }

        default:
        {
            assert( 0 && "unhandled command type!" );
            break;
        }
    }
}

static void
logFunc( int severity, const char * message )
{
    if( severity >= _EVENT_LOG_ERR )
        tr_err( "%s", message );
    else
        tr_dbg( "%s", message );
}

static void
readFromPipe( void * veh )
{
    tr_event_handle * eh = veh;
    tr_dbg( "Starting libevent thread" );

#ifndef WIN32
    /* Don't exit when writing on a broken socket */
    signal( SIGPIPE, SIG_IGN );
#endif

    eh->base = event_init( );
    eh->session->events = eh;

    /* listen to the pipe's read fd */
    event_set( &eh->pipeEvent, eh->fds[0], EV_READ | EV_PERSIST, readFromPipe, veh );
    event_add( &eh->pipeEvent, NULL );
    event_set_log_callback( logFunc );

    /* loop until all the events are done */
    while( !eh->die )
        event_dispatch( );

    /* shut down the thread */
    tr_lockFree( eh->lock );
    event_base_free( eh->base );
    eh->session->events = NULL;
    tr_free( eh );
    tr_dbg( "Closing libevent thread" );
}

void
tr_eventInit( tr_session * session )
{
    tr_event_handle * eh;

    session->events = NULL;

    eh = tr_new0( tr_event_handle, 1 );
    eh->lock = tr_lockNew( );
    pipe( eh->fds );
    eh->session = session;
    eh->thread = tr_threadNew( libeventThreadFunc, eh );

    /* wait until the libevent thread is running */
    while( session->events == NULL )
        tr_wait_msec( 100 );
}

void
tr_eventClose( tr_session * session )
{
    assert( tr_isSession( session ) );

    session->events->die = TRUE;
    tr_deepLog( __FILE__, __LINE__, NULL, "closing trevent pipe" );
    tr_netCloseSocket( session->events->fds[1] );
}

/**
***
**/

tr_bool
tr_amInEventThread( const tr_session * session )
{
    assert( tr_isSession( session ) );
    assert( session->events != NULL );

    return tr_amInThread( session->events->thread );
}

/**
***
**/

void
tr_runInEventThread( tr_session * session,
                     void func( void* ), void * user_data )
{
    assert( tr_isSession( session ) );
    assert( session->events != NULL );

    if( tr_amInThread( session->events->thread ) )
    {
        (func)( user_data );
    }
    else
    {
        const char         ch = 'r';
        int                fd = session->events->fds[1];
        tr_lock *          lock = session->events->lock;
        struct tr_run_data data;

        tr_lockLock( lock );
        pipewrite( fd, &ch, 1 );
        data.func = func;
        data.user_data = user_data;
        pipewrite( fd, &data, sizeof( data ) );
        tr_lockUnlock( lock );
    }
}

Итак, как я понял, в последней фунуции tr_runInEventThread происходит обработка user_data, а именно в строчке (func)( user_data );.

То есть получается, что происходит чтение из сокета данных, и это совсем не данные, а уже готовая функция, которая тупо исплняется!

Я правильно мыслю? Как тогда вмешаться в rpc-управление!?

kuzyara
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.