import of dnsmasq-2.33.tar.gz
diff --git a/contrib/wrt/Makefile b/contrib/wrt/Makefile
new file mode 100644
index 0000000..abda96a
--- /dev/null
+++ b/contrib/wrt/Makefile
@@ -0,0 +1,7 @@
+CFLAGS?= -O2
+
+all: dhcp_release.c
+	$(CC) $(CFLAGS) $(RPM_OPT_FLAGS) -Wall -W dhcp_release.c -o dhcp_release
+
+clean:
+	rm -f *~ *.o core dhcp_release
diff --git a/contrib/wrt/README b/contrib/wrt/README
new file mode 100644
index 0000000..862046f
--- /dev/null
+++ b/contrib/wrt/README
@@ -0,0 +1,81 @@
+This script can be used to implement persistent leases on openWRT, DD-WRT
+etc. Persistent leases are good: if the lease database is lost on a
+reboot, then it will eventually be restored as hosts renew their
+leases. Until a host renews (which may take hours/days) it will
+not exist in the DNS if dnsmasq's DDNS function is in use.
+
+*WRT systems remount all non-volatile fileystems read-only after boot,
+so the normal leasefile will not work. They do, however have NV
+storage, accessed with the nvram command:
+
+/usr/lib #  nvram
+usage: nvram [get name] [set name=value] [unset name] [show]
+
+The principle is that leases are kept in NV variable with data
+corresponding to the line in a leasefile:
+
+dnsmasq_lease_192.168.1.56=3600 00:41:4a:05:80:74 192.168.1.56 * *
+
+By giving dnsmasq the leasefile-ro command, it no longer creates or writes a
+leasefile; responsibility for maintaining the lease database transfers
+to the lease change script. At startup, in leasefile-ro mode,
+dnsmasq will run
+
+"<lease_change_script> init" 
+
+and read whatever that command spits out, expecting it to
+be in dnsmasq leasefile format.
+
+So the lease change script, given "init" as argv[1] will 
+suck existing leases out of the NVRAM and emit them from
+stdout in the correct format.
+
+The second part of the problem is keeping the NVRAM up-to-date: this
+is done by the lease-change script which dnsmasq runs when a lease is
+updated. When it is called with argv[1] as "old", "add", or "del"
+it updates the relevant nvram entry.
+
+So, dnsmasq should be run as :
+
+dnsmasq --leasefile-ro --dhcp-script=/path/to/lease_update.sh
+
+or the same flags added to /etc/dnsmasq.conf
+
+
+
+Notes: 
+
+This needs dnsmasq-2.33 or later to work.
+
+This technique will work with, or without, compilation with
+HAVE_BROKEN_RTC. Compiling with HAVE_BROKEN_RTC is
+_highly_recommended_ for this application since is avoids problems
+with the system clock being warped by NTP, and it vastly reduces the
+number of writes to the NVRAM. With HAVE_BROKEN_RTC, NVRAM is updated
+only when a lease is created or destroyed; without it, a write occurs
+every time a lease is renewed.
+
+It probably makes sense to restrict the number of active DHCP leases
+to an appropriate number using dhcp-lease-max. On a new DD_WRT system,
+there are about 10K bytes free in the NVRAM. Each lease record is
+about 100 bytes, so restricting the number of leases to 50 will limit
+use to half that. (The default limit in the distributed source is 150)
+
+Any UI script which reads the dnsmasq leasefile will have to be
+ammended, probably by changing it to read the output of 
+`lease_update init` instead.
+ 
+
+Thanks:
+
+To Steve Horbachuk for checks on the script and debugging beyond the 
+call of duty.
+
+
+Simon Kelley
+Fri Jul 28 11:51:13 BST 2006
+
+
+
+
+
diff --git a/contrib/wrt/dhcp_release.c b/contrib/wrt/dhcp_release.c
new file mode 100644
index 0000000..2ee98c2
--- /dev/null
+++ b/contrib/wrt/dhcp_release.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2006 Simon Kelley
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 dated June, 1991.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+/* dhcp_release <interface> <address> <MAC address> <client_id>
+   MUST be run as root - will fail otherwise. */
+
+/* Send a DHCPRELEASE message via the specified interface 
+   to tell the local DHCP server to delete a particular lease. 
+   
+   The interface argument is the interface in which a DHCP
+   request _would_ be received if it was coming from the client, 
+   rather than being faked up here.
+   
+   The address argument is a dotted-quad IP addresses and mandatory. 
+   
+   The MAC address is colon separated hex, and is mandatory. It may be 
+   prefixed by an address-type byte followed by -, eg
+
+   10-11:22:33:44:55:66
+
+   but if the address-type byte is missing it is assumed to be 1, the type 
+   for ethernet. This encoding is the one used in dnsmasq lease files.
+
+   The client-id is optional. If it is "*" then it treated as being missing.
+*/
+
+#include <sys/types.h> 
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+
+#define DHCP_CHADDR_MAX          16
+#define BOOTREQUEST              1
+#define DHCP_COOKIE              0x63825363
+#define OPTION_SERVER_IDENTIFIER 54
+#define OPTION_CLIENT_ID         61
+#define OPTION_MESSAGE_TYPE      53
+#define OPTION_END               255
+#define DHCPRELEASE              7
+#define DHCP_SERVER_PORT         67
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+struct dhcp_packet {
+  u8 op, htype, hlen, hops;
+  u32 xid;
+  u16 secs, flags;
+  struct in_addr ciaddr, yiaddr, siaddr, giaddr;
+  u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
+  u32 cookie;
+  unsigned char options[308];
+};
+
+static int parse_hex(char *in, unsigned char *out, int maxlen, int *mac_type)
+{
+  int i = 0;
+  char *r;
+    
+  if (mac_type)
+    *mac_type = 0;
+  
+  while (maxlen == -1 || i < maxlen)
+    {
+      for (r = in; *r != 0 && *r != ':' && *r != '-'; r++);
+      if (*r == 0)
+        maxlen = i;
+      
+      if (r != in )
+        {
+          if (*r == '-' && i == 0 && mac_type)
+           {
+              *r = 0;
+              *mac_type = strtol(in, NULL, 16);
+              mac_type = NULL;
+           }
+          else
+            {
+              *r = 0;
+	      out[i] = strtol(in, NULL, 16);
+              i++;
+            }
+        }
+      in = r+1;
+    }
+    return i;
+}
+
+int main(int argc, char **argv)
+{ 
+  struct in_addr server, lease;
+  int mac_type;
+  struct dhcp_packet packet;
+  unsigned char *p = packet.options;
+  struct sockaddr_in dest;
+  struct ifreq ifr;
+  int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+  if (argc < 4 || argc > 5)
+    { 
+      fprintf(stderr, "usage: dhcp_release <interface> <addr> <mac> [<client_id>]\n");
+      exit(1);
+    }
+
+  if (fd == -1)
+    {
+      perror("cannot create socket");
+      exit(1);
+    }
+  
+  /* This voodoo fakes up a packet coming from the correct interface, which really matters for 
+     a DHCP server */
+  strcpy(ifr.ifr_name, argv[1]);
+  ifr.ifr_addr.sa_family = AF_INET;
+  if (ioctl(fd, SIOCGIFADDR, &ifr) == -1 || setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
+    {
+      perror("cannot setup interface");
+      exit(1);
+    }
+  
+  server = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
+  lease.s_addr = inet_addr(argv[2]);
+  
+  memset(&packet, 0, sizeof(packet));
+ 
+  packet.hlen = parse_hex(argv[3], packet.chaddr, DHCP_CHADDR_MAX, &mac_type);
+  if (mac_type == 0)
+    packet.htype = ARPHRD_ETHER;
+  else
+    packet.htype = mac_type;
+
+  packet.op = BOOTREQUEST;
+  packet.ciaddr = lease;
+  packet.cookie = htonl(DHCP_COOKIE);
+
+  *(p++) = OPTION_MESSAGE_TYPE;
+  *(p++) = 1;
+  *(p++) = DHCPRELEASE;
+
+  *(p++) = OPTION_SERVER_IDENTIFIER;
+  *(p++) = sizeof(server);
+  memcpy(p, &server, sizeof(server));
+  p += sizeof(server);
+
+  if (argc == 5 && strcmp(argv[4], "*") != 0)
+    {
+      unsigned int clid_len = parse_hex(argv[4], p+2, 255, NULL);
+      *(p++) = OPTION_CLIENT_ID;
+      *(p++) = clid_len;
+      p += clid_len;
+    }
+  
+  *(p++) = OPTION_END;
+ 
+  dest.sin_family = AF_INET;
+  dest.sin_port = ntohs(DHCP_SERVER_PORT);
+  dest.sin_addr = server;
+
+  if (sendto(fd, &packet, sizeof(packet), 0, 
+	     (struct sockaddr *)&dest, sizeof(dest)) == 1)
+    {
+      perror("sendto failed");
+      exit(1);
+    }
+
+  return 0;
+}
diff --git a/contrib/wrt/lease_update.sh b/contrib/wrt/lease_update.sh
new file mode 100755
index 0000000..2171d6b
--- /dev/null
+++ b/contrib/wrt/lease_update.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+# Copyright (c) 2006 Simon Kelley
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; version 2 dated June, 1991.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+
+
+# if $1 is add del or old, this is a dnsmasq-called lease-change
+# script, update the nvram database. if $1 is init, emit a 
+# dnsmasq-format lease file to stdout representing the current state of the 
+# database, this is called by dnsmasq at startup.
+
+NVRAM=/usr/sbin/nvram
+PREFIX=dnsmasq_lease_
+
+# Arguments.
+# $1 is action (add, del, old)
+# $2 is MAC 
+# $3 is address
+# $4 is hostname (optional, may be unset)
+
+# env.
+# DNSMASQ_LEASE_LENGTH or DNSMASQ_LEASE_EXPIRES (which depends on HAVE_BROKEN_RTC)
+# DNSMASQ_CLIENT_ID (optional, may be unset)
+
+# File.
+# length|expires MAC addr hostname|* CLID|* 
+
+# Primary key is address.
+
+NVRAM=/usr/sbin/nvram
+PREFIX=dnsmasq_lease_
+
+if [ ${1} = init ] ; then
+     ${NVRAM} show | sed -n -e "/^${PREFIX}.*/ s/^.*=//p"
+else
+     if [ ${1} = del ] ; then
+          ${NVRAM} unset ${PREFIX}${3}
+     fi
+
+     if [ ${1} = old ] || [ ${1} = add ] ; then
+          ${NVRAM} set ${PREFIX}${3}="${DNSMASQ_LEASE_LENGTH:-}${DNSMASQ_LEASE_EXPIRES:-} ${2} ${3} ${4:-*} ${DNSMASQ_CLIENT_ID:-*}"
+     fi
+     ${NVRAM} commit
+fi
+
+
+
+
+