diff options
-rw-r--r-- | include/libbb.h | 6 | ||||
-rw-r--r-- | libbb/udp_io.c | 5 | ||||
-rw-r--r-- | networking/dnsd.c | 117 |
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 | ||
477 | void socket_want_pktinfo(int fd); | 477 | void socket_want_pktinfo(int fd); |
478 | ssize_t send_to_from(int fd, void *buf, size_t len, int flags, | 478 | ssize_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); |
481 | ssize_t recv_from_to(int fd, void *buf, size_t len, int flags, | 482 | ssize_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 | ||
485 | char *xstrdup(const char *s); | 487 | char *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 | ||
29 | ssize_t | 28 | ssize_t |
30 | send_to_from(int fd, void *buf, size_t len, int flags, | 29 | send_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 | ||
47 | struct 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 | |||
53 | struct dns_head { // the message from client and first part of response mag | 47 | struct 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 | */ |
225 | static int process_packet(uint8_t * buf) | 218 | static 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 | } |