I have attached my final program which works on both FreeBSD 2.x and FreeBSD 3.x (I don't have a FreeBSD 4.x box to test this on yet). On FreeBSD 2.x one must be root to run this (to read /dev/kmem), but on FreeBSD 3.x any user can run this. I would argue that this is a potential security vulnerability. Some clever user may be able to exploit this for some protocols to determine the lengths of usernames and passwords (admittedly this is unlikely to work with telnet unless in line mode). The sysctl calls that extract things like TCP control blocks should require privileged access (although the downside of this is that programs like netstat would have to be setuid). -- Dr Graham Wheeler E-mail: [EMAIL PROTECTED] Director, Research and Development WWW: http://www.cequrux.com CEQURUX Technologies Phone: +27(21)423-6065 Firewalls/VPN Specialists Fax: +27(21)424-3656
#include <stdio.h> #include <fcntl.h> #include <kvm.h> #include <nlist.h> #include <sys/types.h> #include <sys/socket.h> #if (__FreeBSD__ > 2) #include <sys/socketvar.h> #endif #include <net/route.h> #include <netinet/in.h> #include <netinet/in_pcb.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/tcp.h> #define TCPSTATES #include <netinet/tcp_fsm.h> #define TCPTIMERS #include <netinet/tcp_timer.h> #include <netinet/tcp_var.h> #if (__FreeBSD__ > 2) #include <sys/sysctl.h> #include <netinet/in_pcb.h> #endif //---------------------------------------------------------------- void Display(struct inpcb *inpcb, struct tcpcb *tcpcb) { if (tcpcb->t_state >= TCPS_ESTABLISHED && tcpcb->t_state < TCP_NSTATES) { printf("%17s:%-5d ", inet_ntoa(inpcb->inp_laddr.s_addr), ntohs(inpcb->inp_lport)); printf("%17s:%-5d ", inet_ntoa(inpcb->inp_faddr.s_addr), ntohs(inpcb->inp_fport)); printf("[%10s] tx: %10lu rx: %10lu\n", tcpstates[tcpcb->t_state], (u_long)tcpcb->snd_nxt - (u_long)tcpcb->iss, (u_long)tcpcb->rcv_nxt - (u_long)tcpcb->irs); } } #if (__FreeBSD__ <= 2) struct nlist nml[] = { #define N_TCB 0 { "_tcb" }, 0 }; void Process_IP_CB(kvm_t *kmem, struct inpcb *inpcb) { struct tcpcb tcpcb; if (kvm_read(kmem, (long)inpcb->inp_ppcb, (char*)&tcpcb, sizeof(tcpcb))>0) Display(inpcb, &tcpcb); } void Process_IP_CBs(kvm_t *kvm) { struct inpcb in_pcb; long off = nml[N_TCB].n_value; if (kvm_read(kvm, off, (char *) &in_pcb, sizeof (struct inpcb))>0) { long prev = off; while (in_pcb.inp_list.le_next != (struct inpcb *)off) { long next = (long)in_pcb.inp_list.le_next; if (kvm_read(kvm, next, (char*)&in_pcb, sizeof(struct inpcb)) < 0 || (long)in_pcb.inp_list.le_prev != prev) // lost sync break; Process_IP_CB(kvm, &in_pcb); prev = next; } } } #endif main(int argc, char **argv) { #if (__FreeBSD__ > 2) int len = 0; if (sysctlbyname("net.inet.tcp.pcblist", 0, &len, 0, 0)<0) perror("sysctlbyname"); else { char *buf = (char*)malloc(len); if (buf == 0) perror("malloc"); else if (sysctlbyname("net.inet.tcp.pcblist", buf, &len, 0, 0)<0) perror("sysctlbyname"); else { struct xinpgen *xig, *oxig; oxig = xig = (struct xinpgen*)buf; for (xig = (struct xinpgen*)(((char*)xig)+xig->xig_len) ; xig->xig_len > sizeof(struct xinpgen); xig = (struct xinpgen*)(((char*)xig)+xig->xig_len)) { struct tcpcb *tcpcb = & ((struct xtcpcb*)xig)->xt_tp; struct inpcb *inpcb = & ((struct xtcpcb*)xig)->xt_inp; if (inpcb->inp_gencnt <= oxig->xig_gen) Display(inpcb, tcpcb); } } if (buf) free(buf); } #else kvm_t *kvm = kvm_open(0,0,0,0,0); if (kvm) { if (kvm_nlist(kvm, nml) < 0) perror("kvm_nlist"); else { Process_IP_CBs(kvm); kvm_close(kvm); } } else perror("kvm_open"); #endif }