Package: ngrep
Version: 1.45.ds2-9
Severity: wishlist
Tags: patch

Let me propose a patch that enables Ngrep to inspect packages
of protocol type AH and ESP, originating with IPsec. This ability
comes handy for me in porting ipsec-tools to GNU/kFreeBSD.

The patch depends, as given here, on the patch variation I submitted
in the recent report #615138, without which the present changes are
only able to detect IPsec under IPv4, not in IPv6.

The present patch has been tested on payloads

   ICMP, UDP, TCP, ESP:   IPv4 and ah/tunnel, ah/transport

   any:                   IPv4 and esp/tunnel, esp/transport

   ICMPv6, UDP, TCP:      IPv6 and ah/transport, ah/tunnel


Best regards,
  Mats Erik Andersson, DM
Description: Inspect protocols AH and ESP for content.
 A rather natural approach to detect IPsec packages
 for AH and ESP protocols is implemented. It depends
 on "<libnet.h>", which the Debian package already needs.
 .
 The parsing of ESP uncovers SPI and SEQ only, whereas
 any AH package is examined further to disclose its
 encapsulated contents. Only the exact payload is dumped,
 for TCP, UDP, ICPM,ICMPv6, IGMP, given that is was
 delivered in AH mode.
 .
 The patch has been verified for multiple instances:
 .
   IPv4: ah/transport, esp/transport, ah/tunnel, es/tunnel
   IPv6: ah/transport, ah/tunnel
Author: Mats Erik Andersson <[email protected]>
Forwarded: no
Last-Update: 2011-02-26

diff -Naur ngrep-1.45.ds2.ipv6/ngrep.c ngrep-1.45.ds2/ngrep.c
--- ngrep-1.45.ds2.ipv6/ngrep.c	2011-02-26 01:01:41.000000000 +0100
+++ ngrep-1.45.ds2/ngrep.c	2011-02-26 14:07:38.000000000 +0100
@@ -81,6 +81,7 @@
 #endif
 
 #include <pcap.h>
+#include <libnet.h>
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -785,6 +786,30 @@
                         igmphdr_offset, fragmented, frag_offset, frag_id);
         } break;
 
+        case IPPROTO_AH: {
+            struct libnet_ah_hdr *ah_pkt = (struct libnet_ah_hdr *)((unsigned char *)(ip4_pkt) + ip_hl);
+            uint8_t ah_byte_len = 4 * (ah_pkt->ah_len + 2);
+
+            data = (unsigned char *)(ah_pkt) + ah_byte_len;
+            len -= link_offset + ip_hl + ah_byte_len;
+
+            dump_packet(h, p, ip_proto, data, len,
+                        ip_src, ip_dst, 0, 0, 0,
+                        ah_byte_len, fragmented, frag_offset, frag_id);
+        } break;
+
+
+        case IPPROTO_ESP: {
+            struct libnet_esp_hdr *esp_pkt = (struct libnet_esp_hdr *)((unsigned char *)(ip4_pkt) + ip_hl);
+
+            data = (unsigned char *)(esp_pkt) + sizeof(*esp_pkt);
+            len -= link_offset + ip_hl + sizeof(*esp_pkt);
+
+            dump_packet(h, p, ip_proto, data, len,
+                        ip_src, ip_dst, 0, 0, 0,
+                        0, fragmented, frag_offset, frag_id);
+        } break;
+
         default: {
             data = (unsigned char *)(ip4_pkt) + ip_hl;
             len -= link_offset + ip_hl;
@@ -831,6 +856,8 @@
             case IPPROTO_ICMP:   ident = ICMP;    break;
             case IPPROTO_ICMPV6: ident = ICMPv6;  break;
             case IPPROTO_IGMP:   ident = IGMP;    break;
+            case IPPROTO_AH:     ident = AH;      break;
+            case IPPROTO_ESP:    ident = ESP;     break;
             default:             ident = UNKNOWN; break;
         }
 
@@ -845,11 +872,134 @@
     if (print_time)
         print_time(h);
 
