]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-pflog.c
CI: Add warning exemptions for Sun C (suncc-5.14) on Solaris 10
[tcpdump] / print-pflog.c
index b8485ea5ea299a7a22aabaa5b2b93ec4d4446199..f65ede295938ba0e39affe17c3c7a316ccf33eb3 100644 (file)
@@ -1,5 +1,3 @@
-/*     $OpenBSD: print-pflog.c,v 1.9 2001/09/18 14:52:53 jakob Exp $   */
-
 /*
  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996
  *     The Regents of the University of California.  All rights reserved.
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#ifndef lint
-static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-pflog.c,v 1.4 2002-09-05 21:25:44 guy Exp $ (LBL)";
-#endif
+/* \summary: *BSD/Darwin packet filter log file printer */
+
+#include <config.h>
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <limits.h>
 
-#include <tcpdump-stdinc.h>
+#include "netdissect-stdinc.h"
 
-#include <stdio.h>
-#include <pcap.h>
+#define ND_LONGJMP_FROM_TCHECK
+#include "netdissect.h"
+#include "extract.h"
+#include "af.h"
+#include "addrtostr.h"
 
-#include "interface.h"
-#include "addrtoname.h"
+/*
+ * pflog headers, at least as they exist now.
+ */
+#define PFLOG_IFNAMSIZ         16
+#define PFLOG_RULESET_NAME_SIZE        16
 
-/* The header in OpenBSD pflog files. */
+struct pf_addr {
+       union {
+               nd_ipv4         v4;
+               nd_ipv6         v6;
+       } pfa;              /* 128-bit address */
+#define v4     pfa.v4
+#define v6     pfa.v6
+};
 
+/*
+ * This header is:
+ *
+ *    61 bytes long on NetBSD, DragonFly BSD. and Darwin;
+ *    84 bytes lon on OpenBSD;
+ *    72 bytes long on FreeBSD;
+ *
+ * which, unfortunately, does not allow us to distinguish, based on
+ * the header length, between the three OSes listed as having 61-byte
+ * headers.  As the action values differ between them, this makes it
+ * impossible to correctly dissect the reason values that differ
+ * between NetBSD and Darwin (reason value 15) without having some
+ * way to explicitly tell tcpdump what to do.
+ *
+ * (We could, I guess, label reason value 15 as
+ * "state-locked (NetBSD)/dummynet (macOS etc.)" or something such as
+ * that.)
+ */
 struct pfloghdr {
-       u_int32_t af;
-       char    ifname[16];
-       int16_t rnr;
-       u_int16_t reason;
-       u_int16_t action;
-       u_int16_t dir;
+       nd_uint8_t      length;
+       nd_uint8_t      af;
+       nd_uint8_t      action;
+       nd_uint8_t      reason;
+       char            ifname[PFLOG_IFNAMSIZ];
+       char            ruleset[PFLOG_RULESET_NAME_SIZE];
+       nd_uint32_t     rulenr;
+       nd_uint32_t     subrulenr;
+       nd_uint32_t     uid;
+       nd_int32_t      pid;
+       nd_uint32_t     rule_uid;
+       nd_int32_t      rule_pid;
+       nd_uint8_t      dir;
+       union {
+               struct pflog_openbsd_only {
+                       nd_uint8_t      rewritten;
+                       nd_uint8_t      naf;
+                       nd_uint8_t      pad[1];
+                       struct pf_addr  saddr;
+                       struct pf_addr  daddr;
+                       nd_uint16_t     sport;
+                       nd_uint16_t     dport;
+               } openbsd;
+               struct pflog_freebsd_only {
+                       nd_uint8_t      pad[3];
+                       nd_uint32_t     ridentifier;
+                       nd_uint8_t      reserve;
+               } freebsd;
+       } u;
 };
