dns_resolve.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. // SPDX-License-Identifier: LGPL-2.1
  2. /*
  3. *
  4. * Copyright (c) 2007 Igor Mammedov
  5. * Author(s): Igor Mammedov ([email protected])
  6. * Steve French ([email protected])
  7. * Wang Lei ([email protected])
  8. * David Howells ([email protected])
  9. *
  10. * Contains the CIFS DFS upcall routines used for hostname to
  11. * IP address translation.
  12. *
  13. */
  14. #include <linux/slab.h>
  15. #include <linux/dns_resolver.h>
  16. #include "dns_resolve.h"
  17. #include "cifsglob.h"
  18. #include "cifsproto.h"
  19. #include "cifs_debug.h"
  20. /**
  21. * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
  22. * @unc: UNC path specifying the server (with '/' as delimiter)
  23. * @ip_addr: Where to return the IP address.
  24. * @expiry: Where to return the expiry time for the dns record.
  25. *
  26. * The IP address will be returned in string form, and the caller is
  27. * responsible for freeing it.
  28. *
  29. * Returns length of result on success, -ve on error.
  30. */
  31. int
  32. dns_resolve_server_name_to_ip(const char *unc, char **ip_addr, time64_t *expiry)
  33. {
  34. struct sockaddr_storage ss;
  35. const char *hostname, *sep;
  36. char *name;
  37. int len, rc;
  38. if (!ip_addr || !unc)
  39. return -EINVAL;
  40. len = strlen(unc);
  41. if (len < 3) {
  42. cifs_dbg(FYI, "%s: unc is too short: %s\n", __func__, unc);
  43. return -EINVAL;
  44. }
  45. /* Discount leading slashes for cifs */
  46. len -= 2;
  47. hostname = unc + 2;
  48. /* Search for server name delimiter */
  49. sep = memchr(hostname, '/', len);
  50. if (sep)
  51. len = sep - hostname;
  52. else
  53. cifs_dbg(FYI, "%s: probably server name is whole unc: %s\n",
  54. __func__, unc);
  55. /* Try to interpret hostname as an IPv4 or IPv6 address */
  56. rc = cifs_convert_address((struct sockaddr *)&ss, hostname, len);
  57. if (rc > 0)
  58. goto name_is_IP_address;
  59. /* Perform the upcall */
  60. rc = dns_query(current->nsproxy->net_ns, NULL, hostname, len,
  61. NULL, ip_addr, expiry, false);
  62. if (rc < 0)
  63. cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n",
  64. __func__, len, len, hostname);
  65. else
  66. cifs_dbg(FYI, "%s: resolved: %*.*s to %s expiry %llu\n",
  67. __func__, len, len, hostname, *ip_addr,
  68. expiry ? (*expiry) : 0);
  69. return rc;
  70. name_is_IP_address:
  71. name = kmalloc(len + 1, GFP_KERNEL);
  72. if (!name)
  73. return -ENOMEM;
  74. memcpy(name, hostname, len);
  75. name[len] = 0;
  76. cifs_dbg(FYI, "%s: unc is IP, skipping dns upcall: %s\n",
  77. __func__, name);
  78. *ip_addr = name;
  79. return 0;
  80. }