]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add filter option
authorAlan T. DeKok <aland@freeradius.org>
Tue, 5 May 2020 14:10:16 +0000 (10:10 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 5 May 2020 14:10:23 +0000 (10:10 -0400)
raddb/sites-available/arp
src/modules/proto_arp/proto_arp_ethernet.c

index c5a1ef308003572a344a70e84f415e435527e889..bac16ddf21e51ab7c9e17bb03cd232afde7be4b6 100644 (file)
@@ -7,29 +7,19 @@
 #
 #  = ARP Virtual Server
 #
-#  This is a virtual server that handles ARP.
+#  This is a virtual server which reads ARP packets
 #
-#  It allows the administrator to log ARP packets on the
-#  local network.  The idea is that the ARP packets can be
-#  checked against a database (e.g. DHCP), or stored in
-#  an ARP-specific database.  If something funny is
-#  going on, it can produce syslog messages informing the
-#  administrator.
-#
-#  See `arpwatch` for examples of what it should do.   For now,
-#  this is just a toy example.
-#
-#  NOTE: It NEVER sends an ARP packet.
-#
-
-#
-#  ## Example configuration
+#  It allows the administrator to log ARP packets on the local
+#  network.  The idea is that the ARP packets can be checked against a
+#  database (e.g. DHCP), or stored in an ARP-specific database.  If
+#  something funny is going on, this virtual server can produce syslog
+#  messages informing the administrator as to what happened.
 #
 
 #
 #  ## server arp { ... }
 #
-#  This is the default `arp` virtual server.
+#  This is the `arp` virtual server.
 #
 server arp {
        #
@@ -53,10 +43,20 @@ server arp {
        #
        listen {
                #
-               #  interface:: The only configuration possible for ARP
-               #  is the name of the interface.
+               #  interface:: The name of the interface.
                #
                interface = en0
+
+               #
+               #  filter:: An optional PCAP filter.
+               #
+               #  If we want to receive only ARPs for a particular
+               #  IP address, then we list it here as `host foo`
+               #
+               #  You can also filter on ethernet via
+               #  `ether src foo` or `ether dst foo`.
+               #
+#              filter = "host 192.0.2.1"
        }
 
 #
index 2963f0ec4468d402973309a2479d1add486ec977..faac9de5c239ff0a9389a5015c8f3c2e36c117eb 100644 (file)
@@ -46,6 +46,7 @@ typedef struct {
 typedef struct {
        CONF_SECTION                    *cs;                    //!< our configuration
        char const                      *interface;             //!< Interface to bind to.
+       char const                      *filter;                //!< Additional PCAP filter
 } proto_arp_ethernet_t;
 
 
@@ -56,9 +57,7 @@ static CONF_PARSER const arp_listen_config[] = {
        { FR_CONF_OFFSET("interface", FR_TYPE_STRING | FR_TYPE_NOT_EMPTY, proto_arp_ethernet_t,
                          interface), .dflt = "eth0" },
 
-       /*
-        *      @todo - allow for pcap filter
-        */
+       { FR_CONF_OFFSET("filter", FR_TYPE_STRING, proto_arp_ethernet_t, filter) },
 
        CONF_PARSER_TERMINATOR
 };
@@ -166,6 +165,8 @@ static int mod_open(fr_listen_t *li)
 
        CONF_SECTION                    *server_cs;
        CONF_ITEM                       *ci;
+       char const                      *filter;
+       char                            buffer[256];
 
        thread->pcap = fr_pcap_init(thread, inst->interface, PCAP_INTERFACE_IN);
        if (!thread->pcap) {
@@ -179,12 +180,17 @@ static int mod_open(fr_listen_t *li)
        }
 
        /*
-        *      Ensure that we only get ARP.
-        *
-        *      @todo - only get ARP requests?
+        *      Ensure that we only get ARP, and an optional additional filter.
         */
-       if (fr_pcap_apply_filter(thread->pcap, "arp") < 0) {
-               PERROR("Failed applying pcap filter");
+       if (!inst->filter) {
+               filter = "arp";
+       } else {
+               filter = buffer;
+               snprintf(buffer, sizeof(buffer), "arp and %s", filter);
+       }
+
+       if (fr_pcap_apply_filter(thread->pcap, filter) < 0) {
+               PERROR("Failed applying pcap filter '%s'", filter);
                return -1;
        }