Asterisk - The Open Source Telephony Project GIT-master-a358458
Data Structures | Functions
enum.h File Reference

DNS and ENUM functions. More...

#include "asterisk/channel.h"
Include dependency graph for enum.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  enum_context
 
struct  enum_naptr_rr
 
struct  naptr
 

Functions

int ast_get_enum (struct ast_channel *chan, const char *number, char *location, int maxloc, char *technology, int maxtech, char *suffix, char *options, unsigned int record, struct enum_context **argcontext)
 Lookup entry in ENUM. More...
 
int ast_get_txt (struct ast_channel *chan, const char *number, char *txt, int maxtxt, char *suffix)
 Lookup DNS TXT record (used by app TXTCIDnum) More...
 

Detailed Description

DNS and ENUM functions.

Definition in file enum.h.

Function Documentation

◆ ast_get_enum()

int ast_get_enum ( struct ast_channel chan,
const char *  number,
char *  location,
int  maxloc,
char *  technology,
int  maxtech,
char *  suffix,
char *  options,
unsigned int  record,
struct enum_context **  argcontext 
)

Lookup entry in ENUM.

Parameters
chanChannel
numberE164 number with or without the leading +
locationNumber returned (or SIP uri)
maxlocMax length
technologyTechnology (from url scheme in response) You can set it to get particular answer RR, if there are many techs in DNS response, example: "sip" If you need any record, then set it to "ALL" string
maxtechMax length
suffixZone suffix (WARNING: No defaults here any more)
optionsOptions 'c' - Count number of NAPTR RR number - Position of the requested RR in the answer list 'u' - Full URI return (does not strip URI scheme) 'i' - Infrastructure ENUM lookup 's' - ISN based lookup 'd' - Direct DNS query
recordThe position of required RR in the answer list
argcontextArgument for caching results into an enum_context pointer (NULL is used for not caching)
Return values
1if found
0if not found
-1on hangup

Definition at line 649 of file enum.c.

