aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libbb.h6
-rw-r--r--libbb/udp_io.c5
-rw-r--r--networking/dnsd.c117
3 files changed, 65 insertions, 63 deletions
diff --git a/include/libbb.h b/include/libbb.h
index ee1ef518e..df8b0ecdb 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -476,10 +476,12 @@ struct hostent *xgethostbyname(const char *name);
476 476
477void socket_want_pktinfo(int fd); 477void socket_want_pktinfo(int fd);
478ssize_t send_to_from(int fd, void *buf, size_t len, int flags, 478ssize_t send_to_from(int fd, void *buf, size_t len, int flags,
479 const struct sockaddr *from, const struct sockaddr *to, 479 const struct sockaddr *to,
480 const struct sockaddr *from,
480 socklen_t tolen); 481 socklen_t tolen);
481ssize_t recv_from_to(int fd, void *buf, size_t len, int flags, 482ssize_t recv_from_to(int fd, void *buf, size_t len, int flags,
482 struct sockaddr *from, struct sockaddr *to, 483 struct sockaddr *from,
484 struct sockaddr *to,
483 socklen_t sa_size); 485 socklen_t sa_size);
484 486
485char *xstrdup(const char *s); 487char *xstrdup(const char *s);
diff --git a/libbb/udp_io.c b/libbb/udp_io.c
index 2f02a138b..e968ecb66 100644
--- a/libbb/udp_io.c
+++ b/libbb/udp_io.c
@@ -25,10 +25,10 @@ socket_want_pktinfo(int fd)
25} 25}
26 26
27 27
28#ifdef UNUSED
29ssize_t 28ssize_t
30send_to_from(int fd, void *buf, size_t len, int flags, 29send_to_from(int fd, void *buf, size_t len, int flags,
31 const struct sockaddr *from, const struct sockaddr *to, 30 const struct sockaddr *to,
31 const struct sockaddr *from,
32 socklen_t tolen) 32 socklen_t tolen)
33{ 33{
34#ifndef IP_PKTINFO 34#ifndef IP_PKTINFO
@@ -92,7 +92,6 @@ send_to_from(int fd, void *buf, size_t len, int flags,
92 return sendmsg(fd, &msg, flags); 92 return sendmsg(fd, &msg, flags);
93#endif 93#endif
94} 94}
95#endif /* UNUSED */
96 95
97/* NB: this will never set port# in 'to'! 96/* NB: this will never set port# in 'to'!
98 * _Only_ IP/IPv6 address part of 'to' is _maybe_ modified. 97 * _Only_ IP/IPv6 address part of 'to' is _maybe_ modified.
diff --git a/networking/dnsd.c b/networking/dnsd.c
index b269bc52a..cb62d2081 100644
--- a/networking/dnsd.c
+++ b/networking/dnsd.c
@@ -36,7 +36,7 @@ enum {
36 ttl(4B) + rlen(2B) + r (MAX_NAME_LEN =21B) + 36 ttl(4B) + rlen(2B) + r (MAX_NAME_LEN =21B) +
37 2*querystring (2 MAX_NAME_LEN= 42B), all together 90 Byte 37 2*querystring (2 MAX_NAME_LEN= 42B), all together 90 Byte
38*/ 38*/
39 MAX_PACK_LEN = 512 + 1, 39 MAX_PACK_LEN = 512,
40 40
41 DEFAULT_TTL = 30, // increase this when not testing? 41 DEFAULT_TTL = 30, // increase this when not testing?
42 42
@@ -44,12 +44,6 @@ enum {
44 REQ_PTR = 12 44 REQ_PTR = 12
45}; 45};
46 46
47struct dns_repl { // resource record, add 0 or 1 to accepted dns_msg in resp
48 uint16_t rlen;
49 uint8_t *r; // resource
50 uint16_t flags;
51};
52
53struct dns_head { // the message from client and first part of response mag 47struct dns_head { // the message from client and first part of response mag
54 uint16_t id; 48 uint16_t id;
55 uint16_t flags; 49 uint16_t flags;
@@ -218,20 +212,20 @@ static int table_lookup(uint16_t type, uint8_t * as, uint8_t * qs)
218 return -1; 212 return -1;
219} 213}
220 214
221
222/* 215/*
223 * Decode message and generate answer 216 * Decode message and generate answer
224 */ 217 */
225static int process_packet(uint8_t * buf) 218static int process_packet(uint8_t *buf)
226{ 219{
220 uint8_t answstr[MAX_NAME_LEN + 1];
227 struct dns_head *head; 221 struct dns_head *head;
228 struct dns_prop *qprop; 222 struct dns_prop *qprop;
229 struct dns_repl outr; 223 uint8_t *from, *answb;
230 void *next, *from, *answb; 224 uint16_t outr_rlen;
231 225 uint16_t outr_flags;
232 uint8_t answstr[MAX_NAME_LEN + 1];
233 int lookup_result, type, len, packet_len;
234 uint16_t flags; 226 uint16_t flags;
227 int lookup_result, type, packet_len;
228 int querystr_len;
235 229
236 answstr[0] = '\0'; 230 answstr[0] = '\0';
237 231
@@ -247,11 +241,12 @@ static int process_packet(uint8_t * buf)
247 } 241 }
248 242
249 from = (void *)&head[1]; // start of query string 243 from = (void *)&head[1]; // start of query string
250 next = answb = from + strlen((char *)from) + 1 + sizeof(struct dns_prop); // where to append answer block 244//FIXME: strlen of untrusted data??!
245 querystr_len = strlen((char *)from) + 1 + sizeof(struct dns_prop);
246 answb = from + querystr_len; // where to append answer block
251 247
252 outr.rlen = 0; // may change later 248 outr_rlen = 0;
253 outr.r = NULL; 249 outr_flags = 0;
254 outr.flags = 0;
255 250
256 qprop = (struct dns_prop *)(answb - 4); 251 qprop = (struct dns_prop *)(answb - 4);
257 type = ntohs(qprop->type); 252 type = ntohs(qprop->type);
@@ -262,7 +257,7 @@ static int process_packet(uint8_t * buf)
262 } 257 }
263 258
264 if (ntohs(qprop->class) != 1 /* class INET */ ) { 259 if (ntohs(qprop->class) != 1 /* class INET */ ) {
265 outr.flags = 4; /* not supported */ 260 outr_flags = 4; /* not supported */
266 goto empty_packet; 261 goto empty_packet;
267 } 262 }
268 /* we only support standard queries */ 263 /* we only support standard queries */
@@ -272,49 +267,50 @@ static int process_packet(uint8_t * buf)
272 267
273 // We have a standard query 268 // We have a standard query
274 bb_info_msg("%s", (char *)from); 269 bb_info_msg("%s", (char *)from);
275 lookup_result = table_lookup(type, answstr, (uint8_t*)from); 270 lookup_result = table_lookup(type, answstr, from);
276 if (lookup_result != 0) { 271 if (lookup_result != 0) {
277 outr.flags = 3 | 0x0400; //name do not exist and auth 272 outr_flags = 3 | 0x0400; // name do not exist and auth
278 goto empty_packet; 273 goto empty_packet;
279 } 274 }
280 if (type == REQ_A) { // return an address 275 if (type == REQ_A) { // return an address
281 struct in_addr a; 276 struct in_addr a; // NB! its "struct { unsigned __long__ s_addr; }"
282 if (!inet_aton((char*)answstr, &a)) {//dotted dec to long conv 277 uint32_t v32;
283 outr.flags = 1; /* Frmt err */ 278 if (!inet_aton((char*)answstr, &a)) { //dotted dec to long conv
279 outr_flags = 1; /* Frmt err */
284 goto empty_packet; 280 goto empty_packet;
285 } 281 }
286 memcpy(answstr, &a.s_addr, 4); // save before a disappears 282 v32 = a.s_addr; /* in case long != int */
287 outr.rlen = 4; // uint32_t IP 283 memcpy(answstr, &v32, 4);
284 outr_rlen = 4; // uint32_t IP
288 } else 285 } else
289 outr.rlen = strlen((char *)answstr) + 1; // a host name 286 outr_rlen = strlen((char *)answstr) + 1; // a host name
290 outr.r = answstr; // 32 bit ip or a host name 287 outr_flags |= 0x0400; /* authority-bit */
291 outr.flags |= 0x0400; /* authority-bit */
292 // we have an answer 288 // we have an answer
293 head->nansw = htons(1); 289 head->nansw = htons(1);
294 290
295 // copy query block to answer block 291 // copy query block to answer block
296 len = answb - from; 292 memcpy(answb, from, querystr_len);
297 memcpy(answb, from, len); 293 answb += querystr_len;
298 next += len;
299 294
300 // and append answer rr 295 // and append answer rr
301 *(uint32_t *) next = htonl(ttl); 296// FIXME: unaligned accesses??
302 next += 4; 297 *(uint32_t *) answb = htonl(ttl);
303 *(uint16_t *) next = htons(outr.rlen); 298 answb += 4;
304 next += 2; 299 *(uint16_t *) answb = htons(outr_rlen);
305 memcpy(next, (void *)answstr, outr.rlen); 300 answb += 2;
306 next += outr.rlen; 301 memcpy(answb, answstr, outr_rlen);
302 answb += outr_rlen;
307 303
308 empty_packet: 304 empty_packet:
309 305
310 flags = ntohs(head->flags); 306 flags = ntohs(head->flags);
311 // clear rcode and RA, set responsebit and our new flags 307 // clear rcode and RA, set responsebit and our new flags
312 flags |= (outr.flags & 0xff80) | 0x8000; 308 flags |= (outr_flags & 0xff80) | 0x8000;
313 head->flags = htons(flags); 309 head->flags = htons(flags);
314 head->nauth = head->nadd = htons(0); 310 head->nauth = head->nadd = 0;
315 head->nquer = htons(1); 311 head->nquer = htons(1);
316 312
317 packet_len = (uint8_t *)next - buf; 313 packet_len = answb - buf;
318 return packet_len; 314 return packet_len;
319} 315}
320 316
@@ -333,10 +329,13 @@ int dnsd_main(int argc ATTRIBUTE_UNUSED, char **argv)
333{ 329{
334 const char *listen_interface = "0.0.0.0"; 330 const char *listen_interface = "0.0.0.0";
335 char *sttl, *sport; 331 char *sttl, *sport;
336 len_and_sockaddr *lsa; 332 len_and_sockaddr *lsa, *from, *to;
333 unsigned lsa_size;
337 int udps; 334 int udps;
338 uint16_t port = 53; 335 uint16_t port = 53;
339 uint8_t buf[MAX_PACK_LEN]; 336 /* Paranoid sizing: querystring x2 + ttl + outr_rlen + answstr */
337 /* I'd rather see process_packet() fixed instead... */
338 uint8_t buf[MAX_PACK_LEN * 2 + 4 + 2 + (MAX_NAME_LEN+1)];
340 339
341 getopt32(argv, "i:c:t:p:dv", &listen_interface, &fileconf, &sttl, &sport); 340 getopt32(argv, "i:c:t:p:dv", &listen_interface, &fileconf, &sttl, &sport);
342 //if (option_mask32 & 0x1) // -i 341 //if (option_mask32 & 0x1) // -i
@@ -375,32 +374,34 @@ int dnsd_main(int argc ATTRIBUTE_UNUSED, char **argv)
375 lsa = xdotted2sockaddr(listen_interface, port); 374 lsa = xdotted2sockaddr(listen_interface, port);
376 udps = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0); 375 udps = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
377 xbind(udps, &lsa->u.sa, lsa->len); 376 xbind(udps, &lsa->u.sa, lsa->len);
378 /* xlisten(udps, 50); - ?!! DGRAM sockets are never listened on I think? */ 377 socket_want_pktinfo(udps); /* needed for recv_from_to to work */
378 lsa_size = LSA_LEN_SIZE + lsa->len;
379 from = xzalloc(lsa_size);
380 to = xzalloc(lsa_size);
381
379 bb_info_msg("Accepting UDP packets on %s", 382 bb_info_msg("Accepting UDP packets on %s",
380 xmalloc_sockaddr2dotted(&lsa->u.sa)); 383 xmalloc_sockaddr2dotted(&lsa->u.sa));
381 384
382 while (1) { 385 while (1) {
383 int r; 386 int r;
384 socklen_t fromlen = lsa->len; 387 /* Try to get *DEST* address (to which of our addresses
385// FIXME: need to get *DEST* address (to which of our addresses 388 * this query was directed), and reply from the same address.
386// this query was directed), and reply from the same address. 389 * Or else we can exhibit usual UDP ugliness:
387// Or else we can exhibit usual UDP ugliness: 390 * [ip1.multihomed.ip2] <= query to ip1 <= peer
388// [ip1.multihomed.ip2] <= query to ip1 <= peer 391 * [ip1.multihomed.ip2] => reply from ip2 => peer (confused) */
389// [ip1.multihomed.ip2] => reply from ip2 => peer (confused) 392 memcpy(to, lsa, lsa_size);
390 393 r = recv_from_to(udps, buf, MAX_PACK_LEN + 1, 0, &from->u.sa, &to->u.sa, lsa->len);
391// TODO: recv_from_to 394 if (r < 12 || r > MAX_PACK_LEN) {
392
393 r = recvfrom(udps, buf, sizeof(buf), 0, &lsa->u.sa, &fromlen);
394 if (OPT_verbose)
395 bb_info_msg("Got UDP packet");
396 if (r < 12 || r > 512) {
397 bb_error_msg("invalid packet size"); 395 bb_error_msg("invalid packet size");
398 continue; 396 continue;
399 } 397 }
398 if (OPT_verbose)
399 bb_info_msg("Got UDP packet");
400 buf[r] = '\0'; /* paranoia */
400 r = process_packet(buf); 401 r = process_packet(buf);
401 if (r <= 0) 402 if (r <= 0)
402 continue; 403 continue;
403 sendto(udps, buf, r, 0, &lsa->u.sa, fromlen); 404 send_to_from(udps, buf, r, 0, &to->u.sa, &from->u.sa, lsa->len);
404 } 405 }
405 return 0; 406 return 0;
406} 407}