$OpenBSD: patch-ngrep_c,v 1.6 2011/06/18 14:02:38 kili Exp $
--- ngrep.c.orig	Tue Nov 28 14:38:43 2006
+++ ngrep.c	Sat Jun 18 14:55:32 2011
@@ -60,6 +60,7 @@
 #include <config.h>
 
 #define strcasecmp stricmp
+#define strncasecmp strnicmp
 
 #else
 
@@ -74,6 +75,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
+#include <locale.h>
 
 #if !defined(_WIN32)
 #include <errno.h>
@@ -92,7 +94,7 @@
 #endif
 
 #if USE_PCRE
-#include "pcre-5.0/pcre.h"
+#include "pcre.h"
 #else
 #include "regex-0.12/regex.h"
 #endif
@@ -114,6 +116,7 @@ uint8_t  show_empty = 0, show_hex = 0, show_proto = 0,
 uint8_t  invert_match = 0, bin_match = 0;
 uint8_t  live_read = 1, want_delay = 0;
 uint8_t  dont_dropprivs = 0;
+uint8_t  enable_hilite = 0;
 
 char *read_file = NULL, *dump_file = NULL;
 char *usedev = NULL;
@@ -145,7 +148,7 @@ uint16_t match_len = 0;
 int8_t (*match_func)() = &blank_match_func;
 
 int8_t dump_single = 0;
-void (*dump_func)(unsigned char *, uint32_t) = &dump_formatted;
+void (*dump_func)(unsigned char *, uint32_t, uint16_t, uint16_t) = &dump_formatted;
 
 /*
  * BPF/Network
@@ -153,10 +156,10 @@ void (*dump_func)(unsigned char *, uint32_t) = &dump_f
 
 char *filter = NULL, *filter_file = NULL;
 char pc_err[PCAP_ERRBUF_SIZE];
-uint8_t link_offset;
+uint8_t link_offset, vlan_offset = 0;
 uint8_t radiotap_present = 0;
 
-pcap_t *pd = NULL;
+pcap_t *pd = NULL, *pd_dumppcap = NULL;
 pcap_dumper_t *pd_dump = NULL;
 struct bpf_program pcapfilter;
 struct in_addr net, mask;
@@ -176,8 +179,7 @@ void (*print_time)() = NULL, (*dump_delay)() = dump_de
 
 
 /*
- * When !Win32, windowsize stuff.  We leave it in regardless to avoid
- * any additional #if complication/obfuscation.
+ * Window-size functionality (adjust output based on width of console display)
  */
 
 uint32_t ws_row, ws_col = 80, ws_col_forced = 0;
