diff --git a/.gitignore b/.gitignore index dd33554..6055141 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .obsidian +venv + diff --git a/archive/functions_dump.py b/archive/functions_dump.py new file mode 100644 index 0000000..856146a --- /dev/null +++ b/archive/functions_dump.py @@ -0,0 +1,32 @@ +def setup_sniff_tcpdump_parser(parser_sniff): + # arguments which will be passed to tcpdump + parser_sniff_tcpdump = parser_sniff.add_argument_group('tcpdump arguments') + # TODO: tcpdump_parser.add_argument('-c', '--count', re) + parser_sniff_tcpdump.add_argument("-a", "--ip-address=", help="IP address of the device to sniff", dest="device_ip") + parser_sniff_tcpdump.add_argument("-i", "--interface=", help="Interface of the capture device.", dest="capture_interface",default="") + parser_sniff_tcpdump.add_argument("-I", "--monitor-mode", help="Put interface into monitor mode", + action="store_true") + parser_sniff_tcpdump.add_argument("-n", help="Deactivate name resolution. Option is set by default.", + action="store_true") + parser_sniff_tcpdump.add_argument("-#", "--number", + help="Print packet number at beginning of line. Set by default.", + action="store_true") + parser_sniff_tcpdump.add_argument("-e", help="Print link layer headers. Option is set by default.", + action="store_true") + parser_sniff_tcpdump.add_argument("-t", action="count", default=0, + help="Please see tcpdump manual for details. Unused by default.") + + +def setup_sniff_parser(subparsers): + # create parser for "sniff" command + parser_sniff = subparsers.add_parser("sniff", help="Start tcpdump capture.") + setup_sniff_tcpdump_parser(parser_sniff) + setup_pcap_filter_parser(parser_sniff) + cap_size_group = parser_sniff.add_mutually_exclusive_group(required=True) + cap_size_group.add_argument("-c", "--count", type=int, help="Number of packets to capture.", default=0) + cap_size_group.add_argument("--mins", type=int, help="Time in minutes to capture.", default=60) + + +def setup_pcap_filter_parser(parser_sniff): + parser_pcap_filter = parser_sniff.add_argument_parser("pcap-filter expression") + pass diff --git a/archive/metadata.py b/archive/metadata.py new file mode 100644 index 0000000..eeb2888 --- /dev/null +++ b/archive/metadata.py @@ -0,0 +1,19 @@ +import json +import uuid +from datetime import datetime + + +class Metadata: + def __init__(self, name): + self.device = name + self.timestamp = datetime.now().timestamp() + self.capture_id = uuid.uuid4().hex + self.capture_mode = ... # TODO: eg. promiscuous/monitor/other + self.host_ip = ... + self.host_mac = ... + self.protocol = ... + + +def create_metadata(filename, unique_id, device_details): + date_string = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") + meta_filename = f"meta_{date_string}_{unique_id}.json" diff --git a/archive/metadata_utils.py b/archive/metadata_utils.py new file mode 100644 index 0000000..3630093 --- /dev/null +++ b/archive/metadata_utils.py @@ -0,0 +1,69 @@ +import json +from pathlib import Path + +from pydantic import BaseModel + +from kydcap.models.device_metadata import DeviceMetadata +from kydcap.config import DEVICE_METADATA_FILE + + +def write_device_metadata_to_file(metadata: DeviceMetadata, device_path: Path): + """Write the device metadata to a JSON file in the specified directory.""" + meta_file_path = device_path / "meta.json" + meta_file_path.write_text(metadata.json(indent=2)) + + +def confirm_device_metadata(metadata: DeviceMetadata) -> bool: + """Display device metadata for user confirmation.""" + print(metadata.json(indent=2)) + return input("Confirm device metadata? (y/n): ").strip().lower() == 'y' + + +def get_device_metadata_from_user() -> DeviceMetadata: + """Prompt the user to enter device details and return a populated DeviceMetadata object.""" + device_name = input("Device name: ") + device_short_name = device_name.lower().replace(" ", "-") + return DeviceMetadata(device_name=device_name, device_short_name=device_short_name) + + +def initialize_device_root_dir(device_name: str) -> Path: + """Create and return the path for the device directory.""" + device_path = Path.cwd() / device_name + device_path.mkdir(exist_ok=True) + return device_path + + +def write_metadata(metadata: BaseModel, device_name: str): + """Write device metadata to a JSON file.""" + meta_path = Path.cwd() / device_name / DEVICE_METADATA_FILE + meta_path.parent.mkdir(parents=True, exist_ok=True) + with meta_path.open('w') as f: + json.dump(metadata.dict(), f, indent=4) + + +def get_device_metadata(file_path: Path) -> DeviceMetadata | None: + """Fetch device metadata from a JSON file.""" + + if dev_metadata_exists(file_path): + with file_path.open('r') as f: + device_metadata_json = json.load(f) + try: + device_metadata = DeviceMetadata.model_validate_json(device_metadata_json) + return device_metadata + except ValueError as e: + print(f"Validation error for device metadata: {e}") + else: + # TODO Decide what to do (e.g. search for file etc) + print(f"No device metadata at {file_path}") + return None + + +def search_device_metadata(filename=DEVICE_METADATA_FILE, start_dir=Path.cwd(), max_parents=3) -> Path: + pass # TODO + + +def dev_metadata_exists(file_path: Path) -> bool: + if file_path.is_file(): + return True + else: + return False diff --git a/code/kydcap/__init__.py b/code/kydcap/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/kydcap/config.py b/code/kydcap/config.py new file mode 100644 index 0000000..683b016 --- /dev/null +++ b/code/kydcap/config.py @@ -0,0 +1,19 @@ +from datetime import datetime +from enum import Flag, unique, global_enum + +DEVICE_METADATA_FILE = "device-metadata.json" +CAPTURE_METADATA_FILE = "capture-metadata.json" +TODAY_DATE_STRING = datetime.now().strftime("%d%b%Y").lower() + + +@unique +@global_enum +class ReturnCodes(Flag): + SUCCESS = 0 + ABORTED = 1 + FAILURE = 2 + UNKNOWN = 3 + FILE_NOT_FOUND = 4 + FILE_ALREADY_EXISTS = 5 + INVALID_ARGUMENT = 6 + INVALID_ARGUMENT_VALUE = 7 diff --git a/code/kydcap/main.py b/code/kydcap/main.py new file mode 100644 index 0000000..f2e864a --- /dev/null +++ b/code/kydcap/main.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +import argparse + +from subcommands.sniff import setup_sniff_parser + +CAP_DIR_PREFIX = ... + + +###################### +# Argparse setup +###################### +def setup_argparse(): + # create top level parser + root_parser = argparse.ArgumentParser(prog="kydcap") + subparsers = root_parser.add_subparsers(title="subcommands", required=True, dest="command") + + setup_sniff_parser(subparsers) + + return root_parser + + +if __name__ == "__main__": + parser = setup_argparse() + args = parser.parse_args() + # if args.command + # create_capture_directory(args.device_name) diff --git a/code/kydcap/models/__init__.py b/code/kydcap/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/kydcap/models/capture_metadata.py b/code/kydcap/models/capture_metadata.py new file mode 100644 index 0000000..6e26975 --- /dev/null +++ b/code/kydcap/models/capture_metadata.py @@ -0,0 +1,47 @@ +import json +import uuid +from datetime import datetime +from pathlib import Path +from typing import Optional, Any + +from pydantic import BaseModel, Field + +from kydcap.config import ReturnCodes + + +class KydcapCaptureMetadata(BaseModel): + # Required Fields + device_id: str + capture_id: uuid.UUID = Field(default_factory=lambda: str(uuid.uuid4())) + capture_date: str = Field(default_factory=lambda: datetime.now().strftime('%d-%m-%YT%H:%M:%S').lower()) + + # Statistics + start_time: str + stop_time: str + packet_count: Optional[int] + + # Optional Fields + device_ip_address: Optional[str] = None + device_mac_address: Optional[str] = None + + app: Optional[str] = None + app_version: Optional[str] = None + firmware_version: Optional[str] = None + + def __init__(self, device_id: str, start_time: str, stop_time: str, /, **data: Any): + super().__init__(**data) # Pycharms orders + assert isinstance(device_id, str) + assert isinstance(start_time, str) + assert isinstance(stop_time, str) + self.device_id = device_id + self.start_time = start_time + self.stop_time = stop_time + + def save_to_json(self, file_path: Path): + if file_path.is_file(): + print(f"File {file_path} already exists, update instead.") + return ReturnCodes.FILE_ALREADY_EXISTS + metadata = self.model_dump_json(indent=2) + with file_path.open('w') as file: + json.dump(metadata, file) + return ReturnCodes.SUCCESS diff --git a/code/kydcap/models/device_metadata.py b/code/kydcap/models/device_metadata.py new file mode 100644 index 0000000..173f92f --- /dev/null +++ b/code/kydcap/models/device_metadata.py @@ -0,0 +1,66 @@ +import json +import uuid +from datetime import datetime +from pathlib import Path +from typing import Optional, List, Any + +# kydcap modules +from kydcap.config import ReturnCodes + +# 3rd party libs +from pydantic import BaseModel, Field + +IMMUTABLE_FIELDS = {"device_name", "device_short_name", "device_id", "date_created"} + + +class DeviceMetadata(BaseModel): + # Required fields + device_name: str + device_short_name: str + device_id: str = Field(default_factory=lambda: str(uuid.uuid4())) + date_created: str = Field(default_factory=lambda: datetime.now().strftime('%d-%m-%YT%H:%M:%S').lower()) + + # Optional Fields + device_type: Optional[str] = None + device_serial_number: Optional[str] = None + device_firmware_version: Optional[str] = None + date_updated: Optional[str] = None + + capture_files: Optional[List[str]] = [] + + def __init__(self, device_name: str, /, **data: Any): + super().__init__(**data) + self.device_name = device_name + self.device_short_name = device_name.lower().replace(" ", "_") + + @classmethod + def load_from_json(cls, file_path: Path): + assert file_path.is_file() + with file_path.open('r') as file: + metadata_json = json.load(file) + metadata_model_obj = cls.model_validate_json(metadata_json) + return metadata_model_obj + + def save_to_json(self, file_path: Path): + if file_path.is_file(): + print(f"File {file_path} already exists, update instead.") + return ReturnCodes.FILE_ALREADY_EXISTS + metadata = self.model_dump_json(indent=2) + with file_path.open('w') as file: + json.dump(metadata, file) + return ReturnCodes.SUCCESS + + @classmethod + def update_metadata_in_json(cls, file_path: Path, **kwargs): + # TODO Maybe not needed at all. + assert file_path.is_file() + for field in IMMUTABLE_FIELDS: + if field in kwargs: + print(f"Field {field} is immutable") + return ReturnCodes.IMMUTABLE + metadata = cls.load_from_json(file_path) + for field, value in kwargs.items(): + if field in metadata.model_fields_set: + setattr(metadata, field, value) + metadata.date_updated = datetime.now().strftime('%d-%m-%YT%H:%M:%S').lower() + pass diff --git a/code/kydcap/subcommands/initialize_device_root_dir.py b/code/kydcap/subcommands/initialize_device_root_dir.py new file mode 100644 index 0000000..ecbb8ad --- /dev/null +++ b/code/kydcap/subcommands/initialize_device_root_dir.py @@ -0,0 +1,39 @@ +import pathlib + +from kydcap.config import DEVICE_METADATA_FILE +from kydcap.models.device_metadata import DeviceMetadata + + +def setup_init_root_dir_parser(subparsers): + parser = subparsers.add_parser("init-device-root", aliases=["idr"]) + parser.add_argument("root_dir", type=pathlib.Path, default=pathlib.Path.cwd()) + group = parser.add_mutually_exclusive_group() + group.add_argument("--dynamic", action="store_false", help="enable guided setup") + group.add_argument("-n", "--name", action="store", required=True, type=str, help="name of device") + parser.set_defaults(func=handle_idr) + + +def handle_idr(args): + root_dir = args.root_dir + device_name = None + if args.dynamic: + response = "N" + while response == "N": + name = input("Please enter name of device: ") + # TODO extended config for other fields like apps, firmware etc. + response = input(f"Confirm device name: {name} [y/N]") + device_name = name + else: + device_name = args.name + root_dir.mkdir(parents=True, exist_ok=True) + root_dir.chdir() + dev_metadata_model = DeviceMetadata(device_name) + file_path = root_dir / device_name / DEVICE_METADATA_FILE + assert not file_path.exists(), f"{file_path} already exists" + if args.dynamic: + response = input(f"Confirm device metadata: {dev_metadata_model.model_dump()} [y/N]") + if response.lower() != "y": + assert False, "TODO implement dynamic setup" + code = dev_metadata_model.save_to_json(file_path) + print(f"Device metadata saved to {file_path}") + return code diff --git a/code/kydcap/subcommands/sniff.py b/code/kydcap/subcommands/sniff.py new file mode 100644 index 0000000..b2446ce --- /dev/null +++ b/code/kydcap/subcommands/sniff.py @@ -0,0 +1,91 @@ +import subprocess +from pathlib import Path + +from kydcap.config import * +from kydcap.models.device_metadata import DeviceMetadata + + +def setup_sniff_parser(subparsers): + parser = subparsers.add_parser('sniff', help='Sniff packets with tcpdump') + # metadata args + parser.add_argument("-a", "--ip-address=", help="IP address of the device to sniff", dest="device_ip") + # tcpdump args + parser_sniff_tcpdump = parser.add_argument_group('tcpdump arguments') + parser_sniff_tcpdump.add_argument("-i", "--interface=", help="Interface to capture on.", dest="capture_interface", + default="any") + parser_sniff_tcpdump.add_argument("-I", "--monitor-mode", help="Put interface into monitor mode", + action="store_true") + parser_sniff_tcpdump.add_argument("-n", help="Deactivate name resolution. Option is set by default.", + action="store_true", dest="no_name_resolution") + parser_sniff_tcpdump.add_argument("-#", "--number", + help="Print packet number at beginning of line. Set by default.", + action="store_true") + parser_sniff_tcpdump.add_argument("-e", help="Print link layer headers. Option is set by default.", + action="store_true", dest="print_link_layer") + parser_sniff_tcpdump.add_argument("-t", action="count", default=0, + help="Please see tcpdump manual for details. Unused by default.") + # parser_sniff_tcpdump.add_argument("--filter",type=str,default="ip help=f"pcap filter expression. \ + # Defaults is '{default}'") + # shared args + cap_size_group = parser.add_mutually_exclusive_group(required=False) + cap_size_group.add_argument("-c", "--count", type=int, help="Number of packets to capture.", default=0) + cap_size_group.add_argument("--mins", type=int, help="Time in minutes to capture.", default=60) + parser.set_defaults(func=handle_sniff) + # return parser + # parser.add_default(func=handle_sniff(args=sniff_args)) + + +def cwd_is_device_root_dir() -> bool: + device_metadata_file = Path.cwd() / DEVICE_METADATA_FILE + return device_metadata_file.exists() + + +def start_guided_device_root_dir_setup(): + assert False, "Not implemented" + + +def handle_metadata(): + assert not cwd_is_device_root_dir() + print(f"Unable to find {DEVICE_METADATA_FILE} in current working directory") + print("You need to setup a device root directory before using this command") + response = input("Would you like to be guided through the setup? [y/n]") + if response.lower() == "y": + start_guided_device_root_dir_setup() + else: + print("'kydcap init-device-root --help' for more information.") + exit(ReturnCodes.ABORTED) + # device_id = handle_capture_metadata() + return ReturnCodes.SUCCESS + + +def handle_capture_metadata(): + device_metadata_json = Path.cwd() / DEVICE_METADATA_FILE + device_metadata = DeviceMetadata.load_from_json(device_metadata_json) + device_id = device_metadata.device_id + return device_id + + +def handle_sniff(args): + if not cwd_is_device_root_dir(): + handle_metadata() + else: + cmd = ['sudo tcpdump', '-i', args.capture_interface] + if args.monitor_mode: + cmd.append('-I') + if args.no_name_resolution: + cmd.append('-n') + if args.number: + cmd.append('-#') + if args.print_link_layer: + cmd.append('-e') + if args.count: + cmd.append('-c') + cmd.append(str(args.count)) + elif args.mins: + pass + print('Executing: ' + ' '.join(cmd)) + # TODO maybe dump this into file -> put into device metadata + start_time = datetime.now().strftime('%H:%M:%S') + subprocess.run(cmd) + stop_time = datetime.now().strftime('%H:%M:%S') + return ReturnCodes.SUCCESS diff --git a/code/kydcap/utils/__init__.py b/code/kydcap/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/code/kydcap/utils/capture_metadata_utils.py b/code/kydcap/utils/capture_metadata_utils.py new file mode 100644 index 0000000..fa5b93a --- /dev/null +++ b/code/kydcap/utils/capture_metadata_utils.py @@ -0,0 +1,40 @@ +import json +from pathlib import Path + +from kydcap.config import ReturnCodes + + +def set_device_ip_address(ip_addr: str, file_path: Path): + assert ip_addr is not None + assert file_path.is_file() + with file_path.open('r') as f: + data = json.load(f) + current_ip = data["device_ip_address"] + if current_ip is not None: + print(f"Device IP Address is set to {current_ip}") + response = input(f"Do you want to change the recorded IP address to {ip_addr}? [Y/N] ") + if response.upper() == "N": + print("Aborting change to device IP address") + return ReturnCodes.ABORTED + with file_path.open('w') as f: + json.dump(data, f) + return ReturnCodes.SUCCESS + + +def set_device_mac_address(mac_addr: str, file_path: Path): + assert mac_addr is not None + assert file_path.is_file() + with file_path.open('r') as f: + data = json.load(f) + current_mac = data["device_mac_address"] + if current_mac is not None: + print(f"Device MAC Address is set to {current_mac}") + response = input(f"Do you want to change the recorded MAC address to {mac_addr}? [Y/N] ") + if response.upper() == "N": + print("Aborting change to device MAC address") + return ReturnCodes.ABORTED + with file_path.open('w') as f: + json.dump(data, f) + return ReturnCodes.SUCCESS + +# TODO finnish for other fields in capture metadata diff --git a/code/kydcap/utils/device_metadata_utils.py b/code/kydcap/utils/device_metadata_utils.py new file mode 100644 index 0000000..380ff3a --- /dev/null +++ b/code/kydcap/utils/device_metadata_utils.py @@ -0,0 +1,49 @@ +import json +from datetime import datetime +from pathlib import Path + +from kydcap.config import ReturnCodes + + +def update_firmware_version(version: str, file_path: Path): + assert file_path.is_file() + with file_path.open('r') as file: + metadata = json.load(file) + metadata['device_firmware_version'] = version + metadata['date_updated'] = datetime.now().strftime('%d-%m-%YT%H:%M:%S').lower() + with file_path.open('w') as file: + json.dump(metadata, file) + return ReturnCodes.SUCCESS + + +def add_capture_file_reference(capture_file_reference: str, file_path: Path): + assert file_path.is_file() + with file_path.open('r') as file: + metadata = json.load(file) + metadata['capture_files'] = capture_file_reference + metadata['date_updated'] = datetime.now().strftime('%d-%m-%YT%H:%M:%S').lower() + with file_path.open('w') as file: + json.dump(metadata, file) + return ReturnCodes.SUCCESS + + +def update_device_serial_number(device_id: str, file_path: Path): + assert file_path.is_file() + with file_path.open('r') as file: + metadata = json.load(file) + metadata['device_id'] = device_id + metadata['date_updated'] = datetime.now().strftime('%d-%m-%YT%H:%M:%S').lower() + with file_path.open('w') as file: + json.dump(metadata, file) + return ReturnCodes.SUCCESS + + +def update_device_type(device_type: str, file_path: Path): + assert file_path.is_file() + with file_path.open('r') as file: + metadata = json.load(file) + metadata['device_type'] = device_type + metadata['date_updated'] = datetime.now().strftime('%d-%m-%YT%H:%M:%S').lower() + with file_path.open('w') as file: + json.dump(metadata, file) + return ReturnCodes.SUCCESS diff --git a/code/kydcap/utils/tcpdump_utils.py b/code/kydcap/utils/tcpdump_utils.py new file mode 100644 index 0000000..08bfb7e --- /dev/null +++ b/code/kydcap/utils/tcpdump_utils.py @@ -0,0 +1,28 @@ +import shutil +import subprocess + + +def check_installed() -> bool: + """Check if tcpdump is installed and available on the system path.""" + return shutil.which('tcpdump') is not None + + +def ensure_installed(): + """Ensure that tcpdump is installed, raise an error if not.""" + if not check_installed(): + raise RuntimeError("tcpdump is not installed. Please install it to continue.") + + +def list_interfaces() -> str: + """List available network interfaces using tcpdump.""" + ensure_installed() + try: + result = subprocess.run(['tcpdump', '--list-interfaces'], capture_output=True, text=True, check=True) + return result.stdout + except subprocess.CalledProcessError as e: + print(f"Failed to list interfaces: {e}") + return "" + + +def start_tcpdump(): + return None diff --git a/code/dnsmasq.conf b/code/misc/dnsmasq.conf similarity index 100% rename from code/dnsmasq.conf rename to code/misc/dnsmasq.conf diff --git a/code/enable-forwarding.sh b/code/misc/enable-forwarding.sh similarity index 100% rename from code/enable-forwarding.sh rename to code/misc/enable-forwarding.sh diff --git a/code/hostapd.conf b/code/misc/hostapd.conf similarity index 100% rename from code/hostapd.conf rename to code/misc/hostapd.conf diff --git a/code/hostapd.conf.bak b/code/misc/hostapd.conf.bak similarity index 100% rename from code/hostapd.conf.bak rename to code/misc/hostapd.conf.bak diff --git a/code/initSwAP b/code/misc/initSwAP similarity index 100% rename from code/initSwAP rename to code/misc/initSwAP diff --git a/code/initSwAP_nftables b/code/misc/initSwAP_nftables similarity index 100% rename from code/initSwAP_nftables rename to code/misc/initSwAP_nftables diff --git a/code/make_ap.sh b/code/misc/make_ap.sh similarity index 100% rename from code/make_ap.sh rename to code/misc/make_ap.sh diff --git a/notes/meeting_18_april/IoTdb2_3.txt b/notes/meeting_18_april/IoTdb2_3.txt index cbc27aa..07f712f 100644 --- a/notes/meeting_18_april/IoTdb2_3.txt +++ b/notes/meeting_18_april/IoTdb2_3.txt @@ -38,7 +38,7 @@ IoT.db2/ └── .... IoT.db3/ ├── Measurements/ -│ ├── m1/ +│ ├── m1/ (Specification of device in this substructure) │ │ ├── follows from above │ │ └── ... │ ├── m2 diff --git a/notes/testbed/data collection/Design document.md b/notes/testbed/data collection/Design document.md new file mode 100644 index 0000000..a874501 --- /dev/null +++ b/notes/testbed/data collection/Design document.md @@ -0,0 +1,16 @@ +# Needed Metadata +- _Must_ contain IP address of *IoT* device +- _Can_ contain IP addr of capture host + +# Options +## tcpdump options +see [[tcpdump]] +## kybcap options +| Option | Desciption| +| ------- | ---------- | +| `--setup` | Go through guided setup process | +| `--meta-config` | Go through guided meta data setup | +| `--mdevice=` | _Metadata_ : Specify device name | +| `--mipdev=` | _Metadata_ : Specify device ip address | +| `--mmac=` | _Metadata_ : Specify device MAC address | +| `--to-csv` | _post_processing: extract pcap into csv | \ No newline at end of file diff --git a/notes/wiki/python-libs.md b/notes/wiki/python-libs.md new file mode 100644 index 0000000..fb9913c --- /dev/null +++ b/notes/wiki/python-libs.md @@ -0,0 +1 @@ +# `argparse` diff --git a/notes/wiki/tcpdump.md b/notes/wiki/tcpdump.md new file mode 100644 index 0000000..dc5b5dc --- /dev/null +++ b/notes/wiki/tcpdump.md @@ -0,0 +1,22 @@ +[docs](https://www.tcpdump.org/manpages/tcpdump.1.html) + +### Options +#### `tcpdump` +| Option | Description | +| ------- | ------------ | +| `-c` _count_
`--count` | to specify number of packets to capture | +| `-i` _interface_
`--interface=` | specify the interface e.g. 'eth0' or 'wlan0' etc. | +| `-F` _file_ | Get filter expression from _file_ | +| `-I`
`--monitor-mode` | Put interface into monitor mode| +| `-n` | No name resolution for addresses (host, port no. etc) | +| `-#`
`--number` | Print a packet number at beginning of line | +|`-t` | _Don't_ print a timestamp on each dump line. | +|`-tt` | Print the timestamp, as seconds since January 1, 1970, 00:00:00, UTC, and fractions of a second since that time, on each dump line. | +| `-ttt` | Print a delta (res dep on `--time-stamp-precision` option) between current and previous line on each dump line. default is microsecond resolution. | +| `-tttt` | Print a timestamp, as hours, minutes, seconds, and fractions of a second since midnight, preceded by the date, on each dump line. | +| `-ttttt` |Print a delta (res dep on `--time-stamp-precision`) between current and first line on each dump line. default is microsecond resolution. | +| `-w` _file_ | Write raw packets to _file_ | +| `-e` | print link level header. See manpage for more details | + + +