summaryrefslogtreecommitdiff
path: root/example
diff options
context:
space:
mode:
authorzhuzhenjun <[email protected]>2023-09-16 10:43:06 +0800
committerzhuzhenjun <[email protected]>2023-09-21 15:05:11 +0800
commit91e6b79afc817f06b570b48fca67d92690bb7d27 (patch)
tree0db3fff1fb3f843df792350bd7fe6abd42a17ab6 /example
parente9b190b0697703f5e8f8ba7550ff1918deccbc72 (diff)
v0.0.0v0.0.0
Diffstat (limited to 'example')
-rw-r--r--example/Makefile.am12
-rw-r--r--example/osfp_example.c655
-rw-r--r--example/osfp_match.c129
3 files changed, 662 insertions, 134 deletions
diff --git a/example/Makefile.am b/example/Makefile.am
index c700652..f6fc004 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -1,11 +1,13 @@
-bin_PROGRAMS = osfp_match
+bin_PROGRAMS = osfp_example
-osfp_match_SOURCES = \
- osfp_match.c
+osfp_example_SOURCES = \
+ osfp_example.c
-osfp_match_LDADD = \
+osfp_example_LDADD = \
../src/.libs/libosfp.la
-osfp_match_LDFLAGS = \
+osfp_example_LDFLAGS = \
-lpcap
+osfp_example_CFLAGS = \
+ -I../src
diff --git a/example/osfp_example.c b/example/osfp_example.c
new file mode 100644
index 0000000..a6c9ab8
--- /dev/null
+++ b/example/osfp_example.c
@@ -0,0 +1,655 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+
+#include <sys/socket.h>
+
+#include <pcap.h>
+
+#include "libosfp.h"
+#include "libosfp_fingerprint.h"
+
+#define DEFAULT_FP_FILE "./fp.json"
+
+#define ETHERNET_HEADER_LEN 14
+#define VLAN_HEADER_LEN 4
+#define IPV4_HEADER_LEN 20
+#define TCP_HEADER_LEN 20
+#define IPV6_HEADER_LEN 40
+
+#define VLAN_MAX_LAYER 2
+
+
+/* Port is just a uint16_t */
+typedef uint16_t Port;
+#define SET_PORT(v, p) ((p) = (v))
+#define COPY_PORT(a,b) ((b) = (a))
+
+/* Address */
+typedef struct Address_ {
+ char family;
+ union {
+ uint32_t address_un_data32[4]; /* type-specific field */
+ uint16_t address_un_data16[8]; /* type-specific field */
+ uint8_t address_un_data8[16]; /* type-specific field */
+ struct in6_addr address_un_in6;
+ } address;
+} Address;
+
+#define addr_data32 address.address_un_data32
+#define addr_data16 address.address_un_data16
+#define addr_data8 address.address_un_data8
+#define addr_in6addr address.address_un_in6
+
+#define COPY_ADDRESS(a, b) do { \
+ (b)->family = (a)->family; \
+ (b)->addr_data32[0] = (a)->addr_data32[0]; \
+ (b)->addr_data32[1] = (a)->addr_data32[1]; \
+ (b)->addr_data32[2] = (a)->addr_data32[2]; \
+ (b)->addr_data32[3] = (a)->addr_data32[3]; \
+ } while (0)
+
+/* Set the IPv4 addresses into the Addrs of the Packet.
+ * Make sure p->ip4h is initialized and validated.
+ *
+ * We set the rest of the struct to 0 so we can
+ * prevent using memset. */
+#define SET_IPV4_SRC_ADDR(p, a) do { \
+ (a)->family = AF_INET; \
+ (a)->addr_data32[0] = (uint32_t)(p)->iph->saddr; \
+ (a)->addr_data32[1] = 0; \
+ (a)->addr_data32[2] = 0; \
+ (a)->addr_data32[3] = 0; \
+ } while (0)
+
+#define SET_IPV4_DST_ADDR(p, a) do { \
+ (a)->family = AF_INET; \
+ (a)->addr_data32[0] = (uint32_t)(p)->iph->daddr; \
+ (a)->addr_data32[1] = 0; \
+ (a)->addr_data32[2] = 0; \
+ (a)->addr_data32[3] = 0; \
+ } while (0)
+
+/* Set the IPv6 addresses into the Addrs of the Packet.
+ * Make sure p->ip6h is initialized and validated. */
+#define SET_IPV6_SRC_ADDR(p, a) do { \
+ (a)->family = AF_INET6; \
+ (a)->addr_data32[0] = (p)->ip6h->saddr.s6_addr32[0]; \
+ (a)->addr_data32[1] = (p)->ip6h->saddr.s6_addr32[1]; \
+ (a)->addr_data32[2] = (p)->ip6h->saddr.s6_addr32[2]; \
+ (a)->addr_data32[3] = (p)->ip6h->saddr.s6_addr32[3]; \
+ } while (0)
+
+#define SET_IPV6_DST_ADDR(p, a) do { \
+ (a)->family = AF_INET6; \
+ (a)->addr_data32[0] = (p)->ip6h->daddr.s6_addr32[0]; \
+ (a)->addr_data32[1] = (p)->ip6h->daddr.s6_addr32[1]; \
+ (a)->addr_data32[2] = (p)->ip6h->daddr.s6_addr32[2]; \
+ (a)->addr_data32[3] = (p)->ip6h->daddr.s6_addr32[3]; \
+ } while (0)
+
+#define TCP_GET_RAW_SRC_PORT(tcph) ntohs((tcph)->source)
+#define TCP_GET_RAW_DST_PORT(tcph) ntohs((tcph)->dest)
+
+#define TCP_GET_SRC_PORT(p) TCP_GET_RAW_SRC_PORT((p)->tcph)
+#define TCP_GET_DST_PORT(p) TCP_GET_RAW_DST_PORT((p)->tcph)
+
+/* Set the TCP ports into the Ports of the Packet.
+ * Make sure p->tcph is initialized and validated. */
+#define SET_TCP_SRC_PORT(pkt, prt) do { \
+ SET_PORT(TCP_GET_SRC_PORT((pkt)), *(prt)); \
+ } while (0)
+
+#define SET_TCP_DST_PORT(pkt, prt) do { \
+ SET_PORT(TCP_GET_DST_PORT((pkt)), *(prt)); \
+ } while (0)
+
+#define GET_IPV4_SRC_ADDR_U32(p) ((p)->src.addr_data32[0])
+#define GET_IPV4_DST_ADDR_U32(p) ((p)->dst.addr_data32[0])
+#define GET_IPV4_SRC_ADDR_PTR(p) ((p)->src.addr_data32)
+#define GET_IPV4_DST_ADDR_PTR(p) ((p)->dst.addr_data32)
+
+#define GET_IPV6_SRC_IN6ADDR(p) ((p)->src.addr_in6addr)
+#define GET_IPV6_DST_IN6ADDR(p) ((p)->dst.addr_in6addr)
+#define GET_IPV6_SRC_ADDR(p) ((p)->src.addr_data32)
+#define GET_IPV6_DST_ADDR(p) ((p)->dst.addr_data32)
+#define GET_TCP_SRC_PORT(p) ((p)->sp)
+#define GET_TCP_DST_PORT(p) ((p)->dp)
+
+
+typedef struct Packet_ {
+ struct ethhdr *ethh;
+ struct iphdr *iph;
+ struct ipv6hdr *ip6h;
+ struct tcphdr *tcph;
+
+ Address src;
+ Address dst;
+ union {
+ Port sp;
+ // icmp type and code of this packet
+ struct {
+ uint8_t type;
+ uint8_t code;
+ } icmp_s;
+ };
+ union {
+ Port dp;
+ // icmp type and code of the expected counterpart (for flows)
+ struct {
+ uint8_t type;
+ uint8_t code;
+ } icmp_d;
+ };
+
+ int vlan_layer;
+} Packet;
+
+
+unsigned char *fp_file;
+unsigned char *if_name;
+unsigned char *pcap_file_name;
+unsigned char *bpf_string;
+pcap_t *pcap_handle;
+
+int processed_packet;
+int link_type;
+
+void usage(void) {
+ fprintf(stderr,
+ "Usage: osfp_match [ ...options... ] [ 'filter rule' ]\n"
+ "\n"
+ "Network interface options:\n"
+ "\n"
+ " -i iface - listen on the specified network interface\n"
+ " -r file - read offline pcap data from a given file\n"
+ " -f file - read fingerprint database from 'file' (%s)\n",
+ DEFAULT_FP_FILE);
+ exit(1);
+}
+
+typedef struct EthernetHdr_ {
+ uint8_t eth_dst[6];
+ uint8_t eth_src[6];
+ uint16_t eth_type;
+} __attribute__((__packed__)) EthernetHdr;
+
+
+int packet_decode_tcp(Packet *p, const unsigned char *data, unsigned int len)
+{
+ int ret = -1;
+ int tcp_hdr_len;
+ struct tcphdr *tcph;
+
+ if (len < TCP_HEADER_LEN) {
+ goto exit;
+ }
+
+ tcph = (struct tcphdr *)data;
+ tcp_hdr_len = tcph->doff << 2;
+
+ if (len < tcp_hdr_len) {
+ goto exit;
+ }
+
+ p->tcph = tcph;
+ SET_TCP_SRC_PORT(p,&p->sp);
+ SET_TCP_DST_PORT(p,&p->dp);
+
+ ret = 0;
+exit:
+ return ret;
+}
+
+int packet_decode_ipv4(Packet *p, const unsigned char *data, unsigned int len)
+{
+ int ret = -1;
+ int ip_total_len, ip_hdr_len;
+ struct iphdr *iph;
+
+ if (len < IPV4_HEADER_LEN) {
+ goto exit;
+ }
+
+ iph = (struct iphdr *)data;
+ ip_total_len = ntohs(iph->tot_len);
+ ip_hdr_len = iph->ihl << 2;
+
+ if (ip_hdr_len < IPV4_HEADER_LEN) {
+ goto exit;
+ }
+
+ if (ip_total_len < ip_hdr_len) {
+ goto exit;
+ }
+
+ if (len < ip_total_len) {
+ goto exit;
+ }
+
+ p->iph = iph;
+ /* set the address struct */
+ SET_IPV4_SRC_ADDR(p,&p->src);
+ SET_IPV4_DST_ADDR(p,&p->dst);
+
+ switch (p->iph->protocol) {
+ case IPPROTO_TCP:
+ packet_decode_tcp(p, data + ip_hdr_len, ip_total_len - ip_hdr_len);
+ break;
+ default:
+ goto exit;
+ }
+
+ ret = 0;
+exit:
+ return ret;
+}
+
+int packet_decode_ipv6(Packet *p, const unsigned char *data, unsigned int len)
+{
+ int ret = -1;
+ unsigned short ip6_payload_len;
+ unsigned char ip6_nexthdr;
+ struct ipv6hdr *ip6h;
+
+ if (len < IPV6_HEADER_LEN) {
+ goto exit;
+ }
+
+ ip6h = (struct ipv6hdr *)data;
+ ip6_payload_len = ntohs(ip6h->payload_len);
+ ip6_nexthdr = ip6h->nexthdr;
+
+ if (len < IPV6_HEADER_LEN + ip6_payload_len) {
+ goto exit;
+ }
+
+ p->ip6h = ip6h;
+ SET_IPV6_SRC_ADDR(p,&p->src);
+ SET_IPV6_DST_ADDR(p,&p->dst);
+
+ switch (ip6_nexthdr) {
+ case IPPROTO_TCP:
+ packet_decode_tcp(p, data + IPV6_HEADER_LEN, ip6_payload_len);
+ break;
+ default:
+ goto exit;
+ }
+
+ ret = 0;
+exit:
+ return ret;
+}
+
+int pakcet_decode_network_layer(Packet *p, const unsigned char *data, unsigned int len, unsigned short proto)
+{
+ switch (proto) {
+ case ETH_P_IP: {
+ packet_decode_ipv4(p, data, len);
+ break;
+ }
+ case ETH_P_IPV6: {
+ packet_decode_ipv6(p, data, len);
+ break;
+ }
+ case ETH_P_8021Q:
+ if (p->vlan_layer > VLAN_MAX_LAYER || len < VLAN_HEADER_LEN) {
+ return -1;
+ }
+ unsigned short vlan_proto = ntohs(*(unsigned short*)(data + 2));
+ pakcet_decode_network_layer(p, data + VLAN_HEADER_LEN, len - VLAN_HEADER_LEN, vlan_proto);
+ break;
+ default:
+ printf("L3 proto type: %02x not yet supported\n", proto);
+ break;
+ }
+
+ return 0;
+}
+
+int packet_decode_ethernet(Packet *p, const unsigned char *data, unsigned int len)
+{
+ int ret = -1;
+ unsigned short proto;
+ struct ethhdr *ethh;
+
+ if (len < ETHERNET_HEADER_LEN) {
+ goto exit;
+ }
+
+ ethh = (struct ethhdr *)data;
+ proto = ntohs(ethh->h_proto);
+
+ p->ethh = ethh;
+
+ ret = pakcet_decode_network_layer(p, data + ETHERNET_HEADER_LEN, len - ETHERNET_HEADER_LEN, proto);
+ if (ret != 0) {
+ goto exit;
+ }
+
+ return 0;
+exit:
+ return ret;
+}
+
+void packet_decode_link_layer(Packet *p, const unsigned char *data, unsigned int len, int datalink)
+{
+ switch (datalink) {
+ case DLT_EN10MB:
+ packet_decode_ethernet(p, data, len);
+ break;
+ default:
+ printf("Datalink type: %02x not yet supported\n", link_type);
+ pcap_breakloop(pcap_handle);
+ break;
+ }
+}
+
+void packet_decode(Packet *p, const unsigned char *data, unsigned int len, int datalink)
+{
+ packet_decode_link_layer(p, data, len, datalink);
+}
+
+size_t strlcat(char *dst, const char *src, size_t siz)
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
+
+static const char *PrintInetIPv6(const void *src, char *dst, socklen_t size)
+{
+ int i;
+ char s_part[6];
+ uint16_t x[8];
+ memcpy(&x, src, 16);
+
+ /* current IPv6 format is fixed size */
+ if (size < 8 * 5) {
+ printf("Too small buffer to write IPv6 address");
+ return NULL;
+ }
+ memset(dst, 0, size);
+ for(i = 0; i < 8; i++) {
+ snprintf(s_part, sizeof(s_part), "%04x:", htons(x[i]));
+ strlcat(dst, s_part, size);
+ }
+ /* suppress last ':' */
+ dst[strlen(dst) - 1] = 0;
+
+ return dst;
+}
+
+const char *PrintInet(int af, const void *src, char *dst, socklen_t size)
+{
+ switch (af) {
+ case AF_INET:
+ snprintf(dst, size, "%u.%u.%u.%u",
+ ((unsigned char *)src)[0],
+ ((unsigned char *)src)[1],
+ ((unsigned char *)src)[2],
+ ((unsigned char *)src)[3]);
+ return dst;
+ case AF_INET6:
+ /* Format IPv6 without deleting zeroes */
+ return PrintInetIPv6(src, dst, size);
+ default:
+ printf("Unsupported protocol: %d", af);
+ }
+ return NULL;
+}
+
+void example_header_match(libosfp_context_t *libosfp_context, Packet *p)
+{
+ // tcp/ip header match
+ int ret;
+ char str_buf[1024];
+
+ unsigned char *iph = (unsigned char *)(p->iph != NULL ? (void *)p->iph : (void *)p->ip6h);
+ unsigned char *tcph = (unsigned char *)p->tcph;
+ libosfp_result_t result;
+
+ printf("Example header match: --------------------------\n");
+
+ ret = libosfp_header_match(libosfp_context, iph, tcph, &result);
+ if (ret != 0) {
+ printf("libosfp header match failed, erro: %s\n", "?");
+ goto exit;
+ }
+
+ char srcip[46] = {0}, dstip[46] = {0};
+ Port sp, dp;
+ if (p->iph) {
+ PrintInet(AF_INET, (const void *)&(p->src.addr_data32[0]), srcip, sizeof(srcip));
+ PrintInet(AF_INET, (const void *)&(p->dst.addr_data32[0]), dstip, sizeof(dstip));
+ } else if (p->ip6h) {
+ PrintInet(AF_INET6, (const void *)&(p->src.address), srcip, sizeof(srcip));
+ PrintInet(AF_INET6, (const void *)&(p->dst.address), dstip, sizeof(dstip));
+ }
+ sp = p->sp;
+ dp = p->dp;
+
+ printf("Connection info: %s:%d -> %s:%d\n", srcip, sp, dstip, dp);
+ printf("Most likely os class: %s\n", libosfp_result_likely_os_class_name_get(&result));
+ printf("Likely score: %u/100\n", libosfp_result_likely_os_class_score_get(&result));
+
+ libosfp_result_to_buf(&result, str_buf, sizeof(str_buf));
+ fprintf(stdout, "%s\n", str_buf);
+
+exit:
+ return;
+}
+
+void example_fingerprint_match(libosfp_context_t *libosfp_context, Packet *p)
+{
+ // fingerprint match
+ int ret;
+ char str_buf[1024];
+
+ unsigned char *iph = (unsigned char *)(p->iph != NULL ? (void *)p->iph : (void *)p->ip6h);
+ unsigned char *tcph = (unsigned char *)p->tcph;
+ libosfp_result_t result;
+ libosfp_fingerprint_t fp;
+
+ printf("Example fingerprint match: --------------------------\n");
+
+ ret = libosfp_fingerprinting(iph, tcph, &fp);
+ if (ret != 0) {
+ printf("libosfp fingerprinting failed\n");
+ goto exit;
+ }
+
+ libosfp_fingerprint_to_json_buf(&fp, str_buf, sizeof(str_buf));
+ fprintf(stdout, "%s\n", str_buf);
+
+ ret = libosfp_score_db_score(libosfp_context, &fp, &result);
+ if (ret != 0) {
+ printf("libosfp fingerprint score failed, error: %d\n", ret);
+ goto exit;
+ }
+
+ printf("Connection info: %s\n", "");
+ printf("Most likely os class: %s\n", libosfp_result_likely_os_class_name_get(&result));
+ printf("Likely score: %u/100\n", libosfp_result_likely_os_class_score_get(&result));
+
+ libosfp_result_to_buf(&result, str_buf, sizeof(str_buf));
+ fprintf(stdout, "%s\n", str_buf);
+
+exit:
+ return;
+}
+
+void process_packet(char *user, struct pcap_pkthdr *h, u_char *pkt)
+{
+ int ret;
+ libosfp_context_t *libosfp_context = (libosfp_context_t *)user;
+ Packet packet = {0}, *p = &packet;
+
+ // decode packet
+ packet_decode(p, pkt, h->len, link_type);
+ if (p->tcph == NULL || (p->iph == NULL && p->ip6h == NULL)) {
+ goto exit;
+ }
+
+ // only for tcp syn request packet
+ if (!p->tcph->syn || p->tcph->ack) {
+ goto exit;
+ }
+
+ example_header_match(libosfp_context, p);
+
+ example_fingerprint_match(libosfp_context, p);
+
+ printf("--------------------------- processed packet count %d\n", ++processed_packet);
+
+exit:
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ int r;
+
+ while ((r = getopt(argc, argv, "+f:i:r:")) != -1) {
+ switch(r) {
+ case 'f':
+ if (fp_file) {
+ printf("Multiple -f options not supported.\n");
+ exit(1);
+ }
+ fp_file = (unsigned char*)optarg;
+ break;
+ case 'i':
+ if (if_name) {
+ printf("Multiple -i options not supported.\n");
+ exit(1);
+ }
+ if_name = (unsigned char*)optarg;
+ break;
+ case 'r':
+ if (pcap_file_name) {
+ printf("Multiple -r options not supported.\n");
+ exit(1);
+ }
+ pcap_file_name = (unsigned char*)optarg;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ if (optind + 1 == argc) {
+ bpf_string = argv[optind];
+ } else {
+ printf("Filter rule must be a single parameter (use quotes).\n");
+ exit(1);
+ }
+ }
+
+ // prepare pcap handle
+
+ char pcap_err[PCAP_ERRBUF_SIZE];
+
+ if (pcap_file_name) {
+ if (access((char*)pcap_file_name, R_OK)) {
+ printf("No such file: %s\n", pcap_file_name);
+ exit(1);
+ }
+ pcap_handle = pcap_open_offline((char*)pcap_file_name, pcap_err);
+ if (pcap_handle == NULL ) {
+ printf("Pcap file open failed. File name: %s, Err: %s\n", pcap_file_name, pcap_err);
+ exit(1);
+ }
+ } else if (if_name) {
+ pcap_handle = pcap_open_live((char*)if_name, 65535, 1, 5, pcap_err);
+ if (pcap_handle == NULL) {
+ printf("Pcap live open failed. Interface name: %s, Err: %s\n", if_name, pcap_err);
+ exit(1);
+ }
+ } else {
+ usage();
+ }
+
+ // setup bpf filter
+ if (bpf_string) {
+ struct bpf_program bpf_filter;
+
+ if (pcap_compile(pcap_handle, &bpf_filter, bpf_string, 1, 0) < 0) {
+ printf("bpf compilation error %s", pcap_geterr(pcap_handle));
+ exit(1);
+ }
+
+ if (pcap_setfilter(pcap_handle, &bpf_filter) < 0) {
+ printf("could not set bpf filter %s", pcap_geterr(pcap_handle));
+ pcap_freecode(&bpf_filter);
+ exit(1);
+ }
+ pcap_freecode(&bpf_filter);
+ }
+
+ // get link type
+ link_type = pcap_datalink(pcap_handle);
+
+ // create libosfp context
+ if (fp_file == NULL) {
+ fp_file = DEFAULT_FP_FILE;
+ }
+
+ libosfp_context_t *libosfp_context = libosfp_context_create(fp_file);
+ if (libosfp_context == NULL) {
+ printf("could not create libosfp context. fingerprints file: %s\n", fp_file);
+ exit(1);
+ }
+
+ // setup libosfp context
+ r = libosfp_context_setup(libosfp_context);
+ if (r != LIBOSFP_NOERR) {
+ printf("could not setup libosfp context. error: %d\n", LIBOSFP_NOERR);
+ exit(1);
+ }
+
+ // loop
+ while (1) {
+ int r = pcap_dispatch(pcap_handle, 0, (pcap_handler)process_packet, (void*)libosfp_context);
+ if (r < 0) {
+ printf("error code: %d, error: %s\n", r, pcap_geterr(pcap_handle));
+ break;
+ }
+ }
+
+ // create libosfp context
+ libosfp_context_destroy(libosfp_context);
+
+ return 0;
+}
+
diff --git a/example/osfp_match.c b/example/osfp_match.c
deleted file mode 100644
index efde9c2..0000000
--- a/example/osfp_match.c
+++ /dev/null
@@ -1,129 +0,0 @@
-#include <stdio.h>
-#include <time.h>
-#include <pcap.h>
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-unsigned char *fp_file;
-unsigned char *if_name;
-unsigned char *pcap_file_name;
-unsigned char *bpf_string;
-
-int processed_packet;
-
-void usage(void) {
- fprintf(stderr,
- "Usage: osfp_match [ ...options... ] [ 'filter rule' ]\n"
- "\n"
- "Network interface options:\n"
- "\n"
- " -i iface - listen on the specified network interface\n"
- " -r file - read offline pcap data from a given file\n"
- " -f file - read fingerprint database from 'file' (%s)\n"
- );
- exit(1);
-}
-
-void process_packet(char *user, struct pcap_pkthdr *h, u_char *pkt)
-{
- printf("packet count %d\n", ++processed_packet);
-}
-
-int main(int argc, char *argv[])
-{
- int r;
-
- while ((r = getopt(argc, argv, "+f:i:r")) != -1) {
- switch(r) {
- case 'f':
- if (fp_file) {
- printf("Multiple -f options not supported.\n");
- exit(1);
- }
- fp_file = (unsigned char*)optarg;
- break;
- case 'i':
- if (if_name) {
- printf("Multiple -i options not supported.\n");
- exit(1);
- }
- if_name = (unsigned char*)optarg;
- break;
- case 'r':
- if (pcap_file_name) {
- printf("Multiple -r options not supported.\n");
- exit(1);
- }
- pcap_file_name = (unsigned char*)optarg;
- break;
- default:
- usage();
- break;
- }
- }
-
- if (optind < argc) {
- if (optind + 1 == argc) {
- bpf_string = argv[optind];
- } else {
- printf("Filter rule must be a single parameter (use quotes).\n");
- exit(1);
- }
- }
-
- // prepare pcap handle
-
- char pcap_err[PCAP_ERRBUF_SIZE];
- pcap_t *pcap_handle;
-
- if (pcap_file_name) {
- if (access((char*)pcap_file_name, R_OK)) {
- printf("No such file: %s\n", pcap_file_name);
- exit(1);
- }
- pcap_handle = pcap_open_offline((char*)pcap_file_name, pcap_err);
- if (pcap_handle == NULL ) {
- printf("Pcap file open failed. File name: %s, Err: %s\n", pcap_file_name, pcap_err);
- exit(1);
- }
- } else if (if_name) {
- pcap_handle = pcap_open_live((char*)if_name, 65535, 1, 5, pcap_err);
- if (pcap_handle == NULL) {
- printf("Pcap live open failed. Interface name: %s, Err: %s\n", if_name, pcap_err);
- exit(1);
- }
- } else {
- usage();
- }
-
- // setup bpf filter
- if (bpf_string) {
- struct bpf_program bpf_filter;
-
- if (pcap_compile(pcap_handle, &bpf_filter, bpf_string, 1, 0) < 0) {
- printf("bpf compilation error %s", pcap_geterr(pcap_handle));
- exit(1);
- }
-
- if (pcap_setfilter(pcap_handle, &bpf_filter) < 0) {
- printf("could not set bpf filter %s", pcap_geterr(pcap_handle));
- pcap_freecode(&bpf_filter);
- exit(1);
- }
- pcap_freecode(&bpf_filter);
- }
-
- // loop
- while (1) {
- int r = pcap_dispatch(pcap_handle, 0, (pcap_handler)process_packet, NULL);
- if (r < 0) {
- printf("error code: %d, error: %s\n", r, pcap_geterr(pcap_handle));
- break;
- }
- }
-
- return 0;
-}
-