DETECT UDP SP00FiNG ON OUR FREEBSD BOX VIA KLD.
11818d662899f1f3be9befbe3281444ed8c4bb2041a3cb4441cf83924c29f7d8
/*
* 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/protosw.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_pcb.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
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));
}