]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
enum.c: Make ast_get_txt() actually do something.
authorSean Bright <sean.bright@gmail.com>
Wed, 4 Mar 2020 22:53:57 +0000 (17:53 -0500)
committerSean Bright <sean.bright@gmail.com>
Wed, 4 Mar 2020 23:02:13 +0000 (17:02 -0600)
The ast_get_txt() API function (and by extension, the TXTCIDNAME
dialplan function) were broken in
65b8381550a9f46fdce84de79960073e9d51b05d such that we would never
actually make a DNS TXT query as described.

This patch restores the documented behavior.

ASTERISK-19460 #close
Reported by: George Joseph

Change-Id: I1b19aea711488cb1ecd63843cddce05010e39376

main/enum.c

index 344ae404d56414ff1febcb3bf4216e99d878f360..12c39e87f1e79ddd00f3c5eae6c1e5a25533c4df 100644 (file)
@@ -931,37 +931,88 @@ int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int ds
        return ret;
 }
 
+/*! \internal
+ * \brief Format a phone number as a domain in an ENUM-adjacent way.
+ *
+ * Creates a domain name suitable for query by:
+ *
+ * 1. Removing non-digits
+ * 2. Adding a '.' between adjacent digits
+ * 3. Reversing the string
+ * 4. Appending the specified suffix (or e164.arpa if none is specified)
+ */
+static char *format_numeric_domain(const char *number, const char *suffix)
+{
+       char *buffer, *dst;
+       size_t suffix_length;
+       size_t number_length = strlen(number);
+       const char *src = number + number_length - 1;
+
+       if (!suffix) {
+               suffix = "e164.arpa";
+       }
+
+       suffix_length = strlen(suffix);
+
+       dst = buffer = ast_malloc(
+               (number_length * 2) /* We need 2 bytes per input digit */
+               + suffix_length     /* ... plus however long the suffix is */
+               + 1                 /* ... plus room for the '.' separator */
+               + 1                 /* ... and room for the \0 byte at the end */);
+
+       if (buffer) {
+               while (src >= number) {
+                       if (isdigit(*src)) {
+                               *dst++ = *src;
+                               *dst++ = '.';
+                       }
+                       src--;
+               }
+
+               /* The length arguments below make sure that the \0 byte is copied into
+                  the final string */
+               if (*suffix == '.') {
+                       memcpy(dst, &suffix[1], suffix_length);
+               } else {
+                       memcpy(dst, suffix, suffix_length + 1);
+               }
+       }
+
+       return buffer;
+}
+
 int ast_get_txt(struct ast_channel *chan, const char *number, char *txt, int txtlen, char *suffix)
 {
        struct txt_context context;
-       char tmp[259 + 512];
-       int pos = strlen(number) - 1;
-       int newpos = 0;
-       int ret = -1;
+       char *domain;
+       int ret;
+       int autoservice = 0;
 
        ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);
 
-       if (pos > 128) {
-               pos = 128;
+       domain = format_numeric_domain(number, suffix);
+       if (!domain) {
+               return -1;
        }
 
-       while (pos >= 0) {
-               if (isdigit(number[pos])) {
-                       tmp[newpos++] = number[pos];
-                       tmp[newpos++] = '.';
-               }
-               pos--;
+       if (chan) {
+               /* DNS might take a while, so service the channel while we're blocked */
+               autoservice = !ast_autoservice_start(chan);
        }
 
-       ast_copy_string(&tmp[newpos], suffix, sizeof(tmp) - newpos);
-
-       if (ret < 0) {
-               ast_debug(2, "No such number found in ENUM: %s (%s)\n", tmp, strerror(errno));
-               ret = 0;
-       } else {
+       ret = ast_search_dns(&context, domain, C_IN, T_TXT, txt_callback);
+       if (ret > 0) {
                ast_copy_string(txt, context.txt, txtlen);
+       } else {
+               ast_debug(2, "No such number found in ENUM: %s (%s)\n", domain, strerror(errno));
        }
-       return ret;
+
+       if (autoservice) {
+               ast_autoservice_stop(chan);
+       }
+
+       ast_free(domain);
+       return 0;
 }
 
 /*! \brief Initialize the ENUM support subsystem */