{"id":20172650,"url":"https://github.com/usarmyresearchlab/arl-active-defense-framework","last_synced_at":"2026-03-13T06:31:11.105Z","repository":{"id":208263212,"uuid":"694694331","full_name":"USArmyResearchLab/ARL-Active-Defense-Framework","owner":"USArmyResearchLab","description":null,"archived":false,"fork":false,"pushed_at":"2025-06-11T20:04:49.000Z","size":174,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-06-11T21:32:28.106Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/USArmyResearchLab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-09-21T14:03:02.000Z","updated_at":"2025-06-11T20:04:53.000Z","dependencies_parsed_at":"2025-06-11T21:28:43.416Z","dependency_job_id":"7b65f11f-1425-47ec-9647-69fa0ae6b5e1","html_url":"https://github.com/USArmyResearchLab/ARL-Active-Defense-Framework","commit_stats":null,"previous_names":["usarmyresearchlab/arl-active-defense-system","usarmyresearchlab/arl-active-defense-framework"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/USArmyResearchLab/ARL-Active-Defense-Framework","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USArmyResearchLab%2FARL-Active-Defense-Framework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USArmyResearchLab%2FARL-Active-Defense-Framework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USArmyResearchLab%2FARL-Active-Defense-Framework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USArmyResearchLab%2FARL-Active-Defense-Framework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/USArmyResearchLab","download_url":"https://codeload.github.com/USArmyResearchLab/ARL-Active-Defense-Framework/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/USArmyResearchLab%2FARL-Active-Defense-Framework/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30460548,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-13T03:55:51.346Z","status":"ssl_error","status_checked_at":"2026-03-13T03:55:33.055Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T01:31:44.352Z","updated_at":"2026-03-13T06:31:11.076Z","avatar_url":"https://github.com/USArmyResearchLab.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ACTIVE DEFENSE FRAMEWORK\n\nThe Active Defense Framework (ADF) is a fully modular packet processing and event-handling framework.\nADF provides a plugin-based architecture and can be implemented on traditional networks or vehicle networks such as a Controller Area Network (CAN) bus.\n\n## Installing\n\nADF requires Python 3.\nBuilding ADF requires PIP and the development packages for Python and libpcap. If these are not available, some components will not be built.  \n`make apt` will try to install these on a system with APT support, as long as you have sudo privileges.\n\n`make` will build the core framework and use PIP to install the dependencies for PCAP and CAN support.\n\nADF requires root or equally privileged access to the interfaces to capture and inject traffic on network interfaces. CAN interfaces do not require privileges.\n\n## USAGE\n\n``` text\nbin/adf \u003cstartup-config | startup commands | - for config from STDIN\u003e\ncommands:\n    inc [filename ...] - load commands from filename\n    import \u003cpackage\u003e - import package\n    env [var[=value]] - get/set environment variables, can be used in commands as $var\n    log \u003clevel=CRITICAL|ERROR|WARNING|INFO|DEBUG\u003e [filename=] [filemode=] | configuration\u003e - set log level or config\n    control \u003clisten-address\u003e \u003cport\u003e [options]- start TCP control server, listens for commands\n    plugin \u003cmodule\u003e [name=\u003cname\u003e] [key=value] ... - load \u003cmodule\u003e as \u003cname\u003e and set config key=value\n    stop \u003cname\u003e - stop plugin \u003cname\u003e\n    config \u003cname\u003e [key=value] ... - set \u003cname\u003e config key to value\n    link \u003cname\u003e [name[:priority]]... - get or link dispatch of traffic from \u003cname\u003e to listed names.\n    unlink \u003cname\u003e [name] - remove link from \u003cname\u003e to all or [name]\n    show [name] - show config of plugin [name] or all\n    call \u003cplugin\u003e \u003cmethod\u003e [args...] - execute plugin.method(args) in plugin process context \n    sub \u003cplugin name\u003e [*|eventnames]... - subscribe plugin to events. * will subscribe to all, -name will unsub from event, -* will unsub all.\n    event \u003cname\u003e [args] - manually queue event\n    lock [timeout] - lock the event queue\n    unlock - unlock the event queue \n    wait [timeout [name]]  - wait [timeout] seconds for [name] or any event to be handled\n    del [name [key=value]] - delete all state or named plugin's key or all state\n    set \u003cname\u003e [key=value] - set named plugin's state key to value\n    get \u003cname\u003e [key] - get named plugin's state key or all\n    load \u003cfilename\u003e [1=flush] [1=restore] - load state from \u003cfilename\u003e, optionally flush existing state, optional restore config\n    save \u003cfilename\u003e [interval] - save state and config to \u003cfilename\u003e and optionally set checkpoint interval\n    restart \u003cstartup commands\u003e - restart framework, replacing startup commands if specified\n    shutdown - shut down framework\n```\n\nIf a single *startup-config* argument is given, `inc` *startup-config* will be assumed.  \nIf the argument is `-` configuration commands will be taken from STDIN. Commands should be terminated with newlines.\nArguments that start and end with \"double quotes\" will include enclosed whitespace. Any text after # not enclosed in quotes is considered a comment and ignored.  \n\n[*arg*] arguments are optional.  ... indicates multiple arguments may be given, separated by whitespace.  \nAll commands elicit a response of the format `{command: result}`. Invalid commands will have a result of `None`. If an exception occurs the result will be `{ExceptionType:Details}`\n\n* `inc` *filename*  \nRead and parse commands from *filename*. Multiple filenames can be provided and will be parsed in the order given.  \nResponse: `{'inc':[{'filename':[results]}, ... ]}`\n\n* `import` *package*  \nImport *package* to ADF namespace. package.module paths are supported.  \nResponse: `{'import':{package:[names]}}`\n\n* `env` *var* [`=`*value*] ...  \nGet environment variable *var*, or set *var* to *value*. Variables can be used in command args with `$`*var*  \nResponse: `{'env':{var:value}}`\n\n* `log` *configuration*  \nSet logging configuration. Arguments such as level=, filename=, filemode=... can be used. If *configuration* is `\"{key:value,...}\"` it will be evaluated as a logging dictConfig. Log level can also be set with the LOG environment variable, or by setting DEBUG=1  \nResponse: `{'log':config}`\n\n* `control` *listen-address* *port* [`ssl` *options*]  \nStarts a TCP control server on *listen-address:port*. Can specify an SSL configuration, set `ssl certfile=... keyfile=... cafile=... verify=0(none)|1(opt)|2(req)`\n`control` with no arguments will stop any running control server  \nResponse: `{'control': ((listen-address, port), {options})}`\n\n* `plugin` *module* [`name=`*name*] [*key*`=`*value* ... ]  \nLoads plugin *module* as *name* and passes *key*=*value* as startup config. *module* can be a full package.module.class path or a class from a previously imported package. If *name* is not specified the class name will be used. All plugins must have unique names. Additional *key*=*value* pairs will be passed to the plugin as the startup configuration. See `config` for details of the configuration key and value format.  \nResponse: `{'plugin': {name:pid}}`  \npid will be the PID of the process hosting the plugin. Typically this is the same PID as the framework's process, but if ADF is running in multiprocessing mode (ADF_MP) it will be different.  \n\n* `stop` *name*   Unlinks and stops plugin *name*.  \n    Response: `{'stop':name}`\n\n* `config` *name* [[`!`]*key*[`=`*value*] ... ]  \n Gets or sets plugin *name* configuration.  \n A *key*=*value* argument will set plugin *name* configuration *key* to *value*.  \n Response: `{'config': {name: {key:value}}}`  \n A *key* argument will return the value of *key* in plugin *name* configuration  \n Response: `{'config': {name: value}}`  \n A !*key* argument will delete *key* from *name*' configuration.  \n Response: `{'config': {name: None}}`  \n No additional arguments will return the full configuration of *name*.  \n Response: `{'config': {name: {config} }}`  \n\n  `config` supports a dotted-key format for specifying nested keys: Key 'a.b.c' will get or set value of `{'a':{'b':{'c':value}}}`  \n  if setting 'a.b.c', the 'a' and 'b' dictionaries will be created if necessary. Key `a.b` would return  `{'c':value}`\n\n  Values are automatically parsed to integers if possible, otherwise remain strings. A comma-separated list of integers (`'1,2,3'`) will be parsed to a list (`[1,2,3]`).\n\n* `link` *name* [*destname*[`:`*priority*] ... ]  \n    Links traffic dispatch from plugin *name* to plugin *destname* with optional *priority*. If no *destname* argument is given, return current links. Links determine how traffic flows between plugins. Priority may be 1, 0, -1, or omitted. If no priority is specified, links with priority 0 will be created from *name* to *destname*, and from *destname* to *name* (bidirectional flow). If a priority is specified, only a link from *name* to *destname* will be created (unidirectional flow)  \n    Response: `{'link': {name: [(destname,priority), ... ]}}`\n\n    After traffic is processed by a plugin it is sent to linked plugins based on dispatch rules:\n  * IF traffic has `dest` info AND any plugins named in `dest` are linked:\n    * Traffic will ONLY be dispatched to plugins in `dest`  \n  * ELSE\n    * Traffic will be dispatched to any plugins linked with a priority of 1\n    * IF traffic has `dispatch` info:\n      * Clear `dispatch` info.  \n      * Dispatch to all plugins in `dispatch` IF they are linked. Links with priority -1 will never get traffic UNLESS named in `dest` or `dispatch`.  \n    * ELSE:  \n      * Dispatch to all plugins linked with priority 0, UNLESS plugin name is in `prev` info. This prevents dispatch loops.\n  * When traffic is dispatched from a plugin, that plugin's name is appended to the `prev` info.\n\n  In summary:\n  * Priority 1 will always receive traffic.\n  * Priority 0 will receive traffic that does not have dispatch info.\n  * Priority -1 will not receive traffic unless is in the dispatch info.\n\n* `unlink` *name* [*destname*... ]  \n    Removes link from plugin *name* to plugin *destname*. By default removes links between *name* and *destname* (bidirectional). To only remove link from *name* to *destname* (unidirectional) specify *destname*`:0` If no *destname* argument is given, remove all links from *name* (unidirectional, any links to *name* are not removed. Returns current links.  \n    Response: `{'unlink': {name: [(destname,priority), ... ]}}`\n\n* `sub` *name* [`*` | `-*` | *eventname*  | `-`*eventname* ... ]  \n    Subscribe plugin *name* to events. If *eventname*(s) given, subscribe *name* to event *eventname*. If `-`*eventname*(s) given, unsubscribe *name* from event *eventname*. If `*` is provided as the event name, subscribe *name* to all events. If `-*` is provided as the event name, unsubscribe *name* from all events. If no event names are provided, return current subscriptions.  \n    Response: `{'sub': {name: True if all events | (eventname, ... )}}`\n\n* `show` [*name* ... ]  \n    Show plugin config, links, and subscriptions. If one or more plugin names are specified, show only those plugins. Else show all loaded plugins.  \n    Response: `{'show': {name: {'config':{config}, 'links': [(destname,priority), ... ], 'subs': True|(eventname,...) }, ... }}`\n\n* `call` *name* *method* [*args*]  \n    Execute *method* in plugin *name*. `call` is used to execute code in plugin *name*'s context, by generating an event and passing it to the plugin. This allows *method* to be run in the proper context even if the plugin is in a different process. All supplied positional and/or keyword (name=value) args will be passed to *method*. `call` return the result from the method called.\n    Response: `{'call': {name: result}}`\n\n* `event` *eventname* [*key*`=`*value* ... ] [`sync=1`]  \n    Generate an *eventname* event containing *data*. An event with name *eventname* will be generated and queued. Any *key*=*value* pairs will populate the event data. The event will be published to all plugins subscribed to *eventname*. If the `sync=1` argument is provided, `event` will block until all subscribers have handled the event.  \n    Response: `{'event': {eventname: {eventdata}}}`\n\n* `lock` [*timeout*]  \n    Lock the event queue. Tries to acquire a lock on the event queue for *timeout* seconds if specified. Otherwise, returns once queue is locked. Response indicates if lock was acquired. When event queue is locked, events may be queued but will not be published to subscribers.  \n    Response: `{'lock': True|False}`\n\n* `unlock`  \n    Unlock the event queue. Response indicates if a lock was actually held.  \n    Response: `{'unlock': True|False}`\n\n* `wait` [*timeout*] [*eventname*]\n    Wait for any event or *eventname* to be handled. Waits up to *timeout* seconds if provided. If *timeout* is not provided or non-numeric, waits forever. If *eventname* is not provided, will return when any event is handled. If *eventname* is provided, will handle all queued events until *eventname* is handled or timeout occurs. If the event queue is not locked, `wait` will lock the queue before waiting and unlock it before returning.  \n    Response: `{'wait': None | {eventname:{eventdata}}}`\n\n* `set` *name* *key*`=`*value* ...  \n    Sets *key* to *value* in plugin *name*'s state dictionary. Dotted-keys are supported (see `config`).  \n    Response: `{'set': {name: value}}`\n\n* `get` [*name*] [*key*]  \n    Get all state, *name* state, or *key* from *name* state. Dotted-keys are supported (see `config`).  \n    *name* and *key* arguments will return the value of *key* in plugin *name* state.  \n    Response: `{'get': {name: value}}`  \n    A *name* argument will return the full state of *name*  \n    Response: `{'get': {state} }}`  \n    No arguments will return the state of all plugins.  \n    Response `{'get': { name: {state}, ... }}`\n\n* `del` [*name*] [*key*]  \n    Delete all state, *name* state, or *key* from *name* state. Dotted-keys are supported (see `config`).  \n    *name* and *key* arguments will delete *key* from plugin *name* state.  \n    Response: `{'del': True|False if *key* was deleted from *name* state}`  \n    A *name* argument will delete all state of *name*.  \n    Response: `{'del': True|False if *name* state was deleted}`  \n    No arguments will delete all state of all plugins.  \n    Response `{'del': True}`\n\n* `save` [*filename*] [*interval*]  \n    Saves plugin and framework state to *filename*. The framework state is loaded plugins and their configuration, plugin links, and event subscriptions. `save` with no arguments will use previously set filename. *interval* will set the interval (in seconds) at which state will be automatically saved. If filename has been set, state will be automatically saved at framework shutdown.  \n    Response: `{'save': filename}`\n\n* `load` [*filename*] [`flush`|`flush restore`]  \n    Loads plugin and optionally framework state from *filename*. If the `flush` argument is given, all plugin state will be deleted before loading state, else loaded state will be merged. If the `flush restore` argument is given, the framework state will be also restored from the loaded state. The framework state is loaded plugins and their configuration, plugin links, and event subscriptions.  \n    Response: `{'load': filename}`\n\n* `restart` [*startup config*]  \n    `restart` with no arguments will restart the framework. State will be saved if `save` was previously called to set a save filename. All plugins will be stopped and the framework will then restart, reapplying any startup command line arguments such as a config file. If *startup config* arguments are provided, that will become the new configuration used whenever the framework restarts. (If specifying a config file, be sure to use the `inc` command: `restart inc` *configfile* ) Any `control` server will remain available, to prevent disconnection if `restart` is issued over the socket.  \n    Response: `{'restart': [current startup config]}`\n\n* `shutdown`  \n    Shut down the framework. State will be saved if `save` was previously called to set a save filename. All plugins will be stopped and the framework will then terminate. `control` server will stop listening and disconnect any clients.  \n    Response: `{'shutdown': None}`\n\n## Plugins\n\nPlugins are the ADF traffic-handling components, and are linked by the framework to other plugins.\nEach packet (IP traffic, CAN message, etc...) is handled by a plugin in the following sequence:\n\n1) Receive: Packets are either immediately handled or queued by the plugin. This is configured by the `queue=0|1` argument.  \n    Traffic is always passed between plugins as an `(info,packet)` tuple.\n    * `info` is a dictionary containing traffic metadata.\n            Basic information such as timestamp and source will always be present.\n            Plugins that perform decoding or traffic analysis can add to info.\n    * `packet` is the actual packet data. For IP this will be a `dpkt` object, for CAN it will be a `can.Message`.\n2) Filter: If a filter expression is configured by the `filter=`*expr* argument, *expr* will be evaluated and the traffic will pass if *expr* returns True.  \n*expr* should be a valid Python expression using `info` the for info dictionary and `packet` for the packet data.\n3) Effect: Performs traffic modification. The `effect()` method is where most custom plugin code is typically written.  \nThe default effect method is to execute any statements defined in `exec*` config arguments.  \n        Like filtering, the statements should expect `info` and `packet` variables. Modifications to `packet` will modify the traffic.\n4) Dispatch: Forward traffic to linked plugins. See `link` under usage for dispatch rules.  \nRelevant keys in `info` that affect dispatch:\n    * `source`: first plugin to handle this traffic.\n    * `dest`: name or list of names the traffic will be unconditionally dispatched to only if plugin is linked, else `dispatch` will apply.\n    * `dispatch`: name or list of names the traffic should be dispatched to. Will be deleted on dispatch.\n    * `prev`: list of plugins this traffic has passed through, to prevent dispatch loops. WUll be updated on dispatch to add this plugin.\n\n### Interface Plugins\n\nInterface plugins are specialized plugins that receive and send traffic to and from ADF.\nNormally this will be via a standard network interface, but interface plugins exist for reading/writing packet capture files,\ncreating virtual interfaces, and connecting to other networks such as Controller Area Network (CAN) bus.\n\n* `Interface` captures packets from a network interface.\nThe Interface plugin will set the `source` key in info to the name of the plugin for incoming packets.\n    Packets dispatched to an Interface plugin will be sent from the interface.  \n    `device=`*devname* is required and selects which network device the plugin attaches to.\n    You must have permission to put the device in promiscuous mode and capture or the plugin will not load.  \nThe `filter=`*expr* argument controls what packets are injected on the interface, not which packets are captured.  \n`decode=0|1` disables or enables decoding with dpkt. Default is to decode.  \n    If decoding is disabled, the `packet` will be raw bytes, not a dpkt object.\n    Keys generated in `info` by decoding:\n\n``` text\n    data    Packet payload, as bytes\n    flags   TCP flags if TCP. Integer value representing flag bits.\n    len     Packet length in bytes.\n    proto   “arp” if ARP or IP protocol value (1=ICMP,6=TCP,17=UDP, etc…)\n    sip,dip     Source and destination IP addresses as IPy objects.\n    smac,dmac   Source and destination MAC addresses as bytes.\n    sport,dport Source and destination TCP/UCP ports if applicable\n    ts          Timestamp of packet\n    vlan        VLAN tag if present\n```\n\n* `Tap`  is an `Interface` plugin, but creates a virtual interface rather than attaching to an existing device.  \n`device=`*tapname* is optional and sets the name of the tap interface. If omitted the system will choose a name.\n    You must have permission to create taps or the plugin will not load.  \n`hwaddr=`*macaddress* sets the MAC address of the tap.  \n`addr=`*ipaddress* sets the IP address of the tap.  \n`netmask=`*netmask* sets the netmask of the tap.  \n`mtu=`*MTU* sets the MTU of the tap. Default is 1514.  \n\n* `Pcap` uses libpcap to read/write PCAP files or to attach to a network interface.  \n`pcap_in=`*filename*    Pcap file to read packets from.  \n    `delta=1`           If delta is enabled, the pcap_in file will be replayed at actual speed based on the timestamp deltas in the file. The default is to replay the capture as fast as possible.  \n`pcap_out=`*filename*   Pcap file to write packets to. Traffic dispatched to a `Pcap` plugin will be written to this file.  \n`device=`*devname*      Network device to capture/inject on using libpcap. `Pcap` functions identically to `Interface` in this mode. Cannot be used with pcap_in or pcap_out, and you must have permission to capture on the device.  \n\n### Event plugins\n\nPlugins implement event handling as well as traffic handling. This is used to transport events between ADF instances or support external events.\n\n* `Channel` sends and receives events via UDP.  \n`addr=`*hostname/ipaddress* Enables sending to this IP address. A multicast or broadcast address can be specified if supported by the OS.  \n`listen=`*ipaddress* Enables listening on this IP address. 0.0.0.0 will listen on all addresses.  \n`port=`*udpport*  Send and listen on this UDP port, default 42223.  \n`bytes=`*bytes*   sets maximum UDP payload size, default 1024. Larger events will be split into multiple UDP packets.\n\n* `Sender` sends events via TCP.  \n`host=`*hostname/ipaddress*     Send to this IP address. Default `localhost`.  \n`port=`*tcpport*                Send to this TCP port, default 42224.  \n`timeout=`*timeout*             The TCP connection is not established until an event needs to be sent.  `Sender` closes the TCP connection if no activity within *timeout* seconds, default 60. If *timeout* is 0 the connection will not be closed when idle.\n\n* `Listener` listens for events via TCP.  \n`listen=`*paddress*     Listen on this IP address. Default `localhost`.  \n`port=`*tcpport*        Listen on this TCP port, default 42224.\n\n* `MQTT` sends and receives events via MQTT. Requires paho-mqtt.  \nIf `MQTT` receives an event, it will publish an MQTT message with the topic set to the event name.  \nIf `MQTT` is subscribed to an MQTT topic, it will generate events with the name set to the MQTT topic.  \n`host=`*hostname/ipaddress*     Connect to this MQTT broker. Default `localhost`.  \n`port=`*tcpport*                MQTT broker port, default 1883.  \n`subscribe=`*topic*             Subscribe to MQTT *topic*.  \n\n## Sample Configurations\n\nA `default.cfg` is included to set up basic logging, control, and event channels:  \n\n```text\nlog level=INFO #filename=adf.log #set default log level and destination\ncontrol localhost 42222 #cleartext control socket\n      plugin Channel addr=10.0.255.255 listen=0.0.0.0 #events broadcast via UDP\nsubscribe Channel * #channel subscribes/broadcasts all events\n```\n\n`inc $ADF/config/default.cfg` will include this from any config file.  \n\nThe following configuration will attach ADF to the `eth0` and `eth1` interfaces and forward traffic between the interfaces via a generic plugin. This is an inline network filter.\n\n``` text\ninc $ADF/config/default.cfg\n\nplugin Interface name=eth0 device=eth0  #attach to eth0\nplugin Interface name=eth1 device=eth1  #attach to eth1\nplugin Plugin name=filtering    #generic plugin\n\nconfig filtering \"filter=True\"  #all packets pass by default, this can be changed at any time.\n\nlink filtering eth0 eth1    #bidirectional links, so eth0\u003c-\u003efiltering\u003c-\u003eeth1 and vice-versa\n```\n\nThis configuration is the same as above, but we attach to `eth0` and create a `tap0`. We place the system's IP address on the `tap0` interface instead of `eth0` so ADF is acting as a host-based filter.\n\n``` text\ninc $ADF/config/default.cfg\n\nplugin Interface name=eth0 device=eth0  #attach to eth0\nplugin Tap name=tap device=tap0 addr=192.168.0.42 netmask=255.255.255.0    #create a tap and assign an IP\nplugin Plugin name=filtering    #generic plugin\n\nconfig filtering \"filter=True\"  #all packets pass by default, this can be changed at any time.\n\nlink filtering eth0 tap     #bidirectional links, so eth0\u003c-\u003efiltering\u003c-\u003etap and vice-versa\n```\n\nWe may want to redirect certain traffic to an alternative interface and log it:\n\n``` text\ninc $ADF/config/default.cfg\nplugin Interface name=eth0 device=eth0  #attach to eth0\nplugin Interface name=eth1 device=eth1  #attach to eth1\nplugin Interface name=eth2 device=eth2  #attach to eth2\n\nplugin plugins.redir.Redir name=redir INTERNAL=eth1 EXTERNAL=eth0 REDIR=connlog    #redirection plugin\n\nplugin plugin.connlog.ConnLog name=connlog logfile=connection.log    #connection logging \n\n# eth0\u003c-\u003eredir\u003c------(not redirected)-----\u003eeth1\n#           ^-(redirected)\u003c-\u003econnlog\u003c-----\u003eeth2\n\nlink connlog eth2       #we are logging traffic to and from eth2 (the redir interface)\nlink redir eth0 eth1   #default bidirectional links, so eth0\u003c-\u003eredir\u003c-\u003eeth1 and vice-versa\nlink redir connlog:-1   #traffic should not go to the logging/eth2 interface unless redir sends it there\nlink connlog redir:0    #unidirectional, only allow logged responses back from the redir interface\n\nconfig redir ... #config redirected IPs and conditions here, see plugins.redir.Redir documentation\n```\n\nADF can also transparently log all traffic between two interfaces:\n\n``` text\ninc $ADF/config/default.cfg\n\nplugin Interface name=eth0 device=eth0  #attach to eth0\nplugin Interface name=eth1 device=eth1  #attach to eth1\nplugin plugins.connlog.ConnLog  name-connlog logfile=connection.log\n\nlink eth0 eth1          #bidirectional links, so eth0\u003c-\u003eeth1 and vice-versa\nlink eth0 connlog:1     #always log eth0 traffic, no traffic back from logger\nlink eth1 connlog:1     #always log eth1 traffic, no traffic back from logger\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusarmyresearchlab%2Farl-active-defense-framework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fusarmyresearchlab%2Farl-active-defense-framework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fusarmyresearchlab%2Farl-active-defense-framework/lists"}