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 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 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 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 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 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 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 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