/* * network kernel hackin' on a FreeBSD box.... * * why not? * * yeah it's possible ... this is an example ... you can change hack_input() * function as you wanna... * * We can change functions of a struct of inetsw[], we can change mbuf * structures... we can access inpcb,inpcbinfo structures... we can change * options of every layer in a connection... * * idea & code by pigpen [deadhead@sikurezza.org, pigpen@s0ftpj.org] * */ /* * uname -a * * FreeBSD storpio.cameretta.pig 4.0-19990705-CURRENT FreeBSD 4.0-19990705- * CURRENT #4 ..... i386 * */ #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; extern int log_in_vain; extern struct inpcbhead udb; extern struct sockaddr_in udp_in; static void (*old_udp_input) __P((register struct mbuf *, int )); static void hack_input __P((register struct mbuf *, int )); static int s_load __P((struct module *, int, void *)); static int s_load (struct module *module, int cmd, void *arg) { int s; switch(cmd) { case MOD_LOAD: printf("Module loaded"); s = splnet(); old_udp_input = inetsw[1].pr_input; inetsw[1].pr_input = hack_input; splx(s); break; case MOD_UNLOAD: s = splnet(); inetsw[1].pr_input = old_udp_input; splx(s); break; } return 0; } static moduledata_t s_mod_1 = { "s_mod", s_load, 0 }; DECLARE_MODULE(s_mod, s_mod_1, SI_SUB_PSEUDO, SI_ORDER_ANY); static void hack_input(m, iphlen) register struct mbuf *m; int iphlen; { register struct ip *ip; register struct udphdr *uh; register struct inpcb *inp; struct mbuf *opts = 0; int len; struct ip save_ip; udpstat.udps_ipackets++; if (iphlen > sizeof (struct ip)) { ip_stripoptions(m, (struct mbuf *)0); iphlen = sizeof(struct ip); } ip = mtod(m, struct ip *); if (m->m_len < iphlen + sizeof(struct udphdr)) { if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) { udpstat.udps_hdrops++; return; } ip = mtod(m, struct ip *); } uh = (struct udphdr *)((caddr_t)ip + iphlen); len = ntohs((u_short)uh->uh_ulen); if (ip->ip_len != len) { if (len > ip->ip_len || len < sizeof(struct udphdr)) { udpstat.udps_badlen++; goto bad; } m_adj(m, len - ip->ip_len); /* ip->ip_len = len; */ } save_ip = *ip; if (uh->uh_sum) { bzero(((struct ipovly *)ip)->ih_x1, 9); ((struct ipovly *)ip)->ih_len = uh->uh_ulen; uh->uh_sum = in_cksum(m, len + sizeof (struct ip)); if (uh->uh_sum) { udpstat.udps_badsum++; m_freem(m); return; } } if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) { struct inpcb *last; udp_in.sin_port = uh->uh_sport; udp_in.sin_addr = ip->ip_src; m->m_len -= sizeof (struct udpiphdr); m->m_data += sizeof (struct udpiphdr); last = NULL; for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { if (inp->inp_lport != uh->uh_dport) continue; if (inp->inp_laddr.s_addr != INADDR_ANY) { if (inp->inp_laddr.s_addr != ip->ip_dst.s_addr) continue; } if (inp->inp_faddr.s_addr != INADDR_ANY) { if (inp->inp_faddr.s_addr != ip->ip_src.s_addr || inp->inp_fport != uh->uh_sport) continue; } if (last != NULL) { struct mbuf *n; if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) ip_savecontrol(last, &opts, ip, n); if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&udp_in, n, opts) == 0) { m_freem(n); if (opts) m_freem(opts); udpstat.udps_fullsock++; } else sorwakeup(last->inp_socket); opts = 0; } } last = inp; if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0) break; } if (last == NULL) { udpstat.udps_noportbcast++; goto bad; } if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) ip_savecontrol(last, &opts, ip, m); if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } sorwakeup(last->inp_socket); return; } inp = in_pcblookup_hash(&udbinfo, ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport, 1); if (inp == NULL) { if (log_in_vain) { char buf[4*sizeof "123"]; strcpy(buf, inet_ntoa(ip->ip_dst)); log(LOG_INFO, "Connection attempt to UDP %s:%d from %s:%d\n", buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src), ntohs(uh->uh_sport)); } udpstat.udps_noport++; if (m->m_flags & (M_BCAST | M_MCAST)) { udpstat.udps_noportbcast++; goto bad; } *ip = save_ip; if (badport_bandlim(0) < 0) goto bad; icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0); return; } udp_in.sin_port = uh->uh_sport; udp_in.sin_addr = ip->ip_src; if (inp->inp_flags & INP_CONTROLOPTS || inp->inp_socket->so_options & SO_TIMESTAMP) ip_savecontrol(inp, &opts, ip, m); iphlen += sizeof(struct udphdr); m->m_len -= iphlen; m->m_pkthdr.len -= iphlen; m->m_data += iphlen; if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } sorwakeup(inp->inp_socket); return; bad: m_freem(m); if (opts) m_freem(opts); }