diff --git a/traffic-mirror/README.md b/traffic-mirror/README.md new file mode 100644 index 0000000..4203a81 --- /dev/null +++ b/traffic-mirror/README.md @@ -0,0 +1,145 @@ +# Traffic Mirroring + +This documentation and the on_boot.d script has been built and tested on a Unifi Dream Machine Special Edition/UDM-SE. + +If you have another model the switchN and interface numbers may be different, though you'll likely have full traffic monitoring features in the Unifi UI. + +For some reason Ubiquiti hasn't made this available on UDM-SE properly and you only mirror from one physical interface to one other physical interface. e.g. VLAN based traffic mirroring is not an option. + +## Prerequisites + +Finish setup of [on_boot.d](../on-boot-script/) + +### Configure Jumbo Frames + +Just will likely need to ensure Ethernet Jumbo Frames are enabled in order to ensure VLAN-in-VLAN tagged Ethernet frames with a full 1500 byte payloard, or can be output to your target switch port. + +NOTE: I've not really validated that is 100% necessary, but it's a common problem in NIDS scenarios, so I've simply enabled it. + +![Global Switch Settings](./global_switch_settings.png) + +![Jumbo Frame Support](./device_switch_settings.png) + +### Determine which VLAN's you want to mirror + +Typically on UDM-SE this will mean you want `switch0.1` at minimum for the default network, and if you have a guest network enabled possibly `switch0.2` as well. + +If you have additional VLAN's, or different VLAN's to monitor you need to identify them to a switch sub-interface, e.g. typically it'll just be `switch0.%{VLAN_ID}` + +### Determine which destination port you will use + +This will typically be an `ethN` port with numbering off by one, because Ubiquiti. + +e.g. so port 7 that you see in the Unifi UI is actually `eth6` under the hood. + +You just simply need to identify a free physical port by number and connect your destination device to it, and know that the `N` numbered port you connected to is actually `ethN-1` + +### Configure the traffic-mirroring script variables + +You need to configure SOURCE_INTERFACES as identified above, and IDS_PORT as identified above, in the `98-traffic-mirror.sh` script + +Example, + +```bash +SOURCE_INTERFACES="switch0.1 switch0.2" +IDS_PORT="eth6" +``` + +### Create an IDS/traffic mirroring only VLAN + +This is entirely optional, but highly recommended, as it will ensure your traffic mirroring destination does not see duplicate traffic. + +e.g. use VLAN#999 and name it "IDS" + +![VLAN Configuration](./vlan.png) + +### Create an IDS/traffic mirroring port profile + +1. Primary network == "IDS" if created in prior step +2. Traffic restriction == "Block"/"Block All" +3. PoE == disabled/off/unticked (unless your destination device is actually powered by PoE!) +4. All Feature options == disabled/off/unticked + +![Port Profile Configuration](./port_profile.png) + +### Configure your destination port with the port profile + +1. The port "Operation" must still be "Switching" even if you find that "Mirroring" is an option. +1. Apply the Ethernet Port Profile as previously configured, e.g. select "IDS" from the drop down menu + +![Destination Port Configuration](./destination_port_using_profile.png) + +Alternatively manually configure the port similar to the below, + +![Destination Port Manual Configuration](./destination_port_using_configuration.png) + +## Run the script manually to ensure it does what you want + +NOTE: You can optionally run `export TEST_ONLY=1` before running the script, in order to see what it will do and validate that it will run without error, without modifying any configuration. + +NOTE: You can run `export VERBOSE=` to get see additional output, e.g. the output from the tc commands which shows how queues and filters have been configured. + +Run the script to start the container. + +```bash +root@UDM-SE:/mnt/data/on_boot.d# export VERBOSE=1 +root@UDM-SE:/mnt/data/on_boot.d# ./98-traffic-mirror +Mirroring traffic from switch0.1 to eth6 +Creating Traffic Control queue for switch0.1...OK + +Current Traffic Control queue for switch0.1... + +qdisc noqueue 0: root refcnt 2 + Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 +qdisc ingress ffff: parent ffff:fff1 ---------------- + Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 + +Creating Traffic Control filter for switch0.1 mirroring to eth6...OK + +Current Traffic Control filter for switch0.1... + +filter protocol all pref 49152 u32 chain 0 +filter protocol all pref 49152 u32 chain 0 fh 800: ht divisor 1 +filter protocol all pref 49152 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 terminal flowid ??? not_in_hw (rule hit 2 success 2) + match 00000000/00000000 at 0 (success 2 ) + action order 1: mirred (Egress Mirror to device eth6) pipe + index 1 ref 1 bind 1 + Action statistics: + Sent 104 bytes 2 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 + + +Mirroring traffic from switch0.2 to eth6 +Creating Traffic Control queue for switch0.2...OK + +Current Traffic Control queue for switch0.2... + +qdisc noqueue 0: root refcnt 2 + Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 +qdisc ingress ffff: parent ffff:fff1 ---------------- + Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 + +Creating Traffic Control filter for switch0.2 mirroring to eth6...OK + +Current Traffic Control filter for switch0.2... + +filter protocol all pref 49152 u32 chain 0 +filter protocol all pref 49152 u32 chain 0 fh 800: ht divisor 1 +filter protocol all pref 49152 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 terminal flowid ??? not_in_hw (rule hit 0 success 0) + match 00000000/00000000 at 0 (success 0 ) + action order 1: mirred (Egress Mirror to device eth6) pipe + index 2 ref 1 bind 1 + Action statistics: + Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0) + backlog 0b 0p requeues 0 + + +root@UDM-SE:/mnt/data/on_boot.d# +``` + +It should run automatically now, if you've configured unifos-utilities on_boot.d correctly. + diff --git a/traffic-mirror/destination_port_using_configuration.png b/traffic-mirror/destination_port_using_configuration.png new file mode 100644 index 0000000..cb32498 Binary files /dev/null and b/traffic-mirror/destination_port_using_configuration.png differ diff --git a/traffic-mirror/destination_port_using_profile.png b/traffic-mirror/destination_port_using_profile.png new file mode 100644 index 0000000..d290617 Binary files /dev/null and b/traffic-mirror/destination_port_using_profile.png differ diff --git a/traffic-mirror/device_switch_settings.png b/traffic-mirror/device_switch_settings.png new file mode 100644 index 0000000..43b9720 Binary files /dev/null and b/traffic-mirror/device_switch_settings.png differ diff --git a/traffic-mirror/global_switch_settings.png b/traffic-mirror/global_switch_settings.png new file mode 100644 index 0000000..5038089 Binary files /dev/null and b/traffic-mirror/global_switch_settings.png differ diff --git a/traffic-mirror/on_boot.d/98-traffic-mirror.sh b/traffic-mirror/on_boot.d/98-traffic-mirror.sh new file mode 100755 index 0000000..d3becdf --- /dev/null +++ b/traffic-mirror/on_boot.d/98-traffic-mirror.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +# if you want output showing extra stuff `export VERBOSE=1` in your shell before running, or set it here. +# VERBOSE=1 + +# if you want to run in test-only/dry mode `export TEST_ONLY=1` in your shell before running, or set it here. +# TEST_ONLY=1 + +# SOURCE_INTERFACES will correspond to the switch and optionally switch sub-interfaces that you want to mirror from +# NOTE: on UDMSE Pro, switch0.1 is typically the "default" network VLAN #1 (untagged) +# NOTE: on UDMSE Pro, switch0.2 is typically the "guest" network VLAN #2 (tagged) +# NOTE: you will probably want to create an "IDS" specific network, e.g. VLAN#999 to which you will assign the IDS port that you're mirroring the traffic out to. This will avoid the switch duplicating traffic to that port, e.g. because the IDS VLAN#999 has nothing else in it there is no other traffic being generated in that VLAN, so the only traffic that will be seen on the IDS_PORT is the mirrored traffic. +# NOTE: This can be a list of interfaces if you want to monitor multiple source VLAN's +SOURCE_INTERFACES="switch0.1 switch0.2" + +# IDS_PORT is the physical wired port that your IDS sensor/inspection device is connected to and to which you will mirror traffic. +# NOTE: This port should be in an IDS specific VLAN that no other traffic is being generated on. e.g. management of the IDS sensor would be on another port in a different VLAN, or via wireless connectivity e.g. if you're using Corelight@Home on a Raspberry Pi. +IDS_PORT="eth6" + +for INTERFACE in ${SOURCE_INTERFACES} ; do + echo "Mirroring traffic from ${INTERFACE} to ${IDS_PORT}" + # configure mirroring queue if not already configured + # test for existance of existing queue for interface + tc -s qdisc ls dev ${INTERFACE} 2>&1 | grep ingress 1>/dev/null 2>&1 + + if [ ${?} -ne 0 ] ; then + # the queue does not exist yet, create it. + test "${VERBOSE}" = "1" && echo -n "Creating Traffic Control queue for ${INTERFACE}..." + test "${TEST_ONLY}" != "1" && tc qdisc add dev ${INTERFACE} handle ffff: ingress && echo "OK" || echo "FAILURE" + echo + else + test "${VERBOSE}" = "1" && echo "Traffic Control queue already exists for ${INTERFACE}..." + fi + + test "${VERBOSE}" = "1" && echo "Current Traffic Control queue for ${INTERFACE}..." && echo + test "${VERBOSE}" = "1" && tc -s qdisc ls dev ${INTERFACE} && echo + + # direct monitored traffic out the physical interface connected to the Corelight sensor + # test for existance of existing filter for interface + tc -s -p filter ls dev ${INTERFACE} parent ffff: 2>&1 | grep "to device ${IDS_PORT}" 1>/dev/null 2>&1 + + if [ ${?} -ne 0 ] ; then + # the filter does not exist yet, create it. + test "${VERBOSE}" = "1" && echo -n "Creating Traffic Control filter for ${INTERFACE} mirroring to ${IDS_PORT}..." + test "${TEST_ONLY}" != "1" && tc filter add dev ${INTERFACE} parent ffff: protocol all u32 match u32 0 0 action mirred egress mirror dev ${IDS_PORT} && echo "OK" || echo "FAILURE" + echo + else + test "${VERBOSE}" = "1" && echo "Traffic Control filter already exists for ${INTERFACE}..." + fi + + test "${VERBOSE}" = "1" && echo "Current Traffic Control filter for ${INTERFACE}..." && echo + test "${VERBOSE}" = "1" && tc -s -p filter ls dev ${INTERFACE} parent ffff: && echo +done + +# EOF \ No newline at end of file diff --git a/traffic-mirror/port_profile.png b/traffic-mirror/port_profile.png new file mode 100644 index 0000000..9f6391a Binary files /dev/null and b/traffic-mirror/port_profile.png differ diff --git a/traffic-mirror/vlan.png b/traffic-mirror/vlan.png new file mode 100644 index 0000000..cdfc50c Binary files /dev/null and b/traffic-mirror/vlan.png differ