@@ -195,7 +197,17 @@ int main(int argc, char **argv) {
     signal(SIGWINCH, update_windowsize);
 #endif
 
-    while ((c = getopt(argc, argv, "LNhXViwqpevxlDtTRMs:n:c:d:A:I:O:S:P:F:W:")) != EOF) {
+#if !defined(_WIN32)
+    {
+        char const *locale = getenv("LANG");
+        if (locale == NULL)
+            locale = "en_US";
+
+        setlocale(LC_CTYPE, locale);
+    }
+#endif
+
+    while ((c = getopt(argc, argv, "LNhXViwqpevxlDtTRMCs:n:c:d:A:I:O:S:P:F:W:")) != EOF) {
         switch (c) {
             case 'W': {
                 if (!strcasecmp(optarg, "normal"))
@@ -257,6 +269,9 @@ int main(int argc, char **argv) {
                 if (value > 0)
                     snaplen = value;
             } break;
+            case 'C':
+                enable_hilite = 1;
+                break;
             case 'M':
                 re_multiline_match = 0;
                 break;
@@ -264,13 +279,18 @@ int main(int argc, char **argv) {
                 dont_dropprivs = 1;
                 break;
             case 'T':
-                print_time = &print_time_diff;
+                if (print_time == &print_time_diff) {
+                    print_time = print_time_offset;
+                    memset(&prev_ts, 0, sizeof(prev_ts));
+                } else {
+                    print_time = &print_time_diff;
 #if defined(_WIN32)
-                prev_ts.tv_sec  = (uint32_t)time(NULL);
-                prev_ts.tv_usec = 0;
+                    prev_ts.tv_sec  = (uint32_t)time(NULL);
+                    prev_ts.tv_usec = 0;
 #else
-                gettimeofday(&prev_ts, NULL);
+                    gettimeofday(&prev_ts, NULL);
 #endif
+                }
                 break;
             case 't':
                 print_time = &print_time_absolute;
@@ -337,7 +357,12 @@ int main(int argc, char **argv) {
 
     } else {
 
-        char *dev = usedev ? usedev : pcap_lookupdev(pc_err);
+        char *dev = usedev ? usedev :
+#if defined(_WIN32)
+            win32_choosedevice();
+#else
+            pcap_lookupdev(pc_err);
+#endif
 
         if (!dev) {
             perror(pc_err);
@@ -391,7 +416,7 @@ int main(int argc, char **argv) {
             filter = get_filter_from_argv(&argv[optind-1]);
 
 #if USE_PCAP_RESTART
-            PCAP_RESTART_FUNC();
+            PCAP_RESTART_FUNC(NULL);
 #endif
             if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) {
                 pcap_perror(pd, "pcap compile");
@@ -408,6 +433,17 @@ int main(int argc, char **argv) {
         }
     }
 
+    /* VLAN support: determine # of +4 offsets to accommodate */
+    if (filter) {
+        char const bpf_vlan[] = "vlan";
+        char *s = filter;
+        while (*s)
+            if (strncasecmp(s++, bpf_vlan, sizeof(bpf_vlan)-1) == 0)
+                vlan_offset++;
+
+        vlan_offset *= VLANHDR_SIZE;
+    }
+
     if (filter && quiet < 2)
         printf("filter: %s\n", filter);
 
@@ -549,6 +585,10 @@ int main(int argc, char **argv) {
             link_offset = PPPHDR_SIZE;
             break;
 
+        case DLT_PPP_ETHER:
+            link_offset = PPPOEHDR_SIZE;
+            break;
+
 #if HAVE_DLT_LOOP
         case DLT_LOOP:
 #endif
@@ -579,21 +619,28 @@ int main(int argc, char **argv) {
             break;
 #endif
 
+#if HAVE_DLT_PFLOG
+        case DLT_PFLOG:
+            link_offset = PFLOGHDR_SIZE;
+            break;
+#endif
+
         default:
             fprintf(stderr, "fatal: unsupported interface type %u\n", pcap_datalink(pd));
             clean_exit(-1);
     }
 
+    link_offset += vlan_offset;
+
     if (dump_file) {
-        if (!(pd_dump = pcap_dump_open(pd, dump_file))) {
+        pd_dump = pcap_dump_open(pd, dump_file);
+        if (!pd_dump) {
             fprintf(stderr, "fatal: %s\n", pcap_geterr(pd));
             clean_exit(-1);
         } else printf("output: %s\n", dump_file);
     }
 
-#if !defined(_WIN32)
     update_windowsize(0);
-#endif
 
 #if defined(_WIN32)
     win32_initwinsock();
@@ -603,7 +650,7 @@ int main(int argc, char **argv) {
     drop_privs();
 #endif
 
-    while (pcap_loop(pd, 0, (pcap_handler)process, 0));
+    while (pcap_loop(pd, -1, (pcap_handler)process, 0));
 
     clean_exit(0);
 
@@ -699,11 +746,6 @@ void process(u_char *d, struct pcap_pkthdr *h, u_char 
             data = (unsigned char *)(tcp_pkt) + tcphdr_offset;
             len -= link_offset + ip_hl + tcphdr_offset;
 
-#if USE_IPv6
-            if (ip_ver == 6)
-                len -= ntohs(ip6_pkt->ip6_plen);
-#endif
-
             if ((int32_t)len < 0)
                 len = 0;
 
@@ -719,20 +761,11 @@ void process(u_char *d, struct pcap_pkthdr *h, u_char 
             data = (unsigned char *)(udp_pkt) + udphdr_offset;
             len -= link_offset + ip_hl + udphdr_offset;
 
-#if USE_IPv6
-            if (ip_ver == 6)
-                len -= ntohs(ip6_pkt->ip6_plen);
-#endif
-
             if ((int32_t)len < 0)
                 len = 0;
 
             dump_packet(h, p, ip_proto, data, len, ip_src, ip_dst,
-#if HAVE_DUMB_UDPHDR
-                        ntohs(udp_pkt->source), ntohs(udp_pkt->dest), 0,
-#else
                         ntohs(udp_pkt->uh_sport), ntohs(udp_pkt->uh_dport), 0,
-#endif
                         udphdr_offset, fragmented, frag_offset, frag_id);
         } break;
 
@@ -757,7 +790,7 @@ void process(u_char *d, struct pcap_pkthdr *h, u_char 
             uint16_t icmp6hdr_offset    = (frag_offset) ? 0 : 4;
 
             data = (unsigned char *)(icmp6_pkt) + icmp6hdr_offset;
-            len -= link_offset + ip_hl + ntohs(ip6_pkt->ip6_plen) + icmp6hdr_offset;
+            len -= link_offset + ip_hl + icmp6hdr_offset;
 
             if ((int32_t)len < 0)
                 len = 0;
@@ -808,13 +841,15 @@ void dump_packet(struct pcap_pkthdr *h, u_char *p, uin
                  const char *ip_src, const char *ip_dst, uint16_t sport, uint16_t dport, uint8_t flags,
                  uint16_t hdr_offset, uint8_t frag, uint16_t frag_offset, uint32_t frag_id) {
 
+    uint16_t match_size, match_index;
+
     if (!show_empty && len == 0)
         return;
 
     if (len > limitlen)
         len = limitlen;
 
-    if ((len > 0 && match_func(data, len) == invert_match) && !keep_matching)
+    if ((len > 0 && match_func(data, len, &match_index, &match_size) == invert_match) && !keep_matching)
         return;
 
     if (!live_read && want_delay)
@@ -879,15 +914,17 @@ void dump_packet(struct pcap_pkthdr *h, u_char *p, uin
         printf("\n");
 
     if (quiet < 3)
-        dump_func(data, len);
+        dump_func(data, len, match_index, match_size);
 
     if (pd_dump)
         pcap_dump((u_char*)pd_dump, h, p);
 }
 
-int8_t re_match_func(unsigned char *data, uint32_t len) {
+int8_t re_match_func(unsigned char *data, uint32_t len, uint16_t *mindex, uint16_t *msize) {
 #if USE_PCRE
-    switch(pcre_exec(pattern, 0, data, (int32_t)len, 0, 0, 0, 0)) {
+
+    static int sub[2];
+    switch(pcre_exec(pattern, 0, (char const *)data, (int32_t)len, 0, 0, 0, 0)) {
         case PCRE_ERROR_NULL:
         case PCRE_ERROR_BADOPTION:
         case PCRE_ERROR_BADMAGIC:
@@ -898,15 +935,25 @@ int8_t re_match_func(unsigned char *data, uint32_t len
 
         case PCRE_ERROR_NOMATCH:
             return 0;
+
+        default:
+            *mindex = sub[0];
+            *msize  = sub[1] - sub[0];
     }
 #else
-    switch (re_search(&pattern, data, (int32_t)len, 0, len, 0)) {
+
+    static struct re_registers regs;
+    switch (re_search(&pattern, (char const *)data, (int32_t)len, 0, len, &regs)) {
         case -2:
             perror("she's dead, jim\n");
             clean_exit(-2);
 
         case -1:
             return 0;
+
+        default:
+            *mindex = regs.start[0];
+            *msize  = regs.end[0] - regs.start[0];
     }
 #endif
 
@@ -919,7 +966,7 @@ int8_t re_match_func(unsigned char *data, uint32_t len
     return 1;
 }
 
-int8_t bin_match_func(unsigned char *data, uint32_t len) {
+int8_t bin_match_func(unsigned char *data, uint32_t len, uint16_t *mindex, uint16_t *msize) {
     int32_t stop = len - match_len;
     int32_t i    = 0;
 
@@ -934,71 +981,118 @@ int8_t bin_match_func(unsigned char *data, uint32_t le
             if (match_after && keep_matching != match_after)
                 keep_matching = match_after;
 
+            *mindex = i - 1;
+            *msize  = match_len;
+
             return 1;
         }
 
     return 0;
 }
 
-
-int8_t blank_match_func(unsigned char *data, uint32_t len) {
+int8_t blank_match_func(unsigned char *data, uint32_t len, uint16_t *mindex, uint16_t *msize) {
     if (max_matches)
         matches++;
 
+    *mindex = 0;
+    *msize  = 0;
+
     return 1;
 }
 
-void dump_byline(unsigned char *data, uint32_t len) {
+void dump_byline(unsigned char *data, uint32_t len, uint16_t mindex, uint16_t msize) {
     if (len > 0) {
-        const unsigned char *s = data;
+        const unsigned char *s      = data;
+        uint8_t should_hilite       = (msize && enable_hilite);
+        unsigned char *hilite_start = data + mindex;
+        unsigned char *hilite_end   = hilite_start + msize;
 
         while (s < data + len) {
+            if (should_hilite && s == hilite_start)
+                printf(ANSI_hilite);
+
             printf("%c", (*s == '\n' || isprint(*s)) ? *s : nonprint_char);
             s++;
+
+            if (should_hilite && s == hilite_end)
+                printf(ANSI_off);
         }
 
         printf("\n");
     }
 }
 
-void dump_unwrapped(unsigned char *data, uint32_t len) {
+void dump_unwrapped(unsigned char *data, uint32_t len, uint16_t mindex, uint16_t msize) {
     if (len > 0) {
-        const unsigned char *s = data;
+        const unsigned char *s      = data;
+        uint8_t should_hilite       = (msize && enable_hilite);
+        unsigned char *hilite_start = data + mindex;
+        unsigned char *hilite_end   = hilite_start + msize;
 
         while (s < data + len) {
+            if (should_hilite && s == hilite_start)
+                printf(ANSI_hilite);
+
             printf("%c", isprint(*s) ? *s : nonprint_char);
             s++;
+
+            if (should_hilite && s == hilite_end)
+                printf(ANSI_off);
         }
 
         printf("\n");
     }
 }
 
-void dump_formatted(unsigned char *data, uint32_t len) {
+void dump_formatted(unsigned char *data, uint32_t len, uint16_t mindex, uint16_t msize) {
     if (len > 0) {
-        unsigned char *str = data;
-             uint8_t width = show_hex ? 16 : (ws_col-5);
-                uint32_t i = 0,
-                         j = 0;
+        uint8_t should_hilite = (msize && enable_hilite);
+           unsigned char *str = data;
+             uint8_t hiliting = 0;
+                uint8_t width = show_hex ? 16 : (ws_col-5);
+                   uint32_t i = 0,
+                            j = 0;
 
         while (i < len) {
             printf("  ");
 
-            if (show_hex)
+            if (show_hex) {
                 for (j = 0; j < width; j++) {
+                    if (should_hilite && (mindex <= (i+j) && (i+j) < mindex + msize)) {
+                        hiliting = 1;
+                        printf(ANSI_hilite);
+                    }
+
                     if (i + j < len)
                         printf("%02x ", str[j]);
                     else printf("   ");
 
                     if ((j+1) % (width/2) == 0)
                         printf("   ");
+
+                    if (hiliting) {
+                        hiliting = 0;
+                        printf(ANSI_off);
+                    }
                 }
+            }
 
-            for (j = 0; j < width; j++)
+            for (j = 0; j < width; j++) {
+                if (should_hilite && mindex <= (i+j) && (i+j) < mindex + msize) {
+                    hiliting = 1;
+                    printf(ANSI_hilite);
+                }
+
                 if (i + j < len)
                     printf("%c", isprint(str[j]) ? str[j] : nonprint_char);
                 else printf(" ");
 
+                if (hiliting) {
+                    hiliting = 0;
+                    printf(ANSI_off);
+                }
+            }
+
             str += width;
             i   += j;
 
@@ -1104,6 +1198,27 @@ void print_time_diff(struct pcap_pkthdr *h) {
     prev_ts.tv_usec = h->ts.tv_usec;
 }
 
+void print_time_offset(struct pcap_pkthdr *h) {
+    uint32_t secs, usecs;
+
+    secs = h->ts.tv_sec - prev_ts.tv_sec;
+    if (h->ts.tv_usec >= prev_ts.tv_usec)
+        usecs = h->ts.tv_usec - prev_ts.tv_usec;
+    else {
+        secs--;
+        usecs = 1000000 - (prev_ts.tv_usec - h->ts.tv_usec);
+    }
+
+    if (prev_ts.tv_sec == 0 && prev_ts.tv_usec == 0) {
+        prev_ts.tv_sec  = h->ts.tv_sec;
+        prev_ts.tv_usec = h->ts.tv_usec;
+        secs  = 0;
+        usecs = 0;
+    }
+
+    printf("+%u.%06u ", secs, usecs);
+}
+
 void dump_delay_proc_init(struct pcap_pkthdr *h) {
     dump_delay = &dump_delay_proc;
 
@@ -1155,26 +1270,36 @@ void dump_delay_proc(struct pcap_pkthdr *h) {
     prev_delay_ts.tv_usec = h->ts.tv_usec;
 }
 
-#if !defined(_WIN32)
 void update_windowsize(int32_t e) {
     if (e == 0 && ws_col_forced)
 
         ws_col = ws_col_forced;
 
     else if (!ws_col_forced) {
+
+#if !defined(_WIN32)
         const struct winsize ws;
 
         if (!ioctl(0, TIOCGWINSZ, &ws)) {
             ws_row = ws.ws_row;
             ws_col = ws.ws_col;
-        } else {
+        }
+#else
+        CONSOLE_SCREEN_BUFFER_INFO csbi;
+        if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
+            ws_row = csbi.dwSize.Y;
+            ws_col = csbi.dwSize.X;
+        }
+#endif
+        else {
             ws_row = 24;
             ws_col = 80;
         }
+
     }
 }
 
-#if USE_DROPPRIVS
+#if !defined(_WIN32) && USE_DROPPRIVS
 void drop_privs(void) {
     struct passwd *pw;
     uid_t newuid;
@@ -1197,6 +1322,14 @@ void drop_privs(void) {
             perror("attempt to drop privileges failed");
             clean_exit(-1);
         }
+    if (chroot("/var/empty") == -1) {
+        perror("attempt to drop privileges failed: chroot failed");
+        clean_exit(-1);
+    }
+    if (chdir("/") == -1) {
+        perror("attempt to drop privileges failed: chdir failed");
+        clean_exit(-1);
+    }
 
     if (((getgid()  != newgid) && (setgid(newgid)  == -1)) ||
         ((getegid() != newgid) && (setegid(newgid) == -1)) ||
@@ -1209,7 +1342,6 @@ void drop_privs(void) {
 }
 
 #endif
-#endif
 
 void usage(int8_t e) {
     printf("usage: ngrep <-"
@@ -1234,6 +1366,7 @@ void usage(int8_t e) {
            "   -D  is replay pcap_dumps with their recorded time intervals\n"
            "   -t  is print timestamp every time a packet is matched\n"
            "   -T  is print delta timestamp every time a packet is matched\n"
+           "         specify twice for delta from first match\n"
            "   -M  is don't do multi-line match (do single-line match instead)\n"
            "   -I  is read packet stream from pcap format file pcap_dump\n"
            "   -O  is dump matched packets in pcap format to pcap_dump\n"
@@ -1292,8 +1425,9 @@ void clean_exit(int32_t sig) {
      && pd && !pcap_stats(pd, &s))
         printf("%u received, %u dropped\n", s.ps_recv, s.ps_drop);
 
-    if (pd)      pcap_close(pd);
-    if (pd_dump) pcap_dump_close(pd_dump);
+    if (pd)           pcap_close(pd);
+    if (pd_dumppcap)  pcap_close(pd_dumppcap);
+    if (pd_dump)      pcap_dump_close(pd_dump);
 
 #if defined(_WIN32)
     if (delay_socket) closesocket(delay_socket);
@@ -1379,6 +1513,28 @@ char *win32_usedevice(const char *index) {
     }
 
     pcap_freealldevs(alldevs);
+
+    return dev;
+}
+
+char *win32_choosedevice(void) {
+    pcap_if_t *alldevs, *d;
+    char errbuf[PCAP_ERRBUF_SIZE];
+    char *dev = NULL;
+
+    if (pcap_findalldevs(&alldevs, errbuf) == -1) {
+        perror("unable to enumerate devices");
+        clean_exit(-1);
+    }
+
+    for (d = alldevs; d != NULL; d = d->next)
+        if ((d->addresses) && (d->addresses->addr))
+            dev = _strdup(d->name);
+
+    pcap_freealldevs(alldevs);
+
+    if (!dev)
+        dev = pcap_lookupdev(errbuf);
 
     return dev;
 }
