Skip to content

Instantly share code, notes, and snippets.

@jwalanta
Last active February 10, 2024 09:16
Show Gist options
  • Save jwalanta/53f55d03fcf5265938b64ffd361502d5 to your computer and use it in GitHub Desktop.
Save jwalanta/53f55d03fcf5265938b64ffd361502d5 to your computer and use it in GitHub Desktop.
Detect new network devices connecting to OpenWrt and send text message

Add the following line in /etc/dnsmasq.conf

dhcp-script=/etc/detect_new_device.sh

Setup sendmail to send email to your text number.

Reference:

Create /etc/detect_new_device.sh with the following content

#!/bin/sh

# script to detect new dhcp lease

# this will be called by dnsmasq everytime a new device is connected
# with the following arguments
# $1 = add | old
# $2 = mac address
# $3 = ip address
# $4 = device name

notification_email="1234567890@txt.att.net"

if [ "$1" == "add" ]; then
  msg="New device on `uci get system.@system[0].hostname`.`uci get dhcp.@dnsmasq[0].domain` $*"
  echo `date` $msg >> /tmp/dhcpmasq.log

  # encode colon (:) and send email
  echo $msg | sed s/:/-/g | sendmail "$notification_email"
fi

Alternative script using whitelist

This script only sends alerts if the mac address is not in the list

#!/bin/sh

# script to detect new dhcp lease

# this will be called by dnsmasq everytime a new device is connected
# with the following arguments
# $1 = add | old
# $2 = mac address
# $3 = ip address
# $4 = device name

known_mac_addr="/etc/known_mac_addr"
notification_email="1234567890@txt.att.net"

# check if the mac is in known devices list
grep -q "$2" "$known_mac_addr"
unknown_mac_addr=$?

if [ "$1" == "add" ] && [ "$unknown_mac_addr" -ne 0 ]; then
  msg="New device on `uci get system.@system[0].hostname`.`uci get dhcp.@dnsmasq[0].domain` $*"
  echo `date` $msg >> /tmp/dhcpmasq.log

  # encode colon (:) and send email
  echo $msg | sed s/:/-/g | sendmail "$notification_email"
fi

When a new device is added, dnsmasq calls detect_new_device.sh with arguments add mac_addr ip_addr devicename. The script checks if the device is new (if the dhcp lease hasn't expired, it calls with old), then logs and emails (which eventually is a text message) the information.

@alixyz
Copy link

alixyz commented May 11, 2023

I checked mine and at some point I moved it to the following location and changed the name:
/etc/hotplug.d/dhcp/00-detect_new_device.sh

Don't recall why, but must have been due to an issue that came up, possibility with v22.xx.x

Also change the file permissions to make it executable using:
chmod +x /etc/hotplug.d/dhcp/00-detect_new_device.sh

@EnlightedBitFox
Copy link

Ahh ok will try it out.
You changed it, because on the ujail permissions.
What about the dnsmasq.conf? I assume, the only thing to do is adjusting the path

@alixyz
Copy link

alixyz commented May 11, 2023

Yes, its coming back to me :)

Actually the dnsmasq.conf file no longer has the entry, I have it commented out.

@EnlightedBitFox
Copy link

Awesome!
Now it works 😁
Thank you ✌️

@Green-m
Copy link

Green-m commented May 17, 2023

I upgrade my openwrt to 23, the dhcp script breaks. I figure it out and finally make it works again. Share my procedure to help others.

This is my dhcp script:

#!/bin/sh

# script to detect new dhcp lease

# this will be called by dnsmasq everytime a new device is connected
# with the following arguments
# $1 = add | old
# $2 = mac address
# $3 = ip address
# $4 = device name
#echo "$0" "My custom script called with $@"
#echo "$1 $2 $3 $4"
known_mac_addr="/etc/config/dhcp"

send_notification(){
    msg="$1"
    curl "https://<myhookapi>/WLAN_NEW_CLIENT_ALERT! $msg"
}

# check if the mac is in known devices list
/bin/grep -iq "$2" "$known_mac_addr"
unknown_mac_addr=$?

if [ "$ACTION" = add ] && [ "$unknown_mac_addr" -ne 0 ]; then
  msg="New device on $(uci get system.@system[0].hostname).$(uci get dhcp.@dnsmasq[0].domain) MAC=$2, IP=$3, NAME=$4"
  echo "$msg"

  send_notification "$3_$4"

fi

After I add it to config with uci set, the openwrt log shows:

...
grep: /etc/config/dhcp: No such file or directory
...
line 24: /bin/grep: not found

There are much logs like that. So I check the dnsmasq service script, thinking maybe the ujail restrict the command and file access, and the I modify the /etc/init.d/dnsmasq file.

DHCPSCRIPT="/usr/lib/dnsmasq/dhcp-script.sh"
DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus /bin/grep /usr/bin/curl /etc/config/dhcp"

I update the DHCPSCRIPT_DEPENDS to add the command and file needed in dhcp script. After that, everything works, and error log has gone.

It's a little nasty, if someone knows there is a more elegant way to change the DHCPSCRIPT_DEPENDS, please share.

