/* * IGMP/ICMP/IPIP/IDP/RSVP/IPIP/IPPROTO_RAW KERNEL CHECKER * * These protocols have the same pr_usrreqs... This is a kld to monitor * their packets via FreeBSD kernel. * * idea & code by pIGpEN [pigpen@s0ftpj.org, deadhead@sikurezza.org ] * * Tested on FreeBSD CURRENT 4.0 * * s0ftpr0ject - digital security for y2k * www.s0ftpj.org * * sikurezza.org - italian security mailing list * www.sikurezza.org * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define _IP_VHL #include #include #include #include #include #include #include #define print_ip(a) printf("%d.%d.%d.%d\n", \ (int)(ntohl(a) >>24) & 0xFF, \ (int)(ntohl(a) >>16) & 0xFF, \ (int)(ntohl(a) >> 8) & 0xFF, \ (int)(ntohl(a)) & 0xFF); static int rip_new_send __P((struct socket *, int, struct mbuf *, struct sockaddr *, struct mbuf *, struct proc *)); static int (*old_rip_send) __P((struct socket *, int, struct mbuf *, struct sockaddr *, struct mbuf *, struct proc *)); static int rip_my_output __P((register struct mbuf *, struct socket *, u_long)); static int s_load __P((struct module *, int, void *)); /* il controllo si poteva fare direttamente su questa funzione.... non l'ho fatto perche' avevo gia' messo la mia rip_my_output nel sorgente :) */ static int rip_new_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct proc *p) { struct inpcb *inp = sotoinpcb(so); register u_long dst; if (so->so_state & SS_ISCONNECTED) { if (nam) { m_freem(m); return EISCONN; } dst = inp->inp_faddr.s_addr; } else { if (nam == NULL) { m_freem(m); return ENOTCONN; } dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr; } return rip_my_output(m, so, dst); } static int rip_my_output(m, so, dst) register struct mbuf *m; struct socket *so; u_long dst; { register struct ip *ip; register struct inpcb *inp = sotoinpcb(so); int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; switch(inp->inp_ip_p) { case IPPROTO_RAW: printf("RAW"); break; case IPPROTO_ICMP: printf("ICMP"); break; case IPPROTO_IGMP: printf("IGMP"); break; case IPPROTO_RSVP: printf("RSVP"); break; case IPPROTO_IPIP: printf("IPIP"); break; case IPPROTO_IDP: printf("IDP"); break; default: printf("#%d", inp->inp_ip_p); break; } printf(" -> "); print_ip(dst); /* * If the user handed us a complete IP packet, use it. * Otherwise, allocate an mbuf for a header and fill it in. */ if ((inp->inp_flags & INP_HDRINCL) == 0) { if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) { m_freem(m); return(EMSGSIZE); } M_PREPEND(m, sizeof(struct ip), M_WAIT); ip = mtod(m, struct ip *); ip->ip_tos = 0; ip->ip_off = 0; ip->ip_p = inp->inp_ip_p; ip->ip_len = m->m_pkthdr.len; ip->ip_src = inp->inp_laddr; ip->ip_dst.s_addr = dst; ip->ip_ttl = MAXTTL; } else { if (m->m_pkthdr.len > IP_MAXPACKET) { m_freem(m); return(EMSGSIZE); } ip = mtod(m, struct ip *); /* don't allow both user specified and setsockopt options, and don't allow packet length sizes that will crash */ if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2)) && inp->inp_options) || (ip->ip_len > m->m_pkthdr.len) || (ip->ip_len < (IP_VHL_HL(ip->ip_vhl) << 2))) { m_freem(m); return EINVAL; } if (ip->ip_id == 0) ip->ip_id = htons(ip_id++); /* XXX prevent ip_output from overwriting header fields */ flags |= IP_RAWOUTPUT; ipstat.ips_rawout++; } return (ip_output(m, inp->inp_options, &inp->inp_route, flags, inp->inp_moptions)); } extern struct protosw inetsw[]; static int s_load (struct module *module, int cmd, void *arg) { int s; switch(cmd) { case MOD_LOAD: s=splnet(); old_rip_send = inetsw[ip_protox[IPPROTO_ICMP]].pr_usrreqs->pru_send; inetsw[ip_protox[IPPROTO_ICMP]].pr_usrreqs->pru_send = rip_new_send; splx(s); break; case MOD_UNLOAD: s=splnet(); inetsw[ip_protox[IPPROTO_ICMP]].pr_usrreqs->pru_send = old_rip_send; splx(s); break; } return 0; } static moduledata_t s_mod_1 = { "raww_mod", s_load, 0 }; DECLARE_MODULE(raww_mod, s_mod_1, SI_SUB_PSEUDO, SI_ORDER_ANY);