Netgate Discussion Forum
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Search
    • Register
    • Login

    Arp2wol, small hack to send wake on lan frames based on arp requests.

    Scheduled Pinned Locked Moved Off-Topic & Non-Support Discussion
    19 Posts 7 Posters 7.0k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • GruensFroeschliG
      GruensFroeschli
      last edited by

      EDIT: second version below.
      Hi
      In a homesetup i have a server which can boot up very fast (~11 seconds).
      So i descided to shut it down whenever its ARP table is empty long enough (for now 20 minutes).
      To boot it up i have a small shellscript on the pfSense running which sends wake on lan packets if it detects an ARP lookup for the IP of this server.

      I thought someone might have some use for this:

      ~~#! /bin/sh

      This listens for arp lookups and triggers something (usually wol?)

      INTERFACE="vr2"
      TARGET_BROADCAST="10.0.8.255"
      TARGET_IP="10.0.8.13"
      TARGET_MAC="00🇩🇪ad:be:ef:99"

      stop="" #this is a hack to prevent tcpdump from looping unnecessarily in the while read (and executing the trigger a lot…)
      while true
      do
             tcpdump -S -l -n -i $INTERFACE arp dst $TARGET_IP | while read data
             do
                     if [ -z "$stop" ]; then
                             fping -c 1 $TARGET_IP
                             if [ "$?" -ne "0" ]; then
                                     logger -t arp2wol "$TARGET_IP is down, starting it."
                                     wol -i $TARGET_BROADCAST $TARGET_MAC
                             fi
                             killall tcpdump
                             stop="1"
                     fi
             done;
             sleep 60
             stop=""
      done;

      Something that just came to mind:
      This will probably break a running packet-capture in the webinterface if the script happens to trigger in the wrong moment.
      Just a warning ^^"~~

      We do what we must, because we can.

      Asking questions the smart way: http://www.catb.org/esr/faqs/smart-questions.html

      1 Reply Last reply Reply Quote 0
      • GruensFroeschliG
        GruensFroeschli
        last edited by

        This is the second version.
        It takes the destination IP, destination subnet and destination mac as parameter now.

        This version allow one to run it multiple times without interfering with other running tcpdumps.
        Also tcpdump runs without putting the interface into promiscuous mode.

        example to start it:
        arp2wol.sh 10.0.8.33 10.0.8.255 01🇩🇪ad:be:ef:33 &

        
        #! /bin/sh
        # This program listens for arp lookups and triggers something
        INTERFACE=vr2                   # Listen on this interface.
        RESTART="1200"                   # After the trigger, wait this long to start listening again.
        TARGET_IP=$1                    # Listen for this IP.
        TARGET_BROADCAST=$2             # Broadcast to send the wol frame to.
        TARGET_MAC=$3                   # MAC address to send the wol frame to.
        
        # Create path to initial pid file. add some randomness in case you want to run it multiple times
        pid="/var/run/dumper$(cat /dev/urandom | tr -dc '0-9' | head -c 10).pid"
        
        while true
        do
                # Check if not another process is using the same pidfile.
                while [ -f $pid ]
                do
                        pid="/var/run/dumper$(cat /dev/urandom | tr -dc '0-9' | head -c 10).pid"
                done;
        
                # Actually run tcpdump
                (tcpdump -p -S -l -n -i $INTERFACE arp dst $TARGET_IP & echo $! >&3 ) 3>$pid | while read data
                do
                        if [ -f $pid ]; then
                                fping -c 1 $TARGET_IP
                                if [ "$?" -ne "0" ]; then
                                        logger -t arp2wol "$TARGET_IP is down, starting it."
                                        wol -i $TARGET_BROADCAST $TARGET_MAC
                                fi
                                kill -9 $(cat $pid)
                                rm $pid
                        fi
                done;
                sleep $RESTART
        done;
        
        

        We do what we must, because we can.

        Asking questions the smart way: http://www.catb.org/esr/faqs/smart-questions.html

        1 Reply Last reply Reply Quote 0
        • D
          doktornotor Banned
          last edited by

          Interesting idea, thanks…

          1 Reply Last reply Reply Quote 0
          • K
            Kohji
            last edited by

            Thank you very much.
            In addition with the help from https://doc.pfsense.org/index.php/Executing_commands_at_boot_time
            it is the answer for my question :-)

            1 Reply Last reply Reply Quote 0
            • B
              bgarwin
              last edited by

              First wanted to thank GruensFroeschli,

              i used his script on ASUS 68U router then switched to PFSENSE, both works fine.
              However, in pfsense the "cat /dev/urandom" causes a loop when the script is used at shellcmd and observed a high CPU use.

              i modified the script slightly to fix this problem, any suggestion to enhance it would be great

              
              #! /bin/sh
              # This program listens for arp lookups and triggers something
              INTERFACE=re1                   # Listen on this interface.
              RESTART="120"                   # After the trigger, wait this long to start listening again.
              TARGET_IP=$1                    # Listen for this IP.
              TARGET_BROADCAST=$2             # Broadcast to send the wol frame to.
              TARGET_MAC=$3                   # MAC address to send the wol frame to.
              
              # Create path to initial pid file. add some randomness in case you want to run it multiple times
              #pid="/var/run/dumper$(cat /dev/urandom | tr -dc '0-9' | head -c 10).pid"
              pid="/var/run/dumper$$.pid"
              trap 'rm -f $pid; exit' EXIT SIGHUP SIGINT SIGTERM
              
              while true
              do
                      # check if not another process is using the same pidfile.
                      #while [ -f $pid ]
                      #do
                              #pid="/var/run/dumper$(cat /dev/urandom | tr -dc '0-9' | head -c 10).pid"
                              #pid="/var/run/dumper$$.pid"
                      #done;
              
                      # Actually run tcpdump
                      (/usr/sbin/tcpdump -p -S -l -n -v -i $INTERFACE arp dst $TARGET_IP & echo $! >&3 ) 3>$pid | while read data
                      do
                              if [ -f $pid ]; then
                                      /usr/local/sbin/fping -c 1 $TARGET_IP
                                      if [ "$?" -ne "0" ]; then
                                              /usr/bin/logger -t arp2wol "$TARGET_IP is down, starting it."
                                              /usr/local/bin/wol -i $TARGET_BROADCAST $TARGET_MAC
                                      fi
                                      kill -9 $(cat $pid)
                                      rm $pid
                              fi
                      done;
                      sleep $RESTART
              done;
              
              
              1 Reply Last reply Reply Quote 0
              • GruensFroeschliG
                GruensFroeschli
                last edited by

                hmmm.
                I'm running this still myself but i haven't seen a loop at all.
                What happens if you execute

                
                cat /dev/urandom | tr -dc '0-9' | head -c 10
                
                

                on a shell directly?

                Your change will not work if you start multiple instances from the same shell since $$ returns the pid of the shell where you ask for $$.
                –> Running it multiple time will reuse the same file and break.

                On pfSense you could use jot to get a random number and then remove the \n.
                e.g.
                jot -r 1 0 9999999999 | tr -d '\n'

                We do what we must, because we can.

                Asking questions the smart way: http://www.catb.org/esr/faqs/smart-questions.html

                1 Reply Last reply Reply Quote 0
                • B
                  bgarwin
                  last edited by

                  it works fine if i run it from the shell directly, it loops only when i run it on boot using shell comand or *sh file under /usr/local/etc/rc.d.

                  The $$ should have a different value(PID) every time you start the script, no? not sure this will work properly with scripts running in the background.

                  1 Reply Last reply Reply Quote 0
                  • GruensFroeschliG
                    GruensFroeschli
                    last edited by

                    @bgarwin:

                    The $$ should have a different value(PID) every time you start the script, no? not sure this will work properly with scripts running in the background.

                    No $$ returns the pid of the current shell.
                    If you fork multiple instance of the arp2wol.sh then all of them will have the same parent (the init script which executes it).
                    –> All of them will use the same pid-file.

                    We do what we must, because we can.

                    Asking questions the smart way: http://www.catb.org/esr/faqs/smart-questions.html

                    1 Reply Last reply Reply Quote 0
                    • B
                      bgarwin
                      last edited by

                      thank you let me test jot.

                      1 Reply Last reply Reply Quote 0
                      • B
                        bilbo
                        last edited by

                        Many thanks for this script  :D

                        Does this log the source of the arp request?

                        1 Reply Last reply Reply Quote 0
                        • GruensFroeschliG
                          GruensFroeschli
                          last edited by

                          Not really, but you can easily extend it to do this.
                          $data contains the line which triggered the event.
                          –> the arp responses look something like

                          13:22:24.457157 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 80.219.3.42 tell 80.219.2.1, length 46

                          We do what we must, because we can.

                          Asking questions the smart way: http://www.catb.org/esr/faqs/smart-questions.html

                          1 Reply Last reply Reply Quote 0
                          • B
                            bilbo
                            last edited by

                            Can this script to be modified to work across subnets ie the device I want to wake up in this instance is on a different subnet to everything that is waking it connected to lan interface em2, those devices waking it are connected to lan em1?

                            1 Reply Last reply Reply Quote 0
                            • GruensFroeschliG
                              GruensFroeschli
                              last edited by

                              I don't know, but this really has nothing to do with this script.

                              This script exists to trigger something based on ARP lookups.
                              What you trigger is your own thing.

                              Try reading the documentation of the /usr/local/bin/wol which is used on pfsense to send magic packet.

                              We do what we must, because we can.

                              Asking questions the smart way: http://www.catb.org/esr/faqs/smart-questions.html

                              1 Reply Last reply Reply Quote 0
                              • B
                                bilbo
                                last edited by

                                I am not 100% sure but I think all I need to do is remove "arp" from the tcpdump command and ensure $TARGET_BROADCAST $TARGET_MAC are those of the machine to be woken and $INTERFACE is the lan on the source machines trying to access the target?

                                1 Reply Last reply Reply Quote 0
                                • K
                                  kpa
                                  last edited by

                                  A client trying access a server on a different network segment (subnet) will never issue an ARP broadcast for the destination address because MAC addresses are local to the connected segment and access to the outside of the local segment is done via a gateway (the router in between the segments).  In other words, the MAC address of the destination host won't show up in the traffic of the client's network. You have to monitor the destination IP instead and then trigger the WOL action on the other network segment where the to be woken up hosts are.

                                  1 Reply Last reply Reply Quote 0
                                  • B
                                    bilbo
                                    last edited by

                                    Yep, removing the arp and it works great, I am actually doing it via port , thanks again for the script.

                                    1 Reply Last reply Reply Quote 0
                                    • GruensFroeschliG
                                      GruensFroeschli
                                      last edited by

                                      If you want to change what the tcpdump is looking for:
                                      Here is some documentation to that: http://www.tcpdump.org/manpages/pcap-filter.7.html

                                      We do what we must, because we can.

                                      Asking questions the smart way: http://www.catb.org/esr/faqs/smart-questions.html

                                      1 Reply Last reply Reply Quote 0
                                      • O
                                        orangewaters
                                        last edited by

                                        I am using the original script posted by @GruensFroeschli with shellcmd. The cpu usage jumps to 100% when I use shellcmd through gui. When I run it as a sh script in ssh, it runs fine and cpu usage stays at 5% but need to login each time after reboot to do that. I am a newbie. Any help is greatly appreciated. I am running 2.4.2-RELEASE-p1 (amd64). Thanks !

                                        1 Reply Last reply Reply Quote 0
                                        • O
                                          orangewaters
                                          last edited by

                                          Anyone have any suggestions .. TIA

                                          1 Reply Last reply Reply Quote 0
                                          • First post
                                            Last post
                                          Copyright 2025 Rubicon Communications LLC (Netgate). All rights reserved.