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