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

    Custom DHCP script

    Scheduled Pinned Locked Moved DHCP and DNS
    dhcpexecute
    5 Posts 2 Posters 782 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.
    • S
      Slyke
      last edited by Slyke

      Hello, I have created the following script:

      /usr/local/etc/rc.d/dhcpdoverride.sh file:

      #/bin/bash
      killall -3 dhcpd
      cat /var/dhcpd/etc/dhcpd.conf.ext >> /var/dhcpd/etc/dhcpd.conf
      # Run: 'ps axww | grep dhcpd' to get /var/run/dhcpd.pid args
      /usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot /var/dhcpd -cf /etc/dhcpd.conf -pf /var/run/dhcpd.pid igb1
      

      In the /var/dhcpd/etc/dhcpd.conf.ext file I have:

      on commit {
        set clip = binary-to-ascii(10, 8, ".", leased-address);
        set clhw = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6));
        execute("/etc/dhcp_update.sh", "commit", clip, clhw);
      }
      
      on expiry {
        set clip = binary-to-ascii(10, 8, ".", leased-address);
        set clhw = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6));
        execute("/etc/dhcp_update.sh", "expiry", clip, clhw);
      }
      
      on release {
        set clip = binary-to-ascii(10, 8, ".", leased-address);
        set clhw = binary-to-ascii(16, 8, ":", substring(hardware, 1, 6));
        execute("/etc/dhcp_update.sh", "release", clip, clhw);
      }
      

      This should execute the script every time one of those events is fired.

      AFAIK dhcpd is chrooted, so the path /etc/dhcp_update.sh should be used, but I also tried /var/dhcpd/etc/dhcp_update.sh just in case.

      However, I'm getting the following errors in dhcpd logs for both paths:

      Jun 25 02:56:14	dhcpd	90788	execute_statement argv[0] = /etc/dhcp_update.sh
      Jun 25 02:56:14	dhcpd	90788	execute_statement argv[1] = commit
      Jun 25 02:56:14	dhcpd	90788	execute_statement argv[2] = 10.1.1.123
      Jun 25 02:56:14	dhcpd	90788	execute_statement argv[3] = XX:XX:XX:XX:XX:XX
      Jun 25 02:56:14	dhcpd	23476	Unable to execute /etc/dhcp_update.sh: No such file or directory
      Jun 25 02:56:14	dhcpd	90788	execute: /etc/dhcp_update.sh exit status 32512
      

      I have run chmod +x /var/dhcpd/etc/dhcp_update.sh from the webui, as I was getting permission denied errors before that.

      I believe the error code 32512 is actually -127, but something funky is happening when reporting it.

      S 1 Reply Last reply Reply Quote 0
      • S
        Slyke @Slyke
        last edited by

        I think there is something wrong with dhcp. I tried using ls and /bin/ls and got the same error:

          execute("/bin/pwd");
          execute("/bin/ls");
        

        Returned:

        Jun 25 12:38:21	dhcpd	76036	execute_statement argv[0] = /bin/pwd
        Jun 25 12:38:21	dhcpd	86801	Unable to execute /bin/pwd: No such file or directory
        Jun 25 12:38:21	dhcpd	76036	execute: /bin/pwd exit status 32512
        Jun 25 12:38:21	dhcpd	76036	execute_statement argv[0] = /bin/ls
        Jun 25 12:38:21	dhcpd	87045	Unable to execute /bin/ls: No such file or directory
        Jun 25 12:38:21	dhcpd	76036	execute: /bin/ls exit status 32512
        
        bmeeksB 1 Reply Last reply Reply Quote 0
        • bmeeksB
          bmeeks @Slyke
          last edited by bmeeks

          @Slyke said in Custom DHCP script:

          I think there is something wrong with dhcp. I tried using ls and /bin/ls and got the same error:

            execute("/bin/pwd");
            execute("/bin/ls");
          

          Returned:

          Jun 25 12:38:21	dhcpd	76036	execute_statement argv[0] = /bin/pwd
          Jun 25 12:38:21	dhcpd	86801	Unable to execute /bin/pwd: No such file or directory
          Jun 25 12:38:21	dhcpd	76036	execute: /bin/pwd exit status 32512
          Jun 25 12:38:21	dhcpd	76036	execute_statement argv[0] = /bin/ls
          Jun 25 12:38:21	dhcpd	87045	Unable to execute /bin/ls: No such file or directory
          Jun 25 12:38:21	dhcpd	76036	execute: /bin/ls exit status 32512
          

          I am pretty sure the dhcpd daemon on pfSense runs in a chroot environment and possibly even a FreeBSD jail. That means certain binary utilities that are present on the main pfSense image will not be present and available for the chroot or jail clients.

          If you are not familiar with the concept of jails, here is the official FreeBSD documentation: https://docs.freebsd.org/en/books/handbook/jails/. Jails are essentially isolated environments that have the minimum files and permissions needed for the particular binary the jail was created for to execute and perform its assigned tasks.

          S 2 Replies Last reply Reply Quote 1
          • S
            Slyke @bmeeks
            last edited by Slyke

            @bmeeks Ah, that makes sense. I'm reading up on it now. Essentially what I'm trying to do is send a GET request when a client connects or disconnects to the network (using DHCP events). I'm just parsing the args and attempting to send a wget/curl command in the /etc/dhcp_update.sh script.

            Is there an easier way to do this while keeping dhcpd chrooted still? Or is there an easy way to add bash and/or curl to the process' chrooted environment? Or should I write some executable in c/c++ and send it that way? Not sure what's the easiest way to achieve this task, and the more I'm digging, the more complex and fragile the solution seems to become.

            1 Reply Last reply Reply Quote 0
            • S
              Slyke @bmeeks
              last edited by

              @bmeeks I solved it by copying both the curl and sh binaries into the chrooted folder and specifying the path to them directly:

              mkdir -p /var/dhcpd/bin
              mkdir -p /var/dhcpd/usr/local/bin
              
              cp /bin/bash /var/dhcpd/bin/
              cp /usr/local/bin/curl /var/dhcpd/usr/local/bin/
              

              Then in my /var/dhcpd/etc/dhcp_update.sh script:

              #!/bin/sh
              
              BASE_URL="http://your-web-server.com/your-endpoint"
              
              EVENT_TYPE="$1"
              IP_ADDRESS="$2"
              MAC_ADDRESS="$3"
              
              case "$EVENT_TYPE" in
                "1")
                  ONLINE_STATE="online"
                  ;;
                "2"|"3")
                  ONLINE_STATE="offline"
                  ;;
                *)
                  ONLINE_STATE="unknown"
                  ;;
              esac
              
              URL="${BASE_URL}?ip=${IP_ADDRESS}&mac=${MAC_ADDRESS}&state=${ONLINE_STATE}&event=${EVENT_TYPE}"
              echo "DHCP Announce: $URL"
              
              /usr/local/bin/curl -X GET "$URL"
              

              It aborted with exit code 6, which means that cURL couldn't resolve the hostname (good news!). I still haven't tested this with my proper endpoint, but I think it will work now.

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