aboutsummaryrefslogtreecommitdiffstats
path: root/enum.c
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2003-04-29 04:26:41 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2003-04-29 04:26:41 +0000
commitc78c8b66e958ce959f8ec2176c80b40d9927d94d (patch)
treeb94ae443902e82e3dc0e80c93904a76a059f69b4 /enum.c
parent29328ccb5a620414ef130754e4e928f5012fe0aa (diff)
Add missing enum files
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@933 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'enum.c')
-rwxr-xr-xenum.c260
1 files changed, 260 insertions, 0 deletions
diff --git a/enum.c b/enum.c
new file mode 100755
index 000000000..d606232ac
--- /dev/null
+++ b/enum.c
@@ -0,0 +1,260 @@
+/*
+ * ENUM support
+ *
+ *
+ * ENUM Support for Asterisk
+ *
+ * Copyright (C) 2003 Digium
+ *
+ * Distributed under the terms of the GNU GPL
+ *
+ */
+
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <resolv.h>
+#include <errno.h>
+
+#include <asterisk/logger.h>
+#include <asterisk/options.h>
+#include <asterisk/enum.h>
+#include <asterisk/channel.h>
+
+#define MAX_SIZE 4096
+
+#define TOPLEV "e164.arpa."
+
+
+static int skip_name(unsigned char *s, int len)
+{
+ /* Shamelessly take from SER */
+ int x = 0;
+ while(x < len) {
+ if (!*s) {
+ s++;
+ x++;
+ break;
+ }
+ if (((*s) & 0xc0) == 0xc0) {
+ s += 2;
+ x += 2;
+ break;
+ }
+ x += *s + 1;
+ s += *s + 1;
+ }
+ if (x >= len)
+ return -1;
+ return x;
+}
+
+struct dn_answer {
+ unsigned short rtype;
+ unsigned short class;
+ unsigned int ttl;
+ unsigned short size;
+} __attribute__ ((__packed__));
+
+struct naptr {
+ unsigned short order;
+ unsigned short pref;
+} __attribute__ ((__packed__));
+
+static int parse_ie(unsigned char *data, int maxdatalen, unsigned char *src, int srclen)
+{
+ int len, olen;
+ len = olen = (int)src[0];
+ src++;
+ srclen--;
+ if (len > srclen) {
+ ast_log(LOG_WARNING, "Want %d, got %d\n", len, srclen);
+ return -1;
+ }
+ if (len > maxdatalen)
+ len = maxdatalen;
+ memcpy(data, src, len);
+ return olen + 1;
+}
+
+static int parse_naptr(unsigned char *dst, int dstsize, char *tech, int techsize, unsigned char *answer, int len)
+{
+ unsigned char *oanswer = answer;
+ unsigned char flags[80] = "";
+ unsigned char services[80] = "";
+ unsigned char regexp[80] = "";
+ unsigned char repl[80] = "";
+ int res;
+
+ if (len < sizeof(struct naptr)) {
+ printf("Length too short\n");
+ return -1;
+ }
+ answer += sizeof(struct naptr);
+ len -= sizeof(struct naptr);
+ if ((res = parse_ie(flags, sizeof(flags) - 1, answer, len)) < 0) {
+ ast_log(LOG_WARNING, "Failed to get flags\n");
+ return -1;
+ } else { answer += res; len -= res; }
+ if ((res = parse_ie(services, sizeof(services) - 1, answer, len)) < 0) {
+ ast_log(LOG_WARNING, "Failed to get services\n");
+ return -1;
+ } else { answer += res; len -= res; }
+ if ((res = parse_ie(regexp, sizeof(regexp) - 1, answer, len)) < 0)
+ return -1; else { answer += res; len -= res; }
+ if ((res = dn_expand(oanswer,answer + len,answer, repl, sizeof(repl) - 1)) < 0) {
+ ast_log(LOG_WARNING, "Failed to expand hostname\n");
+ return -1;
+ }
+#if 0
+ printf("Flags: %s\n", flags);
+ printf("Services: %s\n", services);
+ printf("Regexp: %s\n", regexp);
+ printf("Repl: %s\n", repl);
+#endif
+ if (!strncmp(regexp, "!^.*$!", 6)) {
+ if (!strncmp(services, "E2U+voice:", 10)) {
+ if (regexp[strlen(regexp) - 1] == '!')
+ regexp[strlen(regexp) - 1] = '\0';
+#if 0
+ printf("Technology: %s\n", services + 10);
+ printf("Destination: %s\n", regexp + 6);
+#endif
+ strncpy(dst, regexp + 6, dstsize);
+ strncpy(tech, services + 10, techsize);
+ }
+ } else
+ ast_log(LOG_WARNING, "Non-total substitution not yet supported\n");
+ return 0;
+}
+
+static int parse_answer(unsigned char *dst, int dstlen, unsigned char *tech, int techlen, unsigned char *answer, int len)
+{
+ /*
+ * This function is influenced by "ser" the SIP router.
+ */
+ int x;
+ int res;
+ HEADER *h;
+ struct dn_answer *ans;
+ dst[0] = '\0';
+ tech[0] = '\0';
+#if 0
+ for (x=0;x<len;x++) {
+ if ((answer[x] < 32) || (answer[x] > 127)) {
+ if (lastlit)
+ printf("\"");
+ printf(" 0x%02x", answer[x]);
+ lastlit = 0;
+ } else {
+ if (!lastlit)
+ printf(" \"");
+ printf("%c", answer[x]);
+ lastlit = 1;
+ }
+ }
+ printf("\n");
+#endif
+ h = (HEADER *)answer;
+ /* Skip over DNS header */
+ answer += sizeof(HEADER);
+ len -= sizeof(HEADER);
+#if 0
+ printf("Query count: %d\n", ntohs(h->qdcount));
+#endif
+ for (x=0;x<ntohs(h->qdcount);x++) {
+ if ((res = skip_name(answer, len)) < 0) {
+ ast_log(LOG_WARNING, "Couldn't skip over name\n");
+ return -1;
+ }
+ answer += res;
+ len -= res;
+ answer += 4; /* Skip QCODE / QCLASS */
+ len -= 4;
+ if (len < 0) {
+ ast_log(LOG_WARNING, "Strange query size\n");
+ return -1;
+ }
+ }
+#if 0
+ printf("Length remaining: %d\n", len);
+ printf("Answer count: %d\n", ntohs(h->ancount));
+ printf("Looking for %d/%d\n", C_IN, T_NAPTR);
+#endif
+ for (x=0;x<ntohs(h->ancount);x++) {
+ if ((res = skip_name(answer, len) < 0)) {
+ ast_log(LOG_WARNING, "Failed to skip name :(\n");
+ return -1;
+ }
+ answer += res;
+ len -= res;
+ /* XXX Why am I adding 2 here? XXX */
+ answer += 2;
+ len -= 2;
+ ans = (struct dn_answer *)answer;
+ answer += sizeof(struct dn_answer);
+ len -= sizeof(struct dn_answer);
+ if (len < 0)
+ return -1;
+#if 0
+ printf("Type: %d, class: %d, ttl: %d, length: %d\n", ntohs(ans->rtype), ntohs(ans->class),
+ ntohl(ans->ttl), ntohs(ans->size));
+#endif
+ len -= ntohs(ans->size);
+ if (len < 0) {
+ ast_log(LOG_WARNING, "Length exceeds frame\n");
+ return -1;
+ }
+ if ((ntohs(ans->class) == C_IN) && (ntohs(ans->rtype) == T_NAPTR)) {
+ if (parse_naptr(dst, dstlen, tech, techlen, answer, ntohs(ans->size)))
+ ast_log(LOG_WARNING, "Failed to parse naptr :(\n");
+ if (strlen(dst))
+ return 0;
+ }
+ answer += ntohs(ans->size);
+ }
+ return 0;
+}
+
+int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen)
+{
+ unsigned char answer[MAX_SIZE];
+ char tmp[259 + strlen(TOPLEV)];
+ int pos = strlen(number) - 1;
+ int newpos=0;
+ int res;
+ int ret = -1;
+ struct __res_state enumstate;
+ res_ninit(&enumstate);
+ if (chan && ast_autoservice_start(chan) < 0)
+ return -1;
+
+ if (pos > 128)
+ pos = 128;
+ while(pos >= 0) {
+ tmp[newpos++] = number[pos--];
+ tmp[newpos++] = '.';
+ }
+ strcpy(tmp + newpos, TOPLEV);
+#if 0
+ printf("Looking for '%s'\n", tmp);
+#endif
+ res = res_nsearch(&enumstate, tmp, C_IN, T_NAPTR, answer, sizeof(answer));
+ if (res > 0) {
+ if ((res = parse_answer(dst, dstlen, tech, techlen, answer, res))) {
+ ast_log(LOG_WARNING, "Parse error returned %d\n", res);
+ ret = 0;
+ } else {
+ ast_log(LOG_DEBUG, "Found technology '%s', destination '%s'\n", tech, dst);
+ ret = 1;
+ }
+ } else {
+ ast_log(LOG_DEBUG, "No such number found: %s (%s)\n", tmp, strerror(errno));
+ ret = 0;
+ }
+ if (chan)
+ ret |= ast_autoservice_stop(chan);
+ res_nclose(&enumstate);
+ return ret;
+}