@ktomy
Copy link

ktomy commented Nov 4, 2023

I extended it a bit to send tmessaged through a telegram bot

My script:

#!/bin/sh

# script to detect new dhcp lease

# this will be called by dnsmasq everytime a new device is connected
# with the following arguments
# $1 = add | old
# $2 = mac address
# $3 = ip address
# $4 = device name

# logger -p local0.info -t dhcp-join-notify "$0: My custom script called with $@"

known_mac_addr="/etc/config/dhcp"


BOT_TOKEN='<INSERT_TOKEN_HERE>'
CHAT_ID='<INSERT_GROUP_CHAT_ID>'


send_notification(){
    msg="$1"
    curl -ks https://api.telegram.org/bot$BOT_TOKEN/sendMessage -d chat_id=$CHAT_ID -d parse_mode=HTML -d text="$msg" >/dev/null
}
# check if the mac is in known devices list
/bin/grep -iq "$2" "$known_mac_addr"
unknown_mac_addr=$?

if [ "$1" = add ] && [ "$unknown_mac_addr" -ne 0 ]; then
  local_msg="New device detected: MAC=$2, IP=$3, NAME=$4"
msg="New device joined the home network:
Hostname: <b>$4</b>
IP Address: <b>$3</b>
MAC Address: <b>$2</b>"
  logger -p local0.info -t dhcp-join-notify "$local_msg"

  send_notification "$msg"

fi

The init script change:
DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus /bin/grep /usr/bin/curl /etc/config/dhcp /usr/bin/logger /sbin/uci /etc/ssl/certs/ca-certificates.crt"

I did not use /etc/hotplug... but installed the script through something like uci set dhcp.@dnsmasq[0].dhcpscript='/root/alert_dhcp_new_device.sh'

@hillz2
Copy link

hillz2 commented Feb 7, 2024

I extended it a bit to send tmessaged through a telegram bot

My script:

#!/bin/sh

# script to detect new dhcp lease

# this will be called by dnsmasq everytime a new device is connected
# with the following arguments
# $1 = add | old
# $2 = mac address
# $3 = ip address
# $4 = device name

# logger -p local0.info -t dhcp-join-notify "$0: My custom script called with $@"

known_mac_addr="/etc/config/dhcp"


BOT_TOKEN='<INSERT_TOKEN_HERE>'
CHAT_ID='<INSERT_GROUP_CHAT_ID>'


send_notification(){
    msg="$1"
    curl -ks https://api.telegram.org/bot$BOT_TOKEN/sendMessage -d chat_id=$CHAT_ID -d parse_mode=HTML -d text="$msg" >/dev/null
}
# check if the mac is in known devices list
/bin/grep -iq "$2" "$known_mac_addr"
unknown_mac_addr=$?

if [ "$1" = add ] && [ "$unknown_mac_addr" -ne 0 ]; then
  local_msg="New device detected: MAC=$2, IP=$3, NAME=$4"
msg="New device joined the home network:
Hostname: <b>$4</b>
IP Address: <b>$3</b>
MAC Address: <b>$2</b>"
  logger -p local0.info -t dhcp-join-notify "$local_msg"

  send_notification "$msg"

fi

The init script change: DHCPSCRIPT_DEPENDS="/usr/share/libubox/jshn.sh /usr/bin/jshn /bin/ubus /bin/grep /usr/bin/curl /etc/config/dhcp /usr/bin/logger /sbin/uci /etc/ssl/certs/ca-certificates.crt"

I did not use /etc/hotplug... but installed the script through something like uci set dhcp.@dnsmasq[0].dhcpscript='/root/alert_dhcp_new_device.sh'

Do you have a script for when someone is disconnected from your wifi ? I've been trying to figure out how to do that, currently I only have a script that tells me when a new device is connected to wifi but not when it's disconnected

@bjalek
Copy link

bjalek commented Feb 9, 2024

This is my variation that script (etc\hotplug.d\dhcp\99-detect_new_device_email.sh ).
I have Lan, Guest and IoT.
Router send me an alert when someone connect/disconnect. (lease time run out).
I disabled known/unknown hosts

#!/bin/sh

# script to detect new dhcp lease

# this will be called by dnsmasq everytime a new device is connected with the following arguments
# $1 = $ACTION = add | update
# $2 = $MACADDR = mac address
# $3 = $IPADDR = ip address
# $4 = $HOSTNAME = device name

# this will create log file 
echo "$ACTION     $HOSTNAME     $IPADDR     $MACADDR      `date`">>/tmp/detect.log

known_mac_addr="/etc/config/dhcp"
notification_email="YOUR_Email@gmail.com"
lan="192.168.2."       #Update subnets for the lan, guest, iot
guest="192.168.4."
iot="192.168.3."

# Convert MAC to uppercase if you want
# mac=$(echo "$MACADDR" | awk '{print toupper($0)}')

# check if the mac is in known devices list
grep -q "$mac" "$known_mac_addr"
unknown_mac_addr=$?

# && [ "$unknown_mac_addr" -ne 1 ]

