├── VERSION ├── regex-0.12 ├── ChangeLog ├── AUTHORS ├── configure.in ├── NEWS ├── README ├── doc │ └── Makefile.in ├── Makefile.in ├── test │ └── Makefile.in ├── INSTALL └── install-sh ├── testdata ├── .gitignore ├── utf8.pcap.xz ├── radiotap.pcap.xz └── no_radiotap.pcap.xz ├── winXX ├── .gitignore ├── getopt.h ├── inet_ntop.h ├── wcwidth.h ├── config.h ├── CMakeLists.txt ├── getopt.c ├── wcwidth.c ├── inet_ntop.c └── types.h ├── .gitignore ├── tcpkill.h ├── .dockerignore ├── .github ├── workflows │ ├── build.yml │ ├── docker.yml │ ├── release.yml │ └── matrix.yml ├── WORKFLOW-STRUCTURE.md └── RELEASE.md ├── Dockerfile ├── Dockerfile.ubuntu ├── CREDITS ├── tcpkill.c ├── config.h.in ├── scripts └── multi.pl ├── INSTALL ├── Makefile.in ├── LICENSE ├── ngrep.h ├── README.md ├── DOCKER.md ├── missing ├── compile ├── ngrep.8 ├── install-sh └── EXAMPLES.md /VERSION: -------------------------------------------------------------------------------- 1 | 1.48.3 2 | -------------------------------------------------------------------------------- /regex-0.12/ChangeLog: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testdata/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*.xz 3 | -------------------------------------------------------------------------------- /testdata/utf8.pcap.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpr5/ngrep/HEAD/testdata/utf8.pcap.xz -------------------------------------------------------------------------------- /testdata/radiotap.pcap.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpr5/ngrep/HEAD/testdata/radiotap.pcap.xz -------------------------------------------------------------------------------- /testdata/no_radiotap.pcap.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpr5/ngrep/HEAD/testdata/no_radiotap.pcap.xz -------------------------------------------------------------------------------- /winXX/.gitignore: -------------------------------------------------------------------------------- 1 | *.sdf 2 | *.opensdf 3 | *.suo 4 | *.vcxproj.* 5 | Debug/ 6 | Release/ 7 | build/ 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ngrep 2 | *.o 3 | Makefile 4 | autom4te.cache 5 | config.h 6 | config.log 7 | config.status 8 | stamp-h1 9 | -------------------------------------------------------------------------------- /winXX/getopt.h: -------------------------------------------------------------------------------- 1 | 2 | #define _next_char(string) (char)(*(string+1)) 3 | 4 | extern char * optarg; 5 | extern int optind; 6 | 7 | int getopt(int, char**, char*); 8 | 9 | -------------------------------------------------------------------------------- /tcpkill.h: -------------------------------------------------------------------------------- 1 | #ifndef TCPKILL_H 2 | #define TCPKILL_H 3 | 4 | void tcpkill_init(void); 5 | void tcpkill_kill(const struct pcap_pkthdr *pcap, const u_char *pkt, uint32_t pcap_off, uint32_t kill_count); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /winXX/inet_ntop.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: inet_ntop.h,v 1.1 2005/04/27 22:29:58 jpr5 Exp $ 3 | * 4 | * Compatibility header, supporting WinXX-specific inet_ntop() implementation. 5 | */ 6 | 7 | int inet_ntop(int af, const void *src, char *dst, size_t size); 8 | -------------------------------------------------------------------------------- /winXX/wcwidth.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wcwidth() implementation for Windows 3 | * Based on Markus Kuhn's public domain implementation 4 | */ 5 | 6 | #ifndef WCWIDTH_H 7 | #define WCWIDTH_H 8 | 9 | #include 10 | 11 | /* Determine the column width of a wide character */ 12 | int wcwidth(wchar_t ucs); 13 | 14 | #endif /* WCWIDTH_H */ 15 | -------------------------------------------------------------------------------- /regex-0.12/AUTHORS: -------------------------------------------------------------------------------- 1 | Richard Stallman -- original version and continuing revisions of 2 | regex.c and regex.h, and original version of the documentation. 3 | 4 | Karl Berry and Kathryn Hargreaves -- extensive modifications to above, 5 | and all test files. 6 | 7 | Jim Blandy -- original version of re_set_registers, revisions to regex.c. 8 | 9 | Joe Arceneaux, David MacKenzie, Mike Haertel, Charles Hannum, and 10 | probably others -- revisions to regex.c. 11 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # Git 2 | .git 3 | .github 4 | .gitignore 5 | 6 | # Build artifacts 7 | *.o 8 | *.a 9 | *.so 10 | *.dylib 11 | *.exe 12 | *.dll 13 | ngrep 14 | config.log 15 | config.status 16 | autom4te.cache/ 17 | _install/ 18 | install/ 19 | release/ 20 | 21 | # Documentation 22 | *.md 23 | !README.md 24 | CREDITS 25 | LICENSE 26 | doc/ 27 | 28 | # Development 29 | .vscode/ 30 | .idea/ 31 | *.swp 32 | *.swo 33 | *~ 34 | 35 | # OS 36 | .DS_Store 37 | Thumbs.db 38 | 39 | # Test files 40 | *.pcap 41 | *.dump 42 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: ngrep multiplatform autobuilds 2 | 3 | on: 4 | push: 5 | paths: 6 | - ".github/workflows/build.yml" 7 | - ".github/workflows/matrix.yml" 8 | - "**/*.c" 9 | - "**/*.h" 10 | - "**/*.in" 11 | - "configure*" 12 | - "Makefile*" 13 | - "winXX/build.ps1" 14 | - "winXX/CMakeLists.txt" 15 | branches: 16 | - master 17 | pull_request: 18 | workflow_dispatch: 19 | inputs: 20 | deploymentName: 21 | description: "Name for this deployment" 22 | required: true 23 | default: "Manual Deployment" 24 | 25 | concurrency: 26 | group: ${{ github.workflow }}-${{ github.ref }} 27 | cancel-in-progress: true 28 | 29 | jobs: 30 | build: 31 | uses: ./.github/workflows/matrix.yml 32 | with: 33 | create_artifacts: false 34 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Multi-stage build for minimal final image 2 | FROM alpine:3.20 AS builder 3 | 4 | # Install build dependencies 5 | RUN apk add --no-cache \ 6 | build-base \ 7 | autoconf \ 8 | automake \ 9 | libpcap-dev \ 10 | pcre2-dev \ 11 | libnet-dev 12 | 13 | # Copy source code 14 | WORKDIR /build 15 | COPY . . 16 | 17 | # Build ngrep 18 | RUN ./configure --enable-ipv6 --enable-pcre2 --enable-tcpkill --prefix=/usr && \ 19 | make && \ 20 | make install DESTDIR=/install 21 | 22 | # Final minimal image 23 | FROM alpine:3.20 24 | 25 | # Install only runtime dependencies 26 | RUN apk add --no-cache \ 27 | libpcap \ 28 | pcre2 \ 29 | libnet 30 | 31 | # Copy built binary from builder 32 | COPY --from=builder /install/usr/bin/ngrep /usr/bin/ngrep 33 | COPY --from=builder /install/usr/share/man/man8/ngrep.8 /usr/share/man/man8/ngrep.8 34 | 35 | # ngrep needs to run as root or with NET_CAP_RAW capability 36 | # Alpine uses musl libc which is smaller than glibc 37 | USER root 38 | 39 | ENTRYPOINT ["/usr/bin/ngrep"] 40 | CMD ["-h"] 41 | -------------------------------------------------------------------------------- /winXX/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * WinXX-specific version for manual manipulation. 3 | */ 4 | 5 | /* PCRE2 support - will be defined by CMake if available */ 6 | #ifndef USE_PCRE2 7 | #define USE_PCRE2 0 8 | #endif 9 | 10 | #define USE_IPv6 1 11 | #define USE_VLAN_HACK 1 12 | 13 | #define HAVE_DLT_RAW 1 14 | #define HAVE_DLT_LOOP 1 15 | #define HAVE_DLT_LINUX_SLL 1 16 | #define HAVE_DLT_IEEE802_11 1 17 | #define HAVE_DLT_IEEE802_11_RADIO 1 18 | #define HAVE_DLT_PFLOG 1 19 | #define HAVE_DLT_PFSYNC 1 20 | #define HAVE_DLT_IPNET 0 21 | 22 | #define HAVE_DUMB_UDPHDR 0 23 | #define HAVE_PCAP_FINDALLDEVS 1 24 | 25 | #define USE_PCAP_RESTART 0 26 | #define PCAP_RESTART_FUNC 0 27 | 28 | #define USE_DROPPRIVS 0 29 | #define DROPPRIVS_USER "notused" 30 | 31 | #define USE_TCPKILL 0 32 | 33 | /* Windows doesn't have these */ 34 | #define STDC_HEADERS 1 35 | -------------------------------------------------------------------------------- /Dockerfile.ubuntu: -------------------------------------------------------------------------------- 1 | # Multi-stage build for minimal final image (Ubuntu-based) 2 | # Use this if you need glibc compatibility or prefer Ubuntu 3 | FROM ubuntu:24.04 AS builder 4 | 5 | # Install build dependencies 6 | RUN apt-get update && apt-get install -y \ 7 | build-essential \ 8 | autoconf \ 9 | automake \ 10 | libpcap-dev \ 11 | libpcre2-dev \ 12 | libnet-dev \ 13 | && rm -rf /var/lib/apt/lists/* 14 | 15 | # Copy source code 16 | WORKDIR /build 17 | COPY . . 18 | 19 | # Build ngrep 20 | RUN ./configure --enable-ipv6 --enable-pcre2 --enable-tcpkill --prefix=/usr && \ 21 | make && \ 22 | make install DESTDIR=/install 23 | 24 | # Final minimal image 25 | FROM ubuntu:24.04 26 | 27 | # Install only runtime dependencies 28 | RUN apt-get update && apt-get install -y \ 29 | libpcap0.8 \ 30 | libpcre2-8-0 \ 31 | libnet1 \ 32 | && rm -rf /var/lib/apt/lists/* 33 | 34 | # Copy built binary from builder 35 | COPY --from=builder /install/usr/bin/ngrep /usr/bin/ngrep 36 | COPY --from=builder /install/usr/share/man/man8/ngrep.8 /usr/share/man/man8/ngrep.8 37 | 38 | # ngrep needs to run as root or with NET_CAP_RAW capability 39 | USER root 40 | 41 | ENTRYPOINT ["/usr/bin/ngrep"] 42 | CMD ["-h"] 43 | -------------------------------------------------------------------------------- /regex-0.12/configure.in: -------------------------------------------------------------------------------- 1 | dnl Process this file with autoconf to produce a configure script. 2 | AC_INIT 3 | AC_CONFIG_SRCDIR([regex.c]) 4 | 5 | AC_CANONICAL_TARGET 6 | 7 | AC_PROG_CC 8 | AC_PROG_INSTALL 9 | 10 | dnl I'm not sure if AC_USE_SYSTEM_EXTENSIONS and AC_FUNC_GETMNTENT are really necessary. The 11 | dnl Autoconf documentation isn't specific about which BSD functions they 12 | dnl provide. 13 | AC_USE_SYSTEM_EXTENSIONS 14 | AC_FUNC_GETMNTENT 15 | AC_SEARCH_LIBS([strerror],[cposix]) 16 | AC_USE_SYSTEM_EXTENSIONS 17 | 18 | m4_warn([obsolete], 19 | [The preprocessor macro 'STDC_HEADERS' is obsolete. 20 | Except in unusual embedded environments, you can safely include all 21 | C89 headers unconditionally.])dnl 22 | # Autoupdate added the next two lines to ensure that your configure 23 | # script's behavior did not change. They are probably safe to remove. 24 | AC_CHECK_INCLUDES_DEFAULT 25 | AC_PROG_EGREP 26 | 27 | AC_CHECK_HEADERS([string.h]) 28 | 29 | AC_FUNC_ALLOCA 30 | AC_C_CONST 31 | 32 | AC_PREFIX_PROGRAM([gcc]) 33 | 34 | case "$target_os" in 35 | 36 | *darwin*) 37 | AC_DEFINE(regcomp, regcomp1) 38 | AC_DEFINE(regexec, regexec1) 39 | AC_DEFINE(regfree, regfree1) 40 | AC_DEFINE(regerror, regerror1) 41 | 42 | ;; 43 | 44 | esac 45 | 46 | AC_CONFIG_FILES([Makefile doc/Makefile test/Makefile]) 47 | AC_OUTPUT 48 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Author of ngrep: 2 | 3 | Jordan Ritter 4 | 5 | Use of couch whilst conceiving of the concept: 6 | 7 | Dave Goldsmith and 8 | Window Snyder 9 | 10 | Original (old) porting of ngrep to Win32: 11 | 12 | Mike 13 | 14 | 64-bit clean regex.c patch: 15 | 16 | Jeff 17 | 18 | Hexdump patch: 19 | 20 | Andrew W. Flury 21 | 22 | Elite ideas and loads of licensing advice: 23 | 24 | Dan Frasnelli and 25 | cstone 26 | 27 | Use of OSF/1 box and DDoS research: 28 | 29 | Dave Dittrich 30 | 31 | Compilation patches: 32 | 33 | dugsong 34 | Joerg Dorchain 35 | 36 | Tokenring Patch 37 | 38 | vacuum 39 | 40 | HPUX and Config Updates Patch 41 | 42 | Kevin Steves 43 | 44 | AIX patch 45 | 46 | "Joseph N. Wilson" 47 | 48 | TCP ECN patch 49 | 50 | Maik Pfeil 51 | 52 | Real RPM Packaging 53 | 54 | Dag Wieers 55 | 56 | Excellent patch for adding IPv6 support to ngrep 57 | 58 | Bernard Massot 59 | 60 | Assistance with IPv6 testing 61 | 62 | Ralph Logan 63 | Arrigo Triulzi 64 | 65 | Timestamp diff from first match patch 66 | 67 | Joseph Heenan 68 | 69 | And many others. 70 | -------------------------------------------------------------------------------- /regex-0.12/NEWS: -------------------------------------------------------------------------------- 1 | Version 0.12 2 | 3 | * regex.c does not #define bcmp/bcopy/bzero if they already are. 4 | 5 | * regex.h does not redefine `const' if it is already defined, even if 6 | __STDC__ is not defined. 7 | 8 | * RE_SYNTAX_ED added (same as POSIX BRE's). 9 | 10 | * The following bugs have been fixed, among others: 11 | * The pattern \w+ doesn't infinite loop. 12 | * The pattern ".+\n" is compiled correctly. 13 | * Expressions with more than MAX_REGNUM groups are compiled correctly. 14 | 15 | * Patterns that end in a repetition operator (e.g., `*') match 16 | slightly faster if no looping is actually necessary. 17 | 18 | Version 0.11 (17 Sep 92) 19 | 20 | * Back-references to nonexistent subexpressions, as in the r.e. `abc\1', 21 | are always invalid. Previously, they could match the literal digit, 22 | e.g., the stated r.e. might have matched `abc1'. 23 | 24 | * Empty subexpressions are always valid (POSIX leaves this undefined). 25 | 26 | * Simplified rules for ^ and $ being anchors. 27 | 28 | * One minor speedup (rewriting the C procedure `pop_failure_point' as a 29 | macro again). 30 | 31 | * Bug fixes involving: 32 | - Declarations in regex.h and non-ANSI compilers. 33 | - Bracket expressions with characters between 0x80-0xff. 34 | - Memory leak in re_match_2 on systems requiring `alloca (0)' to 35 | free alloca'd storage. 36 | 37 | * Test and documentation files moved into subdirectories. 38 | 39 | Version 0.10 (9 Sep 92) 40 | 41 | * `obscure_syntax' is now called `re_default_syntax'. 42 | 43 | * `re_comp's return type is no longer `const', for compatibility with BSD. 44 | 45 | * POSIX syntaxes now include as much functionality as possible 46 | (consistent with the standard). 47 | 48 | * Compilation conditionals normalized to what the rest of GNU is 49 | migrating towards these days. 50 | 51 | * Bug fixes involving: 52 | - Ranges with characters between 0x80 and 0xff, e.g., [\001-\377]. 53 | - `re_compile_fastmap' and the sequence `.*\n'. 54 | - Intervals with exact counts, e.g., a{5}. 55 | 56 | * Changed distribution to use a standard Makefile, install the info 57 | files, use a configure script, etc. 58 | 59 | Version 0.9 60 | 61 | * The longest match was not always chosen: `a*|ab' didn't match `aab'. 62 | 63 | -------------------------------------------------------------------------------- /tcpkill.c: -------------------------------------------------------------------------------- 1 | /* 2 | * tcpkill.c 3 | * 4 | * Kill TCP connections already in progress. 5 | * 6 | * Copyright (c) 2000 Dug Song 7 | * 8 | * $Id: tcpkill.c,v 1.17 2001/03/17 08:10:43 dugsong Exp $ 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "ngrep.h" // for net_choosedevice() 22 | #include "tcpkill.h" 23 | 24 | libnet_t *l; 25 | 26 | void 27 | tcpkill_kill(const struct pcap_pkthdr *pcap, const u_char *pkt, 28 | uint32_t pcap_off, uint32_t kill_count) 29 | { 30 | struct libnet_ipv4_hdr *ip; 31 | struct libnet_tcp_hdr *tcp; 32 | char ctext[64]; 33 | uint32_t seq, win, i; 34 | 35 | pkt += pcap_off; 36 | 37 | ip = (struct libnet_ipv4_hdr *)pkt; 38 | if (ip->ip_p != IPPROTO_TCP) 39 | return; 40 | 41 | tcp = (struct libnet_tcp_hdr *)(pkt + (ip->ip_hl << 2)); 42 | if (tcp->th_flags & (TH_SYN|TH_FIN|TH_RST)) 43 | return; 44 | 45 | seq = ntohl(tcp->th_ack); 46 | win = ntohs(tcp->th_win); 47 | 48 | snprintf(ctext, sizeof(ctext), "%s:%d > %s:%d:", 49 | libnet_addr2name4(ip->ip_src.s_addr, LIBNET_DONT_RESOLVE), 50 | ntohs(tcp->th_sport), 51 | libnet_addr2name4(ip->ip_dst.s_addr, LIBNET_DONT_RESOLVE), 52 | ntohs(tcp->th_dport)); 53 | 54 | for (i = 0; i < kill_count; i++) { 55 | seq += (i * win); 56 | 57 | libnet_clear_packet(l); 58 | 59 | libnet_build_tcp(ntohs(tcp->th_dport), ntohs(tcp->th_sport), 60 | seq, 0, TH_RST, 0, 0, 0, LIBNET_TCP_H, 61 | NULL, 0, l, 0); 62 | 63 | libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_TCP_H, 0, 64 | libnet_get_prand(LIBNET_PRu16), 0, 64, 65 | IPPROTO_TCP, 0, ip->ip_dst.s_addr, 66 | ip->ip_src.s_addr, NULL, 0, l, 0); 67 | 68 | if (libnet_write(l) < 0) 69 | fprintf(stderr, "libnet_write failed\n"); 70 | 71 | fprintf(stderr, "%s R %u:%u(0) win 0\n", ctext, seq, seq); 72 | } 73 | } 74 | 75 | void 76 | tcpkill_init(void) 77 | { 78 | char *intf; 79 | char libnet_ebuf[LIBNET_ERRBUF_SIZE]; 80 | 81 | if ((intf = net_choosedevice()) == NULL) 82 | fprintf(stderr, "coudln't locate device to use\n"); 83 | 84 | if ((l = libnet_init(LIBNET_RAW4, intf, libnet_ebuf)) == NULL) 85 | fprintf(stderr, "libnet_init failed\n"); 86 | 87 | libnet_seed_prand(l); 88 | } 89 | -------------------------------------------------------------------------------- /regex-0.12/README: -------------------------------------------------------------------------------- 1 | This directory contains the GNU regex library. It is compliant with 2 | POSIX.2, except for internationalization features. 3 | 4 | See the file NEWS for a list of major changes in the current release. 5 | 6 | See the file INSTALL for compilation instructions. (The only thing 7 | installed is the documentation; regex.c is compiled into regex.o, but 8 | not installed anywhere.) 9 | 10 | The subdirectory `doc' contains a (programmers') manual for the library. 11 | It's probably out-of-date. Improvements are welcome. 12 | 13 | The subdirectory `test' contains the various tests we've written. 14 | 15 | We know this code is not as fast as it might be. If you have specific 16 | suggestions, profiling results, or other such useful information to 17 | report, please do. 18 | 19 | Emacs 18 is not going use this revised regex (but Emacs 19 will). If 20 | you want to try it with Emacs 18, apply the patch at the end of this 21 | file first. 22 | 23 | Mail bug reports to bug-gnu-utils@prep.ai.mit.edu. 24 | 25 | Please include an actual regular expression that fails (and the syntax 26 | used to compile it); without that, there's no way to reproduce the bug, 27 | so there's no way we can fix it. Even if you include a patch, also 28 | include the regular expression in error; otherwise, we can't know for 29 | sure what you're trying to fix. 30 | 31 | Here is the patch to make this version of regex work with Emacs 18. 32 | 33 | *** ORIG/search.c Tue Jan 8 13:04:55 1991 34 | --- search.c Sun Jan 5 10:57:00 1992 35 | *************** 36 | *** 25,26 **** 37 | --- 25,28 ---- 38 | #include "commands.h" 39 | + 40 | + #include 41 | #include "regex.h" 42 | *************** 43 | *** 477,479 **** 44 | /* really needed. */ 45 | ! && *(searchbuf.buffer) == (char) exactn /* first item is "exact match" */ 46 | && searchbuf.buffer[1] + 2 == searchbuf.used) /*first is ONLY item */ 47 | --- 479,482 ---- 48 | /* really needed. */ 49 | ! /* first item is "exact match" */ 50 | ! && *(searchbuf.buffer) == (char) RE_EXACTN_VALUE 51 | && searchbuf.buffer[1] + 2 == searchbuf.used) /*first is ONLY item */ 52 | *************** 53 | *** 1273,1275 **** 54 | searchbuf.allocated = 100; 55 | ! searchbuf.buffer = (char *) malloc (searchbuf.allocated); 56 | searchbuf.fastmap = search_fastmap; 57 | --- 1276,1278 ---- 58 | searchbuf.allocated = 100; 59 | ! searchbuf.buffer = (unsigned char *) malloc (searchbuf.allocated); 60 | searchbuf.fastmap = search_fastmap; 61 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* pseudo-user for running ngrep (default "nobody") */ 4 | #undef DROPPRIVS_USER 5 | 6 | /* presence of DLT_IEEE802_11 in bpf.h */ 7 | #undef HAVE_DLT_IEEE802_11 8 | 9 | /* presence of DLT_IEEE802_11_RADIO in bpf.h */ 10 | #undef HAVE_DLT_IEEE802_11_RADIO 11 | 12 | /* presence of DLT_IPNET in bpf.h */ 13 | #undef HAVE_DLT_IPNET 14 | 15 | /* presence of DLT_LINUX_SLL in bpf.h */ 16 | #undef HAVE_DLT_LINUX_SLL 17 | 18 | /* presence of DLT_LOOP in bpf.h */ 19 | #undef HAVE_DLT_LOOP 20 | 21 | /* presence of DLT_PFLOG in $BPF */ 22 | #undef HAVE_DLT_PFLOG 23 | 24 | /* presence of DLT_RAW in bpf.h */ 25 | #undef HAVE_DLT_RAW 26 | 27 | /* Define to 1 if you have the 'net' library (-lnet). */ 28 | #undef HAVE_LIBNET 29 | 30 | /* Define to 1 if you have the 'nsl' library (-lnsl). */ 31 | #undef HAVE_LIBNSL 32 | 33 | /* Define to 1 if you have the 'pcap' library (-lpcap). */ 34 | #undef HAVE_LIBPCAP 35 | 36 | /* Define to 1 if you have the 'socket' library (-lsocket). */ 37 | #undef HAVE_LIBSOCKET 38 | 39 | /* whether libpcap has `pcap_findalldevs' function */ 40 | #undef HAVE_PCAP_FINDALLDEVS 41 | 42 | /* Define to 1 if you have the 'wcwidth' function. */ 43 | #undef HAVE_WCWIDTH 44 | 45 | /* Define to the address where bug reports for this package should be sent. */ 46 | #undef PACKAGE_BUGREPORT 47 | 48 | /* Define to the full name of this package. */ 49 | #undef PACKAGE_NAME 50 | 51 | /* Define to the full name and version of this package. */ 52 | #undef PACKAGE_STRING 53 | 54 | /* Define to the one symbol short name of this package. */ 55 | #undef PACKAGE_TARNAME 56 | 57 | /* Define to the home page for this package. */ 58 | #undef PACKAGE_URL 59 | 60 | /* Define to the version of this package. */ 61 | #undef PACKAGE_VERSION 62 | 63 | /* routine used for restarting the BPF lexer */ 64 | #undef PCAP_RESTART_FUNC 65 | 66 | /* whether to use privileges dropping (default yes) */ 67 | #undef USE_DROPPRIVS 68 | 69 | /* whether to use IPv6 (default off) */ 70 | #undef USE_IPv6 71 | 72 | /* whether to call the BPF lexer restart function between multiple BPF filter 73 | compilation attempts (default no) */ 74 | #undef USE_PCAP_RESTART 75 | 76 | /* whether to use PCRE2 (default GNU Regex) */ 77 | #undef USE_PCRE2 78 | 79 | /* whether to enable tcpkill functionality (default off) */ 80 | #undef USE_TCPKILL 81 | 82 | /* whether to automatically include VLAN frames (default on) */ 83 | #undef USE_VLAN_HACK 84 | 85 | /* ngrep version */ 86 | #undef VERSION 87 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Docker Build & Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - 'v*' 9 | paths: 10 | - ".github/workflows/docker.yml" 11 | - "**/*.c" 12 | - "**/*.h" 13 | - "**/*.in" 14 | - "configure*" 15 | - "Makefile*" 16 | workflow_dispatch: {} 17 | 18 | env: 19 | REGISTRY: ghcr.io 20 | IMAGE_NAME: ${{ github.repository }} 21 | 22 | jobs: 23 | build-and-push: 24 | runs-on: ubuntu-latest 25 | permissions: 26 | contents: read 27 | packages: write 28 | id-token: write 29 | attestations: write 30 | 31 | steps: 32 | - name: Checkout repository 33 | uses: actions/checkout@v4 34 | 35 | - name: Set up Docker Buildx 36 | uses: docker/setup-buildx-action@v3 37 | 38 | - name: Log in to GitHub Container Registry 39 | uses: docker/login-action@v3 40 | with: 41 | registry: ${{ env.REGISTRY }} 42 | username: ${{ github.actor }} 43 | password: ${{ secrets.GITHUB_TOKEN }} 44 | 45 | - name: Extract metadata (tags, labels) 46 | id: meta 47 | uses: docker/metadata-action@v5 48 | with: 49 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 50 | tags: | 51 | # Tag with version on release tags (v1.48.0 -> 1.48.0) 52 | type=semver,pattern={{version}} 53 | # Tag with major.minor on release tags (v1.48.0 -> 1.48) 54 | type=semver,pattern={{major}}.{{minor}} 55 | # Tag with major on release tags (v1.48.0 -> 1) 56 | type=semver,pattern={{major}} 57 | # Tag with 'latest' on master branch 58 | type=raw,value=latest,enable={{is_default_branch}} 59 | # Tag with branch name 60 | type=ref,event=branch 61 | # Tag with PR number 62 | type=ref,event=pr 63 | # Tag with git short SHA (only on branch pushes) 64 | type=sha,enable={{is_default_branch}} 65 | - name: Build and push Docker image 66 | id: build 67 | uses: docker/build-push-action@v5 68 | with: 69 | context: . 70 | platforms: linux/amd64,linux/arm64 71 | push: true 72 | tags: ${{ steps.meta.outputs.tags }} 73 | labels: ${{ steps.meta.outputs.labels }} 74 | cache-from: type=gha 75 | cache-to: type=gha,mode=max 76 | 77 | - name: Generate artifact attestation 78 | uses: actions/attest-build-provenance@v1 79 | with: 80 | subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 81 | subject-digest: ${{ steps.build.outputs.digest }} 82 | push-to-registry: true 83 | -------------------------------------------------------------------------------- /regex-0.12/doc/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile for regex documentation. 2 | # 3 | # Copyright (C) 1992 Free Software Foundation, Inc. 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | 19 | # Installation directories. 20 | prefix = /usr/local 21 | infodir = $(prefix)/info 22 | 23 | srcdir = @srcdir@ 24 | VPATH = @srcdir@:../@srcdir@ 25 | 26 | INSTALL = @INSTALL@ 27 | INSTALL_DATA = @INSTALL_DATA@ 28 | 29 | MAKEINFO = makeinfo --no-split 30 | SHELL = /bin/sh 31 | TEX = tex 32 | TEXINDEX = texindex 33 | 34 | default all: regex.info regex.dvi 35 | .PHONY: default all 36 | 37 | # We need to include some code from regex.h. 38 | regex.texi: xregex.texi 39 | rm -f $@ 40 | gawk -f include.awk -vsource=../$(srcdir)/regex.h \ 41 | <../$(srcdir)/doc/xregex.texi \ 42 | | expand >$@ 43 | chmod a-w $@ 44 | 45 | regex.dvi: regex.cps 46 | $(TEX) regex.texi 47 | regex.cps: regex.cp 48 | $(TEXINDEX) regex.?? 49 | regex.cp: regex.texi 50 | $(TEX) ../$(srcdir)/doc/regex.texi 51 | 52 | regex.info: regex.texi 53 | $(MAKEINFO) ../$(srcdir)/doc/regex.texi 54 | 55 | # I know of no way to make a good TAGS file from Texinfo source. 56 | TAGS: 57 | 58 | check: 59 | .PHONY: check 60 | 61 | install: regex.info 62 | -mkdir $(prefix) $(infodir) 63 | for i in *.info*; do $(INSTALL_DATA) $$i $(infodir)/$$i; done 64 | .PHONY: install 65 | 66 | clean mostlyclean: 67 | rm -f regex.?? *.dvi *.log *.toc 68 | 69 | distclean: clean 70 | rm -f Makefile 71 | for f in regex.??s; do if test -z "`cat $$f`"; then rm -f $$f; fi; done 72 | 73 | realclean: distclean 74 | rm -f *.info* regex.??? regex.texi TAGS 75 | 76 | extraclean: distclean 77 | rm -f patch* *~* *\#* *.orig *.rej *.bak core a.out 78 | .PHONY: mostlyclean clean distclean realclean extraclean 79 | 80 | Makefile: Makefile.in ../config.status 81 | (cd ..; sh config.status) 82 | 83 | # Prevent GNU make 3 from overflowing arg limit on system V. 84 | .NOEXPORT: 85 | 86 | # Assumes $(distdir) is the place to put our files. 87 | distfiles = Makefile.in *.texi texinfo.tex include.awk \ 88 | regex.info* regex.aux regex.cps 89 | dist: Makefile regex.info regex.cps 90 | mkdir $(distdir) 91 | ln $(distfiles) $(distdir) 92 | .PHONY: dist 93 | -------------------------------------------------------------------------------- /scripts/multi.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # Author: Jordan Ritter 4 | # Date: Thu Jul 5 17:08:18 PDT 2001 5 | # 6 | # Input file format: 7 | # 8 | # Rulename1 file1.gz rule1 bpf_filter1 9 | # Rulename2 file2.gz rule2 bpf_filter2 10 | # Rulename3 file3.gz rule3 bpf_filter3 11 | # 12 | # Output: 13 | # 14 | # ./ngrepped.Rulename1 15 | # ./ngrepped.Rulename2 16 | # ./ngrepped.Rulename3 17 | # 18 | # Considerations: 19 | # 20 | # 1. Not sure how previous script was able to get the pcap filters with spaces using split... 21 | # 2. Don't forget to tweak $max_procs in CONFIG section. 22 | # 3. Blank lines in rule file are bad bad bad. 23 | # 4. Assumes bash. 24 | # 25 | 26 | ########## 27 | # CONFIG # 28 | ########## 29 | 30 | require 5.004; 31 | 32 | use POSIX qw(:signal_h); 33 | 34 | my($sig_set) = POSIX::SigSet->new(SIGINT); 35 | my($old_sig_set) = POSIX::SigSet->new(); 36 | my($max_procs) = 10; 37 | 38 | my($rules_file,%rules, @rules); 39 | my($fork_level); 40 | my($loops); 41 | 42 | $|++; 43 | 44 | 45 | ############# 46 | # FUNCTIONS # 47 | ############# 48 | 49 | sub go { 50 | my($rule_name) = shift @_; 51 | return unless $rule_name; 52 | 53 | my(%rule) = %{$rules{$rule_name}}; 54 | 55 | $fork_level++; 56 | 57 | sigprocmask(SIG_BLOCK, $sig_set, $old_sig_set); 58 | 59 | my($pipe) = "pipe-$rule-$fork_level"; 60 | my($daddy) = open($pipe, "-|"); 61 | 62 | if (not defined $daddy) { 63 | 64 | warn "[$rule_name] fork() error: $!\n"; 65 | sigprocmask(SIG_UNBLOCK, $old_sig_set); 66 | sleep(1); 67 | 68 | } elsif (not $daddy) { 69 | 70 | my(@args); 71 | 72 | $SIG{INT} = 'IGNORE'; 73 | sigprocmask(SIG_UNBLOCK, $old_sig_set); 74 | 75 | system("zcat $rule{'file'} | " . 76 | "ngrep -qtI - $rule{'regex'} $rule{'filter'} 2>&1 > " . 77 | "ngrepped.$rule_name"); 78 | 79 | exit; 80 | 81 | } else { 82 | 83 | sigprocmask(SIG_UNBLOCK, $old_sig_set); 84 | 85 | } 86 | 87 | &go(@_); 88 | 89 | close($pipe); 90 | print "[$rule_name] finished\n"; 91 | } 92 | 93 | 94 | ######## 95 | # MAIN # 96 | ######## 97 | 98 | $rules_file = $ARGV[0]; 99 | 100 | open(RULES, $rules_file) || die "Couldn't open rules file $rules_file: $!.\n"; 101 | my(@lines) = ; 102 | close(RULES); 103 | 104 | if (($loops = scalar(@lines)) == 0) { 105 | die "Rules file $rules_file empty, exiting.\n"; 106 | } 107 | 108 | %rules = map { chomp(local(@fields) = split / /, $_); 109 | $fields[0] => { "file" => $fields[1], 110 | "regex" => $fields[2], 111 | "filter" => $fields[3] }; } @lines; 112 | @rules = keys %rules; 113 | 114 | print "Hi, I'm ngrepper, and here we go.\n"; 115 | 116 | for ( 0 .. int($loops / $max_procs) ) { 117 | 118 | $fork_level = 1; 119 | @rules_for_this_pass = splice(@rules, 0, $max_procs); 120 | 121 | &go(@rules_for_this_pass); 122 | 123 | } 124 | 125 | print "Welp, I'm done.\n"; 126 | 127 | exit; 128 | 129 | 130 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | 2 | ================================================================= 3 | NOTE: These instructions are from the 2006 release of ngrep 1.45. 4 | They are sparse but will still give you the gist. Otherwise 5 | try ngrep from your favorite package manager! 6 | ================================================================= 7 | 8 | ngrep Installation Guide 9 | ------------------------ 10 | 11 | 1. Install the latest Packet Capture Library 12 | 13 | In order to compile ngrep on any platform, the relevant packet capture 14 | (PCAP) client support library must be installed. 15 | 16 | On UNIX, this is called ``libpcap'' and can be installed either from 17 | source or from a distribution's particular package management system. 18 | Some distributions separate the library itself from its development 19 | headers (i.e. libpcap-devel), so make sure to install both if this is 20 | the case. 21 | 22 | On Windows, the client support library is called ``WinPcap Developer's 23 | Pack'' and should be unpacked inside the parent directory of the ngrep 24 | source tree. 25 | 26 | The latest versions can be found at: 27 | 28 | UNIX: http://tcpdump.org/release/ 29 | Win32: http://www.winpcap.org/ 30 | 31 | 32 | 2. Unpack the ngrep source 33 | 34 | Once the client packet capture client support library is installed, 35 | unpack the ngrep source to a directory. 36 | 37 | On Windows, this must be under the same parent directory as the 38 | WinPcap Developer's Pack. 39 | 40 | 41 | 3. Compile the ngrep program 42 | 43 | On UNIX, type the following from the root of the ngrep source tree: 44 | 45 | % ./configure && make 46 | 47 | On Windows, open the ``ngrep.sln'' file located in the ``win32'' 48 | subdirectory of the ngrep source tree using Visual Studio.NET. From 49 | there you should be able to Build the solution in either Debug or 50 | Release mode. Once this is done, copy the resulting ``ngrep.exe'' 51 | (located in either the ``Debug'' or ``Release'' subdirectory depending 52 | on compile configuration) into any directory in your path for easy 53 | usage (``c:\windows'', for instance). 54 | 55 | Please ignore the warnings associated with the GNU Regex library 56 | included in the ngrep source tree. 57 | 58 | 59 | 4. Install the PCAP kernel driver 60 | 61 | ngrep is a PCAP-based program and therefore requires the PCAP kernel 62 | driver to be installed before it will function properly. 63 | 64 | The PCAP Driver is already integrated into the vast majority of UNIX 65 | and Linux kernels released within the last ~20 years. 66 | 67 | The Windows Platform, however, does not come with an integrated PCAP 68 | kernel driver by default, so it is necessary to install one before 69 | ngrep will work. 70 | 71 | 72 | Getting Help 73 | ------------ 74 | 75 | On UNIX, if you still have problems compiling or are compiling on an 76 | unsupported OS, try playing with other build types -- i.e. if you have 77 | a BSD derived system, try the BSD build type. 78 | 79 | If you still have problems, please submit an issue on GitHub or feel 80 | free to email me, however please try to help yourself first and search 81 | Google for possible answers before reaching out. 82 | 83 | Jordan Ritter 84 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2025 Jordan Ritter 3 | # 4 | # Please refer to the LICENSE file for more information. 5 | 6 | CC=@CC@ 7 | 8 | CPPFLAGS = @DEFS@ -D@OS@ @EXTRA_DEFINES@ @CPPFLAGS@ 9 | CFLAGS = @EXTRA_INCLUDES@ @CFLAGS@ 10 | LDFLAGS = @EXTRA_LDFLAGS@ @LDFLAGS@ 11 | LIBS = @LIBS@ @EXTRA_LIBS@ 12 | 13 | OBJS=ngrep.o @EXTRA_OBJS@ 14 | TARGET=ngrep 15 | MANPAGE=ngrep.8 16 | 17 | prefix = @prefix@ 18 | exec_prefix = @exec_prefix@ 19 | datarootdir = @datarootdir@ 20 | 21 | bindir = @bindir@ 22 | datadir = @datadir@ 23 | mandir = @mandir@ 24 | 25 | BINDIR_INSTALL = $(bindir) 26 | MANDIR_INSTALL = $(mandir)/man8 27 | 28 | INSTALL = ./install-sh 29 | STRIP = @STRIP@ 30 | 31 | REGEX_OBJS=@REGEX_OBJS@ 32 | REGEX_DIR=@REGEX_DIR@ 33 | 34 | 35 | all: $(TARGET) 36 | 37 | $(TARGET): debug 38 | $(STRIP) $(TARGET) 39 | 40 | debug: $(REGEX_OBJS) $(OBJS) 41 | $(CC) -g -o $(TARGET) $(OBJS) $(REGEX_OBJS) $(LDFLAGS) $(LIBS) 42 | 43 | static: $(REGEX_OBJS) $(OBJS) 44 | $(CC) -static -o $(TARGET).static $(OBJS) $(REGEX_OBJS) $(LDFLAGS) $(LIBS) 45 | 46 | install: $(TARGET) 47 | $(INSTALL) -c -m 0755 $(TARGET) $(DESTDIR)/$(BINDIR_INSTALL)/$(TARGET) 48 | $(INSTALL) -c -m 0644 $(MANPAGE) $(DESTDIR)/$(MANDIR_INSTALL)/$(MANPAGE) 49 | 50 | .c.o: 51 | $(CC) $(CPPFLAGS) $(CFLAGS) -g -c $< 52 | 53 | clean: 54 | test -n "$(REGEX_DIR)" && $(MAKE) -C $(REGEX_DIR) clean || exit 0 55 | rm -f *~ $(OBJS) $(REGEX_OBJS) $(TARGET) $(TARGET).static 56 | 57 | distclean: clean 58 | test -n "$(REGEX_DIR)" && $(MAKE) -C $(REGEX_DIR) distclean || exit 0 59 | rm -f config.status config.cache config.log config.h Makefile 60 | 61 | $(REGEX_OBJS): $(REGEX_OBJS:.o=.c) $(REGEX_DIR)/*.h 62 | $(MAKE) $(MAKEFLAGS) -C $(REGEX_DIR) $(notdir $(REGEX_OBJS)) 63 | 64 | $(OBJS): Makefile $(OBJS:.o=.c) $(OBJS:.o=.h) 65 | 66 | tardist: 67 | @( VERSION=`perl -ne '/VERSION\s+"(.*)"/ && print "$$1\n"' ngrep.h` ; \ 68 | PKG="ngrep-$$VERSION" ; \ 69 | TMPDIR="/tmp" ; \ 70 | DESTDIR="$$TMPDIR/$$PKG" ; \ 71 | echo ; \ 72 | echo "Building package $$PKG ... " ; \ 73 | echo ; \ 74 | sleep 2 ; \ 75 | rm -rf $$DESTDIR && mkdir $$DESTDIR && \ 76 | make distclean && \ 77 | tar --exclude "CVS" -cf - . | tar xf - -C $$DESTDIR && \ 78 | find $$DESTDIR -name "*~" -o -name ".*#*" | xargs rm -f && \ 79 | cd $$TMPDIR && tar zcf $$PKG.tar.gz $$PKG ; \ 80 | rm -rf $$DESTDIR ; \ 81 | cd $$TMPDIR && gpg -ba $$PKG.tar.gz ; \ 82 | echo ; \ 83 | ls -l $$TMPDIR/$$PKG.tar.gz $$TMPDIR/$$PKG.tar.gz.asc ; \ 84 | echo ; \ 85 | ) 86 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2025 Jordan Ritter. All rights reserved. 2 | 3 | Permission is granted to anyone to use this software for any purpose on 4 | any computer system, and to alter it and redistribute it, subject 5 | to the following restrictions: 6 | 7 | 1. The origin of this software must not be misrepresented, either by 8 | explicit claim or by omission. 9 | 10 | 2. Altered versions must be plainly marked as such, and must not be 11 | misrepresented as being the original software. Any altered version 12 | must clearly and properly represent the origin of this software in 13 | any accompanying documentation. 14 | 15 | 3. All advertising materials which relate specifically to derivate 16 | works of this software must display the following acknowledgement: 17 | This product includes software developed by Jordan Ritter. 18 | 19 | 4. The name of the Author may not be used to endorse or promote 20 | products derived from this software without specific prior written 21 | permission. 22 | 23 | 5. This notice, and any references to this notice, in any original or 24 | derived source distribution of or documentation for this software, 25 | may not be removed or altered. 26 | 27 | 28 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 29 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 32 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 35 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 36 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 37 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 38 | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | 40 | 41 | 42 | Portions were copied from tcpkill (part of dsniff), which has the 43 | following copyright: 44 | 45 | Copyright (c) 1999, 2000 Dug Song 46 | All rights reserved, all wrongs reversed. 47 | 48 | Redistribution and use in source and binary forms, with or without 49 | modification, are permitted provided that the following conditions 50 | are met: 51 | 52 | 1. Redistributions of source code must retain the above copyright 53 | notice, this list of conditions and the following disclaimer. 54 | 2. Redistributions in binary form must reproduce the above copyright 55 | notice, this list of conditions and the following disclaimer in the 56 | documentation and/or other materials provided with the distribution. 57 | 3. The name of author may not be used to endorse or promote products 58 | derived from this software without specific prior written permission. 59 | 60 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 61 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 62 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 63 | THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 64 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 65 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 66 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 67 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 68 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 69 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 70 | -------------------------------------------------------------------------------- /regex-0.12/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile for regex. 2 | # 3 | # Copyright (C) 1992, 1993 Free Software Foundation, Inc. 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | 19 | version = 0.12 20 | 21 | # You can define CPPFLAGS on the command line. Aside from system-specific 22 | # flags, you can define: 23 | # -DREGEX_MALLOC to use malloc/realloc/free instead of alloca. 24 | # -DDEBUG to enable the compiled pattern disassembler and execution 25 | # tracing; code runs substantially slower. 26 | # -DEXTRACT_MACROS to use the macros EXTRACT_* (as opposed to 27 | # the corresponding C procedures). If not -DDEBUG, the macros 28 | # are used. 29 | CPPFLAGS = 30 | 31 | # Likewise, you can override CFLAGS to optimize, use -Wall, etc. 32 | CFLAGS = -g 33 | 34 | # Ditto for LDFLAGS and LOADLIBES. 35 | LDFLAGS = 36 | LOADLIBES = 37 | 38 | srcdir = @srcdir@ 39 | VPATH = @srcdir@ 40 | 41 | CC = @CC@ 42 | DEFS = @DEFS@ 43 | 44 | SHELL = /bin/sh 45 | 46 | subdirs = doc test 47 | 48 | default all:: regex.o 49 | .PHONY: default all 50 | 51 | regex.o: regex.c regex.h 52 | $(CC) $(CFLAGS) $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) -c $< 53 | 54 | configure: configure.in 55 | autoconf 56 | 57 | config.status: configure 58 | sh configure --no-create 59 | 60 | Makefile: Makefile.in config.status 61 | sh config.status 62 | 63 | makeargs = $(MFLAGS) CPPFLAGS='$(CPPFLAGS)' CFLAGS='$(CFLAGS)' CC='$(CC)' \ 64 | DEFS='$(DEFS)' LDFLAGS='$(LDFLAGS)' LOADLIBES='$(LOADLIBES)' 65 | 66 | default all install TAGS check:: 67 | for d in $(subdirs); do (cd $$d; $(MAKE) $(makeargs) $@); done 68 | 69 | # 11/15/06 jpr5: effort to force this makefile to clean up completely 70 | # re-organized the clean statements 71 | # added config.cache and config.log to targets 72 | 73 | clean mostlyclean: 74 | for d in $(subdirs); do (cd $$d; $(MAKE) $(makeargs) $@); done 75 | rm -f *.o 76 | 77 | extraclean realclean distclean: 78 | for d in $(subdirs); do (cd $$d; $(MAKE) $(makeargs) $@); done 79 | rm -f patch* *~* *\#* *.orig *.rej *.bak core a.out 80 | rm -f Makefile config.status config.cache config.log regex.o 81 | 82 | .PHONY: install mostlyclean clean distclean extraclean realclean TAGS check 83 | 84 | 85 | # Prevent GNU make 3 from overflowing arg limit on system V. 86 | .NOEXPORT: 87 | 88 | distfiles = AUTHORS ChangeLog COPYING INSTALL NEWS README \ 89 | *.in configure regex.c regex.h 90 | distdir = regex-$(version) 91 | distargs = version=$(version) distdir=../$(distdir)/$$d 92 | dist: TAGS configure 93 | @echo "Version numbers in: Makefile.in, ChangeLog, NEWS," 94 | @echo " regex.c, regex.h," 95 | @echo " and doc/xregex.texi (if modified)." 96 | rm -rf $(distdir) 97 | mkdir $(distdir) 98 | ln $(distfiles) $(distdir) 99 | for d in $(subdirs); do (cd $$d; $(MAKE) $(distargs) dist); done 100 | tar czhf $(distdir).tar.Z $(distdir) 101 | rm -rf $(distdir) 102 | .PHONY: dist 103 | -------------------------------------------------------------------------------- /winXX/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | # Read version from VERSION file 4 | file(READ "${CMAKE_CURRENT_SOURCE_DIR}/../VERSION" NGREP_VERSION) 5 | string(STRIP "${NGREP_VERSION}" NGREP_VERSION) 6 | 7 | project(ngrep VERSION ${NGREP_VERSION} LANGUAGES C) 8 | 9 | set(CMAKE_C_STANDARD 99) 10 | 11 | # Find Npcap SDK 12 | if(NOT DEFINED NPCAP_SDK_DIR) 13 | set(NPCAP_SDK_DIR "C:/Program Files/Npcap SDK" CACHE PATH "Npcap SDK directory") 14 | endif() 15 | 16 | # Use PCRE2 on Windows to avoid 64-bit issues with ancient regex-0.12 17 | set(USE_PCRE2 ON CACHE BOOL "Use PCRE2 instead of regex-0.12" FORCE) 18 | 19 | # Find PCRE2 via vcpkg (note: lowercase 'pcre2' not 'unofficial-pcre2') 20 | find_package(pcre2 CONFIG QUIET) 21 | if(pcre2_FOUND) 22 | set(PCRE2_LIBRARY PCRE2::8BIT) 23 | message(STATUS "Found PCRE2 via vcpkg") 24 | else() 25 | if(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") 26 | message(WARNING "PCRE2 not found - install via: vcpkg install pcre2:arm64-windows") 27 | else() 28 | message(WARNING "PCRE2 not found - install via: vcpkg install pcre2:x64-windows") 29 | endif() 30 | set(USE_PCRE2 OFF) 31 | endif() 32 | 33 | # Source files - conditionally include regex 34 | if(USE_PCRE2) 35 | set(NGREP_SOURCES 36 | ../ngrep.c 37 | ./getopt.c 38 | ./inet_ntop.c 39 | ./wcwidth.c 40 | ) 41 | else() 42 | set(NGREP_SOURCES 43 | ../ngrep.c 44 | ../regex-0.12/regex.c 45 | ./getopt.c 46 | ./inet_ntop.c 47 | ./wcwidth.c 48 | ) 49 | endif() 50 | 51 | # Headers 52 | set(NGREP_HEADERS 53 | ../ngrep.h 54 | ../regex-0.12/regex.h 55 | ./config.h 56 | ./getopt.h 57 | ./inet_ntop.h 58 | ./types.h 59 | ./wcwidth.h 60 | ) 61 | 62 | # Create executable 63 | add_executable(ngrep ${NGREP_SOURCES} ${NGREP_HEADERS}) 64 | 65 | # Include directories 66 | target_include_directories(ngrep PRIVATE 67 | ${CMAKE_CURRENT_SOURCE_DIR}/ 68 | ${CMAKE_CURRENT_SOURCE_DIR}/../regex-0.12 69 | ${NPCAP_SDK_DIR}/Include 70 | ) 71 | 72 | # Preprocessor definitions 73 | target_compile_definitions(ngrep PRIVATE 74 | STDC_HEADERS 75 | WPCAP 76 | _CRT_SECURE_NO_WARNINGS 77 | REGEX_MALLOC 78 | _WIN32 79 | VERSION="${NGREP_VERSION}" 80 | ) 81 | 82 | # Link libraries - detect architecture 83 | if(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") 84 | set(NPCAP_LIB_DIR "${NPCAP_SDK_DIR}/Lib/ARM64") 85 | message(STATUS "Using ARM64 Npcap libraries") 86 | else() 87 | set(NPCAP_LIB_DIR "${NPCAP_SDK_DIR}/Lib/x64") 88 | message(STATUS "Using x64 Npcap libraries") 89 | endif() 90 | 91 | target_link_libraries(ngrep PRIVATE 92 | ws2_32 93 | ${NPCAP_LIB_DIR}/wpcap.lib 94 | ${NPCAP_LIB_DIR}/Packet.lib 95 | ) 96 | 97 | # PCRE2 support (enabled by default on Windows) 98 | if(USE_PCRE2) 99 | target_compile_definitions(ngrep PRIVATE USE_PCRE2=1 PCRE2_CODE_UNIT_WIDTH=8) 100 | if(DEFINED PCRE2_INCLUDE_DIR) 101 | target_include_directories(ngrep PRIVATE ${PCRE2_INCLUDE_DIR}) 102 | endif() 103 | target_link_libraries(ngrep PRIVATE ${PCRE2_LIBRARY}) 104 | message(STATUS "Building with PCRE2 support (avoids 64-bit issues in regex-0.12)") 105 | else() 106 | target_include_directories(ngrep PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../regex-0.12) 107 | message(STATUS "Building with regex-0.12 (may have 64-bit warnings)") 108 | endif() 109 | 110 | # Set output directory 111 | set_target_properties(ngrep PROPERTIES 112 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin 113 | ) 114 | 115 | # Installation 116 | install(TARGETS ngrep RUNTIME DESTINATION bin) 117 | -------------------------------------------------------------------------------- /winXX/getopt.c: -------------------------------------------------------------------------------- 1 | 2 | #include /* for EOF */ 3 | #include /* for strchr() */ 4 | 5 | #include 6 | 7 | /* static (global) variables that are specified as exported by getopt() */ 8 | char *optarg = NULL; /* pointer to the start of the option argument */ 9 | int optind = 1; /* number of the next argv[] to be evaluated */ 10 | int opterr = 1; /* non-zero if a question mark should be returned 11 | when a non-valid option character is detected */ 12 | 13 | int getopt(int argc, char *argv[], char *opstring) { 14 | static char *pIndexPosition = NULL; /* place inside current argv string */ 15 | char *pArgString = NULL; /* where to start from next */ 16 | char *pOptString; /* the string in our program */ 17 | 18 | if (pIndexPosition != NULL) { 19 | /* we last left off inside an argv string */ 20 | if (*(++pIndexPosition)) { 21 | /* there is more to come in the most recent argv */ 22 | pArgString = pIndexPosition; 23 | } 24 | } 25 | 26 | if (pArgString == NULL) { 27 | /* we didn't leave off in the middle of an argv string */ 28 | if (optind >= argc) { 29 | /* more command-line arguments than the argument count */ 30 | pIndexPosition = NULL; /* not in the middle of anything */ 31 | return EOF; /* used up all command-line arguments */ 32 | } 33 | 34 | /*--------------------------------------------------------------------- 35 | * If the next argv[] is not an option, there can be no more options. 36 | *-------------------------------------------------------------------*/ 37 | pArgString = argv[optind++]; /* set this to the next argument ptr */ 38 | 39 | if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */ 40 | ('-' != *pArgString)) { 41 | --optind; /* point to current arg once we're done */ 42 | optarg = NULL; /* no argument follows the option */ 43 | pIndexPosition = NULL; /* not in the middle of anything */ 44 | return EOF; /* used up all the command-line flags */ 45 | } 46 | 47 | /* check for special end-of-flags markers */ 48 | if ((strcmp(pArgString, "-") == 0) || 49 | (strcmp(pArgString, "--") == 0)) { 50 | optarg = NULL; /* no argument follows the option */ 51 | pIndexPosition = NULL; /* not in the middle of anything */ 52 | return EOF; /* encountered the special flag */ 53 | } 54 | 55 | pArgString++; /* look past the / or - */ 56 | } 57 | 58 | if (':' == *pArgString) { /* is it a colon? */ 59 | /*--------------------------------------------------------------------- 60 | * Rare case: if opterr is non-zero, return a question mark; 61 | * otherwise, just return the colon we're on. 62 | *-------------------------------------------------------------------*/ 63 | return (opterr ? (int)'?' : (int)':'); 64 | } else if ((pOptString = strchr(opstring, *pArgString)) == 0) { 65 | /*--------------------------------------------------------------------- 66 | * The letter on the command-line wasn't any good. 67 | *-------------------------------------------------------------------*/ 68 | optarg = NULL; /* no argument follows the option */ 69 | pIndexPosition = NULL; /* not in the middle of anything */ 70 | return (opterr ? (int)'?' : (int)*pArgString); 71 | } else { 72 | /*--------------------------------------------------------------------- 73 | * The letter on the command-line matches one we expect to see 74 | *-------------------------------------------------------------------*/ 75 | if (':' == _next_char(pOptString)) { /* is the next letter a colon? */ 76 | /* It is a colon. Look for an argument string. */ 77 | if ('\0' != _next_char(pArgString)) /* argument in this argv? */ 78 | optarg = &pArgString[1]; /* Yes, it is */ 79 | else { 80 | /*------------------------------------------------------------- 81 | * The argument string must be in the next argv. 82 | * But, what if there is none (bad input from the user)? 83 | * In that case, return the letter, and optarg as NULL. 84 | *-----------------------------------------------------------*/ 85 | if (optind < argc) 86 | optarg = argv[optind++]; 87 | else { 88 | optarg = NULL; 89 | return (opterr ? (int)'?' : (int)*pArgString); 90 | } 91 | } 92 | 93 | pIndexPosition = NULL; /* not in the middle of anything */ 94 | } else { 95 | /* it's not a colon, so just return the letter */ 96 | optarg = NULL; /* no argument follows the option */ 97 | pIndexPosition = pArgString; /* point to the letter we're on */ 98 | } 99 | return (int)*pArgString; /* return the letter that matched */ 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release Build & Publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' # Triggers on version tags like v1.0.0, v2.1.3, etc. 7 | 8 | jobs: 9 | validate-version: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: Validate version consistency 15 | run: | 16 | TAG_VERSION="${GITHUB_REF#refs/tags/v}" 17 | VERSION_FILE=$(cat VERSION | tr -d '\n') 18 | CONFIGURE_VERSION=$(grep "^# Generated by GNU Autoconf .* for ngrep" configure | sed 's/.*for ngrep \([0-9][0-9.]*\)[^0-9].*/\1/') 19 | 20 | echo "Tag version: v${TAG_VERSION}" 21 | echo "VERSION file: ${VERSION_FILE}" 22 | echo "configure script: ${CONFIGURE_VERSION}" 23 | 24 | if [ "${VERSION_FILE}" != "${TAG_VERSION}" ]; then 25 | echo "ERROR: VERSION file (${VERSION_FILE}) does not match tag (${TAG_VERSION})" 26 | exit 1 27 | fi 28 | 29 | if [ "${CONFIGURE_VERSION}" != "${TAG_VERSION}" ]; then 30 | echo "ERROR: configure script version (${CONFIGURE_VERSION}) does not match tag (${TAG_VERSION})" 31 | echo "Run 'autoconf' to regenerate the configure script" 32 | exit 1 33 | fi 34 | 35 | echo "✓ All versions match: ${TAG_VERSION}" 36 | 37 | build-and-package: 38 | needs: validate-version 39 | uses: ./.github/workflows/matrix.yml 40 | with: 41 | create_artifacts: true 42 | 43 | create-release: 44 | needs: build-and-package 45 | runs-on: ubuntu-latest 46 | permissions: 47 | contents: write 48 | steps: 49 | - uses: actions/checkout@v4 50 | 51 | - name: Download all artifacts 52 | uses: actions/download-artifact@v4 53 | with: 54 | path: artifacts 55 | 56 | - name: Display structure of downloaded files 57 | run: ls -R artifacts 58 | 59 | - name: Prepare release assets 60 | run: | 61 | mkdir -p release-assets 62 | find artifacts -type f \( -name "*.tar.gz" -o -name "*.zip" \) -exec cp {} release-assets/ \; 63 | ls -lh release-assets/ 64 | 65 | - name: Extract version from tag 66 | id: get_version 67 | run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT 68 | 69 | - name: Generate checksums 70 | run: | 71 | cd release-assets 72 | sha256sum * > SHA256SUMS 73 | cat SHA256SUMS 74 | 75 | - name: Create GitHub Release 76 | uses: softprops/action-gh-release@v1 77 | with: 78 | name: ${{ steps.get_version.outputs.VERSION }} 79 | body: | 80 | ## ngrep ${{ steps.get_version.outputs.VERSION }} 81 | 82 | ### Downloads 83 | 84 | Download the appropriate binary for your platform: 85 | 86 | - **Linux x86_64**: `ngrep-linux-x86_64.tar.gz` 87 | - **Linux ARM64**: `ngrep-linux-arm64.tar.gz` 88 | - **macOS 15 (ARM64)**: `ngrep-macos-15-arm64.tar.gz` 89 | - **macOS 26 (ARM64)**: `ngrep-macos-26-arm64.tar.gz` 90 | - **FreeBSD 15**: `ngrep-freebsd-15-x86_64.tar.gz` 91 | - **OpenBSD 7**: `ngrep-openbsd-7-x86_64.tar.gz` 92 | - **NetBSD 10**: `ngrep-netbsd-10-x86_64.tar.gz` 93 | - **Solaris 11**: `ngrep-solaris-11-x86_64.tar.gz` 94 | - **Windows x86_64**: `ngrep-windows-x86_64.zip` 95 | 96 | ### Installation 97 | 98 | **Unix-like systems:** 99 | ```bash 100 | tar -xzf ngrep-*.tar.gz 101 | sudo install -m 755 ngrep /usr/local/bin/ 102 | ``` 103 | 104 | **Dependencies (Unix):** 105 | - libpcap (or equivalent packet capture library) 106 | - libpcre2-8 (if built with PCRE2 support) 107 | 108 | Install via package manager: 109 | - Ubuntu: `apt install libpcap0.8 libpcre2-8-0` 110 | - macOS: `brew install libpcap pcre2` 111 | - FreeBSD: `pkg install pcre2` # libpcap installed by default 112 | - OpenBSD: `pkg_add pcre2` # libpcap installed by default 113 | - NetBSD: `pkg_add libpcap` # pcre2 installed by default 114 | - Solaris: `pkg install libpcap pcre2` 115 | - Windows: the `winXX\build.ps1` script does it all for you 116 | 117 | **Windows:** 118 | Extract the zip file. The package includes `ngrep.exe` and required DLLs. 119 | You'll need [Npcap](https://npcap.com/#download) installed to capture packets. 120 | 121 | ### Verification 122 | 123 | Verify your download with SHA256: 124 | ```bash 125 | sha256sum -c SHA256SUMS 126 | ``` 127 | 128 | ### Full Installation Packages 129 | 130 | Files ending in `-full.tar.gz` contain the complete installation tree including man pages and documentation. 131 | files: | 132 | release-assets/* 133 | draft: false 134 | prerelease: false 135 | fail_on_unmatched_files: true 136 | -------------------------------------------------------------------------------- /regex-0.12/test/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile for regex testing. 2 | # 3 | # Copyright (C) 1992 Free Software Foundation, Inc. 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2, or (at your option) 8 | # any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | 19 | CPPFLAGS = 20 | CFLAGS = -g 21 | LDFLAGS = 22 | 23 | srcdir = @srcdir@ 24 | VPATH = @srcdir@:../@srcdir@ 25 | 26 | CC = @CC@ 27 | DEFS = @DEFS@ 28 | LIBS = @LIBS@ $(LOADLIBES) 29 | 30 | ETAGS = etags 31 | SHELL = /bin/sh 32 | 33 | debug = -DDEBUG 34 | ALL_CPPFLAGS = -I. -I$(srcdir) -I../$(srcdir) $(DEFS) $(CPPFLAGS) $(debug) 35 | 36 | .c.o: 37 | $(CC) $(ALL_CPPFLAGS) $(CFLAGS) -c $< 38 | 39 | 40 | # Define this as `../regex.o' to get the optimized version. 41 | regex_o = dregex.o 42 | test_h = test.h 43 | test_o = test.o bsd-interf.o other.o tregress.o psx-basic.o psx-extend.o \ 44 | psx-generic.o psx-group.o psx-interf.o psx-interv.o 45 | common_o = printchar.o upcase.o xmalloc.o $(malloc) 46 | 47 | # We have a lot of mallocs we can try when we run afoul of strange bugs. 48 | malloc = @ALLOCA@ 49 | #malloc = # the libc malloc 50 | #malloc = g++malloc.o 51 | #malloc = debugmalloc.o 52 | #malloc = emacsmalloc.o 53 | emacsmallocflags = -Drcheck -Dbotch=abort -DUSG 54 | 55 | # default is to do nothing. 56 | default: 57 | 58 | all: regex syntax 59 | 60 | regex: $(regex_o) $(common_o) $(test_o) main.o 61 | $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) 62 | 63 | # As long as we're doing tests, we enable debugging. 64 | dregex.o: ../regex.c ../regex.h 65 | rm -f $@ 66 | $(CC) $(ALL_CPPFLAGS) $(CFLAGS) -c ../$(srcdir)/regex.c 67 | mv regex.o $@ 68 | 69 | # iregex is the interactive regex. 70 | iregex: $(common_o) $(regex_o) iregex.o 71 | $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) 72 | 73 | # fileregex searches for an r.e. in every line of a given file. 74 | fileregex_o = fileregex.o printchar.o $(regex_o) 75 | fileregex: $(fileregex_o) 76 | $(CC) -o $@ $(LDFLAGS) $(fileregex_o) $(LIBS) 77 | 78 | # cppregex is regex with a preprocessed regex.c. Useful when the 79 | # problem is inside some macro. 80 | cppregex: regexcpp.o $(common_o) $(test_o) main.o 81 | $(CC) -o $@ $(LDFLAGS) $^ $(LIBS) 82 | 83 | regexcpp.o: regexcpp.c 84 | 85 | regexcpp.c: regex.c regexcpp.sed 86 | rm -f regexcpp.c 87 | $(CC) -E $(ALL_CPPFLAGS) ../$(srcdir)/regex.c \ 88 | | egrep -v '^#|^ *$$' \ 89 | | sed -f regexcpp.sed \ 90 | > regexcpp.c 91 | chmod a-w regexcpp.c 92 | 93 | # Have to give this malloc special flags. 94 | emacsmalloc.o: emacsmalloc.c 95 | $(CC) -c $(CFLAGS) $(ALL_CPPFLAGS) $(emacsmallocflags) \ 96 | ../$(srcdir)/test/emacsmalloc.c 97 | 98 | syntax: syntax.o 99 | $(CC) $(CFLAGS) -o $@ syntax.o 100 | 101 | syntax.c: syntax.skel bits 102 | sed '/\[\[\[replace.*\]\]\]/r bits' syntax.skel > $@ 103 | 104 | bits: regex.h 105 | sed -n 1,/RE_SYNTAX_EMACS/p ../$(srcdir)/regex.h \ 106 | | grep "#define RE_.*1" \ 107 | | sed 's/^#define \(RE_[A-Z_]*\) .*/ TEST_BIT (\1);/' > $@ 108 | 109 | check: regex 110 | ./regex 111 | 112 | TAGS: regex.c regex.h *.h *.c 113 | $(ETAGS) -t $^ 114 | 115 | depend: 116 | gcc -MM $(ALL_CPPFLAGS) *.c > /tmp/depend 117 | .PHONY: depend 118 | 119 | install: 120 | .PHONY: install 121 | 122 | clean mostlyclean: 123 | rm -f *.o regex cppregex iregex fileregex regexcpp.c syntax 124 | 125 | distclean: clean 126 | rm -f bits syntax.c Makefile 127 | 128 | extraclean: distclean 129 | rm -f *~* *\#* patch* *.orig *.rej *.bak core a.out 130 | 131 | realclean: distclean 132 | rm -f TAGS 133 | 134 | Makefile: Makefile.in ../config.status 135 | (cd ..; sh config.status) 136 | 137 | # Prevent GNU make 3 from overflowing arg limit on system V. 138 | .NOEXPORT: 139 | 140 | # Assumes $(distdir) is the place to put our files. 141 | distfiles = ChangeLog TAGS *.in *.c *.h regexcpp.sed syntax.skel 142 | dist: Makefile TAGS 143 | mkdir $(distdir) 144 | ln $(distfiles) $(distdir) 145 | 146 | # Automatically-generated dependencies below here. 147 | alloca.o : alloca.c 148 | bsd-interf.o : bsd-interf.c 149 | debugmalloc.o : debugmalloc.c 150 | emacsmalloc.o : emacsmalloc.c getpagesize.h 151 | fileregex.o : fileregex.c .././regex.h 152 | g++malloc.o : g++malloc.c //usr/include/stdio.h getpagesize.h 153 | iregex.o : iregex.c .././regex.h 154 | main.o : main.c test.h .././regex.h 155 | malloc-test.o : malloc-test.c 156 | other.o : other.c test.h .././regex.h 157 | printchar.o : printchar.c 158 | psx-basic.o : psx-basic.c test.h .././regex.h 159 | psx-extend.o : psx-extend.c test.h .././regex.h 160 | psx-generic.o : psx-generic.c test.h .././regex.h 161 | psx-group.o : psx-group.c test.h .././regex.h 162 | psx-interf.o : psx-interf.c test.h .././regex.h 163 | psx-interv.o : psx-interv.c test.h .././regex.h 164 | syntax.o : syntax.c .././regex.h 165 | test.o : test.c test.h .././regex.h 166 | tregress.o : tregress.c test.h .././regex.h 167 | upcase.o : upcase.c 168 | xmalloc.o : xmalloc.c 169 | -------------------------------------------------------------------------------- /ngrep.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 Jordan Ritter 3 | * 4 | * Please refer to the LICENSE file for more information. 5 | * 6 | */ 7 | 8 | /* 9 | * VERSION is now defined in config.h, generated from the VERSION file 10 | * by configure.ac (Unix) or CMakeLists.txt (Windows). 11 | */ 12 | 13 | /* 14 | * We cache the standard frame sizes here to save us time and 15 | * additional dependencies on more operating system include files. 16 | */ 17 | 18 | #define ETHHDR_SIZE 14 19 | #define TOKENRING_SIZE 22 20 | #define PPPHDR_SIZE 4 21 | #define SLIPHDR_SIZE 16 22 | #define RAWHDR_SIZE 0 23 | #define LOOPHDR_SIZE 4 24 | #define FDDIHDR_SIZE 21 25 | #define ISDNHDR_SIZE 16 26 | #define IEEE80211HDR_SIZE 32 27 | #define PFLOGHDR_SIZE 48 28 | #define VLANHDR_SIZE 4 29 | #define IPNETHDR_SIZE 24 30 | 31 | #ifndef ETHERTYPE_IP 32 | #define ETHERTYPE_IP 0x0800 33 | #endif 34 | #ifndef ETHERTYPE_IPV6 35 | #define ETHERTYPE_IPV6 0x86dd 36 | #endif 37 | 38 | #define EXTRACT_16BITS(p) \ 39 | ((uint16_t)((uint16_t)*((const uint8_t *)(p) + 0) << 8 | \ 40 | (uint16_t)*((const uint8_t *)(p) + 1))) 41 | 42 | #define _atoui32(p) \ 43 | ((uint32_t)strtoul((p), (char **)NULL, 10)) 44 | 45 | /* 46 | * Default patterns for BPF and regular expression filters. 47 | * 48 | * When targeting IP frames with a BPF filter, optionally-present VLAN frames 49 | * will be excluded by default, thus any IP traffic on a VLAN'd network is 50 | * invisible to ngrep by default. This requires the user to specify "vlan" 51 | * every time they are on a VLAN'd network, which gets irritating fast. 52 | * 53 | * In turn, this leads to a surprising behavior when working with pcap dump 54 | * files created from a "vlan" filter: reading and re-processing them requires 55 | * the same "vlan" filter to be specified, otherwise the traffic will be 56 | * invisible. IOW, when the dump reader is targeting IP traffic in the dump but 57 | * doesn't know (or remember) the "vlan" filter was specified, they will see 58 | * nothing -- and mistakenly blame ngrep. 59 | * 60 | * While the behavior is technically consistent, to the user it can be 61 | * surprising, confusing, and therefore Dumb As Shit. For convenience' sake, we 62 | * fix this for them by including VLAN (optionally) back into the stream 63 | * targeting IP traffic, and compensating for the variable offset in the packet 64 | * decoder. 65 | */ 66 | 67 | #if USE_IPv6 68 | #define BPF_FILTER_IP_TYPE "(ip || ip6)" 69 | #else 70 | #define BPF_FILTER_IP_TYPE "(ip)" 71 | #endif 72 | 73 | #define BPF_TEMPLATE_IP BPF_FILTER_IP_TYPE 74 | #define BPF_TEMPLATE_IP_VLAN "(" BPF_FILTER_IP_TYPE " || (vlan && " BPF_FILTER_IP_TYPE "))" 75 | #define BPF_TEMPLATE_USERSPEC_IP "( %s) and " BPF_TEMPLATE_IP 76 | #define BPF_TEMPLATE_USERSPEC_IP_VLAN "( %s) and " BPF_TEMPLATE_IP_VLAN 77 | 78 | #define WORD_REGEX "((^%s\\W)|(\\W%s$)|(\\W%s\\W))" 79 | 80 | /* 81 | * For retarded operating systems like Solaris that don't have this, 82 | * when everyone else does. Good job, Sun! 83 | */ 84 | 85 | #ifndef IP_OFFMASK 86 | #define IP_OFFMASK 0x1fff 87 | #endif 88 | 89 | /* 90 | * "Newer" flags that older operating systems don't yet recognize. 91 | */ 92 | 93 | #ifndef TH_ECE 94 | #define TH_ECE 0x40 95 | #endif 96 | 97 | #ifndef TH_CWR 98 | #define TH_CWR 0x80 99 | #endif 100 | 101 | 102 | /* 103 | * Single-char packet "ident" flags. 104 | */ 105 | 106 | typedef enum { 107 | TCP = 'T', UDP = 'U', ICMP = 'I', ICMPv6 = 'I', IGMP = 'G', UNKNOWN = '?' 108 | } netident_t; 109 | 110 | /* 111 | * Prototypes function signatures. 112 | */ 113 | 114 | int setup_pcap_source(char *); 115 | int setup_bpf_filter(char **); 116 | int setup_matcher(void); 117 | 118 | void process(u_char *, struct pcap_pkthdr *, u_char *); 119 | 120 | void version(void); 121 | void usage(); 122 | void update_windowsize(int32_t); 123 | void clean_exit(int32_t); 124 | 125 | void dump_packet(struct pcap_pkthdr *, u_char *, uint8_t, unsigned char *, uint32_t, 126 | const char *, const char *, uint16_t, uint16_t, uint8_t, 127 | uint16_t, uint8_t, uint16_t, uint32_t); 128 | 129 | void dump_unwrapped(unsigned char *, uint32_t, uint16_t, uint16_t); 130 | void dump_formatted(unsigned char *, uint32_t, uint16_t, uint16_t); 131 | void dump_byline (unsigned char *, uint32_t, uint16_t, uint16_t); 132 | 133 | void dump_delay_proc_init(struct pcap_pkthdr *); 134 | void dump_delay_proc (struct pcap_pkthdr *); 135 | 136 | int8_t re_match_func (unsigned char *, uint32_t, uint16_t *, uint16_t *); 137 | int8_t bin_match_func (unsigned char *, uint32_t, uint16_t *, uint16_t *); 138 | int8_t blank_match_func(unsigned char *, uint32_t, uint16_t *, uint16_t *); 139 | 140 | void print_time_absolute(struct pcap_pkthdr *); 141 | void print_time_diff (struct pcap_pkthdr *); 142 | void print_time_offset (struct pcap_pkthdr *); 143 | 144 | char *get_filter_from_string(char *); 145 | char *get_filter_from_argv (char **); 146 | 147 | uint8_t strishex(char *); 148 | 149 | #if !defined(_WIN32) && !defined(_WIN64) 150 | void drop_privs(void); 151 | #endif 152 | 153 | #if defined(_WIN32) || defined(_WIN64) 154 | int8_t winXX_initwinsock(void); 155 | void winXX_listdevices(void); 156 | char *winXX_usedevice(const char *); 157 | #endif 158 | 159 | extern char *net_choosedevice(void); // extern for tcp_kill reuse 160 | 161 | 162 | struct NGREP_rtaphdr_t { 163 | uint8_t it_version; 164 | uint8_t it_pad; 165 | uint16_t it_len; 166 | uint32_t it_present; 167 | }; 168 | -------------------------------------------------------------------------------- /winXX/wcwidth.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is an implementation of wcwidth() (and wcswidth()) as defined in 3 | * "The Single UNIX Specification, Version 2, The Open Group, 1997" 4 | * 5 | * 6 | * Markus Kuhn -- 2001-09-08 -- public domain 7 | * 8 | * Adapted for ngrep Windows build 9 | */ 10 | 11 | #include 12 | 13 | struct interval { 14 | unsigned short first; 15 | unsigned short last; 16 | }; 17 | 18 | /* auxiliary function for binary search in interval table */ 19 | static int bisearch(wchar_t ucs, const struct interval *table, int max) { 20 | int min = 0; 21 | int mid; 22 | 23 | if (ucs < table[0].first || ucs > table[max].last) 24 | return 0; 25 | while (max >= min) { 26 | mid = (min + max) / 2; 27 | if (ucs > table[mid].last) 28 | min = mid + 1; 29 | else if (ucs < table[mid].first) 30 | max = mid - 1; 31 | else 32 | return 1; 33 | } 34 | 35 | return 0; 36 | } 37 | 38 | /* The following function defines the column width of an ISO 10646 39 | * character as follows: 40 | * 41 | * - The null character (U+0000) has a column width of 0. 42 | * 43 | * - Other C0/C1 control characters and DEL will lead to a return 44 | * value of -1. 45 | * 46 | * - Non-spacing and enclosing combining characters (general 47 | * category code Mn or Me in the Unicode database) have a 48 | * column width of 0. 49 | * 50 | * - Other format characters (general category code Cf in the Unicode 51 | * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. 52 | * 53 | * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) 54 | * have a column width of 0. 55 | * 56 | * - Spacing characters in the East Asian Wide (W) or East Asian 57 | * FullWidth (F) category as defined in Unicode Technical 58 | * Report #11 have a column width of 2. 59 | * 60 | * - All remaining characters (including all printable 61 | * ISO 8859-1 and WGL4 characters, Unicode control characters, 62 | * etc.) have a column width of 1. 63 | * 64 | * This implementation assumes that wchar_t characters are encoded 65 | * in ISO 10646. 66 | */ 67 | 68 | int wcwidth(wchar_t ucs) 69 | { 70 | /* sorted list of non-overlapping intervals of non-spacing characters */ 71 | static const struct interval combining[] = { 72 | { 0x0300, 0x034E }, { 0x0360, 0x0362 }, { 0x0483, 0x0486 }, 73 | { 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 }, 74 | { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, 75 | { 0x05C4, 0x05C4 }, { 0x064B, 0x0655 }, { 0x0670, 0x0670 }, 76 | { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, 77 | { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, 78 | { 0x07A6, 0x07B0 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C }, 79 | { 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 }, 80 | { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, 81 | { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, 82 | { 0x0A02, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, 83 | { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 }, 84 | { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, 85 | { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0B01, 0x0B01 }, 86 | { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, 87 | { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, 88 | { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, 89 | { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, 90 | { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, 91 | { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA }, 92 | { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 }, 93 | { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 }, 94 | { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD }, 95 | { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, 96 | { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 }, 97 | { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC }, 98 | { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 }, 99 | { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 }, 100 | { 0x1160, 0x11FF }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 }, 101 | { 0x17C9, 0x17D3 }, { 0x180B, 0x180E }, { 0x18A9, 0x18A9 }, 102 | { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x206A, 0x206F }, 103 | { 0x20D0, 0x20E3 }, { 0x302A, 0x302F }, { 0x3099, 0x309A }, 104 | { 0xFB1E, 0xFB1E }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, 105 | { 0xFFF9, 0xFFFB } 106 | }; 107 | 108 | /* test for 8-bit control characters */ 109 | if (ucs == 0) 110 | return 0; 111 | if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) 112 | return -1; 113 | 114 | /* binary search in table of non-spacing characters */ 115 | if (bisearch(ucs, combining, 116 | sizeof(combining) / sizeof(struct interval) - 1)) 117 | return 0; 118 | 119 | /* if we arrive here, ucs is not a combining or C0/C1 control character */ 120 | 121 | return 1 + 122 | (ucs >= 0x1100 && 123 | (ucs <= 0x115f || /* Hangul Jamo init. consonants */ 124 | (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a && 125 | ucs != 0x303f) || /* CJK ... Yi */ 126 | (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ 127 | (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ 128 | (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ 129 | (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */ 130 | (ucs >= 0xffe0 && ucs <= 0xffe6) || 131 | (ucs >= 0x20000 && ucs <= 0x2ffff))); 132 | } 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ngrep 1.48.3 (11.7.2025) [![Build](https://github.com/jpr5/ngrep/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/jpr5/ngrep/actions/workflows/build.yml) 2 | 3 | ngrep is like GNU grep applied to the network layer. It's a PCAP-based tool 4 | that allows you to specify an extended regular or hexadecimal expression to 5 | match against data payloads of packets. It understands many kinds of protocols, 6 | including IPv4/6, TCP, UDP, ICMPv4/6, IGMP and Raw, across a wide variety of 7 | interface types, and understands BPF filter logic in the same fashion as more 8 | common packet sniffing tools, such as tcpdump and snoop. 9 | 10 | ## What's New 11 | 12 | * Support display of UTF8 data when `-u` is specified 13 | * Upgrade to PCRE2 (default on MacOS/homebrew and Windows builds) 14 | * Add additional level of quiet for certain filtering scenarios 15 | * Update to latest autotools for ngrep and regex-0.12 (2.72, 2023) 16 | * Update manpage for missing options and typos 17 | * Fix BPF `DLT_` type detections within libpcap (e.g. `DLT_LINUX_SLL`) 18 | * Allow for specifying location of PCRE2 includes 19 | * Eliminate various non-fatal build warnings (e.g. `pcap_lookupdev` deprecation) 20 | * Fix `./configure --disable-tcpkill` 21 | * Source cleanup (nuke old files, unused vars, missing refs, etc) 22 | * WinXX: `-d` allows device-name now (e.g. `\Device\...`) 23 | * WinXX: Removed `delay_socket` hack in favor of `Sleep()` 24 | * WinXX: Build with PCRE2 by default 25 | * WinXX: Add new dedicated build script (`build.ps1`) 26 | * WinXX: Builds on both x86_64 and ARM64 cpu architectures 27 | 28 | ## Installation 29 | 30 | ### Docker 31 | 32 | The easiest way to run ngrep is via Docker: 33 | 34 | ```bash 35 | docker pull ghcr.io/jpr5/ngrep:latest 36 | docker run --rm --net=host --cap-add=NET_RAW ghcr.io/jpr5/ngrep:latest -q 'GET|POST' tcp port 80 37 | ``` 38 | 39 | See [DOCKER](DOCKER.md) for detailed Docker usage instructions. 40 | 41 | ### Binary Releases 42 | 43 | Download pre-built binaries from the [Releases](https://github.com/jpr5/ngrep/releases) page. 44 | 45 | ### Build from Source 46 | 47 | See [INSTALL](INSTALL) for build instructions. 48 | 49 | ## How to use 50 | 51 | ngrep was originally developed to: 52 | 53 | * debug plaintext protocol interactions such as HTTP, IMAP, DNS, SIP, etc. 54 | * identify and analyze anomalous network communications such as those between 55 | malware, zombies and viruses 56 | * store, read and reprocess pcap dump files while looking for specific data 57 | patterns 58 | 59 | As well, it could be used to do plaintext credential collection, as with HTTP 60 | Basic Authentication, FTP or POP3 authentication. Like all useful tools, it can 61 | be used for good and for bad. 62 | 63 | Visit [EXAMPLES](EXAMPLES.md) to learn more about how ngrep works and can be 64 | leveraged to see all sorts of neat things. 65 | 66 | ## Working Platforms 67 | 68 | ngrep was ported extensively to a multitude of platforms, but over time access to 69 | them diminished. The list below is the original list; for a current list of 70 | confirmed working platforms, see our [autobuilds](https://github.com/jpr5/ngrep/actions/workflows/build.yml), 71 | which includes the most popular OSes, compiler toolchains and cpu architectures. 72 | 73 | * Linux 2.0+ (RH6+, SuSE, TurboLinux, Debian, Gentoo, Ubuntu, Mandrake, Slackware)/x86, RedHat/alpha, Cobalt (Qube2), Linux/MIPS 74 | * Solaris 2.5.1, 2.6/SPARC, Solaris 7, Solaris 8/SPARC, Solaris 9/SPARC 75 | * FreeBSD 2.2.5, 3.1, 3.2, 3.4-RC, 3.4-RELEASE, 4.0, 5.0 76 | * OpenBSD 2.4 (after upgrading pcap from 0.2), 2.9, 3.0, 3.1+ 77 | * NetBSD 1.5/SPARC 78 | * Digital Unix V4.0D (OSF/1), Tru64 5.0, Tru64 5.1A 79 | * HPUX 11 80 | * IRIX 81 | * AIX 4.3.3.0/PowerPC 82 | * BeOS R5 83 | * Mac OS X 10+ 84 | * GNU HURD 85 | * Windows 95, 98, NT, 2000, XP, 2003/x86, 7, 8, 8.1, 10 86 | 87 | ## Support, Feedback, & Patches 88 | 89 | If you need help, have constructive feedback, or would like to submit a patch, 90 | please visit ngrep's project at GitHub and use the online tools there. It will 91 | help the author better manage the various requests and patches so that nothing 92 | is lost or missed (as has been the case in the past, unfortunately). 93 | 94 | * Issues: https://github.com/jpr5/ngrep/issues 95 | * Patches: https://github.com/jpr5/ngrep/pulls 96 | 97 | Please see [CREDITS](CREDITS) for a partial list of the many people who helped make ngrep 98 | what it is today. Also, please note that ngrep is released under a simple 99 | BSD-style license, though depending on which regex library you compile 100 | against, you'll either get the GPL (GNU regex) or BSD (PCRE2). 101 | 102 | ## A Request to Distribution Package Maintainers 103 | 104 | Over the decades (!), ngrep has been included de facto in many popular distributions, 105 | several of which have dedicated package maintainers. Many of them have helpfully 106 | fielded issues reported by users of their distributions, and have even created patches 107 | to ngrep -- but I am seldom made aware. Every few years I have to hunt down what bug 108 | reports and patches may exist, in often arcane vendor-specific tracking systems, so 109 | that I can incorporate them for everyone's benefit. And sometimes I don't find them 110 | all. 111 | 112 | If you are a package maintainer for an OS or distribution, and find yourself 113 | fielding a bug report or writing a patch for ngrep, *please* at minimum CC me so 114 | that I can track (and possibly solve) the issue. Ideally, send me a link to a 115 | patch or pull request so that I can review it and merge it in. 116 | 117 | The way I see it, at the end of the day it's my code, so it's my responsibility, but 118 | I can't be everywhere to see everything. I need your help to do a good job. 119 | 120 | Thank you, sincerely, for all that you have done, and all that you will do. 🙏 121 | -------------------------------------------------------------------------------- /regex-0.12/INSTALL: -------------------------------------------------------------------------------- 1 | This is a generic INSTALL file for utilities distributions. 2 | If this package does not come with, e.g., installable documentation or 3 | data files, please ignore the references to them below. 4 | 5 | To compile this package: 6 | 7 | 1. Configure the package for your system. In the directory that this 8 | file is in, type `./configure'. If you're using `csh' on an old 9 | version of System V, you might need to type `sh configure' instead to 10 | prevent `csh' from trying to execute `configure' itself. 11 | 12 | The `configure' shell script attempts to guess correct values for 13 | various system-dependent variables used during compilation, and 14 | creates the Makefile(s) (one in each subdirectory of the source 15 | directory). In some packages it creates a C header file containing 16 | system-dependent definitions. It also creates a file `config.status' 17 | that you can run in the future to recreate the current configuration. 18 | 19 | Running `configure' takes a minute or two. While it is running, it 20 | prints some messages that tell what it is doing. If you don't want to 21 | see the messages, run `configure' with its standard output redirected 22 | to `/dev/null'; for example, `./configure >/dev/null'. 23 | 24 | To compile the package in a different directory from the one 25 | containing the source code, you must use a version of `make' that 26 | supports the VPATH variable, such as GNU `make'. `cd' to the directory 27 | where you want the object files and executables to go and run 28 | `configure'. `configure' automatically checks for the source code in 29 | the directory that `configure' is in and in `..'. If for some reason 30 | `configure' is not in the source code directory that you are 31 | configuring, then it will report that it can't find the source code. 32 | In that case, run `configure' with the option `--srcdir=DIR', where 33 | DIR is the directory that contains the source code. 34 | 35 | By default, `make install' will install the package's files in 36 | /usr/local/bin, /usr/local/lib, /usr/local/man, etc. You can specify 37 | an installation prefix other than /usr/local by giving `configure' the 38 | option `--prefix=PATH'. Alternately, you can do so by giving a value 39 | for the `prefix' variable when you run `make', e.g., 40 | make prefix=/usr/gnu 41 | 42 | You can specify separate installation prefixes for 43 | architecture-specific files and architecture-independent files. If 44 | you give `configure' the option `--exec-prefix=PATH' or set the 45 | `make' variable `exec_prefix' to PATH, the package will use PATH as 46 | the prefix for installing programs and libraries. Data files and 47 | documentation will still use the regular prefix. Normally, all files 48 | are installed using the regular prefix. 49 | 50 | Another `configure' option is useful mainly in `Makefile' rules for 51 | updating `config.status' and `Makefile'. The `--no-create' option 52 | figures out the configuration for your system and records it in 53 | `config.status', without actually configuring the package (creating 54 | `Makefile's and perhaps a configuration header file). Later, you can 55 | run `./config.status' to actually configure the package. You can also 56 | give `config.status' the `--recheck' option, which makes it re-run 57 | `configure' with the same arguments you used before. This option is 58 | useful if you change `configure'. 59 | 60 | Some packages pay attention to `--with-PACKAGE' options to `configure', 61 | where PACKAGE is something like `gnu-libc' or `x' (for the X Window System). 62 | The README should mention any --with- options that the package recognizes. 63 | 64 | `configure' ignores any other arguments that you give it. 65 | 66 | If your system requires unusual options for compilation or linking 67 | that `configure' doesn't know about, you can give `configure' initial 68 | values for some variables by setting them in the environment. In 69 | Bourne-compatible shells, you can do that on the command line like 70 | this: 71 | CC='gcc -traditional' DEFS=-D_POSIX_SOURCE ./configure 72 | 73 | The `make' variables that you might want to override with environment 74 | variables when running `configure' are: 75 | 76 | (For these variables, any value given in the environment overrides the 77 | value that `configure' would choose:) 78 | CC C compiler program. 79 | Default is `cc', or `gcc' if `gcc' is in your PATH. 80 | INSTALL Program to use to install files. 81 | Default is `install' if you have it, `cp' otherwise. 82 | 83 | (For these variables, any value given in the environment is added to 84 | the value that `configure' chooses:) 85 | DEFS Configuration options, in the form `-Dfoo -Dbar ...' 86 | Do not use this variable in packages that create a 87 | configuration header file. 88 | LIBS Libraries to link with, in the form `-lfoo -lbar ...' 89 | 90 | If you need to do unusual things to compile the package, we encourage 91 | you to figure out how `configure' could check whether to do them, and 92 | mail diffs or instructions to the address given in the README so we 93 | can include them in the next release. 94 | 95 | 2. Type `make' to compile the package. If you want, you can override 96 | the `make' variables CFLAGS and LDFLAGS like this: 97 | 98 | make CFLAGS=-O2 LDFLAGS=-s 99 | 100 | 3. If the package comes with self-tests and you want to run them, 101 | type `make check'. If you're not sure whether there are any, try it; 102 | if `make' responds with something like 103 | make: *** No way to make target `check'. Stop. 104 | then the package does not come with self-tests. 105 | 106 | 4. Type `make install' to install programs, data files, and 107 | documentation. 108 | 109 | 5. You can remove the program binaries and object files from the 110 | source directory by typing `make clean'. To also remove the 111 | Makefile(s), the header file containing system-dependent definitions 112 | (if the package uses one), and `config.status' (all the files that 113 | `configure' created), type `make distclean'. 114 | 115 | The file `configure.in' is used as a template to create `configure' by 116 | a program called `autoconf'. You will only need it if you want to 117 | regenerate `configure' using a newer version of `autoconf'. 118 | -------------------------------------------------------------------------------- /.github/WORKFLOW-STRUCTURE.md: -------------------------------------------------------------------------------- 1 | # GitHub Actions Workflow Structure 2 | 3 | This document explains the workflow architecture for ngrep CI/CD. 4 | 5 | ## Overview 6 | 7 | The workflows use a **reusable workflow pattern** to eliminate code duplication between CI validation and release builds. 8 | 9 | ## Workflow Files 10 | 11 | ### `matrix.yml` (Reusable Workflow) 12 | **Purpose**: Core build logic for all platforms 13 | 14 | **Features**: 15 | - Defines the complete build matrix (14 platform/compiler combinations) 16 | - Contains all build steps for Linux, macOS, BSD, Solaris, and Windows 17 | - Accepts `create_artifacts` input parameter to control artifact generation 18 | - Conditionally packages binaries based on the input parameter 19 | 20 | **Called by**: `build.yml` and `release.yml` 21 | 22 | ### `build.yml` (CI Validation) 23 | **Purpose**: Continuous integration validation on every commit 24 | 25 | **Triggers**: 26 | - Push to `master` branch (when source files change) 27 | - Pull requests 28 | - Manual workflow dispatch 29 | 30 | **Behavior**: 31 | - Calls `matrix.yml` with `create_artifacts: false` 32 | - Builds all platforms to verify compilation 33 | - Does NOT create or upload artifacts 34 | - Fast feedback for development 35 | 36 | ### `release.yml` (Release Builds) 37 | **Purpose**: Create distributable artifacts for releases 38 | 39 | **Triggers**: 40 | - Git tags matching `v*` (e.g., `v1.0.0`, `v2.1.3`) 41 | 42 | **Behavior**: 43 | - Calls `matrix.yml` with `create_artifacts: true` 44 | - Builds all platforms and packages artifacts 45 | - Creates GitHub Release with: 46 | - Binary-only packages (`.tar.gz` / `.zip`) 47 | - Full installation packages (`-full.tar.gz`) 48 | - SHA256 checksums 49 | - Professional release notes 50 | 51 | ### `docker.yml` (Container Builds) 52 | **Purpose**: Build and publish Docker containers to GitHub Container Registry 53 | 54 | **Triggers**: 55 | - Push to `master` branch 56 | - Git tags matching `v*` (e.g., `v1.0.0`, `v2.1.3`) 57 | - Manual workflow dispatch 58 | 59 | **Behavior**: 60 | - Builds multi-architecture Docker images (amd64, arm64) 61 | - Uses Alpine Linux for minimal image size (~15-20MB) 62 | - Publishes to `ghcr.io/jpr5/ngrep` 63 | - Creates build attestations for supply chain security 64 | - Tags appropriately based on trigger: 65 | - `latest` - Latest master build 66 | - `1.0.0`, `1.0`, `1` - Version tags 67 | - `master`, `master-` - Branch tags 68 | 69 | ## Artifact Generation 70 | 71 | Artifacts are only created when `create_artifacts: true`: 72 | 73 | ### Unix/BSD/Solaris Platforms 74 | - `ngrep-.tar.gz` - Binary only 75 | - `ngrep--full.tar.gz` - Complete installation 76 | 77 | ### Windows Platform 78 | - `ngrep-windows-x86_64.zip` - Contains: 79 | - `ngrep.exe` 80 | - `pcre2-8.dll` (automatically detected) 81 | - `README.txt` 82 | 83 | ## Platform Matrix 84 | 85 | The build matrix includes: 86 | 87 | | Platform | Compiler | Architecture | Artifact Name | 88 | |----------|----------|--------------|---------------| 89 | | Ubuntu Latest | GCC | x86_64 | `ngrep-linux-x86_64` | 90 | | Ubuntu Latest | GCC | ARM64 | `ngrep-linux-arm64` | 91 | | Ubuntu Latest | Clang | x86_64 | (CI only) | 92 | | macOS 15 | Clang | ARM64 | `ngrep-macos-15-arm64` | 93 | | macOS 26 | Clang | ARM64 | `ngrep-macos-26-arm64` | 94 | | FreeBSD 15 | GCC | x86_64 | `ngrep-freebsd-15-x86_64` | 95 | | FreeBSD 15 | Clang | x86_64 | (CI only) | 96 | | OpenBSD 7 | GCC | x86_64 | `ngrep-openbsd-7-x86_64` | 97 | | OpenBSD 7 | Clang | x86_64 | (CI only) | 98 | | NetBSD 10 | GCC | x86_64 | `ngrep-netbsd-10-x86_64` | 99 | | NetBSD 10 | Clang | x86_64 | (CI only) | 100 | | Solaris 11 | GCC | x86_64 | `ngrep-solaris-11-x86_64` | 101 | | Solaris 11 | Clang | x86_64 | (CI only) | 102 | | Windows Latest | MSVC | x86_64 | `ngrep-windows-x86_64` | 103 | 104 | **Note**: Clang variants provide CI validation but don't generate release artifacts (GCC builds are sufficient for distribution). 105 | 106 | ## Making Changes 107 | 108 | ### Adding a New Platform 109 | 1. Edit `matrix.yml` 110 | 2. Add to `matrix.name` array 111 | 3. Add to `matrix.include` with `artifact_name` (if releasing) 112 | 4. Add build step with appropriate `if` condition 113 | 114 | ### Changing Build Steps 115 | 1. Edit `matrix.yml` 116 | 2. Modify the relevant platform's build step 117 | 3. Changes apply to both CI and releases automatically 118 | 119 | ### Modifying Release Process 120 | 1. Edit `release.yml` 121 | 2. Modify the `create-release` job 122 | 3. Build steps remain unchanged in `matrix.yml` 123 | 124 | ## Workflow Execution 125 | 126 | ### Normal Development 127 | ``` 128 | git push → build.yml → matrix.yml (artifacts: false) → Validation only 129 | → docker.yml → Build & publish container → ghcr.io/jpr5/ngrep:latest 130 | ``` 131 | 132 | ### Creating a Release 133 | ``` 134 | git tag -a v1.0.0 -m "Release 1.0.0" 135 | git push origin v1.0.0 → release.yml → matrix.yml (artifacts: true) → GitHub Release 136 | → docker.yml → Build & publish container → ghcr.io/jpr5/ngrep:1.0.0 137 | ``` 138 | 139 | ## Version Management 140 | 141 | ngrep uses a **centralized version system**: 142 | 143 | - **Single Source**: `VERSION` file in repository root 144 | - **Unix builds**: `configure.ac` reads `VERSION` → generates `config.h` 145 | - **Windows builds**: `CMakeLists.txt` reads `VERSION` → passes to compiler 146 | - **Result**: All builds get version from one place 147 | 148 | See [RELEASE.md](RELEASE.md) for detailed version management documentation. 149 | 150 | ## Distribution Channels 151 | 152 | ngrep is distributed through multiple channels: 153 | 154 | 1. **Binary Releases** - Platform-specific binaries via GitHub Releases 155 | - Linux (x86_64, ARM64) 156 | - macOS (ARM64) 157 | - FreeBSD, OpenBSD, NetBSD, Solaris (x86_64) 158 | - Windows (x86_64) 159 | 160 | 2. **Docker Containers** - Multi-architecture containers via GHCR 161 | - `ghcr.io/jpr5/ngrep:latest` - Latest master build 162 | - `ghcr.io/jpr5/ngrep:1.0.0` - Specific version 163 | - Alpine-based (~15-20MB) 164 | - Supports linux/amd64 and linux/arm64 165 | 166 | 3. **Source Code** - Via GitHub repository 167 | - Autotools-based build system 168 | - CMake for Windows 169 | -------------------------------------------------------------------------------- /winXX/inet_ntop.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: inet_ntop.c,v 1.2 2005/05/04 18:09:46 jpr5 Exp $ 3 | * 4 | * This is WinXX-specific support functionality for inet_ntop(), 5 | * which is missing from WinXX. The code was used from FreeBSD: 6 | * 7 | * $FreeBSD: /repoman/r/ncvs/src/lib/libc/net/inet_ntop.c,v 1.6.2.2 2002/12/16 15:19:35 robert Exp $" 8 | */ 9 | 10 | /* Copyright (c) 1996 by Internet Software Consortium. 11 | * 12 | * Permission to use, copy, modify, and distribute this software for any 13 | * purpose with or without fee is hereby granted, provided that the above 14 | * copyright notice and this permission notice appear in all copies. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 17 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 19 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 20 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 21 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 22 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 23 | * SOFTWARE. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "types.h" 32 | 33 | /* 34 | * WARNING: Don't even consider trying to compile this on a system where 35 | * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 36 | */ 37 | 38 | static const char *inet_ntop4(const u_char *src, char *dst, size_t size); 39 | static const char *inet_ntop6(const u_char *src, char *dst, size_t size); 40 | 41 | /* char * 42 | * inet_ntop(af, src, dst, size) 43 | * convert a network format address to presentation format. 44 | * return: 45 | * pointer to presentation format address (`dst'), or NULL (see errno). 46 | * author: 47 | * Paul Vixie, 1996. 48 | */ 49 | const char *inet_ntop(int af, const void *src, char *dst, size_t size) { 50 | switch (af) { 51 | case AF_INET: 52 | return (inet_ntop4(src, dst, size)); 53 | case AF_INET6: 54 | return (inet_ntop6(src, dst, size)); 55 | } 56 | 57 | errno = WSAEAFNOSUPPORT; 58 | return (NULL); 59 | } 60 | 61 | /* const char * 62 | * inet_ntop4(src, dst, size) 63 | * format an IPv4 address, more or less like inet_ntoa() 64 | * return: 65 | * `dst' (as a const) 66 | * notes: 67 | * (1) uses no statics 68 | * (2) takes a u_char* not an in_addr as input 69 | * author: 70 | * Paul Vixie, 1996. 71 | */ 72 | static const char *inet_ntop4(const u_char *src, char *dst, size_t size) { 73 | static const char fmt[] = "%u.%u.%u.%u"; 74 | 75 | if ((size_t)_snprintf(dst, size, fmt, src[0], src[1], src[2], src[3]) 76 | >= size) { 77 | errno = ENOSPC; 78 | return (NULL); 79 | } 80 | 81 | return (dst); 82 | } 83 | 84 | /* const char * 85 | * inet_ntop6(src, dst, size) 86 | * convert IPv6 binary address into presentation (printable) format 87 | * author: 88 | * Paul Vixie, 1996. 89 | */ 90 | static const char *inet_ntop6(const u_char *src, char *dst, size_t size) { 91 | /* 92 | * Note that int32_t and int16_t need only be "at least" large enough 93 | * to contain a value of the specified size. On some systems, like 94 | * Crays, there is no such thing as an integer variable with 16 bits. 95 | * Keep this in mind if you think this function should have been coded 96 | * to use pointer overlays. All the world's not a VAX. 97 | */ 98 | char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; 99 | struct { int base, len; } best, cur; 100 | u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; 101 | int i; 102 | 103 | /* 104 | * Preprocess: 105 | * Copy the input (bytewise) array into a wordwise array. 106 | * Find the longest run of 0x00's in src[] for :: shorthanding. 107 | */ 108 | memset(words, '\0', sizeof words); 109 | for (i = 0; i < NS_IN6ADDRSZ; i++) 110 | words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); 111 | 112 | best.base = -1; 113 | cur.base = -1; 114 | 115 | for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) 116 | if (words[i] == 0) { 117 | if (cur.base == -1) 118 | cur.base = i, cur.len = 1; 119 | else 120 | cur.len++; 121 | } else 122 | if (cur.base != -1) { 123 | if (best.base == -1 || cur.len > best.len) 124 | best = cur; 125 | cur.base = -1; 126 | } 127 | 128 | if (cur.base != -1) 129 | if (best.base == -1 || cur.len > best.len) 130 | best = cur; 131 | 132 | if (best.base != -1 && best.len < 2) 133 | best.base = -1; 134 | 135 | /* 136 | * Format the result. 137 | */ 138 | tp = tmp; 139 | 140 | for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { 141 | 142 | /* Are we inside the best run of 0x00's? */ 143 | if (best.base != -1 && i >= best.base 144 | && i < (best.base + best.len)) { 145 | if (i == best.base) 146 | *tp++ = ':'; 147 | continue; 148 | } 149 | 150 | /* Are we following an initial run of 0x00s or any real hex? */ 151 | if (i != 0) 152 | *tp++ = ':'; 153 | 154 | /* Is this address an encapsulated IPv4? */ 155 | if (i == 6 && best.base == 0 && 156 | (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { 157 | if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) 158 | return (NULL); 159 | 160 | tp += strlen(tp); 161 | 162 | break; 163 | } 164 | 165 | tp += sprintf(tp, "%x", words[i]); 166 | } 167 | 168 | /* Was it a trailing run of 0x00's? */ 169 | if (best.base != -1 && (best.base + best.len) == 170 | (NS_IN6ADDRSZ / NS_INT16SZ)) 171 | *tp++ = ':'; 172 | 173 | *tp++ = '\0'; 174 | 175 | /* 176 | * Check for overflow, copy, and we're done. 177 | */ 178 | 179 | if ((size_t)(tp - tmp) > size) { 180 | errno = ENOSPC; 181 | return (NULL); 182 | } 183 | 184 | strcpy(dst, tmp); 185 | return (dst); 186 | } 187 | -------------------------------------------------------------------------------- /DOCKER.md: -------------------------------------------------------------------------------- 1 | # ngrep Docker Container 2 | 3 | ngrep is available as a Docker container from GitHub Container Registry (GHCR). 4 | 5 | ## Quick Start 6 | 7 | ```bash 8 | # Pull the latest image 9 | docker pull ghcr.io/jpr5/ngrep:latest 10 | 11 | # Run ngrep (requires NET_RAW capability for packet capture) 12 | docker run --rm --net=host --cap-add=NET_RAW ghcr.io/jpr5/ngrep:latest -q 'GET|POST' tcp port 80 13 | ``` 14 | 15 | ## Available Tags 16 | 17 | - `latest` - Latest build from master branch 18 | - `1.48`, `1.48.0` - Specific version tags 19 | - `1` - Latest v1.x release 20 | - `master` - Latest master branch build 21 | - `master-` - Specific commit from master 22 | 23 | ## Usage Examples 24 | 25 | ### Basic HTTP Traffic Monitoring 26 | 27 | ```bash 28 | docker run --rm --net=host --cap-add=NET_RAW \ 29 | ghcr.io/jpr5/ngrep:latest \ 30 | -q 'GET|POST' tcp port 80 31 | ``` 32 | 33 | ### DNS Query Monitoring 34 | 35 | ```bash 36 | docker run --rm --net=host --cap-add=NET_RAW \ 37 | ghcr.io/jpr5/ngrep:latest \ 38 | -q -W byline port 53 39 | ``` 40 | 41 | ### Monitor Specific Interface 42 | 43 | ```bash 44 | docker run --rm --net=host --cap-add=NET_RAW \ 45 | ghcr.io/jpr5/ngrep:latest \ 46 | -d eth0 -q '' tcp port 443 47 | ``` 48 | 49 | ### Save to PCAP File 50 | 51 | ```bash 52 | docker run --rm --net=host --cap-add=NET_RAW \ 53 | -v $(pwd):/data \ 54 | ghcr.io/jpr5/ngrep:latest \ 55 | -O /data/capture.pcap -q '' port 80 56 | ``` 57 | 58 | ### Read from PCAP File 59 | 60 | ```bash 61 | docker run --rm \ 62 | -v $(pwd):/data \ 63 | ghcr.io/jpr5/ngrep:latest \ 64 | -I /data/capture.pcap -q 'User-Agent' 65 | ``` 66 | 67 | ## Network Modes 68 | 69 | ### Host Network (Recommended) 70 | 71 | Use `--net=host` to capture traffic on the host's network interfaces: 72 | 73 | ```bash 74 | docker run --rm --net=host --cap-add=NET_RAW ghcr.io/jpr5/ngrep:latest 75 | ``` 76 | 77 | **Pros**: Can see all host traffic, works with all interfaces 78 | **Cons**: Less isolation 79 | 80 | ### Bridge Network 81 | 82 | Capture traffic within the container's network namespace: 83 | 84 | ```bash 85 | docker run --rm --cap-add=NET_RAW ghcr.io/jpr5/ngrep:latest -d eth0 86 | ``` 87 | 88 | **Pros**: Better isolation 89 | **Cons**: Only sees container's own traffic 90 | 91 | ### Container Network 92 | 93 | Monitor traffic from another container: 94 | 95 | ```bash 96 | # Start a container 97 | docker run -d --name web nginx 98 | 99 | # Monitor its traffic 100 | docker run --rm --net=container:web --cap-add=NET_RAW \ 101 | ghcr.io/jpr5/ngrep:latest \ 102 | -q '' port 80 103 | ``` 104 | 105 | ## Required Capabilities 106 | 107 | ngrep requires the `NET_RAW` capability to capture packets. You must run with: 108 | 109 | ```bash 110 | --cap-add=NET_RAW 111 | ``` 112 | 113 | Or for full privileges (not recommended): 114 | 115 | ```bash 116 | --privileged 117 | ``` 118 | 119 | ## Building Locally 120 | 121 | ### Alpine-based (Default, Smallest) 122 | 123 | ```bash 124 | # Clone the repository 125 | git clone https://github.com/jpr5/ngrep.git 126 | cd ngrep 127 | 128 | # Build the Alpine-based image (~16MB) 129 | docker build -t ngrep:local . 130 | 131 | # Run it 132 | docker run --rm --net=host --cap-add=NET_RAW ngrep:local --help 133 | ``` 134 | 135 | ### Ubuntu-based (Alternative) 136 | 137 | If you need glibc compatibility or prefer Ubuntu: 138 | 139 | ```bash 140 | # Build the Ubuntu-based image (~150MB) 141 | docker build -f Dockerfile.ubuntu -t ngrep:ubuntu . 142 | 143 | # Run it 144 | docker run --rm --net=host --cap-add=NET_RAW ngrep:ubuntu --help 145 | ``` 146 | 147 | ## Multi-Architecture Support 148 | 149 | The container is built for multiple architectures: 150 | 151 | - `linux/amd64` (x86_64) 152 | - `linux/arm64` (ARM64/aarch64) 153 | 154 | Docker will automatically pull the correct image for your platform. 155 | 156 | ## Image Details 157 | 158 | - **Base**: Alpine Linux 3.20 159 | - **Size**: ~16MB (compressed) 160 | - **C Library**: musl libc (smaller and more secure than glibc) 161 | - **Runtime Dependencies**: libpcap, pcre2, libnet 162 | - **Build**: Multi-stage for minimal final image 163 | - **Architectures**: linux/amd64, linux/arm64 164 | 165 | ## Security Considerations 166 | 167 | 1. **Capabilities**: Only grant `NET_RAW`, not full `--privileged` 168 | 2. **Network Mode**: Use `--net=host` only when necessary 169 | 3. **User**: Container runs as root (required for packet capture) 170 | 4. **Volumes**: Mount volumes read-only when possible 171 | 172 | ## Troubleshooting 173 | 174 | ### Permission Denied 175 | 176 | ``` 177 | ngrep: pcap_open_live(): socket: Operation not permitted 178 | ``` 179 | 180 | **Solution**: Add `--cap-add=NET_RAW` to your docker run command. 181 | 182 | ### musl libc Compatibility 183 | 184 | The default Alpine-based image uses musl libc instead of glibc. This is smaller and more secure, but if you encounter compatibility issues with certain tools or libraries, use the Ubuntu-based image: 185 | 186 | ```bash 187 | docker build -f Dockerfile.ubuntu -t ngrep:ubuntu . 188 | ``` 189 | 190 | ### No Interfaces Found 191 | 192 | ``` 193 | ngrep: can't get list of interfaces 194 | ``` 195 | 196 | **Solution**: Use `--net=host` to access host interfaces. 197 | 198 | ### Interface Not Found 199 | 200 | ``` 201 | ngrep: unknown interface eth0 202 | ``` 203 | 204 | **Solution**: List available interfaces first: 205 | 206 | ```bash 207 | docker run --rm --net=host --cap-add=NET_RAW \ 208 | ghcr.io/jpr5/ngrep:latest -L 209 | ``` 210 | 211 | ## Kubernetes 212 | 213 | Deploy ngrep as a DaemonSet to monitor cluster traffic: 214 | 215 | ```yaml 216 | apiVersion: apps/v1 217 | kind: DaemonSet 218 | metadata: 219 | name: ngrep 220 | spec: 221 | selector: 222 | matchLabels: 223 | app: ngrep 224 | template: 225 | metadata: 226 | labels: 227 | app: ngrep 228 | spec: 229 | hostNetwork: true 230 | containers: 231 | - name: ngrep 232 | image: ghcr.io/jpr5/ngrep:latest 233 | args: ["-q", "GET|POST", "tcp", "port", "80"] 234 | securityContext: 235 | capabilities: 236 | add: ["NET_RAW"] 237 | ``` 238 | 239 | ## Docker Compose 240 | 241 | ```yaml 242 | version: '3.8' 243 | 244 | services: 245 | ngrep: 246 | image: ghcr.io/jpr5/ngrep:latest 247 | network_mode: host 248 | cap_add: 249 | - NET_RAW 250 | command: ["-q", "GET|POST", "tcp", "port", "80"] 251 | restart: unless-stopped 252 | ``` 253 | 254 | ## Links 255 | 256 | - **GitHub Repository**: https://github.com/jpr5/ngrep 257 | - **Container Registry**: https://github.com/jpr5/ngrep/pkgs/container/ngrep 258 | - **Documentation**: https://github.com/jpr5/ngrep/blob/master/README.md 259 | -------------------------------------------------------------------------------- /winXX/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Because Windows standard headers are woefully inadequate for (real) 3 | * network application development, and because I'm basically lazy, I 4 | * created this header as a container for the types ngrep needs. 5 | * 6 | * These include standard types like u*int*_t's, as well as network 7 | * protocol-specific structures and types. 8 | */ 9 | 10 | typedef unsigned char u_int8_t; 11 | typedef unsigned short int u_int16_t; 12 | typedef unsigned int u_int32_t; 13 | 14 | typedef unsigned char uint8_t; 15 | typedef unsigned short int uint16_t; 16 | typedef unsigned int uint32_t; 17 | 18 | typedef signed char int8_t; 19 | typedef signed short int int16_t; 20 | typedef signed int int32_t; 21 | 22 | 23 | 24 | #define IP_RF 0x8000 /* reserved fragment flag */ 25 | #define IP_DF 0x4000 /* dont fragment flag */ 26 | #define IP_MF 0x2000 /* more fragments flag */ 27 | #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ 28 | 29 | struct ip { 30 | u_int8_t ip_hl:4; /* header length */ 31 | u_int8_t ip_v:4; /* version */ 32 | u_int8_t ip_tos; /* type of service */ 33 | u_int16_t ip_len; /* total length */ 34 | u_int16_t ip_id; /* identification */ 35 | u_int16_t ip_off; /* fragment offset field */ 36 | u_int8_t ip_ttl; /* time to live */ 37 | u_int8_t ip_p; /* protocol */ 38 | u_int16_t ip_sum; /* checksum */ 39 | struct in_addr ip_src, ip_dst; /* source and dest address */ 40 | }; 41 | 42 | #define TH_FIN 0x01 43 | #define TH_SYN 0x02 44 | #define TH_RST 0x04 45 | #define TH_PUSH 0x08 46 | #define TH_ACK 0x10 47 | #define TH_URG 0x20 48 | 49 | typedef u_int32_t tcp_seq; 50 | 51 | struct tcphdr { 52 | u_int16_t th_sport; /* source port */ 53 | u_int16_t th_dport; /* destination port */ 54 | tcp_seq th_seq; /* sequence number */ 55 | tcp_seq th_ack; /* acknowledgement number */ 56 | u_int8_t th_x2:4; /* (unused) */ 57 | u_int8_t th_off:4; /* data offset */ 58 | u_int8_t th_flags; 59 | u_int16_t th_win; /* window */ 60 | u_int16_t th_sum; /* checksum */ 61 | u_int16_t th_urp; /* urgent pointer */ 62 | }; 63 | 64 | struct udphdr { 65 | u_int16_t uh_sport; /* source port */ 66 | u_int16_t uh_dport; /* destination port */ 67 | u_int16_t uh_ulen; /* udp length */ 68 | u_int16_t uh_sum; /* udp checksum */ 69 | }; 70 | 71 | 72 | struct icmp { 73 | u_int8_t icmp_type; 74 | u_int8_t icmp_code; 75 | u_int16_t icmp_cksum; 76 | 77 | union { 78 | u_int8_t ih_pptr; 79 | struct in_addr ih_gwaddr; 80 | struct ih_idseq { 81 | u_int16_t icd_id; 82 | u_int16_t icd_seq; 83 | } ih_idseq; 84 | u_int32_t ih_void; 85 | 86 | struct ih_pmtu { 87 | u_int16_t ipm_void; 88 | u_int16_t ipm_nextmtu; 89 | } ih_pmtu; 90 | 91 | struct ih_rtradv { 92 | u_int8_t irt_num_addrs; 93 | u_int8_t irt_wpa; 94 | u_int16_t irt_lifetime; 95 | } ih_rtradv; 96 | } icmp_hun; 97 | }; 98 | 99 | struct igmp { 100 | u_int8_t igmp_type; /* IGMP type */ 101 | u_int8_t igmp_code; /* routing code */ 102 | u_int16_t igmp_cksum; /* checksum */ 103 | struct in_addr igmp_group; /* group address */ 104 | }; 105 | 106 | /* 107 | * Taken from arpa/namser.h, used by inet_?to?() (WinXX support). 108 | */ 109 | 110 | #define NS_INADDRSZ 4 111 | #define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ 112 | #define NS_INT16SZ 2 /* #/bytes of data in a u_int16_t */ 113 | 114 | /* 115 | * IPv6 and ICMPv6 declarations. 116 | */ 117 | 118 | /* IPv6 address */ 119 | struct UNIX_in6_addr { 120 | union { 121 | uint8_t u6_addr8[16]; 122 | uint16_t u6_addr16[8]; 123 | uint32_t u6_addr32[4]; 124 | } in6_u; 125 | }; 126 | 127 | struct ip6_hdr { 128 | union { 129 | struct ip6_hdrctl { 130 | uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC, 131 | 20 bits flow-ID */ 132 | uint16_t ip6_un1_plen; /* payload length */ 133 | uint8_t ip6_un1_nxt; /* next header */ 134 | uint8_t ip6_un1_hlim; /* hop limit */ 135 | } ip6_un1; 136 | 137 | uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits tclass */ 138 | 139 | } ip6_ctlun; 140 | 141 | struct UNIX_in6_addr ip6_src; /* source address */ 142 | struct UNIX_in6_addr ip6_dst; /* destination address */ 143 | }; 144 | 145 | #define ip6_vfc ip6_ctlun.ip6_un2_vfc 146 | #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow 147 | #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen 148 | #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt 149 | #define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim 150 | #define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim 151 | 152 | /* Fragment header */ 153 | struct ip6_frag { 154 | uint8_t ip6f_nxt; /* next header */ 155 | uint8_t ip6f_reserved; /* reserved field */ 156 | uint16_t ip6f_offlg; /* offset, reserved, and flag */ 157 | uint32_t ip6f_ident; /* identification */ 158 | }; 159 | 160 | #if BYTE_ORDER == BIG_ENDIAN 161 | #define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */ 162 | #define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */ 163 | #define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */ 164 | #else /* BYTE_ORDER == LITTLE_ENDIAN */ 165 | #define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */ 166 | #define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */ 167 | #define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */ 168 | #endif 169 | 170 | struct icmp6_hdr { 171 | uint8_t icmp6_type; /* type field */ 172 | uint8_t icmp6_code; /* code field */ 173 | uint16_t icmp6_cksum; /* checksum field */ 174 | union { 175 | uint32_t icmp6_un_data32[1]; /* type-specific field */ 176 | uint16_t icmp6_un_data16[2]; /* type-specific field */ 177 | uint8_t icmp6_un_data8[4]; /* type-specific field */ 178 | } icmp6_dataun; 179 | }; 180 | -------------------------------------------------------------------------------- /.github/RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release Process 2 | 3 | This document explains how to create a new release of ngrep. 4 | 5 | ## Overview 6 | 7 | ngrep uses **Git tags** to trigger release builds. When you push a version tag, GitHub Actions automatically: 8 | 9 | 1. Builds binaries for all supported platforms (9 platforms total) 10 | 2. Packages them as `.tar.gz` (Unix) or `.zip` (Windows) 11 | 3. Generates SHA256 checksums 12 | 4. Creates a GitHub Release with all artifacts 13 | 5. Builds and publishes Docker containers to GitHub Container Registry 14 | 15 | ## Supported Platforms 16 | 17 | Release builds are created for: 18 | 19 | - **Linux**: Ubuntu (x86_64, ARM64) 20 | - **macOS**: macOS 15 (ARM64), macOS 26 (ARM64) 21 | - **BSD**: FreeBSD 15, OpenBSD 7, NetBSD 10 (x86_64) 22 | - **Solaris**: Solaris 11 (x86_64) 23 | - **Windows**: Windows 11 (x86_64) 24 | 25 | ## Creating a Release 26 | 27 | ### 1. Prepare the Release 28 | 29 | Ensure all changes are committed and pushed to `master`: 30 | 31 | ```bash 32 | git checkout master 33 | git pull 34 | ``` 35 | 36 | ### 2. Update Version Information 37 | 38 | **Version is now centralized in a single `VERSION` file.** 39 | 40 | Update the version number: 41 | 42 | ```bash 43 | # Edit the VERSION file (contains just the version number, e.g., "1.0.0") 44 | echo "1.0.0" > VERSION 45 | 46 | # Optionally update README.md header (line 1) to match 47 | # Example: ## ngrep 1.0.0 (MM.DD.YYYY) 48 | 49 | # Regenerate configure script from configure.ac 50 | autoconf 51 | ``` 52 | 53 | **What gets updated automatically:** 54 | - `config.h` (Unix builds) - Generated by `configure` from `VERSION` 55 | - `ngrep` binary version string - Reads `VERSION` via `config.h` 56 | - Windows builds - CMake reads `VERSION` file directly 57 | 58 | **What you still update manually:** 59 | - `README.md` line 1 - Update version and date in the header 60 | 61 | Commit these changes: 62 | 63 | ```bash 64 | git add VERSION README.md configure 65 | git commit -m "Bump version to 1.0.0" 66 | git push 67 | ``` 68 | 69 | ### 3. Create and Push the Tag 70 | 71 | Create an annotated tag with the version number: 72 | 73 | ```bash 74 | # Format: vMAJOR.MINOR.PATCH 75 | git tag -a v1.0.0 -m "Release 1.0.0" 76 | git push origin v1.0.0 77 | ``` 78 | 79 | **Important**: The tag MUST start with `v` (e.g., `v1.0.0`, `v2.1.3`) 80 | 81 | ### 4. Monitor the Build 82 | 83 | 1. Go to: https://github.com/jpr5/ngrep/actions 84 | 2. Watch the "Release Build & Publish" workflow 85 | 3. Watch the "Docker Build & Publish" workflow 86 | 4. Build takes upwards of ~10 minutes (emulated BSD/Solaris VMs are slower) 87 | 88 | ### 5. Verify the Release 89 | 90 | Once complete: 91 | 92 | 1. **Binary Release**: 93 | - Go to: https://github.com/jpr5/ngrep/releases 94 | - Verify all 9 platform artifacts are present 95 | - Check SHA256SUMS file 96 | - Test download and extraction of at least one artifact 97 | 98 | 2. **Docker Container**: 99 | - Go to: https://github.com/jpr5/ngrep/pkgs/container/ngrep 100 | - Verify the version tag is present (e.g., `1.0.0`) 101 | - Test pulling and running: `docker pull ghcr.io/jpr5/ngrep:1.0.0` 102 | 103 | ### 6. Update Homebrew 104 | 105 | 1. Fork the Homebrew/homebrew-core repository on Github to your account 106 | 107 | 2. Bring local copy of homebrew repo 108 | ```bash 109 | brew tap homebrew/core --force 110 | ``` 111 | 112 | 3. Auto-submit PR for version update 113 | ```bash 114 | brew bump-formula-pr --strict ngrep --version 1.0.0 115 | ``` 116 | 117 | ## Release Artifacts 118 | 119 | Each release includes: 120 | 121 | ### Binary-Only Packages 122 | - `ngrep-.tar.gz` - Just the `ngrep` binary 123 | - `ngrep-windows-x86_64.zip` - Windows executable with DLLs 124 | 125 | ### Full Packages 126 | - `ngrep--full.tar.gz` - Complete installation (binary + man pages + docs) 127 | 128 | ### Checksums 129 | - `SHA256SUMS` - SHA256 checksums for all artifacts 130 | 131 | ### Docker Containers 132 | - `ghcr.io/jpr5/ngrep:1.0.0` - Specific version 133 | - `ghcr.io/jpr5/ngrep:1.0` - Major.minor version 134 | - `ghcr.io/jpr5/ngrep:1` - Major version 135 | - `ghcr.io/jpr5/ngrep:latest` - Latest release 136 | - Multi-architecture: linux/amd64, linux/arm64 137 | - Alpine-based (~15-20MB compressed) 138 | 139 | ## Troubleshooting 140 | 141 | ### Build Failed for One Platform 142 | 143 | If a single platform fails: 144 | 1. Check the workflow logs for that platform 145 | 2. Fix the issue in the code 146 | 3. Delete the tag: `git tag -d v1.0.0 && git push origin :refs/tags/v1.0.0` 147 | 4. Re-create the tag after fixing 148 | 149 | ### Wrong Version Number 150 | 151 | If you tagged the wrong version: 152 | 1. Delete the GitHub Release (if created) 153 | 2. Delete the tag locally: `git tag -d v1.0.0` 154 | 3. Delete the tag remotely: `git push origin :refs/tags/v1.0.0` 155 | 4. Create the correct tag 156 | 157 | ### Pre-release / Beta Versions 158 | 159 | For pre-releases, use tags like: 160 | - `v1.0.0-beta1` 161 | - `v1.0.0-rc1` 162 | - `v2.0.0-alpha` 163 | 164 | The workflow will still build them, but you should manually mark the GitHub Release as "pre-release". 165 | 166 | ## Version Management 167 | 168 | ngrep uses a **centralized version system** with a single source of truth: 169 | 170 | ### Architecture 171 | 172 | **Single Source**: `VERSION` file (contains just the version number, e.g., `1.0.0`) 173 | 174 | **How it flows:** 175 | 176 | 1. **Unix/Linux/BSD/Solaris builds** (autoconf): 177 | - `configure.ac` reads `VERSION` via `m4_esyscmd_s([cat VERSION])` 178 | - `AC_INIT([ngrep],m4_esyscmd_s([cat VERSION]),...)` 179 | - `AC_DEFINE_UNQUOTED(VERSION, "AC_PACKAGE_VERSION", ...)` writes to `config.h` 180 | - `ngrep.c` includes `config.h` and uses `VERSION` macro 181 | 182 | 2. **Windows builds** (CMake): 183 | - `CMakeLists.txt` reads `VERSION` via `file(READ ... NGREP_VERSION)` 184 | - Passes `-DVERSION="1.0.0"` to compiler 185 | - `ngrep.c` uses `VERSION` macro from compile definition 186 | 187 | 3. **Documentation**: 188 | - `README.md` - Still updated manually (includes release date) 189 | 190 | ### Files Involved 191 | 192 | - **`VERSION`** - Single source of truth (edit this to bump version) 193 | - **`configure.ac`** - Reads `VERSION`, generates `config.h` 194 | - **`ngrep.h`** - No longer contains version (removed) 195 | - **`config.h`** - Generated file, contains `#define VERSION "..."` 196 | - **`winXX/CMakeLists.txt`** - Reads `VERSION`, passes to compiler 197 | - **`README.md`** - Manual update (version + date in header) 198 | 199 | ## Workflow Files 200 | 201 | - `.github/workflows/matrix.yml` - Base build steps, reused by build & release 202 | - `.github/workflows/build.yml` - CI validation (runs on every push) 203 | - `.github/workflows/release.yml` - Release builds (runs on tags only) 204 | - `.github/workflows/docker.yml` - Docker container builds (runs on push to master and tags) 205 | 206 | ## Notes 207 | 208 | - **No artifacts on regular commits**: Only tagged releases create downloadable artifacts 209 | - **Retention**: Workflow artifacts are kept for 5 days during build, then moved to GitHub Releases permanently 210 | - **Permissions**: You need write access to the repository to push tags and create releases 211 | - **Docker containers**: Published on both master commits (as `latest`) and version tags (as versioned tags) 212 | 213 | ## Distribution Channels 214 | 215 | After a release, ngrep is available through: 216 | 217 | 1. **GitHub Releases**: https://github.com/jpr5/ngrep/releases 218 | - Platform-specific binaries 219 | - Full installation packages 220 | - SHA256 checksums 221 | 222 | 2. **GitHub Container Registry**: https://github.com/jpr5/ngrep/pkgs/container/ngrep 223 | - Docker containers for linux/amd64 and linux/arm64 224 | - Multiple version tags 225 | - Alpine-based for minimal size 226 | 227 | 3. **Source Code**: https://github.com/jpr5/ngrep 228 | - Git repository with full history 229 | - Build from source instructions 230 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU and other programs. 3 | 4 | scriptversion=2025-06-18.21; # UTC 5 | 6 | # shellcheck disable=SC2006,SC2268 # we must support pre-POSIX shells 7 | 8 | # Copyright (C) 1996-2025 Free Software Foundation, Inc. 9 | # Originally written by Fran,cois Pinard , 1996. 10 | 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation; either version 2, or (at your option) 14 | # any later version. 15 | 16 | # This program is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program. If not, see . 23 | 24 | # As a special exception to the GNU General Public License, if you 25 | # distribute this file as part of a program that contains a 26 | # configuration script generated by Autoconf, you may include it under 27 | # the same distribution terms that you use for the rest of that program. 28 | 29 | if test $# -eq 0; then 30 | echo 1>&2 "Try '$0 --help' for more information" 31 | exit 1 32 | fi 33 | 34 | case $1 in 35 | 36 | --is-lightweight) 37 | # Used by our autoconf macros to check whether the available missing 38 | # script is modern enough. 39 | exit 0 40 | ;; 41 | 42 | --run) 43 | # Back-compat with the calling convention used by older automake. 44 | shift 45 | ;; 46 | 47 | -h|--h|--he|--hel|--help) 48 | echo "\ 49 | $0 [OPTION]... PROGRAM [ARGUMENT]... 50 | 51 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 52 | to PROGRAM being missing or too old. 53 | 54 | Options: 55 | -h, --help display this help and exit 56 | -v, --version output version information and exit 57 | 58 | Supported PROGRAM values: 59 | aclocal autoconf autogen autoheader autom4te automake autoreconf 60 | bison flex help2man lex makeinfo perl yacc 61 | 62 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 63 | 'g' are ignored when checking the name. 64 | 65 | Report bugs to . 66 | GNU Automake home page: . 67 | General help using GNU software: ." 68 | exit $? 69 | ;; 70 | 71 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 72 | echo "missing (GNU Automake) $scriptversion" 73 | exit $? 74 | ;; 75 | 76 | -*) 77 | echo 1>&2 "$0: unknown '$1' option" 78 | echo 1>&2 "Try '$0 --help' for more information" 79 | exit 1 80 | ;; 81 | 82 | esac 83 | 84 | # Run the given program, remember its exit status. 85 | "$@"; st=$? 86 | 87 | # If it succeeded, we are done. 88 | test $st -eq 0 && exit 0 89 | 90 | # Also exit now if we it failed (or wasn't found), and '--version' was 91 | # passed; such an option is passed most likely to detect whether the 92 | # program is present and works. 93 | case $2 in --version|--help) exit $st;; esac 94 | 95 | # Exit code 63 means version mismatch. This often happens when the user 96 | # tries to use an ancient version of a tool on a file that requires a 97 | # minimum version. 98 | if test $st -eq 63; then 99 | msg="probably too old" 100 | elif test $st -eq 127; then 101 | # Program was missing. 102 | msg="missing on your system" 103 | else 104 | # Program was found and executed, but failed. Give up. 105 | exit $st 106 | fi 107 | 108 | perl_URL=https://www.perl.org/ 109 | flex_URL=https://github.com/westes/flex 110 | gnu_software_URL=https://www.gnu.org/software 111 | 112 | program_details () 113 | { 114 | case $1 in 115 | aclocal|automake|autoreconf) 116 | echo "The '$1' program is part of the GNU Automake package:" 117 | echo "<$gnu_software_URL/automake>" 118 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 119 | echo "<$gnu_software_URL/autoconf>" 120 | echo "<$gnu_software_URL/m4/>" 121 | echo "<$perl_URL>" 122 | ;; 123 | autoconf|autom4te|autoheader) 124 | echo "The '$1' program is part of the GNU Autoconf package:" 125 | echo "<$gnu_software_URL/autoconf/>" 126 | echo "It also requires GNU m4 and Perl in order to run:" 127 | echo "<$gnu_software_URL/m4/>" 128 | echo "<$perl_URL>" 129 | ;; 130 | *) 131 | : 132 | ;; 133 | esac 134 | } 135 | 136 | give_advice () 137 | { 138 | # Normalize program name to check for. 139 | normalized_program=`echo "$1" | sed ' 140 | s/^gnu-//; t 141 | s/^gnu//; t 142 | s/^g//; t'` 143 | 144 | printf '%s\n' "'$1' is $msg." 145 | 146 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 147 | autoheader_deps="'acconfig.h'" 148 | automake_deps="'Makefile.am'" 149 | aclocal_deps="'acinclude.m4'" 150 | case $normalized_program in 151 | aclocal*) 152 | echo "You should only need it if you modified $aclocal_deps or" 153 | echo "$configure_deps." 154 | ;; 155 | autoconf*) 156 | echo "You should only need it if you modified $configure_deps." 157 | ;; 158 | autogen*) 159 | echo "You should only need it if you modified a '.def' or '.tpl' file." 160 | echo "You may want to install the GNU AutoGen package:" 161 | echo "<$gnu_software_URL/autogen/>" 162 | ;; 163 | autoheader*) 164 | echo "You should only need it if you modified $autoheader_deps or" 165 | echo "$configure_deps." 166 | ;; 167 | automake*) 168 | echo "You should only need it if you modified $automake_deps or" 169 | echo "$configure_deps." 170 | ;; 171 | autom4te*) 172 | echo "You might have modified some maintainer files that require" 173 | echo "the 'autom4te' program to be rebuilt." 174 | ;; 175 | autoreconf*) 176 | echo "You should only need it if you modified $aclocal_deps or" 177 | echo "$automake_deps or $autoheader_deps or $automake_deps or" 178 | echo "$configure_deps." 179 | ;; 180 | bison*|yacc*) 181 | echo "You should only need it if you modified a '.y' file." 182 | echo "You may want to install the GNU Bison package:" 183 | echo "<$gnu_software_URL/bison/>" 184 | ;; 185 | help2man*) 186 | echo "You should only need it if you modified a dependency" \ 187 | "of a man page." 188 | echo "You may want to install the GNU Help2man package:" 189 | echo "<$gnu_software_URL/help2man/>" 190 | ;; 191 | lex*|flex*) 192 | echo "You should only need it if you modified a '.l' file." 193 | echo "You may want to install the Fast Lexical Analyzer package:" 194 | echo "<$flex_URL>" 195 | ;; 196 | makeinfo*) 197 | echo "You should only need it if you modified a '.texi' file, or" 198 | echo "any other file indirectly affecting the aspect of the manual." 199 | echo "You might want to install the Texinfo package:" 200 | echo "<$gnu_software_URL/texinfo/>" 201 | echo "The spurious makeinfo call might also be the consequence of" 202 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 203 | echo "want to install GNU make:" 204 | echo "<$gnu_software_URL/make/>" 205 | ;; 206 | perl*) 207 | echo "You should only need it to run GNU Autoconf, GNU Automake, " 208 | echo " assorted other tools, or if you modified a Perl source file." 209 | echo "You may want to install the Perl 5 language interpreter:" 210 | echo "<$perl_URL>" 211 | ;; 212 | *) 213 | echo "You might have modified some files without having the proper" 214 | echo "tools for further handling them. Check the 'README' file, it" 215 | echo "often tells you about the needed prerequisites for installing" 216 | echo "this package. You may also peek at any GNU archive site, in" 217 | echo "case some other package contains this missing '$1' program." 218 | ;; 219 | esac 220 | program_details "$normalized_program" 221 | } 222 | 223 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 224 | -e '2,$s/^/ /' >&2 225 | 226 | # Propagate the correct exit status (expected to be 127 for a program 227 | # not found, 63 for a program that failed due to version mismatch). 228 | exit $st 229 | 230 | # Local variables: 231 | # eval: (add-hook 'before-save-hook 'time-stamp nil t) 232 | # time-stamp-start: "scriptversion=" 233 | # time-stamp-format: "%Y-%02m-%02d.%02H" 234 | # time-stamp-time-zone: "UTC0" 235 | # time-stamp-end: "; # UTC" 236 | # End: 237 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for compilers which do not understand '-c -o'. 3 | 4 | scriptversion=2025-06-18.21; # UTC 5 | 6 | # Copyright (C) 1999-2025 Free Software Foundation, Inc. 7 | # Written by Tom Tromey . 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | # This file is maintained in Automake, please report 28 | # bugs to or send patches to 29 | # . 30 | 31 | nl=' 32 | ' 33 | 34 | # We need space, tab and new line, in precisely that order. Quoting is 35 | # there to prevent tools from complaining about whitespace usage. 36 | IFS=" "" $nl" 37 | 38 | file_conv= 39 | 40 | # func_file_conv build_file unneeded_conversions 41 | # Convert a $build file to $host form and store it in $file 42 | # Currently only supports Windows hosts. If the determined conversion 43 | # type is listed in (the comma separated) UNNEEDED_CONVERSIONS, no 44 | # conversion will take place. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | if test -n "$MSYSTEM" && (cygpath --version) >/dev/null 2>&1; then 55 | # MSYS2 environment. 56 | file_conv=cygwin 57 | else 58 | # Original MinGW environment. 59 | file_conv=mingw 60 | fi 61 | ;; 62 | MSYS*) 63 | # Old MSYS environment, or MSYS2 with 32-bit MSYS2 shell. 64 | file_conv=cygwin 65 | ;; 66 | CYGWIN*) 67 | # Cygwin environment. 68 | file_conv=cygwin 69 | ;; 70 | *) 71 | file_conv=wine 72 | ;; 73 | esac 74 | fi 75 | case $file_conv/,$2, in 76 | *,$file_conv,*) 77 | # This is the optimization mentioned above: 78 | # If UNNEEDED_CONVERSIONS contains $file_conv, don't convert. 79 | ;; 80 | mingw/*) 81 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 82 | ;; 83 | cygwin/*) 84 | file=`cygpath -w "$file" || echo "$file"` 85 | ;; 86 | wine/*) 87 | file=`winepath -w "$file" || echo "$file"` 88 | ;; 89 | esac 90 | ;; 91 | esac 92 | } 93 | 94 | # func_cl_dashL linkdir 95 | # Make cl look for libraries in LINKDIR 96 | func_cl_dashL () 97 | { 98 | func_file_conv "$1" 99 | if test -z "$lib_path"; then 100 | lib_path=$file 101 | else 102 | lib_path="$lib_path;$file" 103 | fi 104 | linker_opts="$linker_opts -LIBPATH:$file" 105 | } 106 | 107 | # func_cl_dashl library 108 | # Do a library search-path lookup for cl 109 | func_cl_dashl () 110 | { 111 | lib=$1 112 | found=no 113 | save_IFS=$IFS 114 | IFS=';' 115 | for dir in $lib_path $LIB 116 | do 117 | IFS=$save_IFS 118 | if $shared && test -f "$dir/$lib.dll.lib"; then 119 | found=yes 120 | lib=$dir/$lib.dll.lib 121 | break 122 | fi 123 | if test -f "$dir/$lib.lib"; then 124 | found=yes 125 | lib=$dir/$lib.lib 126 | break 127 | fi 128 | if test -f "$dir/lib$lib.a"; then 129 | found=yes 130 | lib=$dir/lib$lib.a 131 | break 132 | fi 133 | done 134 | IFS=$save_IFS 135 | 136 | if test "$found" != yes; then 137 | lib=$lib.lib 138 | fi 139 | } 140 | 141 | # func_cl_wrapper cl arg... 142 | # Adjust compile command to suit cl 143 | func_cl_wrapper () 144 | { 145 | # Assume a capable shell 146 | lib_path= 147 | shared=: 148 | linker_opts= 149 | for arg 150 | do 151 | if test -n "$eat"; then 152 | eat= 153 | else 154 | case $1 in 155 | -o) 156 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 157 | eat=1 158 | case $2 in 159 | *.o | *.lo | *.[oO][bB][jJ]) 160 | func_file_conv "$2" 161 | set x "$@" -Fo"$file" 162 | shift 163 | ;; 164 | *) 165 | func_file_conv "$2" 166 | set x "$@" -Fe"$file" 167 | shift 168 | ;; 169 | esac 170 | ;; 171 | -I) 172 | eat=1 173 | func_file_conv "$2" mingw 174 | set x "$@" -I"$file" 175 | shift 176 | ;; 177 | -I*) 178 | func_file_conv "${1#-I}" mingw 179 | set x "$@" -I"$file" 180 | shift 181 | ;; 182 | -l) 183 | eat=1 184 | func_cl_dashl "$2" 185 | set x "$@" "$lib" 186 | shift 187 | ;; 188 | -l*) 189 | func_cl_dashl "${1#-l}" 190 | set x "$@" "$lib" 191 | shift 192 | ;; 193 | -L) 194 | eat=1 195 | func_cl_dashL "$2" 196 | ;; 197 | -L*) 198 | func_cl_dashL "${1#-L}" 199 | ;; 200 | -static) 201 | shared=false 202 | ;; 203 | -Wl,*) 204 | arg=${1#-Wl,} 205 | save_ifs="$IFS"; IFS=',' 206 | for flag in $arg; do 207 | IFS="$save_ifs" 208 | linker_opts="$linker_opts $flag" 209 | done 210 | IFS="$save_ifs" 211 | ;; 212 | -Xlinker) 213 | eat=1 214 | linker_opts="$linker_opts $2" 215 | ;; 216 | -*) 217 | set x "$@" "$1" 218 | shift 219 | ;; 220 | *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) 221 | func_file_conv "$1" 222 | set x "$@" -Tp"$file" 223 | shift 224 | ;; 225 | *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) 226 | func_file_conv "$1" mingw 227 | set x "$@" "$file" 228 | shift 229 | ;; 230 | *) 231 | set x "$@" "$1" 232 | shift 233 | ;; 234 | esac 235 | fi 236 | shift 237 | done 238 | if test -n "$linker_opts"; then 239 | linker_opts="-link$linker_opts" 240 | fi 241 | exec "$@" $linker_opts 242 | exit 1 243 | } 244 | 245 | eat= 246 | 247 | case $1 in 248 | '') 249 | echo "$0: No command. Try '$0 --help' for more information." 1>&2 250 | exit 1; 251 | ;; 252 | -h | --h*) 253 | cat <<\EOF 254 | Usage: compile [--help] [--version] PROGRAM [ARGS] 255 | 256 | Wrapper for compilers which do not understand '-c -o'. 257 | Remove '-o dest.o' from ARGS, run PROGRAM with the remaining 258 | arguments, and rename the output as expected. 259 | 260 | If you are trying to build a whole package this is not the 261 | right script to run: please start by reading the file 'INSTALL'. 262 | 263 | Report bugs to . 264 | GNU Automake home page: . 265 | General help using GNU software: . 266 | EOF 267 | exit $? 268 | ;; 269 | -v | --v*) 270 | echo "compile (GNU Automake) $scriptversion" 271 | exit $? 272 | ;; 273 | cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ 274 | clang-cl | *[/\\]clang-cl | clang-cl.exe | *[/\\]clang-cl.exe | \ 275 | icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) 276 | func_cl_wrapper "$@" # Doesn't return... 277 | ;; 278 | esac 279 | 280 | ofile= 281 | cfile= 282 | 283 | for arg 284 | do 285 | if test -n "$eat"; then 286 | eat= 287 | else 288 | case $1 in 289 | -o) 290 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 291 | # So we strip '-o arg' only if arg is an object. 292 | eat=1 293 | case $2 in 294 | *.o | *.obj) 295 | ofile=$2 296 | ;; 297 | *) 298 | set x "$@" -o "$2" 299 | shift 300 | ;; 301 | esac 302 | ;; 303 | *.c) 304 | cfile=$1 305 | set x "$@" "$1" 306 | shift 307 | ;; 308 | *) 309 | set x "$@" "$1" 310 | shift 311 | ;; 312 | esac 313 | fi 314 | shift 315 | done 316 | 317 | if test -z "$ofile" || test -z "$cfile"; then 318 | # If no '-o' option was seen then we might have been invoked from a 319 | # pattern rule where we don't need one. That is ok -- this is a 320 | # normal compilation that the losing compiler can handle. If no 321 | # '.c' file was seen then we are probably linking. That is also 322 | # ok. 323 | exec "$@" 324 | fi 325 | 326 | # Name of file we expect compiler to create. 327 | cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` 328 | 329 | # Create the lock directory. 330 | # Note: use '[/\\:.-]' here to ensure that we don't use the same name 331 | # that we are using for the .o file. Also, base the name on the expected 332 | # object file name, since that is what matters with a parallel build. 333 | lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d 334 | while true; do 335 | if mkdir "$lockdir" >/dev/null 2>&1; then 336 | break 337 | fi 338 | sleep 1 339 | done 340 | # FIXME: race condition here if user kills between mkdir and trap. 341 | trap "rmdir '$lockdir'; exit 1" 1 2 15 342 | 343 | # Run the compile. 344 | "$@" 345 | ret=$? 346 | 347 | if test -f "$cofile"; then 348 | test "$cofile" = "$ofile" || mv "$cofile" "$ofile" 349 | elif test -f "${cofile}bj"; then 350 | test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" 351 | fi 352 | 353 | rmdir "$lockdir" 354 | exit $ret 355 | 356 | # Local Variables: 357 | # mode: shell-script 358 | # sh-indentation: 2 359 | # eval: (add-hook 'before-save-hook 'time-stamp nil t) 360 | # time-stamp-start: "scriptversion=" 361 | # time-stamp-format: "%Y-%02m-%02d.%02H" 362 | # time-stamp-time-zone: "UTC0" 363 | # time-stamp-end: "; # UTC" 364 | # End: 365 | -------------------------------------------------------------------------------- /.github/workflows/matrix.yml: -------------------------------------------------------------------------------- 1 | name: Build Matrix (Reusable) 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | create_artifacts: 7 | description: 'Whether to create release artifacts' 8 | required: false 9 | type: boolean 10 | default: false 11 | 12 | env: 13 | MAKEFLAGS: -j3 14 | 15 | jobs: 16 | build: 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | name: [ ubuntu-latest-gcc, ubuntu-latest-gcc-arm64, ubuntu-latest-clang, macos-15-clang, macos-26-clang, freebsd-15-gcc, freebsd-15-clang, openbsd-7-gcc, openbsd-7-clang, netbsd-10-gcc, netbsd-10-clang, solaris-11-gcc, solaris-11-clang, windows-latest-msvc ] 21 | include: 22 | - name: ubuntu-latest-gcc 23 | os: ubuntu-latest 24 | cc: gcc 25 | artifact_name: ngrep-linux-x86_64 26 | - name: ubuntu-latest-gcc-arm64 27 | os: ubuntu-latest 28 | cc: gcc 29 | arch: arm64 30 | artifact_name: ngrep-linux-arm64 31 | - name: ubuntu-latest-clang 32 | os: ubuntu-latest 33 | cc: clang 34 | - name: macos-15-clang 35 | os: macos-15 36 | cc: clang 37 | artifact_name: ngrep-macos-15-arm64 38 | - name: macos-26-clang 39 | os: macos-26 40 | cc: clang 41 | artifact_name: ngrep-macos-26-arm64 42 | - name: freebsd-15-gcc 43 | os: ubuntu-latest 44 | cc: gcc 45 | artifact_name: ngrep-freebsd-15-x86_64 46 | - name: freebsd-15-clang 47 | os: ubuntu-latest 48 | cc: clang 49 | - name: openbsd-7-gcc 50 | os: ubuntu-latest 51 | cc: egcc 52 | artifact_name: ngrep-openbsd-7-x86_64 53 | - name: openbsd-7-clang 54 | os: ubuntu-latest 55 | cc: clang 56 | - name: netbsd-10-gcc 57 | os: ubuntu-latest 58 | cc: gcc 59 | artifact_name: ngrep-netbsd-10-x86_64 60 | - name: netbsd-10-clang 61 | os: ubuntu-latest 62 | cc: clang 63 | - name: solaris-11-gcc 64 | os: ubuntu-latest 65 | cc: gcc 66 | artifact_name: ngrep-solaris-11-x86_64 67 | - name: solaris-11-clang 68 | os: ubuntu-latest 69 | cc: clang 70 | - name: windows-latest-msvc 71 | os: windows-latest 72 | cc: msvc 73 | artifact_name: ngrep-windows-x86_64 74 | 75 | runs-on: ${{ matrix.os }} 76 | steps: 77 | - uses: actions/checkout@v4 78 | 79 | - name: Set up QEMU for ARM64 80 | if: matrix.arch == 'arm64' 81 | uses: docker/setup-qemu-action@v3 82 | with: 83 | platforms: linux/arm64 84 | 85 | - name: Build Linux 86 | if: startsWith(matrix.name,'ubuntu') && matrix.arch != 'arm64' 87 | run: | 88 | sudo apt-get update 89 | sudo apt-get install -y build-essential clang tree libpcap-dev libnet-dev libpcre2-dev 90 | ./configure --enable-ipv6 --enable-pcre2 --enable-tcpkill --prefix=/usr CC=${{ matrix.cc }} 91 | make 92 | mkdir -p _install 93 | make install DESTDIR=$PWD/_install 94 | tree $PWD/_install/usr 95 | 96 | - name: Build Linux ARM64 97 | if: startsWith(matrix.name,'ubuntu') && matrix.arch == 'arm64' 98 | run: | 99 | docker run --rm --platform linux/arm64 -v $PWD:/work -w /work ubuntu:latest bash -c " 100 | apt-get update -q -y && 101 | apt-get install -q -y build-essential tree libpcap-dev libnet-dev libpcre2-dev && 102 | ./configure --enable-ipv6 --enable-pcre2 --enable-tcpkill --prefix=/usr CC=${{ matrix.cc }} && 103 | make && 104 | mkdir -p /work/_install && 105 | make install DESTDIR=/work/_install && 106 | tree /work/_install/usr 107 | " 108 | 109 | - name: Build MacOS 110 | if: startsWith(matrix.name,'macos') 111 | run: | 112 | brew update 113 | brew install tree libpcap libnet 114 | ./configure --enable-ipv6 --enable-pcre2 --enable-tcpkill --prefix=/usr CC=${{ matrix.cc }} 115 | make 116 | mkdir -p _install 117 | make install DESTDIR=$PWD/_install 118 | tree $PWD/_install/usr 119 | 120 | - name: Build FreeBSD 121 | if: startsWith(matrix.name,'freebsd') 122 | uses: vmactions/freebsd-vm@v1 123 | with: 124 | release: "15.0" 125 | usesh: true 126 | prepare: | 127 | pkg install -y gcc llvm doxygen tree pkgconf libnet pcre2 128 | run: | 129 | ./configure --enable-ipv6 --enable-pcre2 --enable-tcpkill --prefix=/usr CC=${{ matrix.cc }} 130 | make 131 | mkdir -p _install 132 | make install DESTDIR=$PWD/_install 133 | tree $PWD/_install/usr 134 | 135 | - name: Build OpenBSD 136 | if: startsWith(matrix.name,'openbsd') 137 | uses: vmactions/openbsd-vm@v1 138 | with: 139 | usesh: true 140 | prepare: | 141 | export PKG_PATH=https://cdn.openbsd.org/pub/OpenBSD/$(uname -r)/packages/$(uname -m)/ 142 | pkg_add -I gcc%11 llvm%19 doxygen tree pkgconf libnet%1.1 pcre2 143 | run: | 144 | ./configure --enable-ipv6 --enable-pcre2 --enable-tcpkill --prefix=/usr CC=${{ matrix.cc }} 145 | make 146 | mkdir -p _install 147 | make install DESTDIR=$PWD/_install 148 | tree $PWD/_install/usr 149 | 150 | - name: Build NetBSD 151 | if: startsWith(matrix.name,'netbsd') 152 | uses: vmactions/netbsd-vm@v1 153 | with: 154 | usesh: true 155 | prepare: | 156 | export PATH=/usr/sbin:/usr/pkg/sbin:/usr/pkg/bin:$PATH 157 | export PKG_PATH="http://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/$(uname -r | cut -d_ -f1)/All" 158 | pkg_add gcc13 clang pkgconf libpcap libnet 159 | run: | 160 | ./configure --enable-ipv6 --enable-pcre2 --enable-tcpkill --prefix=/usr CC=${{ matrix.cc }} 161 | make 162 | mkdir -p _install 163 | make install DESTDIR=$PWD/_install 164 | tree $PWD/_install/usr 165 | 166 | - name: Build Solaris 167 | if: startsWith(matrix.name,'solaris') 168 | uses: vmactions/solaris-vm@v1 169 | with: 170 | usesh: true 171 | prepare: | 172 | pkg install gcc-c clang pcre2 libpcap libnet 173 | run: | 174 | ./configure --enable-ipv6 --enable-pcre2 --enable-tcpkill --prefix=/usr CC=${{ matrix.cc }} 175 | make 176 | mkdir -p _install 177 | make install DESTDIR=$PWD/_install 178 | tree $PWD/_install/usr 179 | 180 | - name: Build Windows 181 | if: startsWith(matrix.name,'windows') 182 | shell: powershell 183 | run: | 184 | .\winXX\build.ps1 185 | 186 | - name: Package Linux/BSD/Solaris/MacOS 187 | if: inputs.create_artifacts && !startsWith(matrix.name,'windows') && matrix.artifact_name != '' 188 | run: | 189 | mkdir -p release 190 | tar -czf release/${{ matrix.artifact_name }}.tar.gz -C _install/usr/bin ngrep 191 | tar -czf release/${{ matrix.artifact_name }}-full.tar.gz -C _install usr 192 | 193 | - name: Package Windows 194 | if: inputs.create_artifacts && startsWith(matrix.name,'windows') 195 | shell: powershell 196 | run: | 197 | New-Item -ItemType Directory -Force -Path release/ngrep 198 | $exePath = "./winXX/build/bin/Release/ngrep.exe" 199 | if (Test-Path $exePath) { 200 | Copy-Item $exePath -Destination release/ngrep/ 201 | 202 | # Find and copy PCRE2 DLL - check build directory first (ARM64), then vcpkg 203 | $buildDir = "./winXX/build/bin/Release" 204 | $pcre2DllBuild = "$buildDir/pcre2-8.dll" 205 | 206 | if (Test-Path $pcre2DllBuild) { 207 | Copy-Item $pcre2DllBuild -Destination release/ngrep/ 208 | Write-Host "Packaged with PCRE2 DLL from build directory: $pcre2DllBuild" 209 | } else { 210 | # Try vcpkg location (x64 typically uses pre-built binaries) 211 | $vcpkgRoot = if ($env:VCPKG_ROOT) { $env:VCPKG_ROOT } else { "$env:USERPROFILE/vcpkg" } 212 | $arch = $env:PROCESSOR_ARCHITECTURE 213 | $triplet = if ($arch -eq "ARM64") { "arm64-windows" } else { "x64-windows" } 214 | $pcre2Dll = "$vcpkgRoot/installed/$triplet/bin/pcre2-8.dll" 215 | 216 | if (Test-Path $pcre2Dll) { 217 | Copy-Item $pcre2Dll -Destination release/ngrep/ 218 | Write-Host "Packaged with PCRE2 DLL from vcpkg: $pcre2Dll" 219 | } else { 220 | Write-Host "Warning: PCRE2 DLL not found in build dir or vcpkg" 221 | } 222 | } 223 | 224 | # Create README for the package 225 | $readme = "ngrep for Windows`n`n" 226 | $readme += "Requirements:`n" 227 | $readme += "- Npcap: https://npcap.com/#download`n`n" 228 | $readme += "Files included:`n" 229 | $readme += "- ngrep.exe: Main executable`n" 230 | $readme += "- pcre2-8.dll: PCRE2 regular expression library (if built with PCRE2)`n`n" 231 | $readme += "Usage:`n" 232 | $readme += " ngrep.exe [options] `n`n" 233 | $readme += "For help:`n" 234 | $readme += " ngrep.exe -h`n" 235 | $readme | Out-File -FilePath release/ngrep/README.txt -Encoding utf8 236 | 237 | Compress-Archive -Path release/ngrep/* -DestinationPath "release/${{ matrix.artifact_name }}.zip" 238 | } else { 239 | Write-Error "ngrep.exe not found at $exePath" 240 | exit 1 241 | } 242 | 243 | - name: Upload artifacts 244 | if: inputs.create_artifacts && matrix.artifact_name != '' 245 | uses: actions/upload-artifact@v4 246 | with: 247 | name: ${{ matrix.artifact_name }} 248 | path: release/* 249 | retention-days: 5 250 | -------------------------------------------------------------------------------- /ngrep.8: -------------------------------------------------------------------------------- 1 | .\" All content, except portions of the bpf filter explanation, are: 2 | .\" 3 | .\" Copyright (c) 2025 Jordan Ritter 4 | .\" 5 | .\" Please refer to the LICENSE file for more information. 6 | 7 | .TH NGREP 8 "October 2025" *nux "User Manuals" 8 | 9 | .SH NAME 10 | 11 | ngrep \- network grep 12 | 13 | .SH SYNOPSIS 14 | 15 | .B ngrep <-hNXViwqpevxlDtTRMCu> <-IO 16 | .I pcap_dump 17 | .B > < -n 18 | .I num 19 | .B > < -d 20 | .I dev 21 | .B > < -A 22 | .I num 23 | .B > < -s 24 | .I snaplen 25 | .B > < -S 26 | .I limitlen 27 | .B > < -W 28 | .I normal|byline|single|none 29 | .B > < -c 30 | .I cols 31 | .B > < -P 32 | .I char 33 | .B > < -F 34 | .I file 35 | .B > < 36 | .I match expression 37 | .B > < 38 | .I bpf filter 39 | .B > 40 | 41 | .SH DESCRIPTION 42 | 43 | ngrep strives to provide most of GNU grep's common features, applying 44 | them to the network layer. ngrep is a pcap-aware tool that will allow 45 | you to specify extended regular expressions to match against data 46 | payloads of packets. It currently recognizes TCP, UDP and ICMP across 47 | Ethernet, PPP, SLIP, FDDI and null interfaces, and understands bpf 48 | filter logic in the same fashion as more common packet sniffing tools, 49 | such as 50 | .BR tcpdump (8) 51 | and 52 | .BR snoop (1). 53 | 54 | 55 | .SH OPTIONS 56 | .IP -h 57 | Display help/usage information. 58 | 59 | .IP -N 60 | Show sub-protocol number along with single-character identifier 61 | (useful when observing raw or unknown protocols). 62 | 63 | .IP -X 64 | Treat the match expression as a hexadecimal string. See the 65 | explanation of \fImatch expression\fP below. 66 | 67 | .IP -V 68 | Display version information. 69 | 70 | .IP -i 71 | Ignore case for the regex expression. 72 | 73 | .IP -w 74 | Match the regex expression as a word. 75 | 76 | .IP -q 77 | Be quiet; don't output any information other than packet headers and 78 | their payloads (if relevant). 79 | 80 | .IP -p 81 | Don't put the interface into promiscuous mode. 82 | 83 | .IP -e 84 | Show empty packets. Normally empty packets are discarded because they 85 | have no payload to search. If specified, empty packets will be shown, 86 | regardless of the specified regex expression. 87 | 88 | .IP -v 89 | Invert the match; only display packets that don't match. 90 | 91 | .IP -x 92 | Dump packet contents as both hexadecimal and ASCII. 93 | 94 | .IP -l 95 | Make stdout line buffered. 96 | 97 | .IP -C 98 | Colorize matches in packet contents output. 99 | 100 | .IP -u 101 | Display UTF-8 characters in packet contents output. 102 | 103 | .IP -D 104 | When reading pcap_dump files, replay them at their recorded time 105 | intervals (mimic realtime). 106 | 107 | .IP -t 108 | Print a timestamp in the form of YYYY/MM/DD HH:MM:SS.UUUUUU everytime 109 | a packet is matched. 110 | 111 | .IP -T 112 | Print a timestamp in the form of +S.UUUUUU, indicating the delta 113 | between packet matches. Specify a second time to indicate the delta 114 | since the first packet match. 115 | 116 | .IP -R 117 | Do not try to drop privileges to the DROPPRIVS_USER (specified at 118 | build-time). 119 | 120 | ngrep makes no effort to validate input from live or offline sources 121 | as it is focused more on performance and handling large amounts of 122 | data than protocol correctness, which is most often a fair assumption 123 | to make. However, sometimes it matters and thus as a rule ngrep will 124 | try to be defensive and drop any root privileges it might have. 125 | 126 | There exist scenarios where this behaviour can become an obstacle, so 127 | this option is provided to end-users who want to disable this feature, 128 | but must do so with an understanding of the risks. Packets can be 129 | randomly malformed or even specifically designed to overflow sniffers 130 | and take control of them, and revoking root privileges is currently 131 | the only risk mitigation ngrep employs against such an attack. Use 132 | this option and turn it off at your own risk. 133 | 134 | .IP "-c cols" 135 | Explicitly set the console width to ``cols''. Note that this is the 136 | console width, and not the full width of what ngrep prints out as 137 | payloads; depending on the output mode ngrep may print less than 138 | ``cols'' bytes per line (indentation). 139 | 140 | .IP "-F file" 141 | Read in the bpf filter from the specified filename. This is a 142 | compatibility option for users familiar with tcpdump. Please note 143 | that specifying ``-F'' will override any bpf filter specified on the 144 | command-line. 145 | 146 | .IP "-P char" 147 | Specify an alternate character to signify non-printable characters 148 | when displayed. The default is ``.''. 149 | 150 | .IP "-K num" 151 | Kill matching TCP connections (like tcpkill). The numeric argument 152 | controls how many RST segments are sent. 153 | 154 | .IP "-W normal|byline|single|none" 155 | Specify an alternate manner for displaying packets, when not in 156 | hexadecimal mode. The ``byline'' mode honors embedded linefeeds, 157 | wrapping text only when a linefeed is encountered (useful for observing 158 | HTTP transactions, for instance). The ``none'' mode doesn't wrap under 159 | any circumstance (entire payload is displayed on one line). The 160 | ``single'' mode is conceptually the same as ``none'', except that 161 | everything including IP and source/destination header information is all 162 | on one line. ``normal'' is the default mode and is only included for 163 | completeness. This option is incompatible with ``-x''. 164 | 165 | .IP "-s snaplen" 166 | Set the bpf caplen to snaplen (default 65536). 167 | 168 | .IP "-S limitlen" 169 | Set the upper limit on the size of packets that ngrep will look at. 170 | Useful for looking at only the first N bytes of packets without 171 | changing the BPF snaplen. 172 | 173 | .IP "-I pcap_dump" 174 | Input file pcap_dump into ngrep. Works with any pcap-compatible dump 175 | file format. This option is useful for searching for a wide range of 176 | different patterns over the same packet stream. 177 | 178 | .IP "-O pcap_dump" 179 | Output matched packets to a pcap-compatible dump file. This feature 180 | does not interfere with normal output to stdout. 181 | 182 | .IP "-n num" 183 | Match only 184 | .I \fInum\fP 185 | packets total, then exit. 186 | 187 | .IP "-d dev" 188 | By default ngrep will select a default interface to listen on. Use 189 | this option to force ngrep to listen on interface \fIdev\fP. 190 | 191 | .IP "-A num" 192 | Dump \fInum\fP packets of trailing context after matching a packet. 193 | 194 | .IP "\fI match expression\fP" 195 | A match expression is either an extended regular expression, or if the 196 | \fI-X\fP option is specified, a string signifying a hexadecimal value. 197 | An extended regular expression follows the rules as implemented by the 198 | .B GNU regex 199 | .BR library . 200 | Hexadecimal expressions can optionally be preceded by `0x'. E.g., 201 | `DEADBEEF', `0xDEADBEEF'. 202 | 203 | .IP "\fI bpf filter\fP" 204 | Selects a filter that specifies what packets will be dumped. If no 205 | \fIbpf filter\fP is given, all IP packets seen on the selected 206 | interface will be dumped. Otherwise, only packets for which \fIbpf 207 | filter\fP is `true' will be dumped. 208 | .LP 209 | The \fIbpf filter\fP consists of one or more 210 | .I primitives. 211 | Primitives usually consist of an 212 | .I id 213 | (name or number) preceded by one or more qualifiers. There are three 214 | different kinds of qualifier: 215 | .IP \fItype\fP 216 | qualifiers say what kind of thing the id name or number refers to. 217 | Possible types are 218 | .BR host , 219 | .B net 220 | and 221 | .BR port . 222 | E.g., `host blort', `net 1.2.3', `port 80'. If there is no type 223 | qualifier, 224 | .B host 225 | is assumed. 226 | .IP \fIdir\fP 227 | qualifiers specify a particular transfer direction to and/or from 228 | .I id. 229 | Possible directions are 230 | .BR src , 231 | .BR dst , 232 | .B "src or dst" 233 | and 234 | .B "src and" 235 | .BR dst . 236 | E.g., `src foo', `dst net 1.2.3', `src or dst port ftp-data'. If 237 | there is no dir qualifier, 238 | .B "src or dst" 239 | is assumed. 240 | For `null' link layers (i.e. point to point protocols such as slip) the 241 | .B inbound 242 | and 243 | .B outbound 244 | qualifiers can be used to specify a desired direction. 245 | .IP \fIproto\fP 246 | qualifiers are restricted to ip-only protocols. Possible protos are: 247 | .B tcp , 248 | .B udp 249 | and 250 | .BR icmp . 251 | e.g., `udp src foo' or `tcp port 21'. If there is no proto qualifier, 252 | all protocols consistent with the type are assumed. E.g., `src foo' 253 | means `ip and ((tcp or udp) src foo)', `net bar' means `ip and (net 254 | bar)', and `port 53' means `ip and ((tcp or udp) port 53)'. 255 | .LP 256 | In addition to the above, there are some special `primitive' keywords 257 | that don't follow the pattern: 258 | .BR gateway , 259 | .BR broadcast , 260 | .BR less , 261 | .B greater 262 | and arithmetic expressions. All of these are described below. 263 | .LP 264 | More complex filter expressions are built up by using the words 265 | .BR and , 266 | .B or 267 | and 268 | .B not 269 | to combine primitives. E.g., `host blort and not port ftp and not 270 | port ftp-data'. To save typing, identical qualifier lists can be 271 | omitted. E.g., `tcp dst port ftp or ftp-data or domain' is exactly 272 | the same as `tcp dst port ftp or tcp dst port ftp-data or tcp dst port 273 | domain'. 274 | .LP 275 | Allowable primitives are: 276 | 277 | .IP "\fBdst host \fIhost\fR" 278 | True if the IP destination field of the packet is \fIhost\fP, 279 | which may be either an address or a name. 280 | 281 | .IP "\fBsrc host \fIhost\fR" 282 | True if the IP source field of the packet is \fIhost\fP. 283 | 284 | .IP "\fBhost \fIhost\fP" 285 | True if either the IP source or destination of the packet is \fIhost\fP. 286 | Any of the above host expressions can be prepended with the keywords, 287 | \fBip\fP, \fBarp\fP, or \fBrarp\fP as in: 288 | .in +.5i 289 | .nf 290 | \fBip host \fIhost\fR 291 | .fi 292 | .in -.5i 293 | which is equivalent to: 294 | .in +.5i 295 | 296 | 297 | .IP "\fBether dst \fIehost\fP" 298 | True if the ethernet destination address is \fIehost\fP. \fIEhost\fP 299 | may be either a name from /etc/ethers or a number (see 300 | .IR ethers (3N) 301 | for numeric format). 302 | .IP "\fBether src \fIehost\fP" 303 | True if the ethernet source address is \fIehost\fP. 304 | .IP "\fBether host \fIehost\fP" 305 | True if either the ethernet source or destination address is \fIehost\fP. 306 | 307 | .IP "\fBgateway\fP \fIhost\fP" 308 | True if the packet used \fIhost\fP as a gateway. I.e., the ethernet 309 | source or destination address was \fIhost\fP but neither the IP source 310 | nor the IP destination was \fIhost\fP. \fIHost\fP must be a name and 311 | must be found in both /etc/hosts and /etc/ethers. (An equivalent 312 | expression is 313 | .in +.5i 314 | .nf 315 | \fBether host \fIehost \fBand not host \fIhost\fR 316 | .fi 317 | .in -.5i 318 | which can be used with either names or numbers for \fIhost / ehost\fP.) 319 | 320 | .IP "\fBdst net \fInet\fR" 321 | True if the IP destination address of the packet has a network 322 | number of \fInet\fP. \fINet\fP may be either a name from /etc/networks 323 | or a network number (see \fInetworks(4)\fP for details). 324 | 325 | .IP "\fBsrc net \fInet\fR" 326 | True if the IP source address of the packet has a network 327 | number of \fInet\fP. 328 | 329 | .IP "\fBnet \fInet\fR" 330 | True if either the IP source or destination address of the packet has a network 331 | number of \fInet\fP. 332 | 333 | .IP "\fBnet \fInet\fR \fBmask \fImask\fR" 334 | True if the IP address matches \fInet\fR with the specific netmask. 335 | May be qualified with \fBsrc\fR or \fBdst\fR. 336 | 337 | .IP "\fBnet \fInet\fR/\fIlen\fR" 338 | True if the IP address matches \fInet\fR a netmask \fIlen\fR bits wide. 339 | May be qualified with \fBsrc\fR or \fBdst\fR. 340 | 341 | .IP "\fBdst port \fIport\fR" 342 | True if the packet is ip/tcp or ip/udp and has a 343 | destination port value of \fIport\fP. 344 | The \fIport\fP can be a number or a name used in /etc/services (see 345 | .IR tcp (4P) 346 | and 347 | .IR udp (4P)). 348 | If a name is used, both the port 349 | number and protocol are checked. If a number or ambiguous name is used, 350 | only the port number is checked (e.g., \fBdst port 513\fR will print both 351 | tcp/login traffic and udp/who traffic, and \fBport domain\fR will print 352 | both tcp/domain and udp/domain traffic). 353 | 354 | .IP "\fBsrc port \fIport\fR" 355 | True if the packet has a source port value of \fIport\fP. 356 | 357 | .IP "\fBport \fIport\fR" 358 | True if either the source or destination port of the packet is \fIport\fP. 359 | Any of the above port expressions can be prepended with the keywords, 360 | \fBtcp\fP or \fBudp\fP, as in: 361 | .in +.5i 362 | .nf 363 | \fBtcp src port \fIport\fR 364 | .fi 365 | .in -.5i 366 | which matches only tcp packets whose source port is \fIport\fP. 367 | 368 | .IP "\fBless \fIlength\fR" 369 | True if the packet has a length less than or equal to \fIlength\fP. 370 | This is equivalent to: 371 | .in +.5i 372 | .nf 373 | \fBlen <= \fIlength\fP. 374 | .fi 375 | .in -.5i 376 | 377 | .IP "\fBgreater \fIlength\fR" 378 | True if the packet has a length greater than or equal to \fIlength\fP. 379 | This is equivalent to: 380 | .in +.5i 381 | .nf 382 | \fBlen >= \fIlength\fP. 383 | .fi 384 | .in -.5i 385 | 386 | .IP "\fBip proto \fIprotocol\fR" 387 | True if the packet is an ip packet (see 388 | .IR ip (4P)) 389 | of protocol type \fIprotocol\fP. \fIProtocol\fP can be a number or 390 | one of the names \fItcp\fP, \fIudp\fP or \fIicmp\fP. Note that the 391 | identifiers \fItcp\fP and \fIudp\fP are also keywords and must be 392 | escaped via backslash (\\), which is \\\\ in the C-shell. 393 | 394 | .IP "\fBip broadcast\fR" 395 | True if the packet is an IP broadcast packet. It checks for both 396 | the all-zeroes and all-ones broadcast conventions, and looks up 397 | the local subnet mask. 398 | 399 | .IP "\fBip multicast\fR" 400 | True if the packet is an IP multicast packet. 401 | 402 | .IP "\fBip\fR" 403 | Abbreviation for: 404 | .in +.5i 405 | .nf 406 | \fBether proto ip\fR 407 | .fi 408 | .IP "\fBtcp\fR, \fBudp\fR, \fBicmp\fR" 409 | Abbreviations for: 410 | .in +.5i 411 | .nf 412 | \fBip proto \fIp\fR 413 | .fi 414 | .in -.5i 415 | where \fIp\fR is one of the above protocols. 416 | .IP "\fIexpr relop expr\fR" 417 | True if the relation holds, where \fIrelop\fR is one of >, <, >=, <=, =, !=, 418 | and \fIexpr\fR is an arithmetic expression composed of integer constants 419 | (expressed in standard C syntax), the normal binary operators 420 | [+, -, *, /, &, |], a length operator, and special packet data accessors. 421 | To access 422 | data inside the packet, use the following syntax: 423 | .in +.5i 424 | .nf 425 | \fIproto\fB [ \fIexpr\fB : \fIsize\fB ]\fR 426 | .fi 427 | .in -.5i 428 | \fIProto\fR is one of \fBip, tcp, udp \fRor \fBicmp\fR, and 429 | indicates the protocol layer for the index operation. The byte 430 | offset, relative to the indicated protocol layer, is given by 431 | \fIexpr\fR. \fISize\fR is optional and indicates the number of bytes 432 | in the field of interest; it can be either one, two, or four, and 433 | defaults to one. The length operator, indicated by the keyword 434 | \fBlen\fP, gives the length of the packet. 435 | 436 | For example, `\fBether[0] & 1 != 0\fP' catches all multicast traffic. 437 | The expression `\fBip[0] & 0xf != 5\fP' 438 | catches all IP packets with options. The expression 439 | `\fBip[6:2] & 0x1fff = 0\fP' 440 | catches only unfragmented datagrams and frag zero of fragmented datagrams. 441 | This check is implicitly applied to the \fBtcp\fP and \fBudp\fP 442 | index operations. 443 | For instance, \fBtcp[0]\fP always means the first 444 | byte of the TCP \fIheader\fP, and never means the first byte of an 445 | intervening fragment. 446 | .LP 447 | Primitives may be combined using: 448 | .IP 449 | A parenthesized group of primitives and operators 450 | (parentheses are special to the Shell and must be escaped). 451 | .IP 452 | Negation (`\fB!\fP' or `\fBnot\fP'). 453 | .IP 454 | Concatenation (`\fB&&\fP' or `\fBand\fP'). 455 | .IP 456 | Alternation (`\fB||\fP' or `\fBor\fP'). 457 | .LP 458 | Negation has highest precedence. 459 | Alternation and concatenation have equal precedence and associate 460 | left to right. Note that explicit \fBand\fR tokens, not juxtaposition, 461 | are now required for concatenation. 462 | .LP 463 | If an identifier is given without a keyword, the most recent keyword 464 | is assumed. 465 | For example, 466 | .in +.5i 467 | .nf 468 | \fBnot host vs and ace\fR 469 | .fi 470 | .in -.5i 471 | is short for 472 | .in +.5i 473 | .nf 474 | \fBnot host vs and host ace\fR 475 | .fi 476 | .in -.5i 477 | which should not be confused with 478 | .in +.5i 479 | .nf 480 | \fBnot ( host vs or ace )\fR 481 | .fi 482 | .in -.5i 483 | .LP 484 | Expression arguments can be passed to ngrep as either a single 485 | argument or as multiple arguments, whichever is more convenient. 486 | Generally, if the expression contains Shell metacharacters, it is 487 | easier to pass it as a single, quoted argument. Multiple arguments 488 | are concatenated with spaces before being parsed. 489 | 490 | .SH DIAGNOSTICS 491 | 492 | Errors from 493 | .B ngrep, libpcap, 494 | and the 495 | .B GNU regex library 496 | are all output to stderr. 497 | 498 | .SH EXIT STATUS 499 | 500 | The ngrep utility exits with one of the following values: 501 | 502 | 0 One or more frames were matched. 503 | 1 No frames were matched. 504 | 2 An error occurred. 505 | 3+ Hell is freezing over, run! 506 | 507 | .SH AUTHOR 508 | 509 | Written by Jordan Ritter . 510 | 511 | .SH REPORTING BUGS 512 | 513 | Please report bugs to the ngrep's GitHub Issue Tracker, located at 514 | 515 | http://github.com/jpr5/ngrep/issues 516 | 517 | Non-bug, non-feature-request general feedback should be sent to the author 518 | directly by email. 519 | 520 | .SH NOTES 521 | 522 | ALL YOUR BASE ARE BELONG TO US. 523 | -------------------------------------------------------------------------------- /regex-0.12/install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2023-11-23.18; # UTC 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # 'make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | tab=' ' 45 | nl=' 46 | ' 47 | IFS=" $tab$nl" 48 | 49 | # Set DOITPROG to "echo" to test this script. 50 | 51 | doit=${DOITPROG-} 52 | doit_exec=${doit:-exec} 53 | 54 | # Put in absolute file names if you don't have them in your path; 55 | # or use environment vars. 56 | 57 | chgrpprog=${CHGRPPROG-chgrp} 58 | chmodprog=${CHMODPROG-chmod} 59 | chownprog=${CHOWNPROG-chown} 60 | cmpprog=${CMPPROG-cmp} 61 | cpprog=${CPPROG-cp} 62 | mkdirprog=${MKDIRPROG-mkdir} 63 | mvprog=${MVPROG-mv} 64 | rmprog=${RMPROG-rm} 65 | stripprog=${STRIPPROG-strip} 66 | 67 | posix_mkdir= 68 | 69 | # Desired mode of installed file. 70 | mode=0755 71 | 72 | # Create dirs (including intermediate dirs) using mode 755. 73 | # This is like GNU 'install' as of coreutils 8.32 (2020). 74 | mkdir_umask=22 75 | 76 | backupsuffix= 77 | chgrpcmd= 78 | chmodcmd=$chmodprog 79 | chowncmd= 80 | mvcmd=$mvprog 81 | rmcmd="$rmprog -f" 82 | stripcmd= 83 | 84 | src= 85 | dst= 86 | dir_arg= 87 | dst_arg= 88 | 89 | copy_on_change=false 90 | is_target_a_directory=possibly 91 | 92 | usage="\ 93 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 94 | or: $0 [OPTION]... SRCFILES... DIRECTORY 95 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 96 | or: $0 [OPTION]... -d DIRECTORIES... 97 | 98 | In the 1st form, copy SRCFILE to DSTFILE. 99 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 100 | In the 4th, create DIRECTORIES. 101 | 102 | Options: 103 | --help display this help and exit. 104 | --version display version info and exit. 105 | 106 | -c (ignored) 107 | -C install only if different (preserve data modification time) 108 | -d create directories instead of installing files. 109 | -g GROUP $chgrpprog installed files to GROUP. 110 | -m MODE $chmodprog installed files to MODE. 111 | -o USER $chownprog installed files to USER. 112 | -p pass -p to $cpprog. 113 | -s $stripprog installed files. 114 | -S SUFFIX attempt to back up existing files, with suffix SUFFIX. 115 | -t DIRECTORY install into DIRECTORY. 116 | -T report an error if DSTFILE is a directory. 117 | 118 | Environment variables override the default commands: 119 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG 120 | RMPROG STRIPPROG 121 | 122 | By default, rm is invoked with -f; when overridden with RMPROG, 123 | it's up to you to specify -f if you want it. 124 | 125 | If -S is not specified, no backups are attempted. 126 | 127 | Report bugs to . 128 | GNU Automake home page: . 129 | General help using GNU software: ." 130 | 131 | while test $# -ne 0; do 132 | case $1 in 133 | -c) ;; 134 | 135 | -C) copy_on_change=true;; 136 | 137 | -d) dir_arg=true;; 138 | 139 | -g) chgrpcmd="$chgrpprog $2" 140 | shift;; 141 | 142 | --help) echo "$usage"; exit $?;; 143 | 144 | -m) mode=$2 145 | case $mode in 146 | *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) 147 | echo "$0: invalid mode: $mode" >&2 148 | exit 1;; 149 | esac 150 | shift;; 151 | 152 | -o) chowncmd="$chownprog $2" 153 | shift;; 154 | 155 | -p) cpprog="$cpprog -p";; 156 | 157 | -s) stripcmd=$stripprog;; 158 | 159 | -S) backupsuffix="$2" 160 | shift;; 161 | 162 | -t) 163 | is_target_a_directory=always 164 | dst_arg=$2 165 | # Protect names problematic for 'test' and other utilities. 166 | case $dst_arg in 167 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 168 | esac 169 | shift;; 170 | 171 | -T) is_target_a_directory=never;; 172 | 173 | --version) echo "$0 $scriptversion"; exit $?;; 174 | 175 | --) shift 176 | break;; 177 | 178 | -*) echo "$0: invalid option: $1" >&2 179 | exit 1;; 180 | 181 | *) break;; 182 | esac 183 | shift 184 | done 185 | 186 | # We allow the use of options -d and -T together, by making -d 187 | # take the precedence; this is for compatibility with GNU install. 188 | 189 | if test -n "$dir_arg"; then 190 | if test -n "$dst_arg"; then 191 | echo "$0: target directory not allowed when installing a directory." >&2 192 | exit 1 193 | fi 194 | fi 195 | 196 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then 197 | # When -d is used, all remaining arguments are directories to create. 198 | # When -t is used, the destination is already specified. 199 | # Otherwise, the last argument is the destination. Remove it from $@. 200 | for arg 201 | do 202 | if test -n "$dst_arg"; then 203 | # $@ is not empty: it contains at least $arg. 204 | set fnord "$@" "$dst_arg" 205 | shift # fnord 206 | fi 207 | shift # arg 208 | dst_arg=$arg 209 | # Protect names problematic for 'test' and other utilities. 210 | case $dst_arg in 211 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 212 | esac 213 | done 214 | fi 215 | 216 | if test $# -eq 0; then 217 | if test -z "$dir_arg"; then 218 | echo "$0: no input file specified." >&2 219 | exit 1 220 | fi 221 | # It's OK to call 'install-sh -d' without argument. 222 | # This can happen when creating conditional directories. 223 | exit 0 224 | fi 225 | 226 | if test -z "$dir_arg"; then 227 | if test $# -gt 1 || test "$is_target_a_directory" = always; then 228 | if test ! -d "$dst_arg"; then 229 | echo "$0: $dst_arg: Is not a directory." >&2 230 | exit 1 231 | fi 232 | fi 233 | fi 234 | 235 | if test -z "$dir_arg"; then 236 | do_exit='(exit $ret); exit $ret' 237 | trap "ret=129; $do_exit" 1 238 | trap "ret=130; $do_exit" 2 239 | trap "ret=141; $do_exit" 13 240 | trap "ret=143; $do_exit" 15 241 | 242 | # Set umask so as not to create temps with too-generous modes. 243 | # However, 'strip' requires both read and write access to temps. 244 | case $mode in 245 | # Optimize common cases. 246 | *644) cp_umask=133;; 247 | *755) cp_umask=22;; 248 | 249 | *[0-7]) 250 | if test -z "$stripcmd"; then 251 | u_plus_rw= 252 | else 253 | u_plus_rw='% 200' 254 | fi 255 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 256 | *) 257 | if test -z "$stripcmd"; then 258 | u_plus_rw= 259 | else 260 | u_plus_rw=,u+rw 261 | fi 262 | cp_umask=$mode$u_plus_rw;; 263 | esac 264 | fi 265 | 266 | for src 267 | do 268 | # Protect names problematic for 'test' and other utilities. 269 | case $src in 270 | -* | [=\(\)!]) src=./$src;; 271 | esac 272 | 273 | if test -n "$dir_arg"; then 274 | dst=$src 275 | dstdir=$dst 276 | test -d "$dstdir" 277 | dstdir_status=$? 278 | # Don't chown directories that already exist. 279 | if test $dstdir_status = 0; then 280 | chowncmd="" 281 | fi 282 | else 283 | 284 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 285 | # might cause directories to be created, which would be especially bad 286 | # if $src (and thus $dsttmp) contains '*'. 287 | if test ! -f "$src" && test ! -d "$src"; then 288 | echo "$0: $src does not exist." >&2 289 | exit 1 290 | fi 291 | 292 | if test -z "$dst_arg"; then 293 | echo "$0: no destination specified." >&2 294 | exit 1 295 | fi 296 | dst=$dst_arg 297 | 298 | # If destination is a directory, append the input filename. 299 | if test -d "$dst"; then 300 | if test "$is_target_a_directory" = never; then 301 | echo "$0: $dst_arg: Is a directory" >&2 302 | exit 1 303 | fi 304 | dstdir=$dst 305 | dstbase=`basename "$src"` 306 | case $dst in 307 | */) dst=$dst$dstbase;; 308 | *) dst=$dst/$dstbase;; 309 | esac 310 | dstdir_status=0 311 | else 312 | dstdir=`dirname "$dst"` 313 | test -d "$dstdir" 314 | dstdir_status=$? 315 | fi 316 | fi 317 | 318 | case $dstdir in 319 | */) dstdirslash=$dstdir;; 320 | *) dstdirslash=$dstdir/;; 321 | esac 322 | 323 | obsolete_mkdir_used=false 324 | 325 | if test $dstdir_status != 0; then 326 | case $posix_mkdir in 327 | '') 328 | # With -d, create the new directory with the user-specified mode. 329 | # Otherwise, rely on $mkdir_umask. 330 | if test -n "$dir_arg"; then 331 | mkdir_mode=-m$mode 332 | else 333 | mkdir_mode= 334 | fi 335 | 336 | posix_mkdir=false 337 | # The $RANDOM variable is not portable (e.g., dash). Use it 338 | # here however when possible just to lower collision chance. 339 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 340 | 341 | trap ' 342 | ret=$? 343 | rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null 344 | exit $ret 345 | ' 0 346 | 347 | # Because "mkdir -p" follows existing symlinks and we likely work 348 | # directly in world-writeable /tmp, make sure that the '$tmpdir' 349 | # directory is successfully created first before we actually test 350 | # 'mkdir -p'. 351 | if (umask $mkdir_umask && 352 | $mkdirprog $mkdir_mode "$tmpdir" && 353 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 354 | then 355 | if test -z "$dir_arg" || { 356 | # Check for POSIX incompatibilities with -m. 357 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 358 | # other-writable bit of parent directory when it shouldn't. 359 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 360 | test_tmpdir="$tmpdir/a" 361 | ls_ld_tmpdir=`ls -ld "$test_tmpdir"` 362 | case $ls_ld_tmpdir in 363 | d????-?r-*) different_mode=700;; 364 | d????-?--*) different_mode=755;; 365 | *) false;; 366 | esac && 367 | $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { 368 | ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` 369 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 370 | } 371 | } 372 | then posix_mkdir=: 373 | fi 374 | rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 375 | else 376 | # Remove any dirs left behind by ancient mkdir implementations. 377 | rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null 378 | fi 379 | trap '' 0;; 380 | esac 381 | 382 | if 383 | $posix_mkdir && ( 384 | umask $mkdir_umask && 385 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 386 | ) 387 | then : 388 | else 389 | 390 | # mkdir does not conform to POSIX, 391 | # or it failed possibly due to a race condition. Create the 392 | # directory the slow way, step by step, checking for races as we go. 393 | 394 | case $dstdir in 395 | /*) prefix='/';; 396 | [-=\(\)!]*) prefix='./';; 397 | *) prefix='';; 398 | esac 399 | 400 | oIFS=$IFS 401 | IFS=/ 402 | set -f 403 | set fnord $dstdir 404 | shift 405 | set +f 406 | IFS=$oIFS 407 | 408 | prefixes= 409 | 410 | for d 411 | do 412 | test X"$d" = X && continue 413 | 414 | prefix=$prefix$d 415 | if test -d "$prefix"; then 416 | prefixes= 417 | else 418 | if $posix_mkdir; then 419 | (umask $mkdir_umask && 420 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 421 | # Don't fail if two instances are running concurrently. 422 | test -d "$prefix" || exit 1 423 | else 424 | case $prefix in 425 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 426 | *) qprefix=$prefix;; 427 | esac 428 | prefixes="$prefixes '$qprefix'" 429 | fi 430 | fi 431 | prefix=$prefix/ 432 | done 433 | 434 | if test -n "$prefixes"; then 435 | # Don't fail if two instances are running concurrently. 436 | (umask $mkdir_umask && 437 | eval "\$doit_exec \$mkdirprog $prefixes") || 438 | test -d "$dstdir" || exit 1 439 | obsolete_mkdir_used=true 440 | fi 441 | fi 442 | fi 443 | 444 | if test -n "$dir_arg"; then 445 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 446 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 447 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 448 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 449 | else 450 | 451 | # Make a couple of temp file names in the proper directory. 452 | dsttmp=${dstdirslash}_inst.$$_ 453 | rmtmp=${dstdirslash}_rm.$$_ 454 | 455 | # Trap to clean up those temp files at exit. 456 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 457 | 458 | # Copy the file name to the temp name. 459 | (umask $cp_umask && 460 | { test -z "$stripcmd" || { 461 | # Create $dsttmp read-write so that cp doesn't create it read-only, 462 | # which would cause strip to fail. 463 | if test -z "$doit"; then 464 | : >"$dsttmp" # No need to fork-exec 'touch'. 465 | else 466 | $doit touch "$dsttmp" 467 | fi 468 | } 469 | } && 470 | $doit_exec $cpprog "$src" "$dsttmp") && 471 | 472 | # and set any options; do chmod last to preserve setuid bits. 473 | # 474 | # If any of these fail, we abort the whole thing. If we want to 475 | # ignore errors from any of these, just make sure not to ignore 476 | # errors from the above "$doit $cpprog $src $dsttmp" command. 477 | # 478 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && 479 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && 480 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && 481 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 482 | 483 | # If -C, don't bother to copy if it wouldn't change the file. 484 | if $copy_on_change && 485 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && 486 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && 487 | set -f && 488 | set X $old && old=:$2:$4:$5:$6 && 489 | set X $new && new=:$2:$4:$5:$6 && 490 | set +f && 491 | test "$old" = "$new" && 492 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 493 | then 494 | rm -f "$dsttmp" 495 | else 496 | # If $backupsuffix is set, and the file being installed 497 | # already exists, attempt a backup. Don't worry if it fails, 498 | # e.g., if mv doesn't support -f. 499 | if test -n "$backupsuffix" && test -f "$dst"; then 500 | $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null 501 | fi 502 | 503 | # Rename the file to the real destination. 504 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || 505 | 506 | # The rename failed, perhaps because mv can't rename something else 507 | # to itself, or perhaps because mv is so ancient that it does not 508 | # support -f. 509 | { 510 | # Now remove or move aside any old file at destination location. 511 | # We try this two ways since rm can't unlink itself on some 512 | # systems and the destination file might be busy for other 513 | # reasons. In this case, the final cleanup might fail but the new 514 | # file should still install successfully. 515 | { 516 | test ! -f "$dst" || 517 | $doit $rmcmd "$dst" 2>/dev/null || 518 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && 519 | { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } 520 | } || 521 | { echo "$0: cannot unlink or rename $dst" >&2 522 | (exit 1); exit 1 523 | } 524 | } && 525 | 526 | # Now rename the file to the real destination. 527 | $doit $mvcmd "$dsttmp" "$dst" 528 | } 529 | fi || exit 1 530 | 531 | trap '' 0 532 | fi 533 | done 534 | 535 | # Local variables: 536 | # eval: (add-hook 'before-save-hook 'time-stamp) 537 | # time-stamp-start: "scriptversion=" 538 | # time-stamp-format: "%:y-%02m-%02d.%02H" 539 | # time-stamp-time-zone: "UTC0" 540 | # time-stamp-end: "; # UTC" 541 | # End: 542 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2025-06-18.21; # UTC 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # 'make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | tab=' ' 45 | nl=' 46 | ' 47 | IFS=" $tab$nl" 48 | 49 | # Set DOITPROG to "echo" to test this script. 50 | 51 | doit=${DOITPROG-} 52 | doit_exec=${doit:-exec} 53 | 54 | # Put in absolute file names if you don't have them in your path; 55 | # or use environment vars. 56 | 57 | chgrpprog=${CHGRPPROG-chgrp} 58 | chmodprog=${CHMODPROG-chmod} 59 | chownprog=${CHOWNPROG-chown} 60 | cmpprog=${CMPPROG-cmp} 61 | cpprog=${CPPROG-cp} 62 | mkdirprog=${MKDIRPROG-mkdir} 63 | mvprog=${MVPROG-mv} 64 | rmprog=${RMPROG-rm} 65 | stripprog=${STRIPPROG-strip} 66 | 67 | posix_mkdir= 68 | 69 | # Desired mode of installed file. 70 | mode=0755 71 | 72 | # Create dirs (including intermediate dirs) using mode 755. 73 | # This is like GNU 'install' as of coreutils 8.32 (2020). 74 | mkdir_umask=22 75 | 76 | backupsuffix= 77 | chgrpcmd= 78 | chmodcmd=$chmodprog 79 | chowncmd= 80 | mvcmd=$mvprog 81 | rmcmd="$rmprog -f" 82 | stripcmd= 83 | 84 | src= 85 | dst= 86 | dir_arg= 87 | dst_arg= 88 | 89 | copy_on_change=false 90 | is_target_a_directory=possibly 91 | 92 | usage="\ 93 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 94 | or: $0 [OPTION]... SRCFILES... DIRECTORY 95 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 96 | or: $0 [OPTION]... -d DIRECTORIES... 97 | 98 | In the 1st form, copy SRCFILE to DSTFILE. 99 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 100 | In the 4th, create DIRECTORIES. 101 | 102 | Options: 103 | --help display this help and exit. 104 | --version display version info and exit. 105 | 106 | -c (ignored) 107 | -C install only if different (preserve data modification time) 108 | -d create directories instead of installing files. 109 | -g GROUP $chgrpprog installed files to GROUP. 110 | -m MODE $chmodprog installed files to MODE. 111 | -o USER $chownprog installed files to USER. 112 | -p pass -p to $cpprog. 113 | -s $stripprog installed files. 114 | -S SUFFIX attempt to back up existing files, with suffix SUFFIX. 115 | -t DIRECTORY install into DIRECTORY. 116 | -T report an error if DSTFILE is a directory. 117 | 118 | Environment variables override the default commands: 119 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG 120 | RMPROG STRIPPROG 121 | 122 | By default, rm is invoked with -f; when overridden with RMPROG, 123 | it's up to you to specify -f if you want it. 124 | 125 | If -S is not specified, no backups are attempted. 126 | 127 | Report bugs to . 128 | GNU Automake home page: . 129 | General help using GNU software: ." 130 | 131 | while test $# -ne 0; do 132 | case $1 in 133 | -c) ;; 134 | 135 | -C) copy_on_change=true;; 136 | 137 | -d) dir_arg=true;; 138 | 139 | -g) chgrpcmd="$chgrpprog $2" 140 | shift;; 141 | 142 | --help) echo "$usage"; exit $?;; 143 | 144 | -m) mode=$2 145 | case $mode in 146 | *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) 147 | echo "$0: invalid mode: $mode" >&2 148 | exit 1;; 149 | esac 150 | shift;; 151 | 152 | -o) chowncmd="$chownprog $2" 153 | shift;; 154 | 155 | -p) cpprog="$cpprog -p";; 156 | 157 | -s) stripcmd=$stripprog;; 158 | 159 | -S) backupsuffix="$2" 160 | shift;; 161 | 162 | -t) 163 | is_target_a_directory=always 164 | dst_arg=$2 165 | # Protect names problematic for 'test' and other utilities. 166 | case $dst_arg in 167 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 168 | esac 169 | shift;; 170 | 171 | -T) is_target_a_directory=never;; 172 | 173 | --version) echo "$0 (GNU Automake) $scriptversion"; exit $?;; 174 | 175 | --) shift 176 | break;; 177 | 178 | -*) echo "$0: invalid option: $1" >&2 179 | exit 1;; 180 | 181 | *) break;; 182 | esac 183 | shift 184 | done 185 | 186 | # We allow the use of options -d and -T together, by making -d 187 | # take the precedence; this is for compatibility with GNU install. 188 | 189 | if test -n "$dir_arg"; then 190 | if test -n "$dst_arg"; then 191 | echo "$0: target directory not allowed when installing a directory." >&2 192 | exit 1 193 | fi 194 | fi 195 | 196 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then 197 | # When -d is used, all remaining arguments are directories to create. 198 | # When -t is used, the destination is already specified. 199 | # Otherwise, the last argument is the destination. Remove it from $@. 200 | for arg 201 | do 202 | if test -n "$dst_arg"; then 203 | # $@ is not empty: it contains at least $arg. 204 | set fnord "$@" "$dst_arg" 205 | shift # fnord 206 | fi 207 | shift # arg 208 | dst_arg=$arg 209 | # Protect names problematic for 'test' and other utilities. 210 | case $dst_arg in 211 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 212 | esac 213 | done 214 | fi 215 | 216 | if test $# -eq 0; then 217 | if test -z "$dir_arg"; then 218 | echo "$0: no input file specified." >&2 219 | exit 1 220 | fi 221 | # It's OK to call 'install-sh -d' without argument. 222 | # This can happen when creating conditional directories. 223 | exit 0 224 | fi 225 | 226 | if test -z "$dir_arg"; then 227 | if test $# -gt 1 || test "$is_target_a_directory" = always; then 228 | if test ! -d "$dst_arg"; then 229 | echo "$0: $dst_arg: Is not a directory." >&2 230 | exit 1 231 | fi 232 | fi 233 | fi 234 | 235 | if test -z "$dir_arg"; then 236 | do_exit='(exit $ret); exit $ret' 237 | trap "ret=129; $do_exit" 1 238 | trap "ret=130; $do_exit" 2 239 | trap "ret=141; $do_exit" 13 240 | trap "ret=143; $do_exit" 15 241 | 242 | # Set umask so as not to create temps with too-generous modes. 243 | # However, 'strip' requires both read and write access to temps. 244 | case $mode in 245 | # Optimize common cases. 246 | *644) cp_umask=133;; 247 | *755) cp_umask=22;; 248 | 249 | *[0-7]) 250 | if test -z "$stripcmd"; then 251 | u_plus_rw= 252 | else 253 | u_plus_rw='% 200' 254 | fi 255 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 256 | *) 257 | if test -z "$stripcmd"; then 258 | u_plus_rw= 259 | else 260 | u_plus_rw=,u+rw 261 | fi 262 | cp_umask=$mode$u_plus_rw;; 263 | esac 264 | fi 265 | 266 | for src 267 | do 268 | # Protect names problematic for 'test' and other utilities. 269 | case $src in 270 | -* | [=\(\)!]) src=./$src;; 271 | esac 272 | 273 | if test -n "$dir_arg"; then 274 | dst=$src 275 | dstdir=$dst 276 | test -d "$dstdir" 277 | dstdir_status=$? 278 | # Don't chown directories that already exist. 279 | if test $dstdir_status = 0; then 280 | chowncmd="" 281 | fi 282 | else 283 | 284 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 285 | # might cause directories to be created, which would be especially bad 286 | # if $src (and thus $dsttmp) contains '*'. 287 | if test ! -f "$src" && test ! -d "$src"; then 288 | echo "$0: $src does not exist." >&2 289 | exit 1 290 | fi 291 | 292 | if test -z "$dst_arg"; then 293 | echo "$0: no destination specified." >&2 294 | exit 1 295 | fi 296 | dst=$dst_arg 297 | 298 | # If destination is a directory, append the input filename. 299 | if test -d "$dst"; then 300 | if test "$is_target_a_directory" = never; then 301 | echo "$0: $dst_arg: Is a directory" >&2 302 | exit 1 303 | fi 304 | dstdir=$dst 305 | dstbase=`basename "$src"` 306 | case $dst in 307 | */) dst=$dst$dstbase;; 308 | *) dst=$dst/$dstbase;; 309 | esac 310 | dstdir_status=0 311 | else 312 | dstdir=`dirname "$dst"` 313 | test -d "$dstdir" 314 | dstdir_status=$? 315 | fi 316 | fi 317 | 318 | case $dstdir in 319 | */) dstdirslash=$dstdir;; 320 | *) dstdirslash=$dstdir/;; 321 | esac 322 | 323 | obsolete_mkdir_used=false 324 | 325 | if test $dstdir_status != 0; then 326 | case $posix_mkdir in 327 | '') 328 | # With -d, create the new directory with the user-specified mode. 329 | # Otherwise, rely on $mkdir_umask. 330 | if test -n "$dir_arg"; then 331 | mkdir_mode=-m$mode 332 | else 333 | mkdir_mode= 334 | fi 335 | 336 | posix_mkdir=false 337 | # The $RANDOM variable is not portable (e.g., dash). Use it 338 | # here however when possible just to lower collision chance. 339 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 340 | 341 | trap ' 342 | ret=$? 343 | rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null 344 | exit $ret 345 | ' 0 346 | 347 | # Because "mkdir -p" follows existing symlinks and we likely work 348 | # directly in world-writable /tmp, make sure that the '$tmpdir' 349 | # directory is successfully created first before we actually test 350 | # 'mkdir -p'. 351 | if (umask $mkdir_umask && 352 | $mkdirprog $mkdir_mode "$tmpdir" && 353 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 354 | then 355 | if test -z "$dir_arg" || { 356 | # Check for POSIX incompatibility with -m. 357 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 358 | # other-writable bit of parent directory when it shouldn't. 359 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 360 | test_tmpdir="$tmpdir/a" 361 | ls_ld_tmpdir=`ls -ld "$test_tmpdir"` 362 | case $ls_ld_tmpdir in 363 | d????-?r-*) different_mode=700;; 364 | d????-?--*) different_mode=755;; 365 | *) false;; 366 | esac && 367 | $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { 368 | ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` 369 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 370 | } 371 | } 372 | then posix_mkdir=: 373 | fi 374 | rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 375 | else 376 | # Remove any dirs left behind by ancient mkdir implementations. 377 | rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null 378 | fi 379 | trap '' 0;; 380 | esac 381 | 382 | if 383 | $posix_mkdir && ( 384 | umask $mkdir_umask && 385 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 386 | ) 387 | then : 388 | else 389 | 390 | # mkdir does not conform to POSIX, 391 | # or it failed possibly due to a race condition. Create the 392 | # directory the slow way, step by step, checking for races as we go. 393 | 394 | case $dstdir in 395 | /*) prefix='/';; 396 | [-=\(\)!]*) prefix='./';; 397 | *) prefix='';; 398 | esac 399 | 400 | oIFS=$IFS 401 | IFS=/ 402 | set -f 403 | set fnord $dstdir 404 | shift 405 | set +f 406 | IFS=$oIFS 407 | 408 | prefixes= 409 | 410 | for d 411 | do 412 | test X"$d" = X && continue 413 | 414 | prefix=$prefix$d 415 | if test -d "$prefix"; then 416 | prefixes= 417 | else 418 | if $posix_mkdir; then 419 | (umask $mkdir_umask && 420 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 421 | # Don't fail if two instances are running concurrently. 422 | test -d "$prefix" || exit 1 423 | else 424 | case $prefix in 425 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 426 | *) qprefix=$prefix;; 427 | esac 428 | prefixes="$prefixes '$qprefix'" 429 | fi 430 | fi 431 | prefix=$prefix/ 432 | done 433 | 434 | if test -n "$prefixes"; then 435 | # Don't fail if two instances are running concurrently. 436 | (umask $mkdir_umask && 437 | eval "\$doit_exec \$mkdirprog $prefixes") || 438 | test -d "$dstdir" || exit 1 439 | obsolete_mkdir_used=true 440 | fi 441 | fi 442 | fi 443 | 444 | if test -n "$dir_arg"; then 445 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 446 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 447 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 448 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 449 | else 450 | 451 | # Make a couple of temp file names in the proper directory. 452 | dsttmp=${dstdirslash}_inst.$$_ 453 | rmtmp=${dstdirslash}_rm.$$_ 454 | 455 | # Trap to clean up those temp files at exit. 456 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 457 | 458 | # Copy the file name to the temp name. 459 | (umask $cp_umask && 460 | { test -z "$stripcmd" || { 461 | # Create $dsttmp read-write so that cp doesn't create it read-only, 462 | # which would cause strip to fail. 463 | if test -z "$doit"; then 464 | : >"$dsttmp" # No need to fork-exec 'touch'. 465 | else 466 | $doit touch "$dsttmp" 467 | fi 468 | } 469 | } && 470 | $doit_exec $cpprog "$src" "$dsttmp") && 471 | 472 | # and set any options; do chmod last to preserve setuid bits. 473 | # 474 | # If any of these fail, we abort the whole thing. If we want to 475 | # ignore errors from any of these, just make sure not to ignore 476 | # errors from the above "$doit $cpprog $src $dsttmp" command. 477 | # 478 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && 479 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && 480 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && 481 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 482 | 483 | # If -C, don't bother to copy if it wouldn't change the file. 484 | if $copy_on_change && 485 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && 486 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && 487 | set -f && 488 | set X $old && old=:$2:$4:$5:$6 && 489 | set X $new && new=:$2:$4:$5:$6 && 490 | set +f && 491 | test "$old" = "$new" && 492 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 493 | then 494 | rm -f "$dsttmp" 495 | else 496 | # If $backupsuffix is set, and the file being installed 497 | # already exists, attempt a backup. Don't worry if it fails, 498 | # e.g., if mv doesn't support -f. 499 | if test -n "$backupsuffix" && test -f "$dst"; then 500 | $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null 501 | fi 502 | 503 | # Rename the file to the real destination. 504 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || 505 | 506 | # The rename failed, perhaps because mv can't rename something else 507 | # to itself, or perhaps because mv is so ancient that it does not 508 | # support -f. 509 | { 510 | # Now remove or move aside any old file at destination location. 511 | # We try this two ways since rm can't unlink itself on some 512 | # systems and the destination file might be busy for other 513 | # reasons. In this case, the final cleanup might fail but the new 514 | # file should still install successfully. 515 | { 516 | test ! -f "$dst" || 517 | $doit $rmcmd "$dst" 2>/dev/null || 518 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && 519 | { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } 520 | } || 521 | { echo "$0: cannot unlink or rename $dst" >&2 522 | (exit 1); exit 1 523 | } 524 | } && 525 | 526 | # Now rename the file to the real destination. 527 | $doit $mvcmd "$dsttmp" "$dst" 528 | } 529 | fi || exit 1 530 | 531 | trap '' 0 532 | fi 533 | done 534 | 535 | # Local variables: 536 | # eval: (add-hook 'before-save-hook 'time-stamp nil t) 537 | # time-stamp-start: "scriptversion=" 538 | # time-stamp-format: "%Y-%02m-%02d.%02H" 539 | # time-stamp-time-zone: "UTC0" 540 | # time-stamp-end: "; # UTC" 541 | # End: 542 | -------------------------------------------------------------------------------- /EXAMPLES.md: -------------------------------------------------------------------------------- 1 | Some helpful tips: 2 | 3 | * When the intention is to match all packets (i.e. blank regex), it is 4 | technically faster to use an empty regex (`''`) than to use a wildcard 5 | (e.g. `'.*'`, `'*'`). 6 | 7 | * When sniffing interfaces that are very busy or are seeing large amounts of 8 | packet traffic, make sure to craft a BPF filter to limit what PCAP has to 9 | deliver to ngrep. The ngrep parser takes a certain amount of time and while 10 | negligible on a slow interface, it can add up very quickly on a busy one. 11 | 12 | * Hexadecimal expressions can be in straight numeric form, 'DEADBEEF', or in 13 | symbolic form, '0xDEADBEEF'. A byte is the smallest unit of measure you can 14 | match against. 15 | 16 | * As of v1.28, ngrep doesn't require a match expression. However, there are 17 | cases where ngrep can be confused and think part of your bpf filter is the 18 | match expression, as in: 19 | 20 | ``` 21 | % ngrep not port 80 22 | interface: eth0 (192.168.1.0/255.255.255.0) 23 | filter: ip and ( port 80 ) 24 | match: not 25 | ``` 26 | 27 | In cases like this, you will need to specify a blank match expression: 28 | 29 | ``` 30 | % ngrep '' not port 80 31 | interface: eth0 (192.168.1.0/255.255.255.0) 32 | filter: ip and ( not port 80 ) 33 | ``` 34 | 35 | ## Basic Packet Sniffing 36 | 37 | Basic packet sniffing is easy with ngrep. It supports BPF filter logic, which 38 | means to say constraining what ngrep sees and displays is as easy as saying 39 | something like `ngrep host foo.bar.com and port 25`. Following are a few 40 | examples of common invocations of ngrep to do basic packet sniffing. Please 41 | note the usage of `any' as the specified ethernet adaptor to attach to; in most 42 | recent UNIX libpcap implementations this will instruct ngrep to attach to all 43 | interfaces at once, local (lo) and all external interfaces that may be active. 44 | 45 | * `ngrep -d any port 25` 46 | 47 | Monitor all activity crossing source or destination port 25 (SMTP). 48 | 49 | * `ngrep -d any 'error' port syslog` 50 | 51 | Monitor any network-based syslog traffic for the occurrence of the word "error". 52 | ngrep knows how to convert service port names (on UNIX, located in 53 | `/etc/services`) to port numbers. 54 | 55 | * `ngrep -wi -d any 'user|pass' port 21` 56 | 57 | Monitor any traffic crossing source or destination port 21 (FTP), looking 58 | case-insensitively for the words "user" or "pass", matched as word-expressions 59 | (the match term(s) must have non-alphanumeric, delimiting characters surrounding 60 | them). 61 | 62 | ## Debugging HTTP interactions 63 | 64 | In certain scenarios it is desirous to see how web browsers communicate with web 65 | servers, and to inspect the HTTP headers and possibly cookie values that they 66 | are exchanging. 67 | 68 | In this example, we run an ngrep on a webserver. Since it only has 69 | one interface, eth0, we omit specifying the interface manually on the 70 | command line and allow ngrep to choose the default interface for us, 71 | for convenience. 72 | 73 | ``` 74 | # ngrep port 80 75 | interface: eth0 (64.90.164.72/255.255.255.252) 76 | filter: ip and ( port 80 ) 77 | #### 78 | T 67.169.59.38:42167 -> 64.90.164.74:80 [AP] 79 | GET / HTTP/1.1..User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i 80 | 686) Opera 7.21 [en]..Host: www.darkridge.com..Accept: text/html, applicat 81 | ion/xml;q=0.9, application/xhtml+xml;q=0.9, image/png, image/jpeg, image/gi 82 | f, image/x-xbitmap, */*;q=0.1..Accept-Charset: iso-8859-1, utf-8, utf-16, * 83 | ;q=0.1..Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0..Cookie: SQ 84 | MSESSID=5272f9ae21c07eca4dfd75f9a3cda22e..Cookie2: $Version=1..Connection: 85 | Keep-Alive, TE..TE: deflate, gzip, chunked, identity, trailers.... 86 | ## 87 | T 64.90.164.74:80 -> 67.169.59.38:42167 [AP] 88 | HTTP/1.1 200 OK..Date: Mon, 29 Mar 2004 00:44:40 GMT..Server: Apache/2.0.49 89 | (Unix)..Last-Modified: Tue, 04 Nov 2003 12:09:41 GMT..ETag: "210e23-326-f8 90 | 200b40"..Accept-Ranges: bytes..Vary: Accept-Encoding,User-Agent..Content-En 91 | coding: gzip..Content-Length: 476..Keep-Alive: timeout=15, max=100..Connect 92 | ion: Keep-Alive..Content-Type: text/html; charset=ISO-8859-1..Content-Langu 93 | age: en..............}S]..0.|...........H...8........@..\....(.....Dw.%.,.. 94 | ;.k.....Y>q<........d ...........3.i..kdm.u@d{.Q..\....@..B1.0.2YI^..R..... 95 | ....X......X..y...\.....,..(........1...g.......*...j..a.`._@.W....0.....?. 96 | .R.K.j..Y.....>...;kw*U.j.<...\0Tn.l.:......>Fs....'....h.'...u.H4..'.6.vID 97 | I.......N.r.O...}...I.w. ...mX...L.s..{.L.R..-...e....~nu..t.3...H..#..J... 98 | .u.?..]....^..2.....e8v/gP.....].48...qD!..........#y...m}..>/?..#........I 99 | ..I..4.P......2:...n8l.......!.Yr&... 100 | ## 101 | ``` 102 | 103 | As you can see, all headers and aspects of the HTTP transmission are exposed in 104 | their gory detail. It's a little hard to parse though, so let's see what 105 | happens when `-W byline` mode is used: 106 | 107 | ``` 108 | # ngrep -W byline port 80 109 | interface: eth0 (64.90.164.72/255.255.255.252) 110 | filter: ip and ( port 80 ) 111 | #### 112 | T 67.169.59.38:42177 -> 64.90.164.74:80 [AP] 113 | GET / HTTP/1.1. 114 | User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux i686) Opera ... 115 | Host: www.darkridge.com. 116 | Accept: text/html, application/xml;q=0.9, application/xhtml+xml;q=0.9 ... 117 | Accept-Charset: iso-8859-1, utf-8, utf-16, *;q=0.1. 118 | Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0. 119 | Cookie: SQMSESSID=5272f9ae21c07eca4dfd75f9a3cda22e. 120 | Cookie2: $Version=1. 121 | Cache-Control: no-cache. 122 | Connection: Keep-Alive, TE. 123 | TE: deflate, gzip, chunked, identity, trailers. 124 | . 125 | 126 | ## 127 | T 64.90.164.74:80 -> 67.169.59.38:42177 [AP] 128 | HTTP/1.1 200 OK. 129 | Date: Mon, 29 Mar 2004 00:47:25 GMT. 130 | Server: Apache/2.0.49 (Unix). 131 | Last-Modified: Tue, 04 Nov 2003 12:09:41 GMT. 132 | ETag: "210e23-326-f8200b40". 133 | Accept-Ranges: bytes. 134 | Vary: Accept-Encoding,User-Agent. 135 | Content-Encoding: gzip. 136 | Content-Length: 476. 137 | Keep-Alive: timeout=15, max=100. 138 | Connection: Keep-Alive. 139 | Content-Type: text/html; charset=ISO-8859-1. 140 | Content-Language: en. 141 | . 142 | ..........}S]..0.|...........H...8........@..\....(.....Dw.%.,..;.k.. ... 143 | .;kw*U.j.<...\0Tn.l.:......>Fs....'....h.'...u.H4..'.6.vIDI.......N.r ... 144 | ..H..#..J....u.?..]....^..2.....e8v/gP.....].48...qD!..........#y...m ... 145 | #### 146 | ``` 147 | 148 | (Content visually truncated for display purposes.) 149 | 150 | `-W byline` mode tells ngrep to respect embedded line feeds when they occur. 151 | You'll note from the output above that there is still a trailing dot (".") on 152 | each line, which is the carriage-return portion of the CRLF pair. Using this 153 | mode, now the output has become much easier to visually parse. 154 | 155 | ## Processing PCAP dump files, looking for patterns 156 | 157 | I had a friend who worked at Network Solutions and among the things he did was 158 | analyze huge 500M+ PCAP dump files of DNS traffic, looking for patterns and 159 | anomalies. ngrep was an invaluable tool for this purpose; it allowed him to 160 | take one instance of a network dump and search it quickly and repeatedly for 161 | patterns in the data packets. 162 | 163 | To save a PCAP dump file from ngrep is very easy; simply run ngrep as you 164 | normally would but add one more command line option: `-O some.file.dump` (the 165 | name of the file is largely irrelevant). To illustrate another feature of 166 | ngrep, we will use the `-T` option (print time differential information). 167 | 168 | ``` 169 | # ngrep -O /tmp/dns.dump -d any -T port domain 170 | interface: any 171 | filter: ip and ( port domain ) 172 | output: /tmp/dns.dump 173 | # 174 | U +0.000000 203.115.225.24:53 -> 64.90.164.74:53 175 | .............m.razor2.cloudmark.com.......)........ 176 | # 177 | U +0.000281 64.90.164.74:53 -> 203.115.225.24:53 178 | .............m.razor2.cloudmark.com................'.ns1...hostmaster..ws.. 179 | ..p.... ..:.......)........ 180 | # 181 | U +0.078184 195.113.155.7:2949 -> 64.90.164.74:53 182 | .............a.razor2.cloudmark.com..... 183 | # 184 | U +0.000351 64.90.164.74:53 -> 195.113.155.7:2949 185 | .............a.razor2.cloudmark.com..................agony...4..........B.. 186 | ..............ns1...............ns2...............ns3...X..........@Z.J.j.. 187 | ........@Z...|..........B..; 188 | ^Cexit 189 | 6 received, 0 dropped 190 | ``` 191 | 192 | Note the `output:` indicator and timestamp information. Now we have a PCAP dump 193 | file, and so let's search it for some patterns: 194 | 195 | ``` 196 | # ngrep -w 'm' -I /tmp/dns.dump 197 | input: /tmp/dns.dump 198 | match: ((^m\W)|(\Wm$)|(\Wm\W)) 199 | # 200 | U 203.115.225.24:53 -> 64.90.164.74:53 201 | .............m.razor2.cloudmark.com.......)........ 202 | # 203 | U 64.90.164.74:53 -> 203.115.225.24:53 204 | .............m.razor2.cloudmark.com................'.ns1...hostmaster..ws.. 205 | ..p.... ..:.......)........ 206 | ##exit 207 | ``` 208 | 209 | Above we searched for the letter "m", matched as a word (`-w`). This yields two 210 | packets. 211 | 212 | ``` 213 | # ngrep -tD ns3 -I /tmp/dns.dump 214 | input: /tmp/dns.dump 215 | match: ns3 216 | #### 217 | U 2004/03/28 20:32:37.088525 64.90.164.74:53 -> 195.113.155.7:2949 218 | .............a.razor2.cloudmark.com..................agony...4..........B.. 219 | ..............ns1...............ns2...............ns3...X..........@Z.J.j.. 220 | ........@Z...|..........B..; 221 | exit 222 | ``` 223 | 224 | Here we've added `-t` which means print the absolute timestamp on the packet, 225 | and `-D` which means replay the packets by the time interval at which they were 226 | recorded. The latter is a neat little feature for observing the traffic at the 227 | rates/times they originally seen, though in this example it's not terribly 228 | effective as there is only one packet being matched. 229 | 230 | ``` 231 | # ngrep -I /tmp/dns.dump port 80 232 | input: /tmp/dns.dump 233 | filter: ip and ( port 80 ) 234 | exit 235 | ``` 236 | 237 | There's no port 80 traffic in the dump, so of course the BPF filter yields us no 238 | results. 239 | 240 | ## Observing binary being transferred across the wire 241 | 242 | One interesting feature of ngrep is its ability to take a hexademical (binary) 243 | expression and search for that in lieu of a regular expression. ngrep can also 244 | display the packets it observes in a hexadecimal format, which is more effective 245 | for inspecting binary content patterns. 246 | 247 | In this example, we will simply look for a binary pattern in a web stream, but 248 | the more obvious usage is to look for a DDoS Zombie's unique binary signature 249 | (say, from a command packet), or even a Worm/Virus being transferred across the 250 | wire as it propogates itself. 251 | 252 | For this test, let's assume we have a GIF on a web server that has the data 253 | pattern "0xc5d5e5f55666768696a6b6c6d6e6" (hexademical) in it. Once `-X` is 254 | specified, the expression will be interpreted as a hexademical pattern instead 255 | of a regular expression, and the "0x" prefix is optional. 256 | 257 | To see a packet like this cross the wire: 258 | 259 | ``` 260 | # ngrep -xX '0xc5d5e5f55666768696a6b6c6d6e6' port 80 261 | interface: eth0 (64.90.164.72/255.255.255.252) 262 | filter: ip and ( port 80 ) 263 | match: 0xc5d5e5f55666768696a6b6c6d6e6 264 | ### 265 | T 64.90.164.74:80 -> 67.169.59.38:42306 [A] 266 | ff d8 ff e0 00 10 4a 46 49 46 00 01 02 01 00 48 ......JFIF.....H 267 | 00 48 00 00 ff ed 13 ba 50 68 6f 74 6f 73 68 6f .H......Photosho 268 | 70 20 33 2e 30 00 38 42 49 4d 03 ed 00 00 00 00 p 3.0.8BIM...... 269 | 00 10 00 48 00 00 00 01 00 01 00 48 00 00 00 01 ...H.......H.... 270 | 00 01 38 42 49 4d 04 0d 00 00 00 00 00 04 00 00 ..8BIM.......... 271 | 00 78 38 42 49 4d 03 f3 00 00 00 00 00 08 00 00 .x8BIM.......... 272 | 00 00 00 00 00 00 38 42 49 4d 04 0a 00 00 00 00 ......8BIM...... 273 | 00 01 00 00 38 42 49 4d 27 10 00 00 00 00 00 0a ....8BIM'....... 274 | 00 01 00 00 00 00 00 00 00 02 38 42 49 4d 03 f5 ..........8BIM.. 275 | 00 00 00 00 00 48 00 2f 66 66 00 01 00 6c 66 66 .....H./ff...lff 276 | 00 06 00 00 00 00 00 01 00 2f 66 66 00 01 00 a1 ........./ff.... 277 | 99 9a 00 06 00 00 00 00 00 01 00 32 00 00 00 01 ...........2.... 278 | 00 5a 00 00 00 06 00 00 00 00 00 01 00 35 00 00 .Z...........5.. 279 | 00 01 00 2d 00 00 00 06 00 00 00 00 00 01 38 42 ...-..........8B 280 | 49 4d 03 f8 00 00 00 00 00 70 00 00 ff ff ff ff IM.......p...... 281 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 282 | ff ff 03 e8 00 00 00 00 ff ff ff ff ff ff ff ff ................ 283 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff 03 e8 ................ 284 | 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ................ 285 | ff ff ff ff ff ff ff ff ff ff 03 e8 00 00 00 00 ................ 286 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ 287 | ff ff ff ff ff ff 03 e8 00 00 38 42 49 4d 04 08 ..........8BIM.. 288 | 00 00 00 00 00 10 00 00 00 01 00 00 02 40 00 00 .............@.. 289 | 02 40 00 00 00 00 38 42 49 4d 04 14 00 00 00 00 .@....8BIM...... 290 | 00 04 00 00 00 06 38 42 49 4d 04 0c 00 00 00 00 ......8BIM...... 291 | 12 2a 00 00 00 01 00 00 00 70 00 00 00 57 00 00 .*.......p...W.. 292 | 01 50 00 00 72 30 00 00 12 0e 00 18 00 01 ff d8 .P..r0.......... 293 | ff e0 00 10 4a 46 49 46 00 01 02 01 00 48 00 48 ....JFIF.....H.H 294 | 00 00 ff fe 00 26 46 69 6c 65 20 77 72 69 74 74 .....&File writt 295 | 65 6e 20 62 79 20 41 64 6f 62 65 20 50 68 6f 74 en by Adobe Phot 296 | 6f 73 68 6f 70 a8 20 35 2e 30 ff ee 00 0e 41 64 oshop. 5.0....Ad 297 | 6f 62 65 00 64 80 00 00 00 01 ff db 00 84 00 0c obe.d........... 298 | 08 08 08 09 08 0c 09 09 0c 11 0b 0a 0b 11 15 0f ................ 299 | 0c 0c 0f 15 18 13 13 15 13 13 18 11 0c 0c 0c 0c ................ 300 | 0c 0c 11 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c ................ 301 | 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 01 ................ 302 | 0d 0b 0b 0d 0e 0d 10 0e 0e 10 14 0e 0e 0e 14 14 ................ 303 | 0e 0e 0e 0e 14 11 0c 0c 0c 0c 0c 11 11 0c 0c 0c ................ 304 | 0c 0c 0c 11 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c ................ 305 | 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c 0c ................ 306 | ff c0 00 11 08 00 57 00 70 03 01 22 00 02 11 01 ......W.p..".... 307 | 03 11 01 ff dd 00 04 00 07 ff c4 01 3f 00 00 01 ............?... 308 | 05 01 01 01 01 01 01 00 00 00 00 00 00 00 03 00 ................ 309 | 01 02 04 05 06 07 08 09 0a 0b 01 00 01 05 01 01 ................ 310 | 01 01 01 01 00 00 00 00 00 00 00 01 00 02 03 04 ................ 311 | 05 06 07 08 09 0a 0b 10 00 01 04 01 03 02 04 02 ................ 312 | 05 07 06 08 05 03 0c 33 01 00 02 11 03 04 21 12 .......3......!. 313 | 31 05 41 51 61 13 22 71 81 32 06 14 91 a1 b1 42 1.AQa."q.2.....B 314 | 23 24 15 52 c1 62 33 34 72 82 d1 43 07 25 92 53 #$.R.b34r..C.%.S 315 | f0 e1 f1 63 73 35 16 a2 b2 83 26 44 93 54 64 45 ...cs5....&D.TdE 316 | c2 a3 74 36 17 d2 55 e2 65 f2 b3 84 c3 d3 75 e3 ..t6..U.e.....u. 317 | f3 46 27 94 a4 85 b4 95 c4 d4 e4 f4 a5 b5 c5 d5 .F'............. 318 | e5 f5 56 66 76 86 96 a6 b6 c6 d6 e6 f6 37 47 57 ..Vfv........7GW 319 | 67 77 87 97 a7 b7 c7 d7 e7 f7 11 00 02 02 01 02 gw.............. 320 | 04 04 03 04 05 06 07 07 06 05 35 01 00 02 11 03 ..........5..... 321 | 21 31 12 04 41 51 61 71 22 13 05 32 81 91 14 a1 !1..AQaq"..2.... 322 | b1 42 23 c1 52 d1 f0 33 24 62 e1 72 82 92 43 53 .B#.R..3$b.r..CS 323 | 15 63 73 34 f1 25 06 16 a2 b2 83 07 26 35 c2 d2 .cs4.%......&5.. 324 | 44 93 54 a3 17 64 45 55 36 74 65 e2 f2 b3 84 c3 D.T..dEU6te..... 325 | d3 75 e3 f3 46 94 a4 85 b4 95 c4 d4 e4 f4 a5 b5 .u..F........... 326 | c5 d5 e5 f5 56 66 76 86 96 a6 b6 c6 d6 e6 f6 27 ....Vfv........' 327 | 37 47 57 67 77 87 97 a7 b7 c7 ff da 00 0c 03 01 7GWgw........... 328 | 00 02 11 03 11 00 3f 00 f2 a5 3a ad 35 ba 40 0e ......?...:.5.@. 329 | 04 16 90 78 20 a8 25 07 94 aa d3 19 18 90 41 a2 ...x .%.......A. 330 | 13 9a 4b 9b b9 a0 91 c8 3d c8 ef a7 f2 14 46 35 ..K.....=.....F5 331 | af fe 6c 6f f8 73 e3 3b 7e 92 6a ad 2c 30 75 64 ..lo.s.;~.j.,0ud 332 | 82 47 fd f9 a7 f3 5c 8a ec d7 b5 e4 d2 4b 79 0d .G....\......Ky. 333 | 73 a0 ba 3f f2 49 87 8b 61 4d 88 fd de 40 4a 66 s..?.I..aM...@Jf 334 | 51 fd e8 c7 e6 ff 00 03 f4 5a ee 63 d8 76 bd a5 Q........Z.c.v.. 335 | a4 76 22 13 29 d9 75 b6 99 b1 ee 7c 71 b8 ca 82 .v".).u....|q... 336 | 78 be ad 79 70 f1 1e 1b e1 e9 c5 f3 29 24 92 49 x..yp.......)$.I 337 | 0a 49 24 92 52 92 45 c7 c4 bf 25 c5 b4 b7 76 d1 .I$.R.E...%...v. 338 | 2e 3c 00 3f 94 ef a2 d5 6f 33 a3 64 e1 63 7a f9 .<.?....o3.d.cz. 339 | 0f a9 85 c5 bb 29 f5 18 eb 1c 1c 1d b9 e2 ba 9c .....).......... 340 | ff 00 63 36 fe 7a 69 c9 00 44 4c 87 11 da 3d 57 ..c6.zi..DL...=W 341 | 8c 59 0c 4c c4 4f 08 fd 2e 8d 3a da e7 1d 8d 11 .Y.L.O....:..... 342 | 22 75 47 ca fb 35 78 d5 d2 c2 1f 7c 87 58 f6 ea "uG..5x....|.X.. 343 | 06 91 e9 ef fc e4 1b 5f 4c 33 d1 05 a7 68 0f 27 ......._L3...h.' 344 | b9 fc e8 42 4a ac 83 a8 ae 8c 9e e0 84 65 00 23 ...BJ........e.# 345 | 23 21 5c 7f 37 0c 7e 6f 47 f5 9f ff d0 f2 ae ca #!\.7.~oG....... 346 | 62 36 c1 3a 1f c0 84 cd 69 71 81 c9 47 a6 f6 e3 b6.:....iq..G... 347 | 3f 75 41 af 78 e1 ef 12 27 fe 0d bf f9 24 f1 3e ?uA.x...'....$.> 348 | 0d 40 e2 24 55 7f 15 f0 80 91 1c 52 e0 85 eb 2a .@.$U......R...* 349 | e2 ff 00 16 3f a4 c2 fc 5c 8a 1a c7 da c2 c6 d9 ....?...\....... 350 | f4 67 c9 05 5f ca ea 37 3c fa 77 1a b2 1b e2 01 .g.._..7<.w..... 351 | 81 3d 83 bd 8a 2e a8 67 39 b5 e0 63 90 e6 34 9b .=.....g9..c..4. 352 | 00 20 ff 00 68 f1 ec 67 ef a8 63 29 50 e3 00 5f . ..h..g..c)P.._ 353 | 51 f2 b3 f3 18 79 70 66 70 e5 26 30 e1 a8 65 1f Q....ypfp.&0..e. 354 | ad 9c bf 4e 8e 3e 2c 5f f3 d8 62 f4 dc ac a6 ef ...N.>,_..b..... 355 | a8 02 c0 40 73 8b 86 93 fb df 9c b6 3a 66 36 0d ...@s.......:f6. 356 | 6c 73 18 45 b7 6a 2c de ls.E.j,. 357 | ######### 358 | ``` 359 | 360 | Above we specified `-X` to tell ngrep to treat the match expression as 361 | hexadecimal, and `-x` to tell ngrep to print out the patterns it matches in 362 | hexadecimal form. 363 | 364 | As it turns out, several other packets also matched this pattern, but this 365 | should give you a good idea of how to use hexadecimal patterns and the hex 366 | output mode. 367 | --------------------------------------------------------------------------------