diff --git a/T.h b/T.h
index d88f33a81c0cf9de03bb134823d72ad2214542a4..405594f2d4b2b22dd5338c5737a3d494b8b3d81e 100644
--- a/T.h
+++ b/T.h
@@ -115,11 +115,24 @@ extern T_cache_t *T_cache;
 
 #define T_ACTIVE(x) T_active[(intptr_t)x]
 
+#ifdef T_USE_SHARED_MEMORY
+
 #define T_SEND() \
   T_cache[T_LOCAL_slot].busy = 1; \
   T_cache[T_LOCAL_slot].length = T_LOCAL_size; \
   T_send(T_LOCAL_buf, T_LOCAL_size)
 
+#else /* T_USE_SHARED_MEMORY */
+
+/* when not using shared memory, wait for send to finish */
+#define T_SEND() \
+  T_cache[T_LOCAL_slot].busy = 1; \
+  T_cache[T_LOCAL_slot].length = T_LOCAL_size; \
+  T_send(T_LOCAL_buf, T_LOCAL_size); \
+  while (T_cache[T_LOCAL_slot].busy) usleep(1*1000)
+
+#endif /* T_USE_SHARED_MEMORY */
+
 #define T_CHECK_SIZE(len, argnum) \
   if (T_LOCAL_size + (len) > T_BUFFER_MAX) { \
     printf("%s:%d:%s: cannot put argument %d in T macro, not enough space" \
diff --git a/tracer/Makefile b/tracer/Makefile
index a38ba5c2c65cd4188bbba4721bdb556a682d3b67..093acfbe3c380d7274b82a649022d6a860715644 100644
--- a/tracer/Makefile
+++ b/tracer/Makefile
@@ -10,7 +10,7 @@ CFLAGS += -DT_USE_SHARED_MEMORY
 LIBS += -lrt
 
 PROG=tracer
-OBJS=main.o plot.o database.o
+OBJS=main.o plot.o database.o forward.o
 
 $(PROG): $(OBJS)
 	$(CC) $(CFLAGS) -o $(PROG) $(OBJS) $(LIBS)
diff --git a/tracer/defs.h b/tracer/defs.h
index 231255b46d7008c5c1428406d57ce270c2f55609..d9074d35d781195b8653fbba559193ff1a591ef0 100644
--- a/tracer/defs.h
+++ b/tracer/defs.h
@@ -21,4 +21,7 @@ void list_ids(void *database);
 void list_groups(void *database);
 void on_off(void *d, char *item, int *a, int onoff);
 
+void *forwarder(char *ip, int port);
+void forward(void *forwarder, char *buf, int size);
+
 #endif /* _TRACER_DEFS_H_ */
diff --git a/tracer/forward.c b/tracer/forward.c
new file mode 100644
index 0000000000000000000000000000000000000000..77ee156751d2dfe5fc3403700a6d54e792928908
--- /dev/null
+++ b/tracer/forward.c
@@ -0,0 +1,10 @@
+#include "defs.h"
+
+void *forwarder(char *ip, int port)
+{
+  return 0;
+}
+
+void forward(void *_fowarder, char *buf, int size)
+{
+}
diff --git a/tracer/main.c b/tracer/main.c
index 1a30bbef95a63fdde517d214d3511be25a204db3..ba6dc043c3c27dcfe3c766536c21b7b42b1e57a4 100644
--- a/tracer/main.c
+++ b/tracer/main.c
@@ -371,7 +371,7 @@ void init_shm(void)
 void usage(void)
 {
   printf(
-"options:\n"
+"common options:\n"
 "    -d <database file>        this option is mandatory\n"
 "    -li                       print IDs in the database\n"
 "    -lg                       print GROUPs in the database\n"
@@ -383,6 +383,10 @@ void usage(void)
 "    -OFF                      turn all logs OFF\n"
 "note: you may pass several -on/-off/-ON/-OFF, they will be processed in order\n"
 "      by default, all is off\n"
+"\n"
+"remote mode options: in this mode you run a local tracer and a remote one\n"
+"    -r                        remote side\n"
+"    -l <IP address> <port>    local side (forwards packets to remote IP:port)\n"
   );
   exit(1);
 }
@@ -403,6 +407,13 @@ int main(int n, char **v)
   int *on_off_action;
   int on_off_n = 0;
   int is_on[T_NUMBER_OF_IDS];
+  int remote_local = 0;
+  int remote_remote = 0;
+  char *remote_ip = NULL;
+  int remote_port = -1;
+#ifdef T_USE_SHARED_MEMORY
+  void *f;
+#endif
 
   memset(is_on, 0, sizeof(is_on));
 
@@ -425,10 +436,43 @@ int main(int n, char **v)
       { on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=1; continue; }
     if (!strcmp(v[i], "-OFF"))
       { on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=0; continue; }
+    if (!strcmp(v[i], "-r")) { remote_remote = 1; continue; }
+    if (!strcmp(v[i], "-l")) { if (i > n-3) usage(); remote_local = 1;
+      remote_ip = v[++i]; remote_port = atoi(v[++i]); continue; }
     printf("ERROR: unknown option %s\n", v[i]);
     usage();
   }
 
+#ifndef T_USE_SHARED_MEMORY
+  /* gcc shut up */
+  (void)remote_port;
+  (void)remote_ip;
+#endif
+
+#ifdef T_USE_SHARED_MEMORY
+  if (remote_remote) {
+    printf("ERROR: remote 'remote side' does not run with shared memory\n");
+    printf("recompile without T_USE_SHARED_MEMORY (edit Makefile)\n");
+    exit(1);
+  }
+#endif
+
+  if (remote_remote) {
+    /* TODO: setup 'secure' connection with remote part */
+  }
+
+#ifndef T_USE_SHARED_MEMORY
+  if (remote_local) {
+    printf("ERROR: remote 'local side' does not run without shared memory\n");
+    printf("recompile with T_USE_SHARED_MEMORY (edit Makefile)\n");
+    exit(1);
+  }
+#endif
+
+#ifdef T_USE_SHARED_MEMORY
+  if (remote_local) f = forwarder(remote_ip, remote_port);
+#endif
+
   if (database_filename == NULL) {
     printf("ERROR: provide a database file (-d)\n");
     exit(1);
@@ -479,6 +523,18 @@ int main(int n, char **v)
 #ifdef T_USE_SHARED_MEMORY
     wait_message();
 #endif
+
+#ifdef T_USE_SHARED_MEMORY
+    if (remote_local) {
+      forward(f, T_cache[T_busylist_head].buffer,
+              T_cache[T_busylist_head].length);
+      T_cache[T_busylist_head].busy = 0;
+      T_busylist_head++;
+      T_busylist_head &= T_CACHE_SIZE - 1;
+      continue;
+    }
+#endif
+
     get_message(s);
   }
   return 0;