[Dnsmasq-discuss] [PATCH 2/2 v2] Add D-Bus methods to add or remove a lease from the internal database.

Nicolas Cavallari nicolas.cavallari at green-communications.fr
Tue Jun 9 11:14:27 BST 2015


AddDhcpLease can be used to add or update a lease in the internal
database, while DeleteDhcpLease deletes a lease.

These methods will still trigger the notifications via D-Bus or the
lease script.

Update the dbus/DBus-interface document accordingly.
---
 dbus/DBus-interface |  74 ++++++++++++++++++
 src/dbus.c          | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 289 insertions(+)

diff --git a/dbus/DBus-interface b/dbus/DBus-interface
index 9a895eb..2db5c30 100644
--- a/dbus/DBus-interface
+++ b/dbus/DBus-interface
@@ -169,6 +169,80 @@ Return an array of strings, each string is the IP address of an upstream
 server which has been found to loop queries back to this dnsmasq instance, and 
 it therefore not being used.
 
+AddDhcpLease
+------------
+
+Returns nothing. Adds or updates a DHCP or DHCPv6 lease to the internal lease
+database, as if a client requested and obtained a lease.
+
+If a lease for the IPv4 or IPv6 address already exist, it is overwritten.
+
+Note that this function will trigger the DhcpLeaseAdded or DhcpLeaseUpdated
+D-Bus signal and will run the configured DHCP lease script accordingly.
+
+This function takes many arguments which are the lease parameters:
+- A string with the textual representation of the IPv4 or IPv6 address of the
+  client.
+
+  Examples:
+  "192.168.1.115"
+  "1003:1234:abcd::1%eth0"
+  "2001:db8:abcd::1"
+
+- A string representing the hardware address of the client, using the same
+  format as the one used in the lease database.
+
+  Examples:
+
+  "00:23:45:67:89:ab"
+  "06-00:20:e0:3b:13:af" (token ring)
+
+- The hostname of the client, as an array of bytes (so there is no problem
+  with non-ASCII character encoding). May be empty.
+
+  Example (for "hostname.or.fqdn"):
+  [104, 111, 115, 116, 110, 97, 109, 101, 46, 111, 114, 46, 102, 113, 100, 110]
+
+- The client identifier (IPv4) or DUID (IPv6) as an array of bytes. May be
+  empty.
+
+  Examples:
+
+  DHCPv6 DUID:
+  [0, 3, 0, 1, 0, 35, 69, 103, 137, 171]
+  DHCPv4 client identifier:
+  [255, 12, 34, 56, 78, 0, 1, 0, 1, 29, 9, 99, 190, 35, 69, 103, 137, 171]
+
+- The duration of the lease, in seconds. If the lease is updated, then
+  the duration replaces the previous duration.
+
+  Example:
+
+  7200
+
+- The IAID (Identity association identifier) of the DHCPv6 lease, as a network
+  byte-order unsigned integer. For DHCPv4 leases, this must be set to 0.
+
+  Example (for IPv6):
+
+  203569230
+
+- A boolean which, if true, indicates that the DHCPv6 lease is for a temporary
+  address (IA_TA). If false, the DHCPv6 lease is for a non-temporary address
+  (IA_NA). For DHCPv4 leases, this must be set to false.
+
+RemoveDhcpLease
+---------------
+
+Returns nothing. Removes a DHCP or DHCPv6 lease to the internal lease
+database, as if a client sent a release message to abandon a lease.
+
+This function takes only one parameter: the text representation of the
+IPv4 or IPv6 address of the lease to remove.
+
+Note that this function will trigger the DhcpLeaseRemoved signal and the
+configured DHCP lease script will be run with the "del" action.
+
 
 
 2. SIGNALS
diff --git a/src/dbus.c b/src/dbus.c
index 5b69de5..852351e 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -70,6 +70,21 @@ const char* introspection_xml_template =
 "      <arg name=\"hwaddr\" type=\"s\"/>\n"
 "      <arg name=\"hostname\" type=\"s\"/>\n"
 "    </signal>\n"
+#ifdef HAVE_DHCP
+"    <method name=\"AddDhcpLease\">\n"
+"       <arg name=\"ipaddr\" type=\"s\"/>\n"
+"       <arg name=\"hwaddr\" type=\"s\"/>\n"
+"       <arg name=\"hostname\" type=\"ay\"/>\n"
+"       <arg name=\"clid\" type=\"ay\"/>\n"
+"       <arg name=\"lease_duration\" type=\"u\"/>\n"
+"       <arg name=\"ia_id\" type=\"u\"/>\n"
+"       <arg name=\"is_temporary\" type=\"b\"/>\n"
+"    </method>\n"
+"    <method name=\"DeleteDhcpLease\">\n"
+"       <arg name=\"ipaddr\" type=\"s\"/>\n"
+"       <arg name=\"success\" type=\"b\" direction=\"out\"/>\n"
+"    </method>\n"
+#endif
 "  </interface>\n"
 "</node>\n";
 
@@ -433,6 +448,196 @@ static DBusMessage *dbus_set_bool(DBusMessage *message, int flag, char *name)
   return NULL;
 }
 
