diff -Nur dnsmasq-2.39-orig/bld/Makefile dnsmasq-2.39/bld/Makefile
--- dnsmasq-2.39-orig/bld/Makefile	2007-02-17 14:37:06.000000000 +0100
+++ dnsmasq-2.39/bld/Makefile	2007-05-20 18:23:44.000000000 +0200
@@ -2,7 +2,7 @@
 PKG_CONFIG ?= pkg-config
 
 
-OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o network.o \
+OBJS = cache.o rfc1035.o rfc1876.o util.o option.o forward.o isc.o network.o \
        dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
        helper.o tftp.o log.o
 
diff -Nur dnsmasq-2.39-orig/src/dnsmasq.h dnsmasq-2.39/src/dnsmasq.h
--- dnsmasq-2.39-orig/src/dnsmasq.h	2007-04-20 12:53:38.000000000 +0200
+++ dnsmasq-2.39/src/dnsmasq.h	2007-05-20 19:50:37.000000000 +0200
@@ -162,6 +162,12 @@
   struct interface_name *next;
 };
 
+struct loc_record {
+  char *name, loc[16];
+  unsigned short class;
+  struct loc_record *next;
+};
+
 union bigname {
   char name[MAXDNAME];
   union bigname *next; /* freelist */
@@ -476,6 +482,7 @@
   struct mx_srv_record *mxnames;
   struct txt_record *txt;
   struct ptr_record *ptr;
+	struct loc_record *loc;
   struct interface_name *int_names;
   char *mxtarget;
   char *lease_file; 
@@ -725,3 +732,6 @@
 void tftp_request(struct listener *listen, struct daemon *daemon, time_t now);
 void check_tftp_listeners(struct daemon *daemon, fd_set *rset, time_t now);
 #endif
+
+/* rfc1876 */
+u_int32_t loc_aton(const char *ascii, u_char *binary);
diff -Nur dnsmasq-2.39-orig/src/option.c dnsmasq-2.39/src/option.c
--- dnsmasq-2.39-orig/src/option.c	2007-04-19 23:34:49.000000000 +0200
+++ dnsmasq-2.39/src/option.c	2007-05-20 20:15:15.000000000 +0200
@@ -43,6 +43,7 @@
 #define LOPT_REMOTE    269
 #define LOPT_SUBSCR    270
 #define LOPT_INTNAME   271
+#define LOPT_LOC       272
 
 #ifdef HAVE_GETOPT_LONG
 static const struct option opts[] =  
@@ -122,6 +123,7 @@
     {"tftp-root", 1, 0, LOPT_PREFIX },
     {"tftp-max", 1, 0, LOPT_TFTP_MAX },
     {"ptr-record", 1, 0, LOPT_PTR },
+    {"loc-record", 1, 0, LOPT_LOC },
 #if defined(__FreeBSD__) || defined(__DragonFly__)
     {"bridge-interface", 1, 0 , LOPT_BRIDGE },
 #endif
@@ -235,6 +237,7 @@
   { "-y, --localise-queries", gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
   { "-Y  --txt-record=name,txt....", gettext_noop("Specify TXT DNS record."), NULL },
   { "    --ptr-record=name,target", gettext_noop("Specify PTR DNS record."), NULL },
+  { "    --loc-record=name,lat lon alt", gettext_noop("Specify LOC DNS record."), NULL },
   { "    --interface-name=name,interface", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
   { "-z, --bind-interfaces", gettext_noop("Bind only to interfaces in use."), NULL },
   { "-Z, --read-ethers", gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
@@ -1835,6 +1838,37 @@
 	new->intr = safe_string_alloc(comma);
 	break;
       }
+      
+    case LOPT_LOC:
+      {
+	struct loc_record *new;
+	unsigned char *p, *q;
+	
+	comma = split(arg);
+	
+	if (!canonicalise_opt(arg))
+	  {
+	    option = '?';
+	    problem = _("bad LOC record");
+	    break;
+	  }
+	
+	new = safe_malloc(sizeof(struct loc_record));
+	new->next = daemon->loc;
+	daemon->loc = new;
+	new->class = C_IN;
+	if (!comma || loc_aton(comma,new->loc)!=16)
+	  {
+	    option = '?';
+	    problem = _("bad LOC record");
+	    break;
+	  }
+
+	if (comma)
+	  *comma = 0;
+	new->name = safe_string_alloc(arg);
+	break;
+      }
 
     case LOPT_PTR:  /* --ptr-record */
       {
diff -Nur dnsmasq-2.39-orig/src/rfc1035.c dnsmasq-2.39/src/rfc1035.c
--- dnsmasq-2.39-orig/src/rfc1035.c	2007-04-20 12:54:26.000000000 +0200
+++ dnsmasq-2.39/src/rfc1035.c	2007-05-20 18:22:46.000000000 +0200
@@ -1112,6 +1112,27 @@
 	    }
 	}
 
+      if (qtype == T_LOC || qtype == T_ANY)
+	{
+	  struct loc_record *t;
+	  for(t = daemon->loc; t ; t = t->next)
+	    {
+	      if (t->class == qclass && hostname_isequal(name, t->name))
+		{
+		  ans = 1;
+		  if (!dryrun)
+		    {
+		      log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, 0, NULL, 0);
+		      if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, 
+					      daemon->local_ttl, NULL,
+					      T_LOC, t->class, "t", 16, t->loc))
+			anscount++;
+
+		    }
+		}
+	    }
+	}
+
       if (qclass == C_IN)
 	{
 	  if (qtype == T_PTR || qtype == T_ANY)
diff -Nur dnsmasq-2.39-orig/src/rfc1876.c dnsmasq-2.39/src/rfc1876.c
--- dnsmasq-2.39-orig/src/rfc1876.c	1970-01-01 01:00:00.000000000 +0100
+++ dnsmasq-2.39/src/rfc1876.c	2007-05-20 19:50:10.000000000 +0200
@@ -0,0 +1,379 @@
+/*
+ * routines to convert between on-the-wire RR format and zone file
+ * format.  Does not contain conversion to/from decimal degrees;
+ * divide or multiply by 60*60*1000 for that.
+ */
+
+#include "dnsmasq.h"
+
+static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
+                                 1000000,10000000,100000000,1000000000};
+
+/* takes an XeY precision/size value, returns a string representation.*/
+static const char *
+precsize_ntoa(u_int8_t prec)
+{
+        static char retbuf[sizeof("90000000.00")];
+        unsigned long val;
+        int mantissa, exponent;
+
+        mantissa = (int)((prec >> 4) & 0x0f) % 10;
+        exponent = (int)((prec >> 0) & 0x0f) % 10;
+
+        val = mantissa * poweroften[exponent];
+
+        (void) sprintf(retbuf,"%d.%.2d", val/100, val%100);
+        return (retbuf);
+}
+
+/* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer.*/
+static u_int8_t
+precsize_aton(char **strptr)
+{
+        unsigned int mval = 0, cmval = 0;
+        u_int8_t retval = 0;
+        register char *cp;
+        register int exponent;
+        register int mantissa;
+
+        cp = *strptr;
+
+        while (isdigit(*cp))
+                mval = mval * 10 + (*cp++ - '0');
+
+        if (*cp == '.') {               /* centimeters */
+                cp++;
+                if (isdigit(*cp)) {
+                        cmval = (*cp++ - '0') * 10;
+                        if (isdigit(*cp)) {
+                                cmval += (*cp++ - '0');
+                        }
+                }
+        }
+        cmval = (mval * 100) + cmval;
+
+        for (exponent = 0; exponent < 9; exponent++)
+                if (cmval < poweroften[exponent+1])
+                        break;
+
+        mantissa = cmval / poweroften[exponent];
+        if (mantissa > 9)
+                mantissa = 9;
+
+        retval = (mantissa << 4) | exponent;
+
+        *strptr = cp;
+
+        return (retval);
+}
+
+/* converts ascii lat/lon to unsigned encoded 32-bit number.
+ *  moves pointer. */
+static u_int32_t
+latlon2ul(char **latlonstrptr,int *which)
+{
+        register char *cp;
+        u_int32_t retval;
+        int deg = 0, min = 0, secs = 0, secsfrac = 0;
+
+        cp = *latlonstrptr;
+
+        while (isdigit(*cp))
+                deg = deg * 10 + (*cp++ - '0');
+
+        while (isspace(*cp))
+                cp++;
+
+        if (!(isdigit(*cp)))
+                goto fndhemi;
+
+        while (isdigit(*cp))
+                min = min * 10 + (*cp++ - '0');
+        while (isspace(*cp))
+                cp++;
+
+        if (!(isdigit(*cp)))
+                goto fndhemi;
+
+        while (isdigit(*cp))
+                secs = secs * 10 + (*cp++ - '0');
+
+        if (*cp == '.') {               /* decimal seconds */
+                cp++;
+                if (isdigit(*cp)) {
+                        secsfrac = (*cp++ - '0') * 100;
+                        if (isdigit(*cp)) {
+                                secsfrac += (*cp++ - '0') * 10;
+                                if (isdigit(*cp)) {
+                                        secsfrac += (*cp++ - '0');
+                                }
+                        }
+                }
+        }
+
+        while (!isspace(*cp))   /* if any trailing garbage */
+                cp++;
+
+        while (isspace(*cp))
+                cp++;
+
+ fndhemi:
+        switch (*cp) {
+        case 'N': case 'n':
+        case 'E': case 'e':
+                retval = ((unsigned)1<<31)
+                        + (((((deg * 60) + min) * 60) + secs) * 1000)
+                        + secsfrac;
+                break;
+        case 'S': case 's':
+        case 'W': case 'w':
+                retval = ((unsigned)1<<31)
+                        - (((((deg * 60) + min) * 60) + secs) * 1000)
+                        - secsfrac;
+                break;
+        default:
+                retval = 0;     /* invalid value -- indicates error */
+                break;
+        }
+
+        switch (*cp) {
+        case 'N': case 'n':
+        case 'S': case 's':
+                *which = 1;     /* latitude */
+                break;
+        case 'E': case 'e':
+        case 'W': case 'w':
+                *which = 2;     /* longitude */
+                break;
+        default:
+                *which = 0;     /* error */
+                break;
+        }
+
+        cp++;                   /* skip the hemisphere */
+
+        while (!isspace(*cp))   /* if any trailing garbage */
+                cp++;
+
+        while (isspace(*cp))    /* move to next field */
+                cp++;
+
+        *latlonstrptr = cp;
+
+        return (retval);
+}
+
+/* converts a zone file representation in a string to an RDATA
+ * on-the-wire representation. */
+u_int32_t
+loc_aton(const char *ascii, u_char *binary)
+{
+        const char *cp, *maxcp;
+        u_char *bcp;
+
+        u_int32_t latit = 0, longit = 0, alt = 0;
+        u_int32_t lltemp1 = 0, lltemp2 = 0;
+        int altmeters = 0, altfrac = 0, altsign = 1;
+        u_int8_t hp = 0x16;    /* default = 1e6 cm = 10000.00m = 10km */
+        u_int8_t vp = 0x13;    /* default = 1e3 cm = 10.00m */
+        u_int8_t siz = 0x12;   /* default = 1e2 cm = 1.00m */
+        int which1 = 0, which2 = 0;
+
+        cp = ascii;
+        maxcp = cp + strlen(ascii);
+
+        lltemp1 = latlon2ul(&cp, &which1);
+        lltemp2 = latlon2ul(&cp, &which2);
+
+        switch (which1 + which2) {
+        case 3:                 /* 1 + 2, the only valid combination */
+                if ((which1 == 1) && (which2 == 2)) { /* normal case */
+                        latit = lltemp1;
+                        longit = lltemp2;
+                } else if ((which1 == 2) && (which2 == 1)) {/*reversed*/
+                        longit = lltemp1;
+                        latit = lltemp2;
+                } else {        /* some kind of brokenness */
+                        return 0;
+                }
+                break;
+        default:                /* we didn't get one of each */
+                return 0;
+        }
+
+        /* altitude */
+        if (*cp == '-') {
+                altsign = -1;
+                cp++;
+        }
+
+        if (*cp == '+')
+                cp++;
+
+        while (isdigit(*cp))
+                altmeters = altmeters * 10 + (*cp++ - '0');
+
+        if (*cp == '.') {               /* decimal meters */
+                cp++;
+                if (isdigit(*cp)) {
+                        altfrac = (*cp++ - '0') * 10;
+                        if (isdigit(*cp)) {
+                                altfrac += (*cp++ - '0');
+                        }
+                }
+        }
+
+        alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
+
+        while (!isspace(*cp) && (cp < maxcp))
+                                           /* if trailing garbage or m */
+                cp++;
+
+        while (isspace(*cp) && (cp < maxcp))
+                cp++;
+        if (cp >= maxcp)
+                goto defaults;
+
+        siz = precsize_aton(&cp);
+
+        while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/
+                cp++;
+
+        while (isspace(*cp) && (cp < maxcp))
+                cp++;
+
+        if (cp >= maxcp)
+                goto defaults;
+
+        hp = precsize_aton(&cp);
+
+        while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/
+                cp++;
+
+        while (isspace(*cp) && (cp < maxcp))
+                cp++;
+
+        if (cp >= maxcp)
+                goto defaults;
+
+        vp = precsize_aton(&cp);
+
+ defaults:
+
+        bcp = binary;
+        *bcp++ = (u_int8_t) 0;  /* version byte */
+        *bcp++ = siz;
+        *bcp++ = hp;
+        *bcp++ = vp;
+        PUTLONG(latit,bcp);
+        PUTLONG(longit,bcp);
+        PUTLONG(alt,bcp);
+
+        return (16);            /* size of RR in octets */
+}
+
+/* takes an on-the-wire LOC RR and prints it in zone file
+ * (human readable) format. */
+char *
+loc_ntoa(const u_char *binary,char *ascii)
+{
+        static char tmpbuf[255*3];
+
+        register char *cp;
+        register const u_char *rcp;
+
+        int latdeg, latmin, latsec, latsecfrac;
+        int longdeg, longmin, longsec, longsecfrac;
+        char northsouth, eastwest;
+        int altmeters, altfrac, altsign;
+
+        const int referencealt = 100000 * 100;
+
+        int32_t latval, longval, altval;
+        u_int32_t templ;
+        u_int8_t sizeval, hpval, vpval, versionval;
+
+        char *sizestr, *hpstr, *vpstr;
+
+        rcp = binary;
+        if (ascii)
+                cp = ascii;
+        else {
+                cp = tmpbuf;
+        }
+
+        versionval = *rcp++;
+
+        if (versionval) {
+                sprintf(cp,"; error: unknown LOC RR version");
+                return (cp);
+        }
+
+        sizeval = *rcp++;
+
+        hpval = *rcp++;
+        vpval = *rcp++;
+
+        GETLONG(templ,rcp);
+        latval = (templ - ((unsigned)1<<31));
+
+        GETLONG(templ,rcp);
+        longval = (templ - ((unsigned)1<<31));
+
+        GETLONG(templ,rcp);
+        if (templ < referencealt) { /* below WGS 84 spheroid */
+                altval = referencealt - templ;
+                altsign = -1;
+        } else {
+                altval = templ - referencealt;
+                altsign = 1;
+        }
+
+        if (latval < 0) {
+                northsouth = 'S';
+                latval = -latval;
+        }
+        else
+                northsouth = 'N';
+
+        latsecfrac = latval % 1000;
+        latval = latval / 1000;
+        latsec = latval % 60;
+        latval = latval / 60;
+        latmin = latval % 60;
+        latval = latval / 60;
+        latdeg = latval;
+
+        if (longval < 0) {
+                eastwest = 'W';
+                longval = -longval;
+        }
+        else
+                eastwest = 'E';
+
+        longsecfrac = longval % 1000;
+        longval = longval / 1000;
+        longsec = longval % 60;
+        longval = longval / 60;
+        longmin = longval % 60;
+        longval = longval / 60;
+        longdeg = longval;
+
+        altfrac = altval % 100;
+        altmeters = (altval / 100) * altsign;
+
+        sizestr = strdup(precsize_ntoa(sizeval));
+        hpstr = strdup(precsize_ntoa(hpval));
+        vpstr = strdup(precsize_ntoa(vpval));
+
+        sprintf(cp,
+                "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm",
+                latdeg, latmin, latsec, latsecfrac, northsouth,
+                longdeg, longmin, longsec, longsecfrac, eastwest,
+                altmeters, altfrac, sizestr, hpstr, vpstr);
+        free(sizestr);
+        free(hpstr);
+        free(vpstr);
+
+        return (cp);
+}
