Home | History | Annotate | Download | only in pppoatm
      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