+#ifdef HAVE_DHCP
+static DBusMessage *dbus_add_lease(DBusMessage* message)
+{
+  struct dhcp_lease *lease;
+  const char *ipaddr, *hwaddr, *hostname, *tmp;
+  const unsigned char* clid;
+  int clid_len, hostname_len, hw_len, hw_type;
+  dbus_uint32_t expires, ia_id;
+  dbus_bool_t is_temporary;
+  struct all_addr addr;
+  time_t time_now;
+  unsigned char dhcp_chaddr[DHCP_CHADDR_MAX];
+
+  DBusMessageIter iter, array_iter;
+  if (!dbus_message_iter_init(message, &iter))
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Failed to initialize dbus message iter");
+    }
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Expected string as first argument");
+    }
+  dbus_message_iter_get_basic(&iter, &ipaddr);
+  dbus_message_iter_next(&iter);
+
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Expected string as second argument");
+    }
+  dbus_message_iter_get_basic(&iter, &hwaddr);
+  dbus_message_iter_next(&iter);
+
+  if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
+      (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Expected byte array as third argument");
+    }
+  dbus_message_iter_recurse(&iter, &array_iter);
+  dbus_message_iter_get_fixed_array(&array_iter, &hostname, &hostname_len);
+  tmp = memchr(hostname, '\0', hostname_len);
+  if (tmp)
+    {
+      if (tmp == &hostname[hostname_len - 1])
+        {
+          hostname_len--;
+        }
+      else
+        {
+          return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                        "Hostname contains an embedded NUL character");
+        }
+    }
+  dbus_message_iter_next(&iter);
+
+  if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
+      (dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Expected byte array as fourth argument");
+    }
+  dbus_message_iter_recurse(&iter, &array_iter);
+  dbus_message_iter_get_fixed_array(&array_iter, &clid, &clid_len);
+  dbus_message_iter_next(&iter);
+
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Expected uint32 as fifth argument");
+    }
+  dbus_message_iter_get_basic(&iter, &expires);
+  dbus_message_iter_next(&iter);
+
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Expected uint32 as sixth argument");
+    }
+  dbus_message_iter_get_basic(&iter, &ia_id);
+  dbus_message_iter_next(&iter);
+
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Expected uint32 as sixth argument");
+    }
+  dbus_message_iter_get_basic(&iter, &is_temporary);
+
+  if (inet_pton(AF_INET, ipaddr, &addr.addr.addr4))
+    {
+      if (ia_id != 0 || is_temporary)
+	{
+	  return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					"ia_id and is_temporary must be zero for IPv4 lease");
+	}
+      lease = lease_find_by_addr(addr.addr.addr4);
+      if (lease == NULL)
+	{
+	  lease = lease4_allocate(addr.addr.addr4);
+	}
+    }
+#ifdef HAVE_DHCP6
+  else if (inet_pton(AF_INET6, ipaddr, &addr.addr.addr6))
+    {
+      lease = lease6_find_by_addr(&addr.addr.addr6, 128, 0);
+      if (lease == NULL)
+	{
+	  lease = lease6_allocate(&addr.addr.addr6,
+				  is_temporary ? LEASE_TA : LEASE_NA);
+	}
+      lease_set_iaid(lease, ia_id);
+    }
+#endif
+  else
+    {
+      return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
+					   "Invalid IP address '%s'", ipaddr);
+    }
+  hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL,
+		     &hw_type);
+  if (hw_type == 0 && hw_len != 0)
+    hw_type = ARPHRD_ETHER;
+
+  time_now = dnsmasq_time();
+  lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
+                   clid_len, time_now, 0);
+  lease_set_expires(lease, expires, time_now);
+  if (hostname_len)
+    {
+      lease_set_hostname(lease, hostname, 0, get_domain(lease->addr), NULL);
+    }
+  return NULL;
+}
+
+static DBusMessage *dbus_del_lease(DBusMessage* message)
+{
+  struct dhcp_lease *lease;
+  DBusMessageIter iter;
+  const char *ipaddr;
+  DBusMessage *reply;
+  struct all_addr addr;
+  dbus_bool_t ret = 1;
+  if (!dbus_message_iter_init(message, &iter))
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Failed to initialize dbus message iter");
+    }
+  if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+    {
+      return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+                                    "Expected string as first argument");
+    }
+  dbus_message_iter_get_basic(&iter, &ipaddr);
+
+  if (inet_pton(AF_INET, ipaddr, &addr.addr.addr4))
+    {
+      lease = lease_find_by_addr(addr.addr.addr4);
+    }
+#ifdef HAVE_DHCP6
+  else if (inet_pton(AF_INET6, ipaddr, &addr.addr.addr6))
+    {
+      lease = lease6_find_by_addr(&addr.addr.addr6, 128, 0);
+    }
+#endif
+  else
+    {
+      return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
+					   "Invalid IP address '%s'", ipaddr);
+    }
+
+  if (lease != NULL)
+    {
+      lease_prune(lease, 0);
+    }
+  else
+    {
+      ret = 0;
+    }
+  reply = dbus_message_new_method_return(message);
+  if (reply != NULL)
+    {
+      dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &ret,
+			       DBUS_TYPE_INVALID);
+    }
+  return reply;
+}
+#endif
 DBusHandlerResult message_handler(DBusConnection *connection, 
 				  DBusMessage *message, 
 				  void *user_data)
@@ -490,6 +695,16 @@ DBusHandlerResult message_handler(DBusConnection *connection,
     {
       reply = dbus_set_bool(message, OPT_BOGUSPRIV, "bogus-priv");
     }
+#ifdef HAVE_DHCP
+  else if (strcmp(method, "AddDhcpLease") == 0)
+    {
+      reply = dbus_add_lease(message);
+    }
+  else if (strcmp(method, "DeleteDhcpLease") == 0)
+    {
+      reply = dbus_del_lease(message);
+    }
+#endif
   else if (strcmp(method, "ClearCache") == 0)
     clear_cache = 1;
   else
-- 
2.1.4




More information about the Dnsmasq-discuss mailing list