| #include "pfring.h" |
| #include "../../kernel/plugins/dummy_plugin.h" |
| |
| #include <arpa/inet.h> |
| #include <net/ethernet.h> |
| #include <netinet/ip.h> |
| |
| #include <sys/time.h> |
| #include <time.h> |
| #include <signal.h> |
| |
| pfring *pd; |
| |
| int timer_timeout = 2; |
| int verbose = 0; |
| u_int32_t pkt_cnt = 0; |
| |
| |
| /* ************************************************************************ */ |
| |
| static void timer_handler(int signo) |
| { |
| time_t curr_time; |
| curr_time = time(NULL); |
| printf("Packet count %u after %d seconds, time is: %s", |
| pkt_cnt, timer_timeout, ctime(&curr_time)); |
| pkt_cnt = 0; |
| } |
| |
| static void set_signals(void) |
| { |
| struct sigaction sa; |
| int rc; |
| memset(&sa, 0, sizeof(sa)); |
| sa.sa_handler = timer_handler; |
| rc = sigaction(SIGALRM, &sa, NULL); |
| if (rc < 0) { |
| perror("sigaction failed\n"); |
| exit(1); |
| } |
| } |
| |
| /* |
| * configure timer to generate SIGALARM when fired |
| * the timer expires at every timer_timeout seconds |
| */ |
| static void set_timer(void) |
| { |
| timer_t timerid; |
| struct sigevent sev; |
| struct itimerspec its; |
| int rc; |
| |
| sev.sigev_notify = SIGEV_SIGNAL; |
| sev.sigev_signo = SIGALRM; |
| sev.sigev_value.sival_ptr = &timerid; |
| rc = timer_create(CLOCK_REALTIME, &sev, &timerid); |
| if (rc < 0) { |
| perror("timer_create failed\n"); |
| exit(1); |
| } |
| |
| its.it_value.tv_sec = timer_timeout; |
| its.it_value.tv_nsec = 0; /* don't need nanosec */ |
| its.it_interval.tv_sec = its.it_value.tv_sec; |
| its.it_interval.tv_nsec = its.it_value.tv_nsec; |
| |
| rc = timer_settime(timerid, 0, &its, NULL); |
| if (rc < 0) { |
| perror("timer_settime failed\n"); |
| exit(1); |
| } |
| } |
| |
| /* ************************************************************************ */ |
| /* |
| * A faster replacement for inet_ntoa(). |
| */ |
| char* _intoa(unsigned int addr, char* buf, u_short bufLen) |
| { |
| char *cp, *retStr; |
| u_int byte; |
| int n; |
| |
| cp = &buf[bufLen]; |
| *--cp = '\0'; |
| |
| n = 4; |
| do { |
| byte = addr & 0xff; |
| *--cp = byte % 10 + '0'; |
| byte /= 10; |
| if (byte > 0) { |
| *--cp = byte % 10 + '0'; |
| byte /= 10; |
| if (byte > 0) |
| *--cp = byte + '0'; |
| } |
| *--cp = '.'; |
| addr >>= 8; |
| } while (--n > 0); |
| |
| /* Convert the string to lowercase */ |
| retStr = (char*)(cp+1); |
| |
| return(retStr); |
| } |
| |
| /* ************************************ */ |
| |
| char* intoa(unsigned int addr) |
| { |
| static char buf[sizeof "ff:ff:ff:ff:ff:ff:255.255.255.255"]; |
| return(_intoa(addr, buf, sizeof(buf))); |
| } |
| |
| int32_t gmt2local(time_t t) |
| { |
| int dt, dir; |
| struct tm *gmt, *loc; |
| struct tm sgmt; |
| |
| if (t == 0) t = time(NULL); |
| gmt = &sgmt; |
| *gmt = *gmtime(&t); |
| loc = localtime(&t); |
| dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + |
| (loc->tm_min - gmt->tm_min) * 60; |
| |
| /* |
| * If the year or julian day is different, we span 00:00 GMT |
| * and must add or subtract a day. Check the year first to |
| * avoid problems when the julian day wraps. |
| */ |
| dir = loc->tm_year - gmt->tm_year; |
| if (dir == 0) dir = loc->tm_yday - gmt->tm_yday; |
| dt += dir * 24 * 60 * 60; |
| |
| return (dt); |
| } |
| |
| static int32_t thiszone; |
| |
| /* ************************************************************************ */ |
| |
| void processPacket(const struct pfring_pkthdr *h, u_char *p) |
| { |
| struct ether_header ehdr; |
| u_short eth_type, vlan_id; |
| struct ip ip; |
| int i, s; |
| uint usec, nsec=0; |
| |
| if (h->ts.tv_sec == 0) { |
| printf("should parse packet\n"); |
| return; |
| } |
| |
| pkt_cnt++; |
| if (verbose) { |
| printf("---------Packet received-----------\n"); |
| thiszone = gmt2local(0); |
| s = (h->ts.tv_sec + thiszone) % 86400; |
| if (h->extended_hdr.timestamp_ns) { |
| usec = (h->extended_hdr.timestamp_ns / 1000) % 1000000; |
| nsec = h->extended_hdr.timestamp_ns % 1000; |
| } else { |
| usec = h->ts.tv_usec; |
| } |
| usec = h->ts.tv_usec; |
| |
| printf("%02d:%02d:%02d.%06u%03u ", |
| s / 3600, (s % 3600) / 60, s % 60, |
| usec, nsec); |
| |
| struct pfring_extended_pkthdr *ext_hdr = &(h->extended_hdr); |
| printf("%s if_index=%d\n", |
| ext_hdr->rx_direction ? "RX" : "TX", |
| ext_hdr->if_index); |
| |
| p[ext_hdr->parsed_header_len + h->caplen] = '\0'; |
| memcpy(&ehdr, p + h->extended_hdr.parsed_header_len, sizeof(struct ether_header)); |
| eth_type = ntohs(ehdr.ether_type); |
| |
| if(eth_type == 0x8100) { |
| printf("[eth_type: 0x%04X]\n", eth_type); |
| vlan_id = (p[14] & 15) * 256 + p[15]; |
| eth_type = (p[16]) * 256 + p[17]; |
| printf("[vlan %u] ", vlan_id); |
| p += 4; |
| } |
| printf("[eth_type: 0x%04X]\n", eth_type); |
| if(eth_type == 0x0800) { |
| memcpy(&ip, p + h->extended_hdr.parsed_header_len + sizeof(ehdr), sizeof(struct ip)); |
| printf("[%s:%d ", intoa(ntohl(ip.ip_src.s_addr)), h->extended_hdr.parsed_pkt.l4_src_port); |
| printf("-> %s:%d]\n", intoa(ntohl(ip.ip_dst.s_addr)), h->extended_hdr.parsed_pkt.l4_dst_port); |
| } |
| else |
| printf("[not IPv4]\n"); |
| |
| printf("Buffer----------\n"); |
| for (i = 0; i < ext_hdr->parsed_header_len + h->caplen; i++) { |
| printf("%02X ", p[i]); |
| } |
| printf("-----------------------------------------------------------\n"); |
| } |
| } |
| |
| void printHelp(void) { |
| printf("my_test\n"); |
| printf("-h [Print help]\n"); |
| printf("-i <device> [Device name]\n"); |
| printf("-p <protocol> [Dummy protocol filter (6=tcp, 17=udp, 1=icmp)]\n"); |
| printf("-t <time> [Timer timeout]\n"); |
| printf("-v [Verbose]\n"); |
| } |
| |
| |
| int main(int argc, char** argv) |
| { |
| char *device = NULL, c; |
| filtering_rule rule; |
| struct dummy_filter *filter; |
| u_int8_t protocol = 17 /* udp */; |
| u_int32_t version; |
| int rc; |
| |
| while ((c = getopt(argc,argv,"hi:vp:t:")) != -1) { |
| switch(c) { |
| case 'h': |
| printHelp(); |
| return 0; |
| break; |
| case 'i': |
| device = strdup(optarg); |
| break; |
| case 'p': |
| protocol = atoi(optarg); |
| break; |
| case 'v': |
| verbose = 1; |
| break; |
| case 't': |
| timer_timeout = atoi(optarg); |
| break; |
| } |
| } |
| |
| if (!device) |
| device = "eth0"; |
| |
| pd = pfring_open(device, 1500, PF_RING_PROMISC | PF_RING_LONG_HEADER); |
| |
| if (pd == NULL) { |
| perror("pfring_open failed"); |
| return -1; |
| } |
| |
| pfring_version(pd, &version); |
| printf("Using PF_RING v.%d.%d.%d\n", |
| (version & 0xFFFF0000) >> 16, |
| (version & 0x0000FF00) >> 8, |
| version & 0x000000FF); |
| |
| pfring_toggle_filtering_policy(pd, 0); |
| |
| memset(&rule, 0, sizeof(rule)); |
| |
| rule.rule_id = 5; |
| rule.rule_action = forward_packet_and_stop_rule_evaluation; |
| rule.plugin_action.plugin_id = DUMMY_PLUGIN_ID; |
| rule.extended_fields.filter_plugin_id = DUMMY_PLUGIN_ID; |
| filter = (struct dummy_filter*)rule.extended_fields.filter_plugin_data; |
| filter->protocol = protocol; // default udp |
| |
| rc = pfring_add_filtering_rule(pd, &rule); |
| if (rc < 0) { |
| printf("pfring_add_filtering_rule() failed rc = %d\n", rc); |
| return -1; |
| } |
| |
| rc = pfring_enable_ring(pd); |
| if (rc < 0) { |
| printf("pfring_enable_ring() failed rc = %d\n", rc); |
| return -1; |
| } |
| |
| set_signals(); |
| set_timer(); |
| |
| while (1) { |
| u_char *buffer; |
| struct pfring_pkthdr hdr; |
| |
| rc = pfring_recv(pd, &buffer, 0, &hdr, 1); |
| switch(rc) { |
| case 0: |
| printf("No packet received\n"); |
| break; |
| case 1: |
| processPacket(&hdr, buffer); |
| break; |
| default: |
| printf("Error\n"); |
| break; |
| } |
| } |
| |
| rc = pfring_disable_ring(pd); |
| if (rc < 0) { |
| printf("pfring_disable_ring() failed rc = %d\n", rc); |
| return -1; |
| } |
| |
| pfring_close(pd); |
| return 0; |
| } |