views:

62

answers:

2

I want to debug TCP/IP interactions for a program I'm enhancing. I don't have root access (so no tcpdump etc), but the app runs under my own id. I could use e.g. strace to intercept the system calls, but are there alternatives worth recommending over that? If so, why - what do they offer? Command line prefered (no X server installed on my PC right now :-(), but curious about GUIs too.

Ideally, it would say something like:

    app listening on port <portA>
    app listening on port <portB>
    client connection #1 accepted on listening port <portA> to local port <portC>
        from remote <hostX:portXA>
    app sent #1 <number> bytes "<data dump...>"
    app received from client #1 <number> bytes "<data dump...>"
    client #1 closed connection

Would scratch one together myself, but too many wheels to reinvent as is....

Thanks in advance.

UPDATE: both paulrubel and ypnos have made very helpful suggestions... (wish I could accept both answers, as they're distinct and equally good). Code implementing Paul's suggested LD_PRELOAD interception follows:

// TCP comms trace library
//   as per http://www.jayconrod.com/cgi/view_post.py?23

#define _GNU_SOURCE

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <dlfcn.h>


typedef ssize_t (*Recv)(int s, void* buf, size_t len, int flags);

ssize_t recv(int s, void* buf, size_t len, int flags)
{
    static Recv real = NULL;

    if (!real)
        real = (Recv)dlsym(RTLD_NEXT, "recv");

    fprintf(stderr, "> recv(s '%d', buf %p, len %lld, flags %d)...\n",
            s, buf, len, flags);
    ssize_t result = real(s, buf, len, flags);
    fprintf(stderr, "< recv(s '%d', buf %p, len %lld, flags %d) return %lld\n",
            s, buf, len, flags, result);

    return result;
}

typedef ssize_t (*Send)(int s, const void* buf, size_t len, int flags);

ssize_t send(int s, const void* buf, size_t len, int flags)
{
    static Send real = NULL;

    if (!real)
        real = (Send)dlsym(RTLD_NEXT, "send");

    fprintf(stderr, "> send(s '%d', buf %p, len %lld, flags %d)...\n",
            s, buf, len, flags);
    ssize_t result = real(s, buf, len, flags);
    fprintf(stderr, "< recv(s '%d', buf %p, len %lld, flags %d) return %lld\n",
            s, buf, len, flags, result);

    return result;
}

typedef int (*Connect)(int s, const struct sockaddr* serv_addr, socklen_t addrlen);

int connect(int s, const struct sockaddr* serv_addr, socklen_t addrlen)
{
    static Connect real = NULL;

    if (!real)
        real = (Connect)dlsym(RTLD_NEXT, "connect");

    fprintf(stderr, "> connect(s %d, sockaddr %p, addrlen %d)\n",
            s, (void*)serv_addr, addrlen);
    int result = real(s, serv_addr, addrlen);
    fprintf(stderr, "< connect(s %d, sockaddr %p, addrlen %d) return %d\n",
            s, (void*)serv_addr, addrlen, result);

    return result;
}

typedef int (*Accept)(int s, const struct sockaddr* serv_addr, socklen_t* addrlen);

int accept(int s, struct sockaddr* serv_addr, socklen_t* addrlen)
{
    static Accept real = NULL;

    if (!real)
        real = (Accept)dlsym(RTLD_NEXT, "accept");

    fprintf(stderr, "> accept(s %d, sockaddr %p, addrlen %p)\n",
            s, (void*)serv_addr, addrlen);
    int result = real(s, serv_addr, addrlen);
    fprintf(stderr, "< accept(s %d, sockaddr %p, addrlen %p -> %d) return %d\n",
            s, (void*)serv_addr, addrlen, *addrlen, result);

    return result;
}
+1  A: 

There is no way to intercept socket connections even if you're running on the same user id as the victim program.

What you need to do is

  1. Let your own program print socket numbers etc.

  2. Let your program connect to another program that in fact tunnels the connection to the real destination. There you can dump all the data sent/received.

ypnos
2's a good idea, thanks. 1's too fiddly in my particular case - whole idea was to get something independent of the program because I don't trust it very much. More generally, programs like strace and gdb launch (or attach to running programs) as controlling processes, and seem to do similar kinds of things to this, so I'm doubtful that you're right about there being "no way to intercept". Thanks for your help and ideas.
Tony
Well you can always tell your debugger to watch the output buffer variable before your program calls write(), if that would count as intercepting for you, too. However beyond that call you are in kernel space and you cannot debug kernel space without being root. strace just operates at the border to kernel space, and has specific support in the kernel for that. If you find any kernel interface for "socket debugging", tell me. There is none that I know of.
ypnos
+2  A: 

One idea, and it may be a bit of sledgehammer to swat a fly solution, is to use library interpositioning. You basically wrap a system call, connect and sendto seem like a good starting point for you, and log the parameters seen before passing off the data to the real call.

Paul Rubel
This is a really good suggestion. I implemented it (though long, will add to question above).
Tony
Just FYI / have decided to accept ypnos's answer as he got less votes, so it'll even things up as I value your assistance equally. I've +1ed you both already, and credited you re the code above. Many thanks again.
Tony