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