-#define PFLOG_HDRLEN    sizeof(struct pfloghdr)
-
-/* Actions */
-#define PF_PASS  0
-#define PF_DROP  1
-#define PF_SCRUB 2
-
-/* Directions */
-#define PF_IN  0
-#define PF_OUT 1
-
-static struct tok pf_reasons[] = {
-       { 0,    "match" },
-       { 1,    "bad-offset" },
-       { 2,    "fragment" },
-       { 3,    "short" },
-       { 4,    "normalize" },
-       { 5,    "memory" },
+
+/*
+ * FreeBSD header length.
+ */
+#define PFLOG_HEADER_LEN_FREEBSD       69
+
+/*
+ * OpenBSD header length.
+ */
+#define PFLOG_HEADER_LEN_OPENBSD       100
+
+/*
+ * DragonFly BSD, NetBSD and Darwin header length.
+ * Older versions of FreeBSD and OpenBSD may have used this
+ * as well.
+ *
+ * Unfortunately, this means we can't distinguish between Darwin, NetBSD,
+ * and DragonFly BSD based on the header length.
+ */
+#define PFLOG_HEADER_LEN_OTHER         61
+
+/*
+ * These are the minimum and maximum pflog header lengths.
+ */
+#define MIN_PFLOG_HDRLEN 61
+#define MAX_PFLOG_HDRLEN 100
+
+/*
+ * Reason values.
+ */
+#define PFRES_MATCH    0
+#define PFRES_BADOFF   1
+#define PFRES_FRAG     2
+#define PFRES_SHORT    3
+#define PFRES_NORM     4
+#define PFRES_MEMORY   5
+#define PFRES_TS       6
+#define PFRES_CONGEST  7
+#define PFRES_IPOPTIONS 8
+#define PFRES_PROTCKSUM 9
+#define PFRES_BADSTATE 10
+#define PFRES_STATEINS 11
+#define PFRES_MAXSTATES        12
+#define PFRES_SRCLIMIT 13
+#define PFRES_SYNPROXY 14
+
+/* FreeBSD */
+#define PFRES_MAPFAILED        15
+
+/* OpenBSD */
+#define PFRES_TRANSLATE        15
+#define PFRES_NOROUTE  16
+
+/* NetBSD/Darwin */
+#define PFRES_STATELOCKED_DUMMYNET 15  /* STATELOCKED on NetBSD, DUMMYNET on Darwin */
+#define PFRES_INVPORT  16 /* INVPORT on Darwin */
+
+static const struct tok pf_reasons_freebsd[] = {
+       { PFRES_MATCH,          "0(match)" },
+       { PFRES_BADOFF,         "1(bad-offset)" },
+       { PFRES_FRAG,           "2(fragment)" },
+       { PFRES_SHORT,          "3(short)" },
+       { PFRES_NORM,           "4(normalize)" },
+       { PFRES_MEMORY,         "5(memory)" },
+       { PFRES_TS,             "6(bad-timestamp)" },
+       { PFRES_CONGEST,        "7(congestion)" },
+       { PFRES_IPOPTIONS,      "8(ip-option)" },
+       { PFRES_PROTCKSUM,      "9(proto-cksum)" },
+       { PFRES_BADSTATE,       "10(state-mismatch)" },
+       { PFRES_STATEINS,       "11(state-insert)" },
+       { PFRES_MAXSTATES,      "12(state-limit)" },
+       { PFRES_SRCLIMIT,       "13(src-limit)" },
+       { PFRES_SYNPROXY,       "14(synproxy)" },
+       { PFRES_MAPFAILED,      "15(map-failed)" },
+       { 0,    NULL }
+};
+
+static const struct tok pf_reasons_openbsd[] = {
+       { PFRES_MATCH,          "0(match)" },
+       { PFRES_BADOFF,         "1(bad-offset)" },
+       { PFRES_FRAG,           "2(fragment)" },
+       { PFRES_SHORT,          "3(short)" },
+       { PFRES_NORM,           "4(normalize)" },
+       { PFRES_MEMORY,         "5(memory)" },
+       { PFRES_TS,             "6(bad-timestamp)" },
+       { PFRES_CONGEST,        "7(congestion)" },
+       { PFRES_IPOPTIONS,      "8(ip-option)" },
+       { PFRES_PROTCKSUM,      "9(proto-cksum)" },
+       { PFRES_BADSTATE,       "10(state-mismatch)" },
+       { PFRES_STATEINS,       "11(state-insert)" },
+       { PFRES_MAXSTATES,      "12(state-limit)" },
+       { PFRES_SRCLIMIT,       "13(src-limit)" },
+       { PFRES_SYNPROXY,       "14(synproxy)" },
+       { PFRES_TRANSLATE,      "15(translate)" },
+       { PFRES_NOROUTE,        "16(no-route)" },
+       { 0,    NULL }
+};
+
+static const struct tok pf_reasons_other[] = {
+       { PFRES_MATCH,          "0(match)" },
+       { PFRES_BADOFF,         "1(bad-offset)" },
+       { PFRES_FRAG,           "2(fragment)" },
+       { PFRES_SHORT,          "3(short)" },
+       { PFRES_NORM,           "4(normalize)" },
+       { PFRES_MEMORY,         "5(memory)" },
+       { PFRES_TS,             "6(bad-timestamp)" },
+       { PFRES_CONGEST,        "7(congestion)" },
+       { PFRES_IPOPTIONS,      "8(ip-option)" },
+       { PFRES_PROTCKSUM,      "9(proto-cksum)" },
+       { PFRES_BADSTATE,       "10(state-mismatch)" },
+       { PFRES_STATEINS,       "11(state-insert)" },
+       { PFRES_MAXSTATES,      "12(state-limit)" },
+       { PFRES_SRCLIMIT,       "13(src-limit)" },
+       { PFRES_SYNPROXY,       "14(synproxy)" },
+       { PFRES_STATELOCKED_DUMMYNET,
+                               "15(state-locked (NetBSD)/dummynet(Darwin)" },
+       { PFRES_INVPORT,        "16(invalid-port (Darwin))" },
        { 0,    NULL }
 };
 
-static struct tok pf_actions[] = {
-       { PF_PASS,      "pass" },
-       { PF_DROP,      "drop" },
-       { PF_SCRUB,     "scrub" },
+/*
+ * Action values.
+ */
+#define PFACT_PASS             0
+#define PFACT_DROP             1
+#define PFACT_SCRUB            2
+#define PFACT_NOSCRUB          3
+#define PFACT_NAT              4
+#define PFACT_NONAT            5
+#define PFACT_BINAT            6
+#define PFACT_NOBINAT          7
+#define PFACT_RDR              8
+#define PFACT_NORDR            9
+#define PFACT_SYNPROXY_DROP    10
+
+/* FreeBSD and OpenBSD */
+#define PFACT_DEFER            11
+
+/* FreeBSD */
+#define PFACT_MATCH            12
+
+/* OpenBSD */
+#define PFACT_MATCH            12
+#define PFACT_DIVERT           13
+#define PFACT_RT               14
+#define PFACT_AFRT             15
+
+/* Darwin */
+#define PFACT_DUMMYNET         11
+#define PFACT_NODUMMYNET       12
+#define PFACT_NAT64            13
+#define PFACT_NONAT64          14
+
+static const struct tok pf_actions_freebsd[] = {
+       { PFACT_PASS,           "pass" },
+       { PFACT_DROP,           "block" },
+       { PFACT_SCRUB,          "scrub" },
+       { PFACT_NOSCRUB,        "noscrub" },
+       { PFACT_NAT,            "nat" },
+       { PFACT_NONAT,          "nonat" },
+       { PFACT_BINAT,          "binat" },
+       { PFACT_NOBINAT,        "nobinat" },
+       { PFACT_RDR,            "rdr" },
+       { PFACT_NORDR,          "nordr" },
+       { PFACT_SYNPROXY_DROP,  "synproxy-drop" },
+       { PFACT_DEFER,          "defer" },
+       { PFACT_MATCH,          "match" },
+       { 0,                    NULL }
+};
+
+static const struct tok pf_actions_openbsd[] = {
+       { PFACT_PASS,           "pass" },
+       { PFACT_DROP,           "block" },
+       { PFACT_SCRUB,          "scrub" },
+       { PFACT_NOSCRUB,        "noscrub" },
+       { PFACT_NAT,            "nat" },
+       { PFACT_NONAT,          "nonat" },
+       { PFACT_BINAT,          "binat" },
+       { PFACT_NOBINAT,        "nobinat" },
+       { PFACT_RDR,            "rdr" },
+       { PFACT_NORDR,          "nordr" },
+       { PFACT_SYNPROXY_DROP,  "synproxy-drop" },
+       { PFACT_DEFER,          "defer" },
+       { PFACT_MATCH,          "match" },
+       { PFACT_DIVERT,         "divert" },
+       { PFACT_RT,             "rt" },
+       { PFACT_AFRT,           "afrt" },
+       { 0,                    NULL }
+};
+
+static const struct tok pf_actions_darwin[] = {
+       { PFACT_PASS,           "pass" },
+       { PFACT_DROP,           "block" },
+       { PFACT_SCRUB,          "scrub" },
+       { PFACT_NOSCRUB,        "noscrub" },
+       { PFACT_NAT,            "nat" },
+       { PFACT_NONAT,          "nonat" },
+       { PFACT_BINAT,          "binat" },
+       { PFACT_NOBINAT,        "nobinat" },
+       { PFACT_RDR,            "rdr" },
+       { PFACT_NORDR,          "nordr" },
+       { PFACT_SYNPROXY_DROP,  "synproxy-drop" },
+       { PFACT_DUMMYNET,       "dummynet (Darwin)" },
+       { PFACT_NODUMMYNET,     "nodummynet (Darwin)" },
+       { PFACT_NAT64,          "nat64 (Darwin)" },
+       { PFACT_NONAT64,        "nonat64 (Darwin)" },
+       { 0,                    NULL }
+};
+
+/*
+ * Direction values.
+ */
+#define PFDIR_INOUT    0
+#define PFDIR_IN       1
+#define PFDIR_OUT      2
+
+/* OpenBSD */
+#define PFDIR_FWD      3
+
+static const struct tok pf_directions_freebsd[] = {
+       { PFDIR_INOUT,  "in/out" },
+       { PFDIR_IN,     "in" },
+       { PFDIR_OUT,    "out" },
        { 0,            NULL }
 };
 
-static struct tok pf_directions[] = {
-       { PF_IN,        "in" },
-       { PF_OUT,       "out" },
+static const struct tok pf_directions_openbsd[] = {
+       { PFDIR_INOUT,  "in/out" },
+       { PFDIR_IN,     "in" },
+       { PFDIR_OUT,    "out" },
+       { PFDIR_FWD,    "fwd" },
        { 0,            NULL }
 };
 
-#define OPENBSD_AF_INET                2
-#define OPENBSD_AF_INET6       24
+static const struct tok pf_directions_other[] = {
+       { PFDIR_INOUT,  "in/out" },
+       { PFDIR_IN,     "in" },
+       { PFDIR_OUT,    "out" },
+       { 0,            NULL }
+};
 
 static void
-pflog_print(const struct pfloghdr *hdr)
+print_pf_addr(netdissect_options *ndo, const char *tag, u_int naf,
+    const struct pf_addr *addr, const nd_uint16_t port)
 {
-       printf("rule %d/%s: %s %s on %s: ",
-           (short)ntohs(hdr->rnr),
-           tok2str(pf_reasons, "unkn(%u)", ntohs(hdr->reason)),
-           tok2str(pf_actions, "unkn(%u)", ntohs(hdr->action)),
-           tok2str(pf_directions, "unkn(%u)", ntohs(hdr->dir)),
-           hdr->ifname);
+       char buf[INET6_ADDRSTRLEN];
+       uint16_t portnum;
+
+       ND_PRINT("%s ", tag);
+       ND_TCHECK_SIZE(addr);
+       switch (naf) {
+
+       case BSD_AF_INET:
+               addrtostr(addr->v4, buf, sizeof(buf));
+               break;
+
+       case BSD_AF_INET6_BSD:
+               addrtostr6(addr->v6, buf, sizeof(buf));
+               break;
+
+       default:
+               strlcpy(buf, "?", sizeof(buf));
+               break;
+       }
+       ND_PRINT("%s:", buf);
+       portnum = GET_BE_U_2(port);
+       ND_PRINT("%u", portnum);
 }
 
-void
-pflog_if_print(u_char *user _U_, const struct pcap_pkthdr *h,
-     register const u_char *p)
+static void
+pflog_print(netdissect_options *ndo, const struct pfloghdr *hdr)
 {
-       u_int length = h->len;
-       u_int caplen = h->caplen;
-       const struct pfloghdr *hdr;
-       u_int8_t af;
+       uint8_t length;
+       uint32_t rulenr, subrulenr;
+       uint32_t uid;
+       uint32_t ridentifier;
 
-       ts_print(&h->ts);
+       ndo->ndo_protocol = "pflog";
+       length = GET_U_1(hdr->length);
 
-       if (caplen < PFLOG_HDRLEN) {
-               printf("[|pflog]");
-               goto out;
+       rulenr = GET_BE_U_4(hdr->rulenr);
+       subrulenr = GET_BE_U_4(hdr->subrulenr);
+       ND_PRINT("rule ");
+       if (rulenr != (uint32_t)-1) {
+               ND_PRINT("%u", rulenr);
+               if (hdr->ruleset[0] != '\0') {
+                       ND_PRINT(".");
+                       nd_printjnp(ndo, (const u_char*)hdr->ruleset, PFLOG_RULESET_NAME_SIZE);
+               }
+               if (subrulenr != (uint32_t)-1)
+                       ND_PRINT(".%u", subrulenr);
        }
+       ND_PRINT("/");
+
+       if (length == PFLOG_HEADER_LEN_FREEBSD)
+               ND_PRINT("%s", tok2str(pf_reasons_freebsd, "unkn(%u)", GET_U_1(hdr->reason)));
+       else if (length == PFLOG_HEADER_LEN_OPENBSD)
+               ND_PRINT("%s", tok2str(pf_reasons_openbsd, "unkn(%u)", GET_U_1(hdr->reason)));
+       else
+               ND_PRINT("%s", tok2str(pf_reasons_other, "unkn(%u)", GET_U_1(hdr->reason)));
 
        /*
-        * Some printers want to get back at the link level addresses,
-        * and/or check that they're not walking off the end of the packet.
-        * Rather than pass them all the way down, we set these globals.
+        * In Darwin (macOS, etc.) and NetBSD, uid is set to
+        * UID_MAX if there's no UID, and UID_MAX is 2^31-1.
+        * UID_MAX is 2^31-1.
+        *
+        * In OpenBSD, uid is set to -1 if there's no UID, which
+        * means we'll see it as UINT_MAX, as we treat it as
+        * unsigned. UID_MAX is 2^32-1.
+        *
+        * In FreeBSD and DragonFly BSD, uid is set to UID_MAX
+        * if there's no UID. UID_MAX is 2^32-1.
+        *
+        * So:
+        *
+        *   For OpenBSD and FreeBSD, check only for 2^32-1 (0xFFFFFFFFU)
+        *   if there's no UID.
+        *
+        *   For other OSes, it's either NetBSD, DragonFly BSD, or Darwin,
+        *   check for both 2^31-1 (0x7FFFFFFFU) (NetBSD and Darwin) and
+        *   2^32-1 (0xFFFFFFFFU) (DragonFly BSD). That runs the risk of
+        *   the UID not being printed for a DragonFly BSD log if it's
+        *   0x7FFFFFFF, but that's *probably* not going to be the case.
         */
-       packetp = p;
-       snapend = p + caplen;
+       uid = GET_BE_U_4(hdr->uid);
+       if (length == PFLOG_HEADER_LEN_FREEBSD ||
+           length == PFLOG_HEADER_LEN_OPENBSD) {
+               if (uid != 0xFFFFFFFFU)
+                       ND_PRINT(" [uid %u]", uid);
+       } else {
+               if (uid != 0xFFFFFFFFU && uid != 0x7FFFFFFFU)
+                       ND_PRINT(" [uid %u]", uid);
+       }
+
+       if (length == PFLOG_HEADER_LEN_FREEBSD) {
+               ridentifier = GET_BE_U_4(hdr->u.freebsd.ridentifier);
+               if (ridentifier != 0)
+                       ND_PRINT(" [ridentifier %u]", ridentifier);
+       }
+
+       if (length == PFLOG_HEADER_LEN_FREEBSD) {
+               ND_PRINT(": %s %s on ",
+                   tok2str(pf_actions_freebsd, "unkn(%u)", GET_U_1(hdr->action)),
+                   tok2str(pf_directions_freebsd, "unkn(%u)", GET_U_1(hdr->dir)));
+       } else if (length == PFLOG_HEADER_LEN_OPENBSD) {
+               ND_PRINT(": %s %s on ",
+                   tok2str(pf_actions_openbsd, "unkn(%u)", GET_U_1(hdr->action)),
+                   tok2str(pf_directions_openbsd, "unkn(%u)", GET_U_1(hdr->dir)));
+       } else {
+               /*
+                * We use the Darwin set of actions, as it's a superset
+                * of the NetBSD/DragonFly BSD set of actions.
+                */
+               ND_PRINT(": %s %s on ",
+                   tok2str(pf_actions_darwin, "unkn(%u)", GET_U_1(hdr->action)),
+                   tok2str(pf_directions_other, "unkn(%u)", GET_U_1(hdr->dir)));
+       }
+       nd_printjnp(ndo, (const u_char*)hdr->ifname, PFLOG_IFNAMSIZ);
+       ND_PRINT(": ");
+       if (length == PFLOG_HEADER_LEN_OPENBSD) {
+               if (ndo->ndo_vflag && GET_U_1(hdr->u.openbsd.rewritten)) {
+                       uint8_t naf;
+
+                       ND_PRINT("[rewritten: ");
+                       naf = GET_U_1(hdr->u.openbsd.naf);
+                       print_pf_addr(ndo, "src", naf, &hdr->u.openbsd.saddr,
+                           hdr->u.openbsd.sport);
+                       ND_PRINT(", ");
+                       print_pf_addr(ndo, "src", naf, &hdr->u.openbsd.daddr,
+                           hdr->u.openbsd.dport);
+                       ND_PRINT("; ");
+               }
+       }
+}
+
+void
+pflog_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h,
+               const u_char *p)
+{
+       u_int length = h->len;
+       u_int hdrlen;
+       u_int caplen = h->caplen;
+       const struct pfloghdr *hdr;
+       uint8_t af;
+
+       ndo->ndo_protocol = "pflog";
+       /* check length */
+       ND_ICHECK_U(length, <, MIN_PFLOG_HDRLEN);
 
        hdr = (const struct pfloghdr *)p;
-       if (eflag)
-               pflog_print(hdr);
-       af = ntohl(hdr->af);
-       length -= PFLOG_HDRLEN;
-       caplen -= PFLOG_HDRLEN;
-       p += PFLOG_HDRLEN;
+       hdrlen = GET_U_1(hdr->length);
+       ND_ICHECK_U(hdrlen, <, MIN_PFLOG_HDRLEN);
+       ND_ICHECK_U(hdrlen, >, MAX_PFLOG_HDRLEN);
+       hdrlen = roundup2(hdrlen, 4);
+
+       /* print what we know */
+       ND_TCHECK_LEN(hdr, hdrlen);
+       ndo->ndo_ll_hdr_len += hdrlen;
+       if (ndo->ndo_eflag)
+               pflog_print(ndo, hdr);
+
+       /* skip to the real packet */
+       af = GET_U_1(hdr->af);
+       length -= hdrlen;
+       caplen -= hdrlen;
+       p += hdrlen;
        switch (af) {
 
-       case OPENBSD_AF_INET:
-               ip_print(p, length);
-               break;
+               /*
+                * If there's a system that doesn't use the AF_INET
+                * from 4.2BSD, feel free to add its value to af.h
+                * and use it here.
+                *
+                * Hopefully, there isn't.
+                */
+               case BSD_AF_INET:
+                       ip_print(ndo, p, length);
+                       break;
 
-#ifdef INET6
-       case OPENBSD_AF_INET6:
-               ip6_print(p, length);
-               break;
-#endif
+               /*
+                * Try all AF_INET6 values for all systems with pflog,
+                * including Darwin.
+                */
+               case BSD_AF_INET6_BSD:
+               case BSD_AF_INET6_FREEBSD:
+               case BSD_AF_INET6_DARWIN:
+                       ip6_print(ndo, p, length);
+                       break;
 
        default:
                /* address family not handled, print raw packet */
-               if (!eflag)
-                       pflog_print(hdr);
-               if (!xflag && !qflag)
-                       default_print(p, caplen);
+               if (!ndo->ndo_eflag)
+                       pflog_print(ndo, hdr);
+               if (!ndo->ndo_suppress_default_print)
+                       ND_DEFAULTPRINT(p, caplen);
        }
 
-       if (xflag)
-               default_print(p, caplen);
-out:
-       putchar('\n');
-       --infodelay;
-       if (infoprint)
-               info(0);
+       return;
+
+invalid:
+       nd_print_invalid(ndo);
 }