static int daq_nfq_callback( struct nfq_q_handle* qh, struct nfgenmsg* nfmsg, struct nfq_data* nfad, void* data) { NfqImpl *impl = (NfqImpl*)data; struct nfqnl_msg_packet_hdr* ph = nfq_get_msg_packet_hdr(nfad); DAQ_Verdict verdict; DAQ_PktHdr_t hdr; uint8_t* pkt; int nf_verdict; uint32_t data_len; if ( impl->state != DAQ_STATE_STARTED ) return -1; if ( !ph || SetPktHdr(impl, nfad, &hdr, &pkt) ) { DPE(impl->error, "%s: can't setup packet header", __FUNCTION__); return -1; } if ( impl->fcode.bf_insns && sfbpf_filter(impl->fcode.bf_insns, pkt, hdr.caplen, hdr.caplen) == 0 ) { verdict = DAQ_VERDICT_PASS; impl->stats.packets_filtered++; } else { verdict = impl->user_func(impl->user_data, &hdr, pkt); if ( verdict >= MAX_DAQ_VERDICT ) verdict = DAQ_VERDICT_BLOCK; impl->stats.verdicts[verdict]++; impl->stats.packets_received++; } nf_verdict = ( impl->passive || s_fwd[verdict] ) ? NF_ACCEPT : NF_DROP; data_len = ( verdict == DAQ_VERDICT_REPLACE ) ? hdr.caplen : 0; nfq_set_verdict( impl->nf_queue, ntohl(ph->packet_id), nf_verdict, data_len, pkt); return 0; }
int main() { struct sfbpf_program fcode; const char *filter = "tcp"; char data[1514]; int len = 1514; memset(data, 0, sizeof(data)); if (sfbpf_compile(1514, DLT_EN10MB, &fcode, filter, 1, 0) < 0) { fprintf(stderr, "%s: BPF state machine compilation failed!", __FUNCTION__); return EXIT_FAILURE; } if (fcode.bf_insns && sfbpf_filter(fcode.bf_insns, data, len, len) == 0) { fprintf(stderr, "Packet ignored!\n"); } sfbpf_freecode(&fcode); return EXIT_SUCCESS; }
static int ipq_daq_acquire ( void* handle, int cnt, DAQ_Analysis_Func_t callback, void* user) { IpqImpl* impl = (IpqImpl*)handle; int n = 0; DAQ_PktHdr_t hdr; // If cnt is <= 0, don't limit the packets acquired. However, // impl->count = 0 has a special meaning, so interpret accordingly. impl->count = (cnt == 0) ? -1 : cnt; hdr.device_index = 0; hdr.flags = 0; while ( impl->count < 0 || n < impl->count ) { int ipqt, status = ipq_read( impl->ipqh, impl->buf, MSG_BUF_SIZE, impl->timeout); if ( status <= 0 ) { if ( status < 0 ) { DPE(impl->error, "%s: ipq_read=%d error %s", __FUNCTION__, status, ipq_errstr()); return DAQ_ERROR; } return 0; } ipqt = ipq_message_type(impl->buf); if ( ipqt == IPQM_PACKET ) { DAQ_Verdict verdict; ipq_packet_msg_t* ipqm = ipq_get_packet(impl->buf); SetPktHdr(impl, ipqm, &hdr); impl->stats.hw_packets_received++; if ( impl->fcode.bf_insns && sfbpf_filter(impl->fcode.bf_insns, ipqm->payload, hdr.caplen, hdr.caplen) == 0 ) { verdict = DAQ_VERDICT_PASS; impl->stats.packets_filtered++; } else { verdict = callback(user, &hdr, (uint8_t*)ipqm->payload); impl->stats.verdicts[verdict]++; impl->stats.packets_received++; } if ( impl->passive ) verdict = DAQ_VERDICT_PASS; switch ( verdict ) { case DAQ_VERDICT_BLOCK: case DAQ_VERDICT_BLACKLIST: status = ipq_set_verdict( impl->ipqh, ipqm->packet_id, NF_DROP, 0, NULL); break; case DAQ_VERDICT_REPLACE: status = ipq_set_verdict( impl->ipqh, ipqm->packet_id, NF_ACCEPT, hdr.pktlen, ipqm->payload); break; case DAQ_VERDICT_PASS: case DAQ_VERDICT_WHITELIST: case DAQ_VERDICT_IGNORE: default: status = ipq_set_verdict( impl->ipqh, ipqm->packet_id, NF_ACCEPT, 0, NULL); break; } if ( status < 0 ) { DPE(impl->error, "%s: ipq_set_verdict=%d error %s", __FUNCTION__, status, ipq_errstr()); return DAQ_ERROR; } n++; } else { // NLMSG_ERROR is supposed to be the only other valid type status = ipq_get_msgerr(impl->buf); DPE(impl->error, "%s: ipq_message_type=%d error=%d %s", __FUNCTION__, ipqt, status, ipq_errstr()); // ipq_message_type=2 error=1 Timeout // keep looping upon timeout or other errors } } return 0; }
static int afpacket_daq_acquire(void *handle, int cnt, DAQ_Analysis_Func_t callback, void *user) { AFPacket_Context_t *afpc = (AFPacket_Context_t *) handle; AFPacketInstance *instance; DAQ_PktHdr_t daqhdr; DAQ_Verdict verdict; union thdr hdr; struct pollfd pfd[AF_PACKET_MAX_INTERFACES]; const uint8_t *data; uint32_t i; int got_one, ignored_one; int result, c = 0; struct sockaddr_ll *sll; const struct ethhdr *eth; unsigned int tp_len, tp_mac, tp_snaplen, tp_sec, tp_usec; while (cnt <= 0 || c < cnt) { got_one = 0; ignored_one = 0; for (instance = afpc->instances; instance; instance = instance->next) { /* Has breakloop() been called? */ if (afpc->break_loop) { afpc->break_loop = 0; return 0; } hdr = instance->entry->hdr; if ((instance->tp_version == TPACKET_V1 && hdr.h1->tp_status) #ifdef HAVE_TPACKET2 || (instance->tp_version == TPACKET_V2 && hdr.h2->tp_status) #endif ) { switch (instance->tp_version) { case TPACKET_V1: tp_len = hdr.h1->tp_len; tp_mac = hdr.h1->tp_mac; tp_snaplen = hdr.h1->tp_snaplen; tp_sec = hdr.h1->tp_sec; tp_usec = hdr.h1->tp_usec; break; #ifdef HAVE_TPACKET2 case TPACKET_V2: tp_len = hdr.h2->tp_len; tp_mac = hdr.h2->tp_mac; tp_snaplen = hdr.h2->tp_snaplen; tp_sec = hdr.h2->tp_sec; tp_usec = hdr.h2->tp_nsec / 1000; break; #endif default: DPE(afpc->errbuf, "%s: Unknown TPACKET version: %u!", __FUNCTION__, instance->tp_version); return DAQ_ERROR; } data = instance->entry->begin + tp_mac; verdict = DAQ_VERDICT_PASS; if (afpc->fcode.bf_insns && sfbpf_filter(afpc->fcode.bf_insns, data, tp_len, tp_snaplen) == 0) { ignored_one = 1; afpc->stats.packets_filtered++; goto send_packet; } got_one = 1; daqhdr.caplen = tp_snaplen; daqhdr.pktlen = tp_len; daqhdr.ts.tv_sec = tp_sec; daqhdr.ts.tv_usec = tp_usec; daqhdr.device_index = instance->index; daqhdr.flags = 0; if (callback) { verdict = callback(user, &daqhdr, data); if (verdict >= MAX_DAQ_VERDICT) verdict = DAQ_VERDICT_PASS; afpc->stats.verdicts[verdict]++; verdict = verdict_translation_table[verdict]; } afpc->stats.packets_received++; c++; send_packet: if (verdict == DAQ_VERDICT_PASS && instance->peer) { eth = (const struct ethhdr *)data; sll = &instance->peer->sll; sll->sll_protocol = eth->h_proto; sendto(instance->peer->fd, data, tp_snaplen, 0, (struct sockaddr *) sll, sizeof(*sll)); } switch (instance->tp_version) { case TPACKET_V1: hdr.h1->tp_status = TP_STATUS_KERNEL; break; #ifdef HAVE_TPACKET2 case TPACKET_V2: hdr.h2->tp_status = TP_STATUS_KERNEL; break; #endif } instance->entry = instance->entry->next; } } if (!got_one && !ignored_one) { for (i = 0, instance = afpc->instances; instance; i++, instance = instance->next) { pfd[i].fd = instance->fd; pfd[i].revents = 0; pfd[i].events = POLLIN; } result = poll(pfd, afpc->intf_count, afpc->timeout); if (result < 0) { /* If we were interrupted by a signal, just return without error. */ if (errno == EINTR) break; DPE(afpc->errbuf, "%s: Poll failed: %s (%d)", __FUNCTION__, strerror(errno), errno); return DAQ_ERROR; } else if (result == 0) break; } } return 0; }
static int afpacket_daq_acquire(void *handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t metaback, void *user) { AFPacket_Context_t *afpc = (AFPacket_Context_t *) handle; AFPacketInstance *instance; DAQ_PktHdr_t daqhdr; DAQ_Verdict verdict; union thdr hdr; struct pollfd pfd[AF_PACKET_MAX_INTERFACES]; const uint8_t *data; uint32_t i; int got_one, ignored_one; int ret, c = 0; unsigned int tp_len, tp_mac, tp_snaplen, tp_sec, tp_usec; while (c < cnt || cnt <= 0) { got_one = 0; ignored_one = 0; for (instance = afpc->instances; instance; instance = instance->next) { /* Has breakloop() been called? */ if (afpc->break_loop) { afpc->break_loop = 0; return 0; } hdr = instance->rx_ring.cursor->hdr; if (instance->tp_version == TPACKET_V2 && (hdr.h2->tp_status & TP_STATUS_USER)) { switch (instance->tp_version) { case TPACKET_V2: tp_len = hdr.h2->tp_len; tp_mac = hdr.h2->tp_mac; tp_snaplen = hdr.h2->tp_snaplen; tp_sec = hdr.h2->tp_sec; tp_usec = hdr.h2->tp_nsec / 1000; break; default: DPE(afpc->errbuf, "%s: Unknown TPACKET version: %u!", __FUNCTION__, instance->tp_version); return DAQ_ERROR; } if (tp_mac + tp_snaplen > instance->rx_ring.layout.tp_frame_size) { DPE(afpc->errbuf, "%s: Corrupted frame on kernel ring (MAC offset %u + CapLen %u > FrameSize %d)", __FUNCTION__, tp_mac, tp_snaplen, instance->rx_ring.layout.tp_frame_size); return DAQ_ERROR; } data = instance->rx_ring.cursor->hdr.raw + tp_mac; /* Make a valiant attempt at reconstructing the VLAN tag if it has been stripped. This really sucks. :( */ if ((instance->tp_version == TPACKET_V2) && #if defined(TP_STATUS_VLAN_VALID) (hdr.h2->tp_vlan_tci || (hdr.h2->tp_status & TP_STATUS_VLAN_VALID)) && #else hdr.h2->tp_vlan_tci && #endif tp_snaplen >= (unsigned int) vlan_offset) { struct vlan_tag *tag; data -= VLAN_TAG_LEN; memmove((void *) data, data + VLAN_TAG_LEN, vlan_offset); tag = (struct vlan_tag *) (data + vlan_offset); tag->vlan_tpid = htons(ETH_P_8021Q); tag->vlan_tci = htons(hdr.h2->tp_vlan_tci); tp_snaplen += VLAN_TAG_LEN; tp_len += VLAN_TAG_LEN; } verdict = DAQ_VERDICT_PASS; if (afpc->fcode.bf_insns && sfbpf_filter(afpc->fcode.bf_insns, data, tp_len, tp_snaplen) == 0) { ignored_one = 1; afpc->stats.packets_filtered++; goto send_packet; } got_one = 1; daqhdr.ts.tv_sec = tp_sec; daqhdr.ts.tv_usec = tp_usec; daqhdr.caplen = tp_snaplen; daqhdr.pktlen = tp_len; daqhdr.ingress_index = instance->index; daqhdr.egress_index = instance->peer ? instance->peer->index : DAQ_PKTHDR_UNKNOWN; daqhdr.ingress_group = DAQ_PKTHDR_UNKNOWN; daqhdr.egress_group = DAQ_PKTHDR_UNKNOWN; daqhdr.flags = 0; daqhdr.opaque = 0; daqhdr.priv_ptr = NULL; daqhdr.address_space_id = 0; if (callback) { verdict = callback(user, &daqhdr, data); if (verdict >= MAX_DAQ_VERDICT) verdict = DAQ_VERDICT_PASS; afpc->stats.verdicts[verdict]++; verdict = verdict_translation_table[verdict]; } afpc->stats.packets_received++; c++; send_packet: if (verdict == DAQ_VERDICT_PASS && instance->peer) { AFPacketEntry *entry = instance->peer->tx_ring.cursor; int rc; if (entry->hdr.h2->tp_status == TP_STATUS_AVAILABLE) { memcpy(entry->hdr.raw + TPACKET_ALIGN(instance->peer->tp_hdrlen), data, tp_snaplen); entry->hdr.h2->tp_len = tp_snaplen; entry->hdr.h2->tp_status = TP_STATUS_SEND_REQUEST; rc = send(instance->peer->fd, NULL, 0, 0); instance->peer->tx_ring.cursor = entry->next; } /* Else, don't forward the packet... */ } /* Release the TPACKET buffer back to the kernel. */ switch (instance->tp_version) { case TPACKET_V2: hdr.h2->tp_status = TP_STATUS_KERNEL; break; } instance->rx_ring.cursor = instance->rx_ring.cursor->next; } } if (!got_one && !ignored_one) { for (i = 0, instance = afpc->instances; instance; i++, instance = instance->next) { pfd[i].fd = instance->fd; pfd[i].revents = 0; pfd[i].events = POLLIN; } ret = poll(pfd, afpc->intf_count, afpc->timeout); /* If we were interrupted by a signal, start the loop over. The user should call daq_breakloop to actually exit. */ if (ret < 0 && errno != EINTR) { DPE(afpc->errbuf, "%s: Poll failed: %s (%d)", __FUNCTION__, strerror(errno), errno); return DAQ_ERROR; } /* If the poll times out, return control to the caller. */ if (ret == 0) break; /* If some number of of sockets have events returned, check them all for badness. */ if (ret > 0) { for (i = 0; i < afpc->intf_count; i++) { if (pfd[i].revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) { if (pfd[i].revents & (POLLHUP | POLLRDHUP)) DPE(afpc->errbuf, "%s: Hang-up on a packet socket", __FUNCTION__); else if (pfd[i].revents & POLLERR) DPE(afpc->errbuf, "%s: Encountered error condition on a packet socket", __FUNCTION__); else if (pfd[i].revents & POLLNVAL) DPE(afpc->errbuf, "%s: Invalid polling request on a packet socket", __FUNCTION__); return DAQ_ERROR; } } } } } return 0; }