+    /* Begin with AH in order that also encapsulated payload be made visible. */
+
+    if (proto == IPPROTO_AH) {
+        struct libnet_ah_hdr *ah_hdr = (struct libnet_ah_hdr *)(data - hdr_offset);
+        const char *ident;
+
+        printf("%s -> %s ", ip_src, ip_dst);
+
+        printf("spi=%#010x seq=%#x ", ntohl(ah_hdr->ah_spi), ntohl(ah_hdr->ah_seq));
+
+        printf("ahlen=%u%s ", 4 * ah_hdr->ah_len, dump_single ? "" : "\n   ");
+
+        /* Uncover the inner payload. */
+        proto = ah_hdr->ah_nh;
+
+        if (proto == IPPROTO_IPIP) {
+            /* IP-to-IP encapsulation, go one step further
+             * and continue parsing. */
+            struct ip *ip4_pkt = (struct ip *) data;
+
+            printf("IP => ");
+            proto  = ip4_pkt->ip_p;
+            data  += 4 * ip4_pkt->ip_hl;
+            len   -= 4 * ip4_pkt->ip_hl;
+            inet_ntop(AF_INET, &ip4_pkt->ip_src, (char *) ip_src, sizeof(ip_src));
+            inet_ntop(AF_INET, &ip4_pkt->ip_dst, (char *) ip_dst, sizeof(ip_dst));
+        }
+
+#if USE_IPv6
+        if (proto == IPPROTO_IPV6) {
+            /* IPv6 encapsulation, go one step further
+             * and continue parsing. */
+            struct ip6_hdr *ip6_pkt = (struct ip6_hdr *) data;
+
+            printf("IP6 => ");
+            proto  = ip6_pkt->ip6_nxt;
+            data  += sizeof(struct ip6_hdr);
+            len   -= sizeof(struct ip6_hdr);
+            inet_ntop(AF_INET6, &ip6_pkt->ip6_src, (char *) ip_src, sizeof(ip_src));
+            inet_ntop(AF_INET6, &ip6_pkt->ip6_dst, (char *) ip_dst, sizeof(ip_dst));
+        }
+#endif
+
+        switch (proto) {
+            case IPPROTO_TCP: {
+                    struct tcphdr *tcp_pkt = (struct tcphdr *) data;
+
+                    ident = "TCP";
+                    proto = IPPROTO_TCP;
+                    sport = ntohs(tcp_pkt->th_sport);
+                    dport = ntohs(tcp_pkt->th_dport);
+                    flags = tcp_pkt->th_flags;
+
+                    hdr_offset = (frag_offset) ? 0 : (4 * tcp_pkt->th_off);
+                    data  += hdr_offset;
+                    len   -= hdr_offset;
+            } break;
+
+            case IPPROTO_UDP: {
+                    ident = "UDP";
+                    proto = IPPROTO_UDP;
+#if HAVE_DUMB_UDPHDR
+                    sport = ntohs(((struct udphdr *) data)->source);
+                    dport = ntohs(((struct udphdr *) data)->dest);
+#else
+                    sport = ntohs(((struct udphdr *) data)->uh_sport);
+                    dport = ntohs(((struct udphdr *) data)->uh_dport);
+#endif
+                    if (!frag_offset)
+                            data += sizeof(struct udphdr), len -= sizeof(struct udphdr);
+            } break;
+
+            case IPPROTO_ESP: {
+                    ident = "ESP";
+                    proto = IPPROTO_ESP;
+                    data += sizeof(struct libnet_esp_hdr);
+                    len  -= sizeof(struct libnet_esp_hdr);
+            } break;
+
+            case IPPROTO_ICMP: {
+                    ident = "ICMP";
+                    proto = IPPROTO_ICMP;
+                    sport = ((struct icmp *) data)->icmp_type;
+                    dport = ((struct icmp *) data)->icmp_code;
+                    if (!frag_offset)
+                            data += 4, len -= 4;
+            } break;
+
+#if USE_IPv6
+            case IPPROTO_ICMPV6: {
+                    ident = "ICMPv6";
+                    proto = IPPROTO_ICMPV6;
+                    sport = ((struct icmp6_hdr *) data)->icmp6_type;
+                    dport = ((struct icmp6_hdr *) data)->icmp6_code;
+                    if (!frag_offset)
+                            data += 4, len -= 4;
+            } break;
+#endif
+
+            case IPPROTO_IGMP: {
+                    ident = "IGMP";
+                    proto = IPPROTO_IGMP;
+                    sport = ((struct igmp *) data)->igmp_type;
+                    dport = ((struct igmp *) data)->igmp_code;
+                    if (!frag_offset)
+                            data += 4, len -= 4;
+            } break;
+
+            case IPPROTO_AH:     ident = "AH";      break;
+
+            default:             ident = "UNKNOWN"; break;
+        }
+
+        printf("%s ", ident);
+    }
+
+    if (proto == IPPROTO_ESP) {
+        struct libnet_esp_hdr *esp_hdr = (struct libnet_esp_hdr *)(data - sizeof(struct libnet_esp_hdr));
+
+        printf("%s -> %s ", ip_src, ip_dst);
+        printf("spi=%#010x seq=%#x ", ntohl(esp_hdr->esp_spi), ntohl(esp_hdr->esp_seq));
+    }
+
     if ((proto == IPPROTO_TCP || proto == IPPROTO_UDP) && (sport || dport) && (hdr_offset || frag_offset == 0))
 
         printf("%s:%u -> %s:%u", ip_src, sport, ip_dst, dport);
 
-    else
+    else if (proto != IPPROTO_ESP)
 
         printf("%s -> %s", ip_src, ip_dst);
 
diff -Naur ngrep-1.45.ds2.ipv6/ngrep.h ngrep-1.45.ds2/ngrep.h
--- ngrep-1.45.ds2.ipv6/ngrep.h	2007-08-12 20:30:00.000000000 +0200
+++ ngrep-1.45.ds2/ngrep.h	2011-02-24 23:57:57.000000000 +0100
@@ -66,7 +66,8 @@
  */
 
 typedef enum {
-    TCP = 'T', UDP = 'U', ICMP = 'I', ICMPv6 = 'I', IGMP = 'G', UNKNOWN = '?'
+    TCP = 'T', UDP = 'U', ICMP = 'I', ICMPv6 = 'I', IGMP = 'G', UNKNOWN = '?',
+    AH = 'A', ESP = 'E'
 } netident_t;
 
 /*

Attachment: signature.asc
Description: Digital signature

Reply via email to