UInt32 darwin_iwi3945::outputPacket(mbuf_t m, void * param) { //IOLog("outputPacket\n"); if((fNetif->getFlags() & IFF_RUNNING)!=0 || m==NULL) { if (m) if (!(mbuf_type(m) == MBUF_TYPE_FREE) ) freePacket(m); m=NULL; netStats->outputErrors++; return kIOReturnOutputDropped; } mbuf_t nm; int ret = kIOReturnOutputDropped; //checking supported packet IWI_DEBUG("outputPacket t: %d f:%04x\n",mbuf_type(m),mbuf_flags(m)); //drop mbuf is not PKTHDR if (!(mbuf_flags(m) & MBUF_PKTHDR) ){ IWI_ERR("BUG: dont support mbuf without pkthdr and dropped \n"); netStats->outputErrors++; goto finish; } if(mbuf_type(m) == MBUF_TYPE_FREE){ IWI_ERR("BUG: this is freed packet and dropped \n"); netStats->outputErrors++; goto finish; } nm = mergePacket(m); if (nm==NULL) { netStats->outputErrors++; goto finish; } if(mbuf_next(nm)){ IWI_ERR("BUG: dont support chains mbuf\n"); IWI_ERR("BUG: tx packet is not single mbuf mbuf_len(%d) mbuf_pkthdr_len(%d)\n",mbuf_len(nm) , mbuf_pkthdr_len(nm) ); IWI_ERR("BUG: next mbuf size %d\n",mbuf_len(mbuf_next(nm))); } IWI_DEBUG_FULL("call ieee80211_xmit - not done yet\n"); //ret = ieee80211_xmit(nm,priv->net_dev); //struct ieee80211_tx_control ctrl; //ret=ipw_tx_skb(priv, nm, &ctrl); finish: /* free finished packet */ //freePacket(m); //m=NULL; if (ret == kIOReturnOutputDropped) { //if (nm) //if (!(mbuf_type(nm) == MBUF_TYPE_FREE) ) freePacket(nm); //nm=NULL; } return ret; }
//callback for incoming data // only interested in DNS responses for IP:URL mappings // code inspired by: https://github.com/williamluke/peerguardian-linux/blob/master/pgosx/kern/ppfilter.c static errno_t data_in(void *cookie, socket_t so, const struct sockaddr *from, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags) { //dbg msg IOLog("LULU: in %s\n", __FUNCTION__); //port in_port_t port = 0; //peer name struct sockaddr_in6 peerName = {0}; //mem buffer mbuf_t memBuffer = NULL; //response size size_t responseSize = 0; //dns header dnsHeader* dnsHeader = NULL; //firewall event firewallEvent event = {0}; //destination socket ('from') might be null? // if so, grab it via 'getpeername' from the socket if(NULL == from) { //lookup remote socket info if(0 != sock_getpeername(so, (struct sockaddr*)&peerName, sizeof(peerName))) { //err msg IOLog("LULU ERROR: sock_getpeername() failed\n"); //bail goto bail; } //now, assign from = (const struct sockaddr*)&peerName; } //get port switch(from->sa_family) { //IPv4 case AF_INET: port = ntohs(((const struct sockaddr_in*)from)->sin_port); break; //IPv6 case AF_INET6: port = ntohs(((const struct sockaddr_in6*)from)->sin6_port); break; default: break; } //ignore non-DNS if(53 != port) { //bail goto bail; } //init memory buffer memBuffer = *data; if(NULL == memBuffer) { //bail goto bail; } //get memory buffer while(MBUF_TYPE_DATA != mbuf_type(memBuffer)) { //get next memBuffer = mbuf_next(memBuffer); if(NULL == memBuffer) { //bail goto bail; } } //sanity check length if(mbuf_len(memBuffer) <= sizeof(struct dnsHeader)) { //bail goto bail; } //get data // should be a DNS header dnsHeader = (struct dnsHeader*)mbuf_data(memBuffer); //ignore everything that isn't a DNS response // top bit flag will be 0x1, for "a name service response" if(0 == ((ntohs(dnsHeader->flags)) & (1<<(15)))) { //bail goto bail; } //ignore any errors // bottom (4) bits will be 0x0 for "successful response" if(0 != ((ntohs(dnsHeader->flags)) & (1<<(0)))) { //bail goto bail; } //ignore any packets that don't have answers if(0 == ntohs(dnsHeader->ancount)) { //bail goto bail; } //zero out event struct bzero(&event, sizeof(firewallEvent)); //set type event.dnsResponseEvent.type = EVENT_DNS_RESPONSE; //set size // max, 512 responseSize = MIN(sizeof(event.dnsResponseEvent.response), mbuf_len(memBuffer)); //copy response memcpy(event.dnsResponseEvent.response, mbuf_data(memBuffer), responseSize); //queue it up sharedDataQueue->enqueue_tail(&event, sizeof(firewallEvent)); bail: return kIOReturnSuccess; }
mbuf_t darwin_iwi3945::mergePacket(mbuf_t m) { mbuf_t nm,nm2; int offset; if(!mbuf_next(m)) { offset = (4 - ((int)(mbuf_data(m)) & 3)) % 4; //packet needs to be 4 byte aligned if (offset==0) return m; IWI_DEBUG_FULL("this packet dont have mbuf_next, merge is not required\n"); goto copy_packet; } /* allocate and Initialize New mbuf */ nm = allocatePacket(mbuf_pkthdr_len(m)); if (nm==0) return NULL; //if (mbuf_getpacket(MBUF_WAITOK, &nm)!=0) return NULL; mbuf_setlen(nm,0); mbuf_pkthdr_setlen(nm,0); if( mbuf_next(nm)) IWI_ERR("merged mbuf_next\n"); /* merging chains to single mbuf */ for (nm2 = m; nm2; nm2 = mbuf_next(nm2)) { memcpy (skb_put (nm, mbuf_len(nm2)), (UInt8*)mbuf_data(nm2), mbuf_len(nm2)); } /* checking if merged or not. */ if( mbuf_len(nm) == mbuf_pkthdr_len(m) ) { if (m!=NULL) if (!(mbuf_type(m) == MBUF_TYPE_FREE)) freePacket(m); m=NULL; return nm; } /* merging is not completed. */ IWI_LOG("mergePacket is failed: data copy dont work collectly\n"); //IWI_LOG("orig_len %d orig_pktlen %d new_len %d new_pktlen %d\n", // mbuf_len(m),mbuf_pkthdr_len(m), // mbuf_len(nm),mbuf_pkthdr_len(nm) ); if (m!=NULL) if (!(mbuf_type(m) == MBUF_TYPE_FREE)) freePacket(m); m=NULL; if (nm!=NULL) if (!(mbuf_type(nm) == MBUF_TYPE_FREE) ) freePacket(nm); nm=NULL; return NULL; copy_packet: if (mbuf_dup(m, MBUF_WAITOK , &nm)!=0) { if (m!=NULL) if (!(mbuf_type(m) == MBUF_TYPE_FREE)) freePacket(m); m=NULL; return NULL; } if (m!=NULL) if (!(mbuf_type(m) == MBUF_TYPE_FREE) ) freePacket(m); m=NULL; return nm; //return copyPacket(m, 0); }
// data in is currently used for PASV FTP support static errno_t ppfilter_data_in (__unused void *cookie, socket_t so, const struct sockaddr *from, mbuf_t *data, __unused mbuf_t *control, __unused sflt_data_flag_t flags) { in_addr_t ip4; in_port_t port; if (!from) { struct sockaddr_in6 local; if (0 != sock_getpeername(so, (struct sockaddr*)&local, sizeof(local))) bzero(&local, sizeof(local)); from = (const struct sockaddr*)&local; } if (AF_INET == from->sa_family) { port = ntohs(((const struct sockaddr_in*)from)->sin_port); } else if (AF_INET6 == from->sa_family) { const struct sockaddr_in6* addr6 = (const struct sockaddr_in6*)from; if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr) || !IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) return (0); // tables do not contain native ip6 addreses port = ntohs(addr6->sin6_port); } else return (0); // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // Short-circuit optimization for ftp filter -- if any other filters are ever added, // this will have to be removed. if (21 != port) return (0); // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX mbuf_t mdata = *data; while (mdata && MBUF_TYPE_DATA != mbuf_type(mdata)) { mdata = mbuf_next(mdata); } if (!mdata) return (0); char *pkt = mbuf_data(mdata); if (!pkt) return (0); size_t len = mbuf_len(mdata); ip4 = INADDR_NONE; int block, i; pp_data_filter_t filt = pp_data_filters[0]; for (i = 1; filt; ++i) { block = filt(pkt, len, &ip4, &port); if (INADDR_NONE != ip4) { // add to dynamic list pp_dynentries_lock(); pp_dyn_entry_t e = pp_dyn_entry_get(); if (e) { e->addr = ip4; e->port = port; e->block = block; } pp_dynentries_unlock(); break; } filt = pp_data_filters[i]; } return (0); }