#!/bin/sh# Define your interfaceINTERFACE="em0"# Define the prefix you want to claim (this example is for 2aba:baba:abab:abab:ab::/72. Note the split # in [48:4], [52:4], [56:1]. I haven't checked if a simpler syntax like [48:9] would work, but splitting # into 4, 2, and 1 byte groups should be safer to be accepted)BPF_FILTER="icmp6 and ip6[40] == 135 and ip6[48:4] == 0x2abababa and ip6[52:4] == 0xabababab and ip6[56:1] == 0xab" ##################################### No more config needed below here ###################################### VariablesSCRIPT_NAME="ndp-prefix-bouncer.py"SERVICE_NAME="ndp_prefix_bouncer"SERVICE_FILE="/usr/local/etc/rc.d/$SERVICE_NAME"SCRIPT_PATH="/usr/local/bin/$SCRIPT_NAME"MONIT_CONFIG_PATH="/usr/local/etc/monit.opnsense.d/ndp_prefix_bouncer.conf"PYTHON_PATH=$(which python3) # Check if Python is installed correctlyif [ ! -x "$PYTHON_PATH" ]; then echo "Python 3 is not installed correctly or not found in the expected path." exit 1fi# Step 1: Install Python dependenciesecho "Installing Python dependencies..."$PYTHON_PATH -m ensurepip --upgrade$PYTHON_PATH -m pip install scapy netifaces# Step 2: Create the Python scriptecho "Creating the Python script at $SCRIPT_PATH..."cat <<EOF > $SCRIPT_PATH#!$PYTHON_PATHfrom scapy.all import sniff, sendp, Ether, IPv6, ICMPv6ND_NS, ICMPv6ND_NA, ICMPv6NDOptDstLLAddrimport netifacesimport loggingimport logging.handlersINTERFACE = "$INTERFACE"BPF_FILTER = "$BPF_FILTER"def get_mac_address(interface): return netifaces.ifaddresses(interface)[netifaces.AF_LINK][0]['addr']MAC_ADDRESS = get_mac_address(INTERFACE)logger = logging.getLogger('NdpPrefixBouncer')logger.setLevel(logging.INFO)filter_log_handler = logging.handlers.SysLogHandler(address='/var/run/log', facility='local0')formatter = logging.Formatter('filterlog: %(message)s')filter_log_handler.setFormatter(formatter)logger.addHandler(filter_log_handler)def create_ndp_response(original_packet): target_ip = original_packet[ICMPv6ND_NS].tgt response = Ether(dst=original_packet[Ether].src, src=MAC_ADDRESS) / \\ IPv6(src=target_ip, dst=original_packet[IPv6].src) / \\ ICMPv6ND_NA(tgt=target_ip, R=1, S=1, O=1) / \\ ICMPv6NDOptDstLLAddr(lladdr=MAC_ADDRESS) return responsedef packet_callback(pkt): if ICMPv6ND_NS in pkt: target_ip = pkt[ICMPv6ND_NS].tgt src_ip = pkt[IPv6].src log_entry = f"0,,,0,{INTERFACE},match,Received_NS_for_destination_IP_and_sending_NDP_response_to_claim_it,in,6,0x00,0x00000,58,ipv6-icmp,58,,{src_ip},{target_ip}," logger.info(log_entry) response_packet = create_ndp_response(pkt) sendp(response_packet, iface=INTERFACE, verbose=False) sniff(iface=INTERFACE, prn=packet_callback, filter=BPF_FILTER, store=0)EOFchmod +x $SCRIPT_PATH# Step 3: Create the service script to start at boot and monitoreecho "Creating service script at $SERVICE_FILE..."cat <<EOF > $SERVICE_FILE#!/bin/sh## PROVIDE: ndp_prefix_bouncer# REQUIRE: NETWORKING# KEYWORD: shutdown#. /etc/rc.subrname="ndp_prefix_bouncer"rcvar="\${name}_enable"# Specify the command and interpretercommand="/usr/local/bin/ndp-prefix-bouncer.py"command_interpreter="/usr/local/bin/python3"pidfile="/var/run/\${name}.pid"# Set the start command to run the script in the backgroundstart_cmd="ndp_prefix_bouncer_start"stop_cmd="ndp_prefix_bouncer_stop"# Function to start the service as a daemonndp_prefix_bouncer_start() { echo "Starting \${name}..." nohup \${command_interpreter} \${command} > /dev/null 2>&1 & echo \$! > \${pidfile}}# Function to stop the servicendp_prefix_bouncer_stop() { if [ -f \${pidfile} ]; then kill -15 \$(cat \${pidfile}) rm -f \${pidfile} else echo "\${name} is not running." fi}load_rc_config \$name: \${ndp_prefix_bouncer_enable:="YES"}run_rc_command "\$1"EOFchmod +x $SERVICE_FILEif ! grep -q "^ndp_prefix_bouncer_enable=" /etc/rc.conf.local; then echo 'ndp_prefix_bouncer_enable="YES"' >> /etc/rc.conf.localfi# Step 4: Configure Monitecho "Creating Monit configuration at $MONIT_CONFIG_PATH..."cat <<EOF > $MONIT_CONFIG_PATHcheck process ndp_prefix_bouncer with pidfile /var/run/ndp_prefix_bouncer.pid start program = "/usr/local/etc/rc.d/ndp_prefix_bouncer start" stop program = "/usr/local/etc/rc.d/ndp_prefix_bouncer stop" if does not exist then restart if 3 restarts within 5 cycles then alertEOFecho "Reloading Monit configuration..."service monit reload# Step 5: Go!echo "Starting NDP Prefix Bouncer service..."service ndp_prefix_bouncer startecho "Installation complete. NDP Prefix Bouncer is running and being monitored by Monit."