ans.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /* ans.c - Interface for text2atm and atm2text to ANS */
  2. /* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */
  3. /*
  4. * This stuff is a temporary hack to avoid using gethostbyname_nsap and such
  5. * without doing the "full upgrade" to getaddrinfo/getnameinfo. This also
  6. * serves as an exercise for me to get all the details right before I propose
  7. * a patch that would eventually end up in libc (and that should therefore be
  8. * as stable as possible).
  9. */
  10. #if HAVE_CONFIG_H
  11. #include <config.h>
  12. #endif
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <netinet/in.h>
  17. #include <arpa/nameser.h>
  18. #include <netdb.h>
  19. #include <resolv.h>
  20. #include "atm.h"
  21. #include "atmres.h"
  22. #define MAX_ANSWER 2048
  23. #define MAX_NAME 1024
  24. #define MAX_LINE 2048 /* in /etc/e164_cc */
  25. #define E164_CC_DEFAULT_LEN 2
  26. #define E164_CC_FILE "/etc/e164_cc"
  27. #define GET16(pos) (((pos)[0] << 8) | (pos)[1])
  28. static int ans(const char *text,int wanted,void *result,int res_len)
  29. {
  30. unsigned char answer[MAX_ANSWER];
  31. unsigned char name[MAX_NAME];
  32. unsigned char *pos,*data,*found;
  33. int answer_len,name_len,data_len,found_len;
  34. int questions,answers;
  35. found_len = 0; /* gcc wants it */
  36. if ((answer_len = res_search(text,C_IN,wanted,answer,MAX_ANSWER)) < 0)
  37. return TRY_OTHER;
  38. /*
  39. * Response header: id, flags, #queries, #answers, #authority,
  40. * #additional (all 16 bits)
  41. */
  42. pos = answer+12;
  43. if (answer[3] & 15) return TRY_OTHER; /* rcode != 0 */
  44. questions = GET16(answer+4);
  45. if (questions != 1) return TRY_OTHER; /* trouble ... */
  46. answers = GET16(answer+6);
  47. if (answers < 1) return TRY_OTHER;
  48. /*
  49. * Query: name, type (16), class (16)
  50. */
  51. if ((name_len = dn_expand(answer,answer+answer_len,pos,name,MAX_NAME)) < 0)
  52. return TRY_OTHER;
  53. pos += name_len;
  54. if (GET16(pos) != wanted || GET16(pos+2) != C_IN) return TRY_OTHER;
  55. pos += 4;
  56. /*
  57. * Iterate over answers until we find something we like, giving priority
  58. * to ATMA_AESA (until signaling is fixed to work with E.164 too)
  59. */
  60. found = NULL;
  61. while (answers--) {
  62. /*
  63. * RR: name, type (16), class (16), TTL (32), resource_len (16),
  64. * resource_data ...
  65. */
  66. if ((name_len = dn_expand(answer,answer+answer_len,pos,name,MAX_NAME))
  67. < 0) return TRY_OTHER;
  68. pos += name_len;
  69. data_len = GET16(pos+8);
  70. data = pos+10;
  71. pos = data+data_len;
  72. if (GET16(data-10) != wanted || GET16(data-8) != C_IN || !--data_len)
  73. continue;
  74. switch (wanted) {
  75. case T_NSAP:
  76. data_len++;
  77. if (data_len != ATM_ESA_LEN) continue;
  78. memcpy(((struct sockaddr_atmsvc *) result)->
  79. sas_addr.prv,data,ATM_ESA_LEN);
  80. return 0;
  81. case T_ATMA:
  82. switch (*data++) {
  83. case ATMA_AESA:
  84. if (data_len != ATM_ESA_LEN) continue;
  85. memcpy(((struct sockaddr_atmsvc *) result)->
  86. sas_addr.prv,data,ATM_ESA_LEN);
  87. return 0;
  88. case ATMA_E164:
  89. if (data_len > ATM_E164_LEN) continue;
  90. if (!found) {
  91. found = data;
  92. found_len = data_len;
  93. }
  94. break;
  95. default:
  96. continue;
  97. }
  98. case T_PTR:
  99. if (dn_expand(answer,answer+answer_len,data,result,
  100. res_len) < 0) return FATAL;
  101. return 0;
  102. default:
  103. continue;
  104. }
  105. }
  106. if (!found) return TRY_OTHER;
  107. memcpy(((struct sockaddr_atmsvc *) result)->sas_addr.pub,found,
  108. found_len);
  109. ((struct sockaddr_atmsvc *) result)->sas_addr.pub[found_len] = 0;
  110. return 0;
  111. }
  112. int ans_byname(const char *text,struct sockaddr_atmsvc *addr,int length,
  113. int flags)
  114. {
  115. if (!(flags & T2A_SVC) || length != sizeof(*addr)) return TRY_OTHER;
  116. memset(addr,0,sizeof(*addr));
  117. addr->sas_family = AF_ATMSVC;
  118. if (!ans(text,T_ATMA,addr,length)) return 0;
  119. return ans(text,T_NSAP,addr,length);
  120. }
  121. static int encode_nsap(char *buf,const unsigned char *addr)
  122. {
  123. static int fmt_dcc[] = { 2,12,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  124. 4,2,0 };
  125. static int fmt_e164[] = { 2,12,1,1,1,1,1,1,1,1,16,2,0 };
  126. int *fmt;
  127. int pos,i,j;
  128. switch (*addr) {
  129. case ATM_AFI_DCC:
  130. case ATM_AFI_ICD:
  131. case ATM_AFI_LOCAL:
  132. case ATM_AFI_DCC_GROUP:
  133. case ATM_AFI_ICD_GROUP:
  134. case ATM_AFI_LOCAL_GROUP:
  135. fmt = fmt_dcc;
  136. break;
  137. case ATM_AFI_E164:
  138. case ATM_AFI_E164_GROUP:
  139. fmt = fmt_e164;
  140. break;
  141. default:
  142. return TRY_OTHER;
  143. }
  144. pos = 2*ATM_ESA_LEN;
  145. for (i = 0; fmt[i]; i++) {
  146. pos -= fmt[i];
  147. for (j = 0; j < fmt[i]; j++)
  148. sprintf(buf++,"%x",
  149. (addr[(pos+j) >> 1] >> 4*(1-((pos+j) & 1))) & 0xf);
  150. *buf++ = '.';
  151. }
  152. strcpy(buf,"AESA.ATMA.INT.");
  153. return 0;
  154. }
  155. static int encode_nsap_new(char *buf,const unsigned char *addr)
  156. {
  157. int i;
  158. int digit;
  159. for (i = 20; i; ) {
  160. i--;
  161. digit = addr[i] & 0x0F;
  162. *(buf++) = digit + (digit >= 10 ? '7' : '0');
  163. *(buf++) = '.';
  164. digit = ((unsigned char) (addr[i])) >> 4;
  165. *(buf++) = digit + (digit >= 10 ? '7' : '0');
  166. *(buf++) = '.';
  167. }
  168. strcpy (buf, "NSAP.INT.");
  169. return 0;
  170. }
  171. static int cc_len(int p0,int p1)
  172. {
  173. static char *cc_table = NULL;
  174. FILE *file;
  175. char buffer[MAX_LINE];
  176. char *here;
  177. int cc;
  178. if (!cc_table) {
  179. if (!(cc_table = malloc(100))) {
  180. perror("malloc");
  181. return E164_CC_DEFAULT_LEN;
  182. }
  183. memset(cc_table,E164_CC_DEFAULT_LEN,100);
  184. if (!(file = fopen(E164_CC_FILE,"r")))
  185. perror(E164_CC_FILE);
  186. else {
  187. while (fgets(buffer,MAX_LINE,file)) {
  188. here = strchr(buffer,'#');
  189. if (here) *here = 0;
  190. if (sscanf(buffer,"%d",&cc) == 1) {
  191. if (cc < 10) cc_table[cc] = 1;
  192. else if (cc < 100) cc_table[cc] = 2;
  193. else cc_table[cc/10] = 3;
  194. }
  195. }
  196. fclose(file);
  197. }
  198. }
  199. if (cc_table[p0] == 1) return 1;
  200. return cc_table[p0*10+p1];
  201. }
  202. static int encode_e164(char *buf,const char *addr)
  203. {
  204. const char *prefix,*here;
  205. prefix = addr+cc_len(addr[0]-48,addr[1]-48);
  206. here = strchr(addr,0);
  207. while (here > prefix) {
  208. *buf++ = *--here;
  209. *buf++ = '.';
  210. }
  211. while (here > addr) *buf++ = *addr++;
  212. strcpy(buf,".E164.ATMA.INT.");
  213. return 0;
  214. }
  215. int ans_byaddr(char *buffer,int length,const struct sockaddr_atmsvc *addr,
  216. int flags)
  217. {
  218. char tmp[MAX_NAME]; /* could be smaller ... */
  219. int res;
  220. if (addr->sas_addr.prv) {
  221. res = encode_nsap(tmp,addr->sas_addr.prv);
  222. if (!res && !ans(tmp,T_PTR,buffer,length)) return 0;
  223. res = encode_nsap_new(tmp,addr->sas_addr.prv);
  224. if (res < 0) return res;
  225. return ans(tmp,T_PTR,buffer,length);
  226. } else {
  227. res = encode_e164(tmp,addr->sas_addr.pub);
  228. if (res < 0) return res;
  229. return ans(tmp,T_PTR,buffer,length);
  230. }
  231. }