650{
651 struct enum_context *context;
652 char tmp[512];
653 char domain[256];
654 char left[128];
655 char middle[128];
656 char naptrinput[128];
657 char apex[128] = "";
658 int ret = -1;
659 /* for ISN rewrite */
660 char *p1 = NULL;
661 char *p2 = NULL;
662 char *p3 = NULL;
663 int k = 0;
664 int i = 0;
665 int z = 0;
666 int spaceleft = 0;
667 struct timeval time_start, time_end;
668
669 if (ast_strlen_zero(suffix)) {
670 ast_log(LOG_WARNING, "ast_get_enum need a suffix parameter now.\n");
671 return -1;
672 }
673
674 ast_debug(2, "num='%s', tech='%s', suffix='%s', options='%s', record=%u\n", number, tech, suffix, options, record);
675
676/*
677 We don't need that any more, that "n" preceding the number has been replaced by a flag
678 in the options paramter.
679 ast_copy_string(naptrinput, number, sizeof(naptrinput));
680*/
681/*
682 * The "number" parameter includes a leading '+' if it's a full E.164 number (and not ISN)
683 * We need to preserve that as the regex inside NAPTRs expect the +.
684 *
685 * But for the domain generation, the '+' is a nuisance, so we get rid of it.
686*/
687 ast_copy_string(naptrinput, number[0] == 'n' ? number + 1 : number, sizeof(naptrinput));
688 if (number[0] == '+') {
689 number++;
690 }
691
692 if (!(context = ast_calloc(1, sizeof(*context)))) {
693 return -1;
694 }
695
696 if ((p3 = strchr(naptrinput, '*'))) {
697 *p3='\0';
698 }
699
700 context->naptrinput = naptrinput; /* The number */
701 context->dst = dst; /* Return string */
702 context->dstlen = dstlen;
703 context->tech = tech;
704 context->techlen = techlen;
705 context->options = 0;
706 context->position = record > 0 ? record : 1;
707 context->count = 0;
708 context->naptr_rrs = NULL;
709 context->naptr_rrs_count = 0;
710
711 /*
712 * Process options:
713 *
714 * c Return count, not URI
715 * i Use infrastructure ENUM
716 * s Do ISN transformation
717 * d Direct DNS query: no reversing.
718 *
719 */
720 if (options != NULL) {
721 if (strchr(options,'s')) {
723 } else if (strchr(options,'i')) {
725 } else if (strchr(options,'d')) {
727 }
728 if (strchr(options,'c')) {
730 }
731 if (strchr(number,'*')) {
733 }
734 }
735 ast_debug(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
736 ast_debug(1, "n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
737 number, tech, suffix, context->options, context->position);
738
739 /*
740 * This code does more than simple RFC3261 ENUM. All these rewriting
741 * schemes have in common that they build the FQDN for the NAPTR lookup
742 * by concatenating
743 * - a number which needs be flipped and "."-seperated (left)
744 * - some fixed string (middle)
745 * - an Apex. (apex)
746 *
747 * The RFC3261 ENUM is: left=full number, middle="", apex=from args.
748 * ISN: number = "middle*left", apex=from args
749 * I-ENUM: EBL parameters build the split, can change apex
750 * Direct: left="", middle=argument, apex=from args
751 *
752 */
753
754 /* default: the whole number will be flipped, no middle domain component */
755 ast_copy_string(left, number, sizeof(left));
756 middle[0] = '\0';
757 /*
758 * I-ENUM can change the apex, thus we copy it
759 */
760 ast_copy_string(apex, suffix, sizeof(apex));
761 /* ISN rewrite */
762 if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
763 *p1++ = '\0';
764 ast_copy_string(left, number, sizeof(left));
765 ast_copy_string(middle, p1, sizeof(middle) - 1);
766 strcat(middle, ".");
767 ast_debug(2, "ISN ENUM: left=%s, middle='%s'\n", left, middle);
768 /* Direct DNS lookup rewrite */
769 } else if (context->options & ENUMLOOKUP_OPTIONS_DIRECT) {
770 left[0] = 0; /* nothing to flip around */
771 ast_copy_string(middle, number, sizeof(middle) - 1);
772 strcat(middle, ".");
773 ast_debug(2, "DIRECT ENUM: middle='%s'\n", middle);
774 /* Infrastructure ENUM rewrite */
775 } else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
776 int sdl = 0;
777 char cc[8];
778 char sep[256], n_apex[256];
779 int cc_len = cclen(number);
780 sdl = cc_len;
782 ast_copy_string(sep, ienum_branchlabel, sizeof(sep)); /* default */
784
785 switch (ebl_alg) {
787 ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
788 sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);
789
790 if (sdl >= 0) {
791 ast_copy_string(apex, n_apex, sizeof(apex));
792 ast_debug(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
793 } else {
794 sdl = cc_len;
795 }
796 break;
798 ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
799 sdl = blr_txt(cc, suffix);
800
801 if (sdl < 0) {
802 sdl = cc_len;
803 }
804 break;
805
806 case ENUMLOOKUP_BLR_CC: /* BLR is at the country-code level */
807 default:
808 sdl = cc_len;
809 break;
810 }
811
812 if (sdl > strlen(number)) { /* Number too short for this sdl? */
813 ast_log(LOG_WARNING, "I-ENUM: subdomain location %d behind number %s\n", sdl, number);
815 return 0;
816 }
817 ast_copy_string(left, number + sdl, sizeof(left));
818
820 ast_copy_string(middle, sep, sizeof(middle) - 1);
821 strcat(middle, ".");
823
824 /* check the space we need for middle */
825 if ((sdl * 2 + strlen(middle) + 2) > sizeof(middle)) {
826 ast_log(LOG_WARNING, "ast_get_enum: not enough space for I-ENUM rewrite.\n");
828 return -1;
829 }
830
831 p1 = middle + strlen(middle);
832 for (p2 = (char *) number + sdl - 1; p2 >= number; p2--) {
833 if (isdigit(*p2)) {
834 *p1++ = *p2;
835 *p1++ = '.';
836 }
837 }
838 *p1 = '\0';
839
840 ast_debug(2, "I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n", cc_len, left, middle, apex);
841 }
842
843 if (strlen(left) * 2 + 2 > sizeof(domain)) {
844 ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
846 return -1;
847 }
848
849 /* flip left into domain */
850 p1 = domain;
851 for (p2 = left + strlen(left); p2 >= left; p2--) {
852 if (isdigit(*p2)) {
853 *p1++ = *p2;
854 *p1++ = '.';
855 }
856 }
857 *p1 = '\0';
858
859 if (chan && ast_autoservice_start(chan) < 0) {
861 return -1;
862 }
863
864 spaceleft = sizeof(tmp) - 2;
865 ast_copy_string(tmp, domain, spaceleft);
866 spaceleft -= strlen(domain);
867
868 if (*middle) {
869 strncat(tmp, middle, spaceleft);
870 spaceleft -= strlen(middle);
871 }
872
873 strncat(tmp,apex,spaceleft);
874 time_start = ast_tvnow();
875 ret = ast_search_dns(context, tmp, C_IN, T_NAPTR, enum_callback);
876 time_end = ast_tvnow();
877
878 ast_debug(2, "profiling: %s, %s, %" PRIi64 " ms\n",
879 (ret == 0) ? "OK" : "FAIL", tmp, ast_tvdiff_ms(time_end, time_start));
880
881 if (ret < 0) {
882 ast_debug(1, "No such number found: %s (%s)\n", tmp, strerror(errno));
883 context->naptr_rrs_count = -1;
884 strcpy(dst, "0");
885 ret = 0;
886 }
887
888 if (context->naptr_rrs_count >= context->position && ! (context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
889 /* sort array by NAPTR order/preference */
890 for (k = 0; k < context->naptr_rrs_count; k++) {
891 for (i = 0; i < context->naptr_rrs_count; i++) {
892 /* use order first and then preference to compare */
893 if ((ntohs(context->naptr_rrs[k].naptr.order) < ntohs(context->naptr_rrs[i].naptr.order)
894 && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
895 || (ntohs(context->naptr_rrs[k].naptr.order) > ntohs(context->naptr_rrs[i].naptr.order)
896 && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
897 z = context->naptr_rrs[k].sort_pos;
898 context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
899 context->naptr_rrs[i].sort_pos = z;
900 continue;
901 }
902 if (ntohs(context->naptr_rrs[k].naptr.order) == ntohs(context->naptr_rrs[i].naptr.order)) {
903 if ((ntohs(context->naptr_rrs[k].naptr.pref) < ntohs(context->naptr_rrs[i].naptr.pref)
904 && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
905 || (ntohs(context->naptr_rrs[k].naptr.pref) > ntohs(context->naptr_rrs[i].naptr.pref)
906 && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
907 z = context->naptr_rrs[k].sort_pos;
908 context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
909 context->naptr_rrs[i].sort_pos = z;
910 }
911 }
912 }
913 }
914 for (k = 0; k < context->naptr_rrs_count; k++) {
915 if (context->naptr_rrs[k].sort_pos == context->position - 1) {
916 ast_copy_string(context->dst, context->naptr_rrs[k].result, dstlen);
917 ast_copy_string(context->tech, context->naptr_rrs[k].tech, techlen);
918 break;
919 }
920 }
921 } else if (!(context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
922 context->dst[0] = 0;
923 } else if ((context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
924 snprintf(context->dst, context->dstlen, "%d", context->naptr_rrs_count + context->count);
925 }
926
927 if (chan) {
928 ret |= ast_autoservice_stop(chan);
929 }
930
931 if (!argcontext) {
932 for (k = 0; k < context->naptr_rrs_count; k++) {
933 ast_free(context->naptr_rrs[k].result);
934 ast_free(context->naptr_rrs[k].tech);
935 }
936 ast_free(context->naptr_rrs);
938 } else {
939 *argcontext = context;
940 }
941
942 return ret;
943}
#define ast_free(a)
Definition: astmm.h:180
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
static int tmp()
Definition: bt_open.c:389
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
int ast_search_dns(void *context, const char *dname, int class, int type, int(*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
Perform DNS lookup (used by DNS, enum and SRV lookups)
Definition: dns.c:491
static int blr_ebl(const char *cc, const char *suffix, char *separator, int sep_len, char *apex, int apex_len)
Evaluate the I-ENUM branch as stored in an EBL record.
Definition: enum.c:330
#define ENUMLOOKUP_BLR_TXT
Definition: enum.c:94
static char ienum_branchlabel[32]
Definition: enum.c:91
#define ENUMLOOKUP_BLR_CC
Definition: enum.c:93
#define ENUMLOOKUP_OPTIONS_COUNT
Definition: enum.c:607
#define ENUMLOOKUP_BLR_EBL
Definition: enum.c:95
static int enum_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Callback from ENUM lookup function.
Definition: enum.c:616
static int cclen(const char *number)
Determine the length of a country code when given an E.164 string.
Definition: enum.c:116
static ast_mutex_t enumlock
Definition: enum.c:101
#define ENUMLOOKUP_OPTIONS_ISN
Definition: enum.c:609
static int blr_txt(const char *cc, const char *suffix)
Determine the branch location record as stored in a TXT record.
Definition: enum.c:201
#define ENUMLOOKUP_OPTIONS_IENUM
Definition: enum.c:611
#define ENUMLOOKUP_OPTIONS_DIRECT
Definition: enum.c:613
static int ebl_alg
Definition: enum.c:96
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
int errno
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * naptrinput
Definition: enum.h:49
Number structure.
Definition: app_followme.c:154
static struct test_options options
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159

References ast_autoservice_start(), ast_autoservice_stop(), ast_calloc, ast_copy_string(), ast_debug, ast_free, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_search_dns(), ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), blr_ebl(), blr_txt(), cclen(), voicemailpwcheck::context, ebl_alg, enum_callback(), enumlock, ENUMLOOKUP_BLR_CC, ENUMLOOKUP_BLR_EBL, ENUMLOOKUP_BLR_TXT, ENUMLOOKUP_OPTIONS_COUNT, ENUMLOOKUP_OPTIONS_DIRECT, ENUMLOOKUP_OPTIONS_IENUM, ENUMLOOKUP_OPTIONS_ISN, errno, ienum_branchlabel, LOG_WARNING, enum_context::naptrinput, NULL, options, and tmp().

Referenced by enum_query_read(), and function_enum().

◆ ast_get_txt()

int ast_get_txt ( struct ast_channel chan,
const char *  number,
char *  txt,
int  maxtxt,
char *  suffix 
)

Lookup DNS TXT record (used by app TXTCIDnum)

Really has nothing to do with enum, but anyway... Actually, there is now an internet-draft which describes how callerID should be stored in ENUM domains: draft-ietf-enum-cnam-04.txt The algorithm implemented here will thus be obsolete soon.

Parameters
chanChannel
numberE164 number with or without the leading +
txtText string (return value)
maxtxtMax length of "txt"
suffixZone suffix
Version
1.6.1 new suffix parameter to take into account caller ids that aren't in e164.arpa
1.6.1 removed parameters location, maxloc, technology, maxtech as all the information is stored the txt string

Definition at line 995 of file enum.c.

996{
997 struct txt_context context;
998 char *domain;
999 int ret;
1000 int autoservice = 0;
1001
1002 ast_debug(4, "ast_get_txt: Number = '%s', suffix = '%s'\n", number, suffix);
1003
1004 domain = format_numeric_domain(number, suffix);
1005 if (!domain) {
1006 return -1;
1007 }
1008
1009 if (chan) {
1010 /* DNS might take a while, so service the channel while we're blocked */
1011 autoservice = !ast_autoservice_start(chan);
1012 }
1013
1014 ret = ast_search_dns(&context, domain, C_IN, T_TXT, txt_callback);
1015 if (ret > 0) {
1017 } else {
1018 ast_debug(2, "No such number found in ENUM: %s (%s)\n", domain, strerror(errno));
1019 }
1020
1021 if (autoservice) {
1023 }
1024
1025 ast_free(domain);
1026 return 0;
1027}
static int txt_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Callback for TXT record lookup, /ol version.
Definition: enum.c:151
static char * format_numeric_domain(const char *number, const char *suffix)
Definition: enum.c:955
int txtlen
Definition: enum.c:147
char txt[1024]
Definition: enum.c:146

References ast_autoservice_start(), ast_autoservice_stop(), ast_copy_string(), ast_debug, ast_free, ast_search_dns(), voicemailpwcheck::context, errno, format_numeric_domain(), txt_context::txt, txt_callback(), and txt_context::txtlen.

Referenced by function_txtcidname().