1 /* ans.c - Interface for text2atm and atm2text to ANS */
3 /* Written 1996-2000 by Werner Almesberger, EPFL-LRC/ICA */
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).
22 #include <netinet/in.h>
23 #include <arpa/nameser.h>
31 #define MAX_ANSWER 2048
34 #define MAX_LINE 2048 /* in /etc/e164_cc */
35 #define E164_CC_DEFAULT_LEN 2
36 #define E164_CC_FILE "/etc/e164_cc"
38 #define GET16(pos) (((pos)[0] << 8) | (pos)[1])
41 static int ans(const char *text,int wanted,void *result,int res_len)
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;
49 found_len = 0; /* gcc wants it */
50 if ((answer_len = res_search(text,C_IN,wanted,answer,MAX_ANSWER)) < 0)
53 * Response header: id, flags, #queries, #answers, #authority,
54 * #additional (all 16 bits)
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;
63 * Query: name, type (16), class (16)
65 if ((name_len = dn_expand(answer,answer+answer_len,pos,name,MAX_NAME)) < 0)
68 if (GET16(pos) != wanted || GET16(pos+2) != C_IN) return TRY_OTHER;
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)
77 * RR: name, type (16), class (16), TTL (32), resource_len (16),
80 if ((name_len = dn_expand(answer,answer+answer_len,pos,name,MAX_NAME))
81 < 0) return TRY_OTHER;
83 data_len = GET16(pos+8);
86 if (GET16(data-10) != wanted || GET16(data-8) != C_IN || !--data_len)
91 if (data_len != ATM_ESA_LEN) continue;
92 memcpy(((struct sockaddr_atmsvc *) result)->
93 sas_addr.prv,data,ATM_ESA_LEN);
98 if (data_len != ATM_ESA_LEN) continue;
99 memcpy(((struct sockaddr_atmsvc *) result)->
100 sas_addr.prv,data,ATM_ESA_LEN);
103 if (data_len > ATM_E164_LEN) continue;
106 found_len = data_len;
113 if (dn_expand(answer,answer+answer_len,data,result,
114 res_len) < 0) return FATAL;
120 if (!found) return TRY_OTHER;
121 memcpy(((struct sockaddr_atmsvc *) result)->sas_addr.pub,found,
123 ((struct sockaddr_atmsvc *) result)->sas_addr.pub[found_len] = 0;
128 int ans_byname(const char *text,struct sockaddr_atmsvc *addr,int length,
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);
139 static int encode_nsap(char *buf,const unsigned char *addr)
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,
143 static int fmt_e164[] = { 2,12,1,1,1,1,1,1,1,1,16,2,0 };
151 case ATM_AFI_DCC_GROUP:
152 case ATM_AFI_ICD_GROUP:
153 case ATM_AFI_LOCAL_GROUP:
157 case ATM_AFI_E164_GROUP:
164 for (i = 0; fmt[i]; i++) {
166 for (j = 0; j < fmt[i]; j++)
168 (addr[(pos+j) >> 1] >> 4*(1-((pos+j) & 1))) & 0xf);
171 strcpy(buf,"AESA.ATMA.INT.");
176 static int encode_nsap_new(char *buf,const unsigned char *addr)
183 digit = addr[i] & 0x0F;
184 *(buf++) = digit + (digit >= 10 ? '7' : '0');
186 digit = ((unsigned char) (addr[i])) >> 4;
187 *(buf++) = digit + (digit >= 10 ? '7' : '0');
190 strcpy (buf, "NSAP.INT.");
195 static int cc_len(int p0,int p1)
197 static char *cc_table = NULL;
199 char buffer[MAX_LINE];
204 if (!(cc_table = malloc(100))) {
206 return E164_CC_DEFAULT_LEN;
208 memset(cc_table,E164_CC_DEFAULT_LEN,100);
209 if (!(file = fopen(E164_CC_FILE,"r")))
210 perror(E164_CC_FILE);
212 while (fgets(buffer,MAX_LINE,file)) {
213 here = strchr(buffer,'#');
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;
224 if (cc_table[p0] == 1) return 1;
225 return cc_table[p0*10+p1];
229 static int encode_e164(char *buf,const char *addr)
231 const char *prefix,*here;
233 prefix = addr+cc_len(addr[0]-48,addr[1]-48);
234 here = strchr(addr,0);
235 while (here > prefix) {
239 while (here > addr) *buf++ = *addr++;
240 strcpy(buf,".E164.ATMA.INT.");
245 int ans_byaddr(char *buffer,int length,const struct sockaddr_atmsvc *addr,
248 char tmp[MAX_NAME]; /* could be smaller ... */
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);
258 res = encode_e164(tmp,addr->sas_addr.pub);
259 if (res < 0) return res;
260 return ans(tmp,T_PTR,buffer,length);