+#ifdef HAVE_PCAP_SETDIRECTION
+#define Q_FLAG "Q:"
+#else
+#define Q_FLAG
+#endif
+
+/*
+ * Long options.
+ *
+ * We do not currently have long options corresponding to all short
+ * options; we should probably pick appropriate option names for them.
+ *
+ * However, the short options where the number of times the option is
+ * specified matters, such as -v and -d and -t, should probably not
+ * just map to a long option, as saying
+ *
+ * tcpdump --verbose --verbose
+ *
+ * doesn't make sense; it should be --verbosity={N} or something such
+ * as that.
+ *
+ * For long options with no corresponding short options, we define values
+ * outside the range of ASCII graphic characters, make that the last
+ * component of the entry for the long option, and have a case for that
+ * option in the switch statement.
+ */
+#define OPTION_VERSION 128
+#define OPTION_TSTAMP_PRECISION 129
+#define OPTION_IMMEDIATE_MODE 130
+
+static const struct option longopts[] = {
+#if defined(HAVE_PCAP_CREATE) || defined(WIN32)
+ { "buffer-size", required_argument, NULL, 'B' },
+#endif
+ { "list-interfaces", no_argument, NULL, 'D' },
+ { "help", no_argument, NULL, 'h' },
+ { "interface", required_argument, NULL, 'i' },
+#ifdef HAVE_PCAP_CREATE
+ { "monitor-mode", no_argument, NULL, 'I' },
+#endif
+#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
+ { "time-stamp-type", required_argument, NULL, 'j' },
+ { "list-time-stamp-types", no_argument, NULL, 'J' },
+#endif
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+ { "time-stamp-precision", required_argument, NULL, OPTION_TSTAMP_PRECISION},
+#endif
+ { "dont-verify-checksums", no_argument, NULL, 'K' },
+ { "list-data-link-types", no_argument, NULL, 'L' },
+ { "no-optimize", no_argument, NULL, 'O' },
+ { "no-promiscuous-mode", no_argument, NULL, 'p' },
+#ifdef HAVE_PCAP_SETDIRECTION
+ { "direction", required_argument, NULL, 'Q' },
+#endif
+ { "snapshot-length", required_argument, NULL, 's' },
+ { "absolute-tcp-sequence-numbers", no_argument, NULL, 'S' },
+#ifdef HAVE_PCAP_DUMP_FLUSH
+ { "packet-buffered", no_argument, NULL, 'U' },
+#endif
+ { "linktype", required_argument, NULL, 'y' },
+#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
+ { "immediate-mode", no_argument, NULL, OPTION_IMMEDIATE_MODE },
+#endif
+#if defined(HAVE_PCAP_DEBUG) || defined(HAVE_YYDEBUG)
+ { "debug-filter-parser", no_argument, NULL, 'Y' },
+#endif
+ { "relinquish-privileges", required_argument, NULL, 'Z' },
+ { "number", no_argument, NULL, '#' },
+ { "version", no_argument, NULL, OPTION_VERSION },
+ { NULL, 0, NULL, 0 }
+};
+
+#ifndef WIN32
+/* Drop root privileges and chroot if necessary */
+static void
+droproot(const char *username, const char *chroot_dir)
+{
+ struct passwd *pw = NULL;
+
+ if (chroot_dir && !username) {
+ fprintf(stderr, "tcpdump: Chroot without dropping root is insecure\n");
+ exit(1);
+ }
+
+ pw = getpwnam(username);
+ if (pw) {
+ if (chroot_dir) {
+ if (chroot(chroot_dir) != 0 || chdir ("/") != 0) {
+ fprintf(stderr, "tcpdump: Couldn't chroot/chdir to '%.64s': %s\n",
+ chroot_dir, pcap_strerror(errno));
+ exit(1);
+ }
+ }
+#ifdef HAVE_LIBCAP_NG
+ int ret = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_NO_FLAG);
+ if (ret < 0) {
+ fprintf(stderr, "error : ret %d\n", ret);
+ }
+ else {
+ fprintf(stderr, "dropped privs to %s\n", username);
+ }
+#else
+ if (initgroups(pw->pw_name, pw->pw_gid) != 0 ||
+ setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) {
+ fprintf(stderr, "tcpdump: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n",
+ username,
+ (unsigned long)pw->pw_uid,
+ (unsigned long)pw->pw_gid,
+ pcap_strerror(errno));
+ exit(1);
+ }
+ else {
+ fprintf(stderr, "dropped privs to %s\n", username);
+ }
+#endif /* HAVE_LIBCAP_NG */
+ }
+ else {
+ fprintf(stderr, "tcpdump: Couldn't find user '%.32s'\n",
+ username);
+ exit(1);
+ }
+#ifdef HAVE_LIBCAP_NG
+ /* We don't need CAP_SETUID and CAP_SETGID any more. */
+ capng_updatev(
+ CAPNG_DROP,
+ CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+ CAP_SETUID,
+ CAP_SETGID,
+ -1);
+ capng_apply(CAPNG_SELECT_BOTH);
+#endif /* HAVE_LIBCAP_NG */
+
+}