Thursday, September 17, 2009
openvpn over ipv6 patch
Friday, September 19, 2008
@Kirk McKursick's FreeBSD Internals course
![]() | ![]() May the source be with you ... `:-) |
One interesting discussion I had with Kirk was about the behavior of zombie processes with respect to opened sockets and TCP data lingering: he stated that a process could be in zombie state while pushing the data ashes thru an already opened TCP socket ... something that I couldn't agree with, mainly because this would imply a high wait() "latency" in under a pkt loss/congestion scenario.
Linux even has a tcp_max_orphans sysctl explicitly there for this (man 7 tcp), anyhow I wanted to be sure about the behavior of Linux and xBSD, so I coded a quick&dirty test, see zocket.c and Makefile below.
Result: as expected, the sockets were orphaned after the process became zombie, and remained as is (FIN_WAIT1) independently from the process path to death =) (tested on Linux, FreeBSd and OpenBSD).
As a side note, was interesting to find that in Linux you can push a BPF down to filter the very data stream, but in FreeBSD you can only hook at the accept() syscall with another mechanism (man 9 accept_filter), this is somewhat 2-sided for Linux: cool that you can arbitrary filter the data stream, notso-cool that you can easily create a local DoS with this power :)
make && make test ## should do the magic:
/*
* zocket.c: connect a socket, block its data stream, write data @children:
* show zombie and socket lifetime afterwards
*
* Author: JuanJo: jjo () google com
* License: GPLv2+
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#if __linux__
#include <linux/filter.h>
#endif
/* quickie wrapper over syscall error checking */
#define ERR_IF(cond) do { if(cond) { perror( #cond ); abort(); } } while (0)
static int block_fromto(int sockfd, const struct sockaddr_in *sp,
const struct sockaddr_in *dp) {
#ifdef __linux__
/*
* Push a BPF into _this_ socket only, interesting enough
* this seems to be a linux-only feature, BSD has this available
* only at accept().
*/
struct sock_filter bpf_blockme[]= {
BPF_STMT(BPF_RET+BPF_K, 0), /* just accept 0 bytes ;) */
};
struct sock_fprog filter = {
sizeof(bpf_blockme)/sizeof(*bpf_blockme), bpf_blockme,
};
ERR_IF(setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER,
&filter, sizeof(filter))<0);
#else /* assuming BSD: block at PF level */
char cmd[1024];
cmd[sizeof cmd-1]=0;
snprintf(cmd, sizeof cmd-1,
"echo block drop out inet proto tcp "
"from %s port %d to %s port %d| pfctl -f-",
/* leaking but effective ... */
strdup(inet_ntoa(sp->sin_addr)), htons(sp->sin_port),
strdup(inet_ntoa(dp->sin_addr)), htons(dp->sin_port));
printf("====== configuring pf:\n+ %s\n", cmd);
ERR_IF(system(cmd)<0);
#endif
return 0;
}
int main(int argc, const char *argv[]) {
int sock;
int pid;
int syncpipe[2];
unsigned n;
char cmd[2048];
struct sockaddr_in dest,me;
#ifndef __linux__
/* need to use /sbin/pfctl for blocking pkt stream if !linux */
assert(getuid()==0);
#endif
if (argc != 3) {
fprintf(stderr, "ERROR: Usage: %s <ip> <port>\n", argv[0]);
exit(255);
}
dest.sin_family = AF_INET;
ERR_IF( inet_aton(argv[1], &dest.sin_addr) == 0);
dest.sin_port=htons(atoi(argv[2]));
sock = socket(AF_INET, SOCK_STREAM, 0);
ERR_IF(sock <0);
ERR_IF(connect (sock, (struct sockaddr *)&dest, sizeof dest) < 0);
n=sizeof me;
getsockname(sock, (struct sockaddr *)&me, &n);
/* unbuffer stdout */
setbuf(stdout, NULL);
/* block (output) data stream */
block_fromto(sock, &me, &dest);
pipe(syncpipe);
for(n=3;n;n--) {
switch(pid=fork()) {
case 0:
close(syncpipe[0]);
write(sock, "1234567890", 10);
_exit(0);
case -1: ERR_IF(1);
}
}
close(sock);
/* sync to children death */
read(syncpipe[0], NULL, 0);
cmd[sizeof cmd -1]=0;
snprintf(cmd, sizeof cmd -1,
"ps -o pid,ppid,stat,command|egrep [z]ocket;"
"netstat -tn|egrep '[.:]%d .*[.:]%d'",
ntohs(me.sin_port), ntohs(dest.sin_port));
/* this will show the zombies and the socket send-q (as netstat -tn) */
printf("====== BEFORE wait() ======\n+ %s\n", cmd); system(cmd);
while(wait(NULL)>0);
/* obviously the zombies are gone, what about the (orphaned) socket ?*/
printf("====== AFTER wait() ======\n+ %s\n", cmd); system(cmd);
return 0;
}
## Makefile for zocket.c
## Tested on: Linux 2.6, FreeBSD 6.x(dragonfly), OpenBSD 4.3
CFLAGS=-Wall -g
T=zocket.bin.$(OS)
DEST=10.255.255.1 111
## No portable (GNU,BSD) way of doing VAR=<output_from_shellcmd>, wrap
## them by invoking make again
all:
make OS=`uname -s` all_os
test:
make OS=`uname -s` test_os
all_os: $(T)
setup_pf:
## FreeBSD: dynload PF module
-@test -x /sbin/kldload && \
{ /sbin/kldstat | egrep pf.ko || { kldload pf; sleep 1;};}
## Enable PF
-@test -x /sbin/pfctl && \
sudo /sbin/pfctl -e -f- </dev/null 2>/dev/null;exit 0
test_os: all_os setup_pf
@ulimit -c 0; [ $(OS) != Linux -a -x /usr/bin/sudo ] && SUDO=sudo;\
exec $$SUDO ./$(T) $(DEST) | tee test.out.$(OS)
$(T): zocket.c
$(CC) $(CFLAGS) -o $(@) $(?)
clean:
rm -fv zocket.bin.*
%.html: %
c2html -s $(^)
Thursday, May 17, 2007
Jugando con IPv6 (apto para todo IPv4-público ;)
Ingredientes: tan sólo 1 IP pública
Resultado: estemmm ... exactamente 1208925819614629174706176 (2^80 ;) direcciones IPv6, las cuales han estado ahí desde hace tiempo esperándote :-P
Para saborear más aún: end-to-end para las máquinas que quieras ... como en los buenos viejos tiempos, por ej. podrás hacer desde "afuera":
ssh -6 flamanteIPv6_de_esa_PC_que_no_tiene_IP_publica
El mecanismo se llama tunneling 6to4, está descripto por doquier, en particular yo escribí un mini artículo para el seminario de IPv6 que dimos en el 2005 en la UM.
Podés probar usando mi script: ipv6-setup6to4.sh , el cual sólo muestra los comandos necesarios (es decir: inofensivo :-), por ejemplo con una dir. IPv4= 65.1.2.3 da como salida:
bash$ ./ipv6-setup6to4.sh
IP4_ADDR=65.1.2.3
IP6TO4_PREF=2002:4101:203
#check you allow ipv6 encap: iptables -I INPUT -p 41 -d 65.1.2.3
ip tunnel add tun6to4 mode sit remote any local 65.1.2.3 ttl 64
ip addr flush dev tun6to4 2>/dev/null
ip link set dev tun6to4 up
ip addr add 2002:4101:203::1/16 dev tun6to4
ip route add ::/96 dev tun6to4
ip route add 2000::/3 via ::192.88.99.1 dev tun6to4 metric 1
#you may do something like: ip -6 addr add 2002:4101:203:0001::1/64 dev eth0
#NOTHING done, use me as: ./ipv6/ipv6-setup6to4.sh |sudo sh -x
Que lo disfrutes!

