You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

util.c 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. /* Copyright (c) 2014, Vsevolod Stakhov
  2. * All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. * * Redistributions of source code must retain the above copyright
  7. * notice, this list of conditions and the following disclaimer.
  8. * * Redistributions in binary form must reproduce the above copyright
  9. * notice, this list of conditions and the following disclaimer in the
  10. * documentation and/or other materials provided with the distribution.
  11. *
  12. * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
  13. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  16. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #include <sys/socket.h>
  24. #include <netinet/in.h>
  25. #include <arpa/inet.h>
  26. #include <sys/un.h>
  27. #include <sys/stat.h>
  28. #include <unistd.h>
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <errno.h>
  33. #include <netdb.h>
  34. #include <fcntl.h>
  35. #include <ctype.h>
  36. #include "ottery.h"
  37. #include "util.h"
  38. #include "logger.h"
  39. static int
  40. rdns_make_socket_nonblocking (int fd)
  41. {
  42. int ofl;
  43. ofl = fcntl (fd, F_GETFL, 0);
  44. if (fcntl (fd, F_SETFL, ofl | O_NONBLOCK) == -1) {
  45. return -1;
  46. }
  47. return 0;
  48. }
  49. static int
  50. rdns_make_inet_socket (int type, struct addrinfo *addr)
  51. {
  52. int fd, r, s_error;
  53. socklen_t optlen;
  54. struct addrinfo *cur;
  55. cur = addr;
  56. while (cur) {
  57. /* Create socket */
  58. fd = socket (cur->ai_family, type, 0);
  59. if (fd == -1) {
  60. goto out;
  61. }
  62. if (rdns_make_socket_nonblocking (fd) < 0) {
  63. goto out;
  64. }
  65. /* Set close on exec */
  66. if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) {
  67. goto out;
  68. }
  69. r = connect (fd, cur->ai_addr, cur->ai_addrlen);
  70. if (r == -1) {
  71. if (errno != EINPROGRESS) {
  72. goto out;
  73. }
  74. }
  75. else {
  76. /* Still need to check SO_ERROR on socket */
  77. optlen = sizeof (s_error);
  78. getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *)&s_error, &optlen);
  79. if (s_error) {
  80. errno = s_error;
  81. goto out;
  82. }
  83. }
  84. break;
  85. out:
  86. if (fd != -1) {
  87. close (fd);
  88. }
  89. fd = -1;
  90. cur = cur->ai_next;
  91. }
  92. return (fd);
  93. }
  94. static int
  95. rdns_make_unix_socket (const char *path, struct sockaddr_un *addr, int type)
  96. {
  97. int fd = -1, s_error, r, serrno;
  98. socklen_t optlen;
  99. if (path == NULL) {
  100. return -1;
  101. }
  102. addr->sun_family = AF_UNIX;
  103. memset (addr->sun_path, 0, sizeof (addr->sun_path));
  104. memccpy (addr->sun_path, path, 0, sizeof (addr->sun_path) - 1);
  105. #ifdef FREEBSD
  106. addr->sun_len = SUN_LEN (addr);
  107. #endif
  108. fd = socket (PF_LOCAL, type, 0);
  109. if (fd == -1) {
  110. return -1;
  111. }
  112. if (rdns_make_socket_nonblocking (fd) < 0) {
  113. goto out;
  114. }
  115. /* Set close on exec */
  116. if (fcntl (fd, F_SETFD, FD_CLOEXEC) == -1) {
  117. goto out;
  118. }
  119. r = connect (fd, (struct sockaddr *)addr, SUN_LEN (addr));
  120. if (r == -1) {
  121. if (errno != EINPROGRESS) {
  122. goto out;
  123. }
  124. }
  125. else {
  126. /* Still need to check SO_ERROR on socket */
  127. optlen = sizeof (s_error);
  128. getsockopt (fd, SOL_SOCKET, SO_ERROR, (void *)&s_error, &optlen);
  129. if (s_error) {
  130. errno = s_error;
  131. goto out;
  132. }
  133. }
  134. return (fd);
  135. out:
  136. serrno = errno;
  137. if (fd != -1) {
  138. close (fd);
  139. }
  140. errno = serrno;
  141. return (-1);
  142. }
  143. /**
  144. * Make a universal socket
  145. * @param credits host, ip or path to unix socket
  146. * @param port port (used for network sockets)
  147. * @param async make this socket asynced
  148. * @param is_server make this socket as server socket
  149. * @param try_resolve try name resolution for a socket (BLOCKING)
  150. */
  151. int
  152. rdns_make_client_socket (const char *credits, uint16_t port,
  153. int type)
  154. {
  155. struct sockaddr_un un;
  156. struct stat st;
  157. struct addrinfo hints, *res;
  158. int r;
  159. char portbuf[8];
  160. if (*credits == '/') {
  161. r = stat (credits, &st);
  162. if (r == -1) {
  163. /* Unix socket doesn't exists it must be created first */
  164. errno = ENOENT;
  165. return -1;
  166. }
  167. else {
  168. if ((st.st_mode & S_IFSOCK) == 0) {
  169. /* Path is not valid socket */
  170. errno = EINVAL;
  171. return -1;
  172. }
  173. else {
  174. return rdns_make_unix_socket (credits, &un, type);
  175. }
  176. }
  177. }
  178. else {
  179. /* TCP related part */
  180. memset (&hints, 0, sizeof (hints));
  181. hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
  182. hints.ai_socktype = type; /* Type of the socket */
  183. hints.ai_flags = 0;
  184. hints.ai_protocol = 0; /* Any protocol */
  185. hints.ai_canonname = NULL;
  186. hints.ai_addr = NULL;
  187. hints.ai_next = NULL;
  188. hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
  189. snprintf (portbuf, sizeof (portbuf), "%d", (int)port);
  190. if ((r = getaddrinfo (credits, portbuf, &hints, &res)) == 0) {
  191. r = rdns_make_inet_socket (type, res);
  192. freeaddrinfo (res);
  193. return r;
  194. }
  195. else {
  196. return -1;
  197. }
  198. }
  199. /* Not reached */
  200. return -1;
  201. }
  202. const char *
  203. rdns_strerror (enum dns_rcode rcode)
  204. {
  205. rcode &= 0xf;
  206. static char numbuf[16];
  207. if ('\0' == dns_rcodes[rcode][0]) {
  208. snprintf (numbuf, sizeof (numbuf), "UNKNOWN: %d", (int)rcode);
  209. return numbuf;
  210. }
  211. return dns_rcodes[rcode];
  212. }
  213. const char *
  214. rdns_strtype (enum rdns_request_type type)
  215. {
  216. return dns_types[type];
  217. }
  218. enum rdns_request_type
  219. rdns_type_fromstr (const char *str)
  220. {
  221. if (str) {
  222. if (strcmp (str, "a") == 0) {
  223. return RDNS_REQUEST_A;
  224. }
  225. else if (strcmp (str, "ns") == 0) {
  226. return RDNS_REQUEST_NS;
  227. }
  228. else if (strcmp (str, "soa") == 0) {
  229. return RDNS_REQUEST_SOA;
  230. }
  231. else if (strcmp (str, "ptr") == 0) {
  232. return RDNS_REQUEST_PTR;
  233. }
  234. else if (strcmp (str, "mx") == 0) {
  235. return RDNS_REQUEST_MX;
  236. }
  237. else if (strcmp (str, "srv") == 0) {
  238. return RDNS_REQUEST_SRV;
  239. }
  240. else if (strcmp (str, "txt") == 0) {
  241. return RDNS_REQUEST_TXT;
  242. }
  243. else if (strcmp (str, "spf") == 0) {
  244. return RDNS_REQUEST_SPF;
  245. }
  246. else if (strcmp (str, "aaaa") == 0) {
  247. return RDNS_REQUEST_AAAA;
  248. }
  249. else if (strcmp (str, "tlsa") == 0) {
  250. return RDNS_REQUEST_TLSA;
  251. }
  252. else if (strcmp (str, "any") == 0) {
  253. return RDNS_REQUEST_ANY;
  254. }
  255. }
  256. return RDNS_REQUEST_INVALID;
  257. }
  258. const char *
  259. rdns_str_from_type (enum rdns_request_type rcode)
  260. {
  261. switch (rcode) {
  262. case RDNS_REQUEST_INVALID:
  263. return "(invalid)";
  264. case RDNS_REQUEST_A:
  265. return "a";
  266. case RDNS_REQUEST_NS:
  267. return "ns";
  268. case RDNS_REQUEST_SOA:
  269. return "soa";
  270. case RDNS_REQUEST_PTR:
  271. return "ptr";
  272. case RDNS_REQUEST_MX:
  273. return "mx";
  274. case RDNS_REQUEST_TXT:
  275. return "txt";
  276. case RDNS_REQUEST_SRV:
  277. return "srv";
  278. case RDNS_REQUEST_SPF:
  279. return "spf";
  280. case RDNS_REQUEST_AAAA:
  281. return "aaaa";
  282. case RDNS_REQUEST_TLSA:
  283. return "tlsa";
  284. case RDNS_REQUEST_ANY:
  285. return "any";
  286. default:
  287. return "(unknown)";
  288. }
  289. }
  290. enum dns_rcode
  291. rdns_rcode_fromstr (const char *str)
  292. {
  293. if (str) {
  294. if (strcmp (str, "noerror") == 0) {
  295. return RDNS_RC_NOERROR;
  296. }
  297. else if (strcmp (str, "formerr") == 0) {
  298. return RDNS_RC_FORMERR;
  299. }
  300. else if (strcmp (str, "servfail") == 0) {
  301. return RDNS_RC_SERVFAIL;
  302. }
  303. else if (strcmp (str, "nxdomain") == 0) {
  304. return RDNS_RC_NXDOMAIN;
  305. }
  306. else if (strcmp (str, "notimp") == 0) {
  307. return RDNS_RC_NOTIMP;
  308. }
  309. else if (strcmp (str, "yxdomain") == 0) {
  310. return RDNS_RC_YXDOMAIN;
  311. }
  312. else if (strcmp (str, "yxrrset") == 0) {
  313. return RDNS_RC_YXRRSET;
  314. }
  315. else if (strcmp (str, "nxrrset") == 0) {
  316. return RDNS_RC_NXRRSET;
  317. }
  318. else if (strcmp (str, "notauth") == 0) {
  319. return RDNS_RC_NOTAUTH;
  320. }
  321. else if (strcmp (str, "notzone") == 0) {
  322. return RDNS_RC_NOTZONE;
  323. }
  324. else if (strcmp (str, "timeout") == 0) {
  325. return RDNS_RC_TIMEOUT;
  326. }
  327. else if (strcmp (str, "neterr") == 0) {
  328. return RDNS_RC_NETERR;
  329. }
  330. else if (strcmp (str, "norec") == 0) {
  331. return RDNS_RC_NOREC;
  332. }
  333. }
  334. return RDNS_RC_INVALID;
  335. }
  336. uint16_t
  337. rdns_permutor_generate_id (void)
  338. {
  339. uint16_t id;
  340. id = ottery_rand_unsigned ();
  341. return id;
  342. }
  343. void
  344. rdns_reply_free (struct rdns_reply *rep)
  345. {
  346. struct rdns_reply_entry *entry, *tmp;
  347. /* We don't need to free data for faked replies */
  348. if (!rep->request || rep->request->state != RDNS_REQUEST_FAKE) {
  349. LL_FOREACH_SAFE (rep->entries, entry, tmp) {
  350. switch (entry->type) {
  351. case RDNS_REQUEST_PTR:
  352. free (entry->content.ptr.name);
  353. break;
  354. case RDNS_REQUEST_NS:
  355. free (entry->content.ns.name);
  356. break;
  357. case RDNS_REQUEST_MX:
  358. free (entry->content.mx.name);
  359. break;
  360. case RDNS_REQUEST_TXT:
  361. case RDNS_REQUEST_SPF:
  362. free (entry->content.txt.data);
  363. break;
  364. case RDNS_REQUEST_SRV:
  365. free (entry->content.srv.target);
  366. break;
  367. case RDNS_REQUEST_TLSA:
  368. free (entry->content.tlsa.data);
  369. break;
  370. case RDNS_REQUEST_SOA:
  371. free (entry->content.soa.mname);
  372. free (entry->content.soa.admin);
  373. break;
  374. }
  375. free (entry);
  376. }
  377. }
  378. free (rep);
  379. }
  380. void
  381. rdns_request_free (struct rdns_request *req)
  382. {
  383. unsigned int i;
  384. if (req != NULL) {
  385. if (req->packet != NULL) {
  386. free (req->packet);
  387. }
  388. for (i = 0; i < req->qcount; i ++) {
  389. free (req->requested_names[i].name);
  390. }
  391. if (req->requested_names != NULL) {
  392. free (req->requested_names);
  393. }
  394. if (req->reply != NULL) {
  395. rdns_reply_free (req->reply);
  396. }
  397. if (req->async_event) {
  398. if (req->state == RDNS_REQUEST_WAIT_REPLY) {
  399. /* Remove timer */
  400. req->async->del_timer (req->async->data,
  401. req->async_event);
  402. /* Remove from id hashes */
  403. HASH_DEL (req->io->requests, req);
  404. req->async_event = NULL;
  405. }
  406. else if (req->state == RDNS_REQUEST_WAIT_SEND) {
  407. /* Remove retransmit event */
  408. req->async->del_write (req->async->data,
  409. req->async_event);
  410. HASH_DEL (req->io->requests, req);
  411. req->async_event = NULL;
  412. }
  413. else if (req->state == RDNS_REQUEST_FAKE) {
  414. req->async->del_write (req->async->data,
  415. req->async_event);
  416. req->async_event = NULL;
  417. }
  418. }
  419. #ifdef TWEETNACL
  420. if (req->curve_plugin_data != NULL) {
  421. req->resolver->curve_plugin->cb.curve_plugin.finish_cb (
  422. req, req->resolver->curve_plugin->data);
  423. }
  424. #endif
  425. if (req->io != NULL && req->state > RDNS_REQUEST_NEW) {
  426. REF_RELEASE (req->io);
  427. REF_RELEASE (req->resolver);
  428. }
  429. free (req);
  430. }
  431. }
  432. void
  433. rdns_ioc_free (struct rdns_io_channel *ioc)
  434. {
  435. struct rdns_request *req, *rtmp;
  436. HASH_ITER (hh, ioc->requests, req, rtmp) {
  437. REF_RELEASE (req);
  438. }
  439. ioc->resolver->async->del_read (ioc->resolver->async->data,
  440. ioc->async_io);
  441. close (ioc->sock);
  442. free (ioc);
  443. }
  444. void
  445. rdns_resolver_release (struct rdns_resolver *resolver)
  446. {
  447. REF_RELEASE (resolver);
  448. }
  449. struct rdns_request*
  450. rdns_request_retain (struct rdns_request *req)
  451. {
  452. REF_RETAIN (req);
  453. return req;
  454. }
  455. void
  456. rdns_request_unschedule (struct rdns_request *req)
  457. {
  458. if (req->async_event) {
  459. if (req->state == RDNS_REQUEST_WAIT_REPLY) {
  460. req->async->del_timer (req->async->data,
  461. req->async_event);
  462. /* Remove from id hashes */
  463. HASH_DEL (req->io->requests, req);
  464. req->async_event = NULL;
  465. }
  466. else if (req->state == RDNS_REQUEST_WAIT_SEND) {
  467. req->async->del_write (req->async->data,
  468. req->async_event);
  469. /* Remove from id hashes */
  470. HASH_DEL (req->io->requests, req);
  471. req->async_event = NULL;
  472. }
  473. }
  474. }
  475. void
  476. rdns_request_release (struct rdns_request *req)
  477. {
  478. rdns_request_unschedule (req);
  479. REF_RELEASE (req);
  480. }
  481. static bool
  482. rdns_resolver_conf_process_line (struct rdns_resolver *resolver,
  483. const char *line, rdns_resolv_conf_cb cb, void *ud)
  484. {
  485. const char *p, *c, *end;
  486. bool has_obrace = false;
  487. unsigned int port = dns_port;
  488. end = line + strlen (line);
  489. if (end - line > sizeof ("nameserver") - 1 &&
  490. strncmp (line, "nameserver", sizeof ("nameserver") - 1) == 0) {
  491. p = line + sizeof ("nameserver") - 1;
  492. /* Skip spaces */
  493. while (*p == ' ' || *p == '\t') {
  494. p ++;
  495. }
  496. if (*p == '[') {
  497. has_obrace = true;
  498. p ++;
  499. }
  500. if (isxdigit (*p) || *p == ':') {
  501. c = p;
  502. while (isxdigit (*p) || *p == ':' || *p == '.') {
  503. p ++;
  504. }
  505. if (has_obrace && *p != ']') {
  506. return false;
  507. }
  508. else if (*p != '\0' && !isspace (*p) && *p != '#') {
  509. return false;
  510. }
  511. if (has_obrace) {
  512. p ++;
  513. if (*p == ':') {
  514. /* Maybe we have a port definition */
  515. port = strtoul (p + 1, NULL, 10);
  516. if (port == 0 || port > UINT16_MAX) {
  517. return false;
  518. }
  519. }
  520. }
  521. if (cb == NULL) {
  522. return rdns_resolver_add_server (resolver, c, port, 0,
  523. default_io_cnt) != NULL;
  524. }
  525. else {
  526. return cb (resolver, c, port, 0,
  527. default_io_cnt, ud);
  528. }
  529. }
  530. else {
  531. return false;
  532. }
  533. }
  534. /* XXX: skip unknown resolv.conf lines */
  535. return false;
  536. }
  537. bool
  538. rdns_resolver_parse_resolv_conf_cb (struct rdns_resolver *resolver,
  539. const char *path, rdns_resolv_conf_cb cb, void *ud)
  540. {
  541. FILE *in;
  542. char buf[BUFSIZ];
  543. char *p;
  544. bool processed = false;
  545. in = fopen (path, "r");
  546. if (in == NULL) {
  547. return false;
  548. }
  549. while (!feof (in)) {
  550. if (fgets (buf, sizeof (buf) - 1, in) == NULL) {
  551. break;
  552. }
  553. /* Strip trailing spaces */
  554. p = buf + strlen (buf) - 1;
  555. while (p > buf &&
  556. (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) {
  557. *p-- = '\0';
  558. }
  559. if (rdns_resolver_conf_process_line (resolver, buf, cb, ud)) {
  560. processed = true;
  561. }
  562. }
  563. fclose (in);
  564. return processed;
  565. }
  566. bool
  567. rdns_resolver_parse_resolv_conf (struct rdns_resolver *resolver, const char *path)
  568. {
  569. return rdns_resolver_parse_resolv_conf_cb (resolver, path, NULL, NULL);
  570. }
  571. bool
  572. rdns_request_has_type (struct rdns_request *req, enum rdns_request_type type)
  573. {
  574. unsigned int i;
  575. for (i = 0; i < req->qcount; i ++) {
  576. if (req->requested_names[i].type == type) {
  577. return true;
  578. }
  579. }
  580. return false;
  581. }
  582. const struct rdns_request_name *
  583. rdns_request_get_name (struct rdns_request *req, unsigned int *count)
  584. {
  585. if (count != NULL) {
  586. *count = req->qcount;
  587. }
  588. return req->requested_names;
  589. }
  590. char *
  591. rdns_generate_ptr_from_str (const char *str)
  592. {
  593. union {
  594. struct in_addr v4;
  595. struct in6_addr v6;
  596. } addr;
  597. char *res = NULL;
  598. unsigned char *bytes;
  599. size_t len;
  600. if (inet_pton (AF_INET, str, &addr.v4) == 1) {
  601. bytes = (unsigned char *)&addr.v4;
  602. len = 4 * 4 + sizeof ("in-addr.arpa");
  603. res = malloc (len);
  604. if (res) {
  605. snprintf (res, len, "%u.%u.%u.%u.in-addr.arpa",
  606. (unsigned)bytes[3]&0xFF,
  607. (unsigned)bytes[2]&0xFF,
  608. (unsigned)bytes[1]&0xFF,
  609. (unsigned)bytes[0]&0xFF);
  610. }
  611. }
  612. else if (inet_pton (AF_INET6, str, &addr.v6) == 1) {
  613. bytes = (unsigned char *)&addr.v6;
  614. len = 2*32 + sizeof ("ip6.arpa");
  615. res = malloc (len);
  616. if (res) {
  617. snprintf(res, len,
  618. "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
  619. "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa",
  620. bytes[15]&0xF, bytes[15] >> 4, bytes[14]&0xF, bytes[14] >> 4,
  621. bytes[13]&0xF, bytes[13] >> 4, bytes[12]&0xF, bytes[12] >> 4,
  622. bytes[11]&0xF, bytes[11] >> 4, bytes[10]&0xF, bytes[10] >> 4,
  623. bytes[9]&0xF, bytes[9] >> 4, bytes[8]&0xF, bytes[8] >> 4,
  624. bytes[7]&0xF, bytes[7] >> 4, bytes[6]&0xF, bytes[6] >> 4,
  625. bytes[5]&0xF, bytes[5] >> 4, bytes[4]&0xF, bytes[4] >> 4,
  626. bytes[3]&0xF, bytes[3] >> 4, bytes[2]&0xF, bytes[2] >> 4,
  627. bytes[1]&0xF, bytes[1] >> 4, bytes[0]&0xF, bytes[0] >> 4);
  628. }
  629. }
  630. return res;
  631. }