/* * DETECT UDP SP00FiNG ON OUR FREEBSD BOX VIA KLD * ---------------------------------------------- * * This is a partial porting of my linux lkm to detect spoofing from our box.. * to another system.... * * This kld detects only UDP Spoofing. Other implementations are possible * changing pru_send function of the protocol you are interested in... You * can use this kld to understand how to do that on another protocol or you * can write me for other implementations. * * Set MY_IP, MY_SECOND_IP with your address/es... * * This kld modifies a function of udp pr_usrreqs structure... other **bsd * systems have a function to interface socket routines with protocols. * * Notes: TCP implementation is possible via kld * IGMP & ICMP are also possible but they use pru_send in common * so check inp->inp_ip_p for IPPROTO_IGMP, IPPROTO_ICMP and so * on... * * idea & code by pIGpEN [pigpen@s0ftpj.org, deadhead@sikurezza.org] * * s0ftpr0ject - digital security for y2k * www.s0ftpj.org * * sikurezza.org - italian security mailing list * www.sikurezza.org * */ /* * pay attention: this code is compatible only with new kernels with * for example jail support... so you have to change pru_send to have * it working on old versions. * * uname -a * * FreeBSD storpio.cameretta.pig 4.0-19990705-CURRENT FreeBSD 4.0-19990705- * CURRENT #4 ..... i386 * * If you wanna a porting of this code and you have no time to do that * write to me at: deadhead@sikurezza.org with subject "PORTING A KLD" * */ #define MY_IP "192.168.1.2" #define MY_SECOND_IP "192.168.1.2" /* my machine has only an ip address and no other eth# or ip aliases */ #define LOOPBACK "127.0.0.1" #define DONT_PASS #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern struct protosw inetsw[]; extern struct udpstat udpstat; static int udpcksum = 1; static int s_load __P((struct module *, int, void *)); static int udp_send __P((struct socket * , int , struct mbuf *, struct sockaddr *, struct mbuf *, struct proc *)); static int (*old_udp_send) __P((struct socket * , int , struct mbuf *, struct sockaddr *, struct mbuf *, struct proc *)); static int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *, struct mbuf *, struct proc *)); static u_int32_t inaton __P((const char *)); /* ipfw macro... inet_ntoa() also works well from here it's the same thing */ #define print_ip(a) printf("%d.%d.%d.%d", \ (int)(ntohl(a.s_addr) >> 24) & 0xFF, \ (int)(ntohl(a.s_addr) >> 16) & 0xFF, \ (int)(ntohl(a.s_addr) >> 8 ) & 0xFF, \ (int)(ntohl(a.s_addr)) & 0xFF); static int s_load (struct module *module, int cmd, void *arg) { int s; switch(cmd) { case MOD_LOAD: s = splnet(); old_udp_send = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs->pru_send; inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs->pru_send = udp_send; splx(s); break; case MOD_UNLOAD: s = splnet(); inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs->pru_send = old_udp_send; splx(s); break; } return 0; } static moduledata_t s_mod_1 = { "udp_mod", s_load, 0 }; DECLARE_MODULE(udp_mod, s_mod_1, SI_SUB_PSEUDO, SI_ORDER_ANY); static int udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, struct mbuf *control, struct proc *p) { struct inpcb *inp; inp = sotoinpcb(so); if (inp == 0) { m_freem(m); return EINVAL; } return udp_output(inp, m, addr, control, p); } static int udp_output(inp, m, addr, control, p) register struct inpcb *inp; register struct mbuf *m; struct sockaddr *addr; struct mbuf *control; struct proc *p; { register struct udpiphdr *ui; register int len = m->m_pkthdr.len; struct in_addr laddr; struct sockaddr_in *sin; int s = 0, error = 0; if (control) m_freem(control); /* XXX */ if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) { error = EMSGSIZE; goto release; } if (addr) { sin = (struct sockaddr_in *)addr; prison_remote_ip(p, 0, &sin->sin_addr.s_addr); laddr = inp->inp_laddr; if (inp->inp_faddr.s_addr != INADDR_ANY) { error = EISCONN; goto release; } /* * Must block input while temporarily connected. */ s = splnet(); error = in_pcbconnect(inp, addr, p); if (error) { splx(s); goto release; } } else { if (inp->inp_faddr.s_addr == INADDR_ANY) { error = ENOTCONN; goto release; } } /* * Calculate data length and get a mbuf * for UDP and IP headers. */ M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT); if (m == 0) { error = ENOBUFS; if (addr) splx(s); goto release; } /* * Fill in mbuf with extended UDP header * and addresses and length put into network format. */ ui = mtod(m, struct udpiphdr *); bzero(ui->ui_x1, sizeof(ui->ui_x1)); ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); ui->ui_src = inp->inp_laddr; ui->ui_dst = inp->inp_faddr; ui->ui_sport = inp->inp_lport; ui->ui_dport = inp->inp_fport; ui->ui_ulen = ui->ui_len; /* * Stuff checksum and output datagram. */ ui->ui_sum = 0; if (udpcksum) { if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) ui->ui_sum = 0xffff; } ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */ ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */ if(ui->ui_src.s_addr != inaton(MY_IP) && ui->ui_src.s_addr != inaton(MY_SECOND_IP) && ui->ui_src.s_addr != inaton(LOOPBACK)) { printf("UDP Spoofing detected as: "); print_ip(ui->ui_src); printf(" to "); print_ip(ui->ui_dst); #ifdef DONT_PASS printf(" Packet not accepted to be sent\n"); goto release; #endif } udpstat.udps_opackets++; error = ip_output(m, inp->inp_options, &inp->inp_route, inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), inp->inp_moptions); if (addr) { in_pcbdisconnect(inp); inp->inp_laddr = laddr; /* XXX rehash? */ splx(s); } return (error); release: m_freem(m); return (error); } u_int32_t inaton(const char *str) { unsigned long l; unsigned int val; int i; l = 0; for(i=0; i < 4; i++) { l <<= 8; if(*str != '\0') { val = 0; while(*str != '\0' && *str != '.') { val *= 10; val += *str - '0'; str++; } l |= val; if(*str != '\0') str++; } } return(htonl(l)); }