if [ "$ACTION" == "add" ]; then

  if test "${IPADDR#*$lan}" != "$IPADDR"; then
      ( echo "Subject: $HOSTNAME    Connected"
        echo ""
        echo "NAME:  $HOSTNAME"
        echo ""
        echo "MAC:   $(echo "$MACADDR" | awk '{print toupper($0)}')"
        echo "IP:   $IPADDR" 
        echo ""
        echo "LAN") | sendmail "$notification_email"
  fi

  if test "${IPADDR#*$guest}" != "$IPADDR"; then
      ( echo "Subject: $HOSTNAME    Connected"
        echo ""
        echo "NAME:  $HOSTNAME"
        echo ""
        echo "MAC:   $(echo "$MACADDR" | awk '{print toupper($0)}')"
        echo "IP:   $IPADDR" 
        echo ""
        echo "Guest") | sendmail "$notification_email"
  fi

  if test "${IPADDR#*$iot}" != "$IPADDR"; then
      ( echo "Subject: $HOSTNAME    Connected"
        echo ""
        echo "NAME:  $HOSTNAME"
        echo ""
        echo "MAC:   $(echo "$MACADDR" | awk '{print toupper($0)}')"
        echo "IP:   $IPADDR" 
        echo ""
        echo "IoT") | sendmail "$notification_email"
  fi
fi
if [ "$ACTION" == "remove" ]; then

  if test "${IPADDR#*$lan}" != "$IPADDR"; then
      ( echo "Subject: $HOSTNAME    Disconnected"
        echo ""
        echo "NAME:  $HOSTNAME"
        echo ""
        echo "MAC:   $(echo "$MACADDR" | awk '{print toupper($0)}')"
        echo "IP:   $IPADDR" 
        echo ""
        echo "LAN") | sendmail "$notification_email"
  fi

  if test "${IPADDR#*$guest}" != "$IPADDR"; then
      ( echo "Subject: $HOSTNAME    Disconnected"
        echo ""
        echo "NAME:  $HOSTNAME"
        echo ""
        echo "MAC:   $(echo "$MACADDR" | awk '{print toupper($0)}')"
        echo "IP:   $IPADDR" 
        echo ""
        echo "Guest") | sendmail "$notification_email"
  fi

  if test "${IPADDR#*$iot}" != "$IPADDR"; then
      ( echo "Subject: $HOSTNAME    Disconnected"
        echo ""
        echo "NAME:  $HOSTNAME"
        echo ""
        echo "MAC:   $(echo "$MACADDR" | awk '{print toupper($0)}')"
        echo "IP:   $IPADDR" 
        echo ""
        echo "IoT") | sendmail "$notification_email"
  fi
fi

@hillz2
Copy link

hillz2 commented Feb 9, 2024

"$ACTION" == "remove"

This action doesn't work when someone's device disconnects from a wifi network, I have a workaround by pinging their device IP every minute and send me a notification when the ping fails but it's not very reliable, sometimes the ping fails when their device is still connected to my wifi

@bjalek
Copy link

bjalek commented Feb 9, 2024

"$ACTION" == "remove"

This action doesn't work when someone's device disconnects from a wifi network, I have a workaround by pinging their device IP every minute and send me a notification when the ping fails but it's not very reliable, sometimes the ping fails when their device is still connected to my wifi

You have to wait til DHCP lease time run out. Set up lease time shorter. I have 30m (=30 minutes).
Check out log file (/tmp/detect.log).

@hillz2
Copy link

hillz2 commented Feb 9, 2024

"$ACTION" == "remove"

This action doesn't work when someone's device disconnects from a wifi network, I have a workaround by pinging their device IP every minute and send me a notification when the ping fails but it's not very reliable, sometimes the ping fails when their device is still connected to my wifi

You have to wait til DHCP lease time run out. Set up lease time shorter. I have 30m (=30 minutes). Check out log file (/tmp/detect.log).

Correct me if I'm wrong here, if you set the lease time of 30 minutes doesn't that mean "$ACTION" == "remove" will always be triggered every 30 minutes ? And that doesn't even mean that a device is disconnected from wifi

@bjalek
Copy link

bjalek commented Feb 9, 2024

"$ACTION" == "remove"

This action doesn't work when someone's device disconnects from a wifi network, I have a workaround by pinging their device IP every minute and send me a notification when the ping fails but it's not very reliable, sometimes the ping fails when their device is still connected to my wifi

You have to wait til DHCP lease time run out. Set up lease time shorter. I have 30m (=30 minutes). Check out log file (/tmp/detect.log).

Correct me if I'm wrong here, if you set the lease time of 30 minutes doesn't that mean "$ACTION" == "remove" will always be triggered every 30 minutes ? And that doesn't even mean that a device is disconnected from wifi

Yes, Every 30 minutes will try DHCP add new lease or Update or remove lease. But you can specify every host own lease time or general lease time reduce to 2m (2 minutes).

I tried to use hostapd, but it was not ideal:

  1. lots of connections and disconections when signal is not perfect everywhere
  2. missing host IP in hostapd

If somebody have better soution please share it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment