1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include "utility.hh"
5 #include <cstdio>
6 #include <math.h>
7 #include <cstdlib>
8 #include <sys/types.h>
9 #include <string>
10 #include <errno.h>
11 #include "dnsrecords.hh"
12 
13 static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
14                                  1000000,10000000,100000000,1000000000};
15 
16 /* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer.*/
precsize_aton(const char ** strptr)17 static uint8_t precsize_aton(const char **strptr)
18 {
19   unsigned int mval = 0, cmval = 0;
20   uint8_t retval = 0;
21   const char *cp;
22   int exponent;
23   int mantissa;
24 
25   cp = *strptr;
26 
27   while (isdigit(*cp))
28     mval = mval * 10 + (*cp++ - '0');
29 
30   if (*cp == '.') {               /* centimeters */
31     cp++;
32     if (isdigit(*cp)) {
33       cmval = (*cp++ - '0') * 10;
34       if (isdigit(*cp)) {
35         cmval += (*cp++ - '0');
36       }
37     }
38   }
39   cmval = (mval * 100) + cmval;
40 
41   for (exponent = 0; exponent < 9; exponent++)
42     if (cmval < poweroften[exponent+1])
43       break;
44 
45   mantissa = cmval / poweroften[exponent];
46   if (mantissa > 9)
47     mantissa = 9;
48 
49   retval = (mantissa << 4) | exponent;
50 
51   *strptr = cp;
52 
53   return (retval);
54 }
55 
56 /* converts ascii lat/lon to unsigned encoded 32-bit number.
57  *  moves pointer. */
58 static uint32_t
latlon2ul(const char ** latlonstrptr,int * which)59 latlon2ul(const char **latlonstrptr, int *which)
60 {
61   const char *cp;
62   uint32_t retval;
63   int deg = 0, min = 0, secs = 0, secsfrac = 0;
64 
65   cp = *latlonstrptr;
66 
67   while (isdigit(*cp))
68     deg = deg * 10 + (*cp++ - '0');
69 
70   while (isspace(*cp))
71     cp++;
72 
73   if (!(isdigit(*cp)))
74     goto fndhemi;
75 
76   while (isdigit(*cp))
77     min = min * 10 + (*cp++ - '0');
78 
79   while (isspace(*cp))
80     cp++;
81 
82   if (*cp && !(isdigit(*cp)))
83     goto fndhemi;
84 
85   while (isdigit(*cp))
86     secs = secs * 10 + (*cp++ - '0');
87 
88   if (*cp == '.') {               /* decimal seconds */
89     cp++;
90     if (isdigit(*cp)) {
91       secsfrac = (*cp++ - '0') * 100;
92       if (isdigit(*cp)) {
93         secsfrac += (*cp++ - '0') * 10;
94         if (isdigit(*cp)) {
95           secsfrac += (*cp++ - '0');
96         }
97       }
98     }
99   }
100 
101   while (*cp && !isspace(*cp))   /* if any trailing garbage */
102     cp++;
103 
104   while (isspace(*cp))
105     cp++;
106 
107  fndhemi:
108   switch (*cp) {
109   case 'N': case 'n':
110   case 'E': case 'e':
111     retval = ((unsigned)1<<31)
112       + (((((deg * 60) + min) * 60) + secs) * 1000)
113       + secsfrac;
114     break;
115   case 'S': case 's':
116   case 'W': case 'w':
117     retval = ((unsigned)1<<31)
118       - (((((deg * 60) + min) * 60) + secs) * 1000)
119       - secsfrac;
120     break;
121   default:
122     retval = 0;     /* invalid value -- indicates error */
123     break;
124   }
125 
126   switch (*cp) {
127   case 'N': case 'n':
128   case 'S': case 's':
129     *which = 1;     /* latitude */
130     break;
131   case 'E': case 'e':
132   case 'W': case 'w':
133     *which = 2;     /* longitude */
134     break;
135   default:
136     *which = 0;     /* error */
137     break;
138   }
139 
140   if (!*cp)
141     return 0;
142 
143   cp++;                   /* skip the hemisphere */
144 
145   while (*cp && !isspace(*cp))   /* if any trailing garbage */
146     cp++;
147 
148   while (isspace(*cp))    /* move to next field */
149     cp++;
150 
151   *latlonstrptr = cp;
152 
153   return (retval);
154 }
155 
report()156 void LOCRecordContent::report()
157 {
158   regist(1, QType::LOC, &make, &make, "LOC");
159   regist(254, QType::LOC, &make, &make, "LOC");
160 }
161 
make(const string & content)162 std::shared_ptr<DNSRecordContent> LOCRecordContent::make(const string& content)
163 {
164   return std::make_shared<LOCRecordContent>(content);
165 }
166 
167 
toPacket(DNSPacketWriter & pw)168 void LOCRecordContent::toPacket(DNSPacketWriter& pw)
169 {
170   pw.xfr8BitInt(d_version);
171   pw.xfr8BitInt(d_size);
172   pw.xfr8BitInt(d_horizpre);
173   pw.xfr8BitInt(d_vertpre);
174 
175   pw.xfr32BitInt(d_latitude);
176   pw.xfr32BitInt(d_longitude);
177   pw.xfr32BitInt(d_altitude);
178 }
179 
make(const DNSRecord & dr,PacketReader & pr)180 std::shared_ptr<LOCRecordContent::DNSRecordContent> LOCRecordContent::make(const DNSRecord &dr, PacketReader& pr)
181 {
182   auto ret=std::make_shared<LOCRecordContent>();
183   pr.xfr8BitInt(ret->d_version);
184   pr.xfr8BitInt(ret->d_size);
185   pr.xfr8BitInt(ret->d_horizpre);
186   pr.xfr8BitInt(ret->d_vertpre);
187 
188   pr.xfr32BitInt(ret->d_latitude);
189   pr.xfr32BitInt(ret->d_longitude);
190   pr.xfr32BitInt(ret->d_altitude);
191 
192   return ret;
193 }
194 
LOCRecordContent(const string & content,const string & zone)195 LOCRecordContent::LOCRecordContent(const string& content, const string& zone)
196 {
197   // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m
198   // convert this to d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude
199   d_version = 0;
200 
201   const char *cp, *maxcp;
202 
203   uint32_t lltemp1 = 0, lltemp2 = 0;
204   int altmeters = 0, altfrac = 0, altsign = 1;
205   d_horizpre = 0x16;    /* default = 1e6 cm = 10000.00m = 10km */
206   d_vertpre = 0x13;    /* default = 1e3 cm = 10.00m */
207   d_size = 0x12;   /* default = 1e2 cm = 1.00m */
208   int which1 = 0, which2 = 0;
209 
210   cp = content.c_str();
211   maxcp = cp + strlen(content.c_str());
212 
213   lltemp1 = latlon2ul(&cp, &which1);
214   lltemp2 = latlon2ul(&cp, &which2);
215 
216   switch (which1 + which2) {
217   case 3:                 /* 1 + 2, the only valid combination */
218     if ((which1 == 1) && (which2 == 2)) { /* normal case */
219       d_latitude = lltemp1;
220       d_longitude = lltemp2;
221     } else if ((which1 == 2) && (which2 == 1)) {/*reversed*/
222       d_latitude = lltemp1;
223       d_longitude = lltemp2;
224     } else {        /* some kind of brokenness */
225       return;
226     }
227     break;
228   default:                /* we didn't get one of each */
229     throw MOADNSException("Error decoding LOC content");
230   }
231 
232   /* altitude */
233   if (*cp == '-') {
234     altsign = -1;
235     cp++;
236   }
237 
238   if (*cp == '+')
239     cp++;
240 
241   while (isdigit(*cp))
242     altmeters = altmeters * 10 + (*cp++ - '0');
243 
244   if (*cp == '.') {               /* decimal meters */
245     cp++;
246     if (isdigit(*cp)) {
247       altfrac = (*cp++ - '0') * 10;
248       if (isdigit(*cp)) {
249         altfrac += (*cp++ - '0');
250       }
251     }
252   }
253 
254   d_altitude = (10000000 + (altsign * (altmeters * 100 + altfrac)));
255 
256   while (!isspace(*cp) && (cp < maxcp))
257     /* if trailing garbage or m */
258     cp++;
259 
260   while (isspace(*cp) && (cp < maxcp))
261     cp++;
262 
263 
264   if (cp >= maxcp)
265     goto defaults;
266 
267   d_size = precsize_aton(&cp);
268 
269   while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/
270     cp++;
271 
272   while (isspace(*cp) && (cp < maxcp))
273     cp++;
274 
275   if (cp >= maxcp)
276     goto defaults;
277 
278   d_horizpre = precsize_aton(&cp);
279 
280   while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/
281     cp++;
282 
283   while (isspace(*cp) && (cp < maxcp))
284     cp++;
285 
286   if (cp >= maxcp)
287     goto defaults;
288 
289   d_vertpre = precsize_aton(&cp);
290 
291  defaults:
292   ;
293 }
294 
295 
getZoneRepresentation(bool noDot) const296 string LOCRecordContent::getZoneRepresentation(bool noDot) const
297 {
298   // convert d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude to:
299   // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m
300 
301   double latitude= ((int32_t)((uint32_t)d_latitude  - ((uint32_t)1<<31)))/3600000.0;
302   double longitude=((int32_t)((uint32_t)d_longitude - ((uint32_t)1<<31)))/3600000.0;
303   double altitude= ((int32_t)d_altitude           )/100.0 - 100000;
304 
305   double size=0.01*((d_size>>4)&0xf);
306   int count=d_size & 0xf;
307   while(count--)
308     size*=10;
309 
310   double horizpre=0.01*((d_horizpre>>4) & 0xf);
311   count=d_horizpre&0xf;
312   while(count--)
313     horizpre*=10;
314 
315   double vertpre=0.01*((d_vertpre>>4)&0xf);
316   count=d_vertpre&0xf;
317   while(count--)
318     vertpre*=10;
319 
320   double remlat=60.0*(latitude-(int)latitude);
321   double remlong=60.0*(longitude-(int)longitude);
322   static const boost::format fmt("%d %d %2.03f %c %d %d %2.03f %c %.2fm %.2fm %.2fm %.2fm");
323   std::string ret = boost::str(
324     boost::format(fmt)
325     % abs((int)latitude) % abs((int) ((latitude-(int)latitude)*60))
326     % fabs((double)((remlat-(int)remlat)*60.0)) % (latitude>0 ? 'N' : 'S')
327     % abs((int)longitude) % abs((int) ((longitude-(int)longitude)*60))
328     % fabs((double)((remlong-(int)remlong)*60.0)) % (longitude>0 ? 'E' : 'W')
329     % altitude % size
330     % horizpre % vertpre
331     );
332 
333   return ret;
334 }
335