/* * This kld gives you an example of how you can modify * the output function of an Ethernet Interface.... * * * Note: Don't use it for loopback, ppp or other no eth interfaces ! * * pigpen [pigpen@s0ftpj.org, deadhead@sikurezza.org] * * SoftProject NoProfit * Italian Security Organization * www.s0ftpj.org * * Sikurezza.org * Italian Security MailingList * www.sikurezza.org * */ /* * pay attention... this kld can change in future... * * 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 me at: deadhead@sikurezza.org with subject "PORTING A KLD" * */ #define INTERFACE "ed" #define INTERFACE_NUM 0 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IFP2AC(IFP) ((struct arpcom *) IFP) #define senderr(e) do { error = (e); goto bad;} while (0) int my_eth_output __P((register struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); static int module_handler __P((struct module *, int, void *)); /* * Ethernet output routine. * Encapsulate a packet of type family for the local net. * Use trailer local net encapsulation if enough data in first * packet leaves a multiple of 512 bytes of data in remainder. * Assumes that ifp is actually pointer to arpcom structure. */ int my_eth_output(ifp, m0, dst, rt0) register struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst; struct rtentry *rt0; { short type; int s, error = 0; u_char edst[6]; register struct mbuf *m = m0; register struct rtentry *rt; register struct ether_header *eh; int off, len = m->m_pkthdr.len, loop_copy = 0; int hlen; /* link layer header lenght */ struct arpcom *ac = IFP2AC(ifp); if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); rt = rt0; if (rt) { if ((rt->rt_flags & RTF_UP) == 0) { rt0 = rt = rtalloc1(dst, 1, 0UL); if (rt0) rt->rt_refcnt--; else senderr(EHOSTUNREACH); } if (rt->rt_flags & RTF_GATEWAY) { if (rt->rt_gwroute == 0) goto lookup; if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { rtfree(rt); rt = rt0; lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); if ((rt = rt->rt_gwroute) == 0) senderr(EHOSTUNREACH); } } if (rt->rt_flags & RTF_REJECT) if (rt->rt_rmx.rmx_expire == 0 || time_second < rt->rt_rmx.rmx_expire) senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } hlen = ETHER_HDR_LEN; switch (dst->sa_family) { case AF_INET: if (!arpresolve(ac, rt, m, dst, edst, rt0)) return (0); /* if not yet resolved */ off = m->m_pkthdr.len - m->m_len; type = htons(ETHERTYPE_IP); break; case AF_UNSPEC: loop_copy = -1; /* if this is for us, don't do it */ eh = (struct ether_header *)dst->sa_data; (void)memcpy(edst, eh->ether_dhost, sizeof (edst)); type = eh->ether_type; break; default: printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, dst->sa_family); senderr(EAFNOSUPPORT); } /* * Add local net header. If no space in first mbuf, * allocate another. */ M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); if (m == 0) senderr(ENOBUFS); eh = mtod(m, struct ether_header *); (void)memcpy(&eh->ether_type, &type, sizeof(eh->ether_type)); (void)memcpy(eh->ether_dhost, edst, sizeof (edst)); (void)memcpy(eh->ether_shost, ac->ac_enaddr, sizeof(eh->ether_shost)); /* * If a simplex interface, and the packet is being sent to our * Ethernet address or a broadcast address, loopback a copy. * XXX To make a simplex device behave exactly like a duplex * device, we should copy in the case of sending to our own * ethernet address (thus letting the original actually appear * on the wire). However, we don't do that here for security * reasons and compatibility with the original behavior. */ if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); (void) if_simloop(ifp, n, dst, hlen); } else if (bcmp(eh->ether_dhost, eh->ether_shost, ETHER_ADDR_LEN) == 0) { (void) if_simloop(ifp, m, dst, hlen); return (0); /* XXX */ } } /*#ifdef BRIDGE if (do_bridge) { struct mbuf *m0 = m ; if (m->m_pkthdr.rcvif) m->m_pkthdr.rcvif = NULL ; ifp = bridge_dst_lookup(m); bdg_forward(&m0, ifp); if (m0) m_freem(m0); return (0); } #endif*/ s = splimp(); /* * Queue message on interface, and start output if interface * not yet active. */ if (IF_QFULL(&ifp->if_snd)) { IF_DROP(&ifp->if_snd); splx(s); senderr(ENOBUFS); } IF_ENQUEUE(&ifp->if_snd, m); if ((ifp->if_flags & IFF_OACTIVE) == 0) (*ifp->if_start)(ifp); splx(s); ifp->if_obytes += len + sizeof (struct ether_header); if (m->m_flags & M_MCAST) ifp->if_omcasts++; return (error); bad: if (m) m_freem(m); return (error); } static int module_handler(struct module *module, int cmd, void *arg) { int s; struct ifnet *ifp; switch(cmd) { case MOD_LOAD: s = splimp(); for(ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { /* pig: sys/queue.h-> TAILQ_FOREACH(ifp, &ifnet, if_link) */ printf("%s%d -> ", ifp->if_name, ifp->if_unit); if(!strcmp(ifp->if_name,INTERFACE) && ifp->if_unit == INTERFACE_NUM) { ifp->if_output = my_eth_output; printf("MODIFIED"); } else printf("no"); printf("\n"); } splx(s); break; case MOD_UNLOAD: s = splimp(); for(ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { if( !strcmp(ifp->if_name,INTERFACE) && ifp->if_unit == INTERFACE_NUM) { ifp->if_output = ether_output; printf("%s%d output funct: Updated\n",ifp->if_name, ifp->if_unit); } } splx(s); break; } return 0; } static moduledata_t mymod = { "eth_out", module_handler, 0 }; DECLARE_MODULE(eth_out, mymod, SI_SUB_PSEUDO, SI_ORDER_ANY);