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;
}