5e95a2a2efdd9601ab8a8d6b88c26768b1c06e3f
[tinc] / lib / fake-getaddrinfo.c
1 /*
2  * fake library for ssh
3  *
4  * This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
5  * These funtions are defined in rfc2133.
6  *
7  * But these functions are not implemented correctly. The minimum subset
8  * is implemented for ssh use only. For exapmle, this routine assumes
9  * that ai_family is AF_INET. Don't use it for another purpose.
10  */
11
12 #include "config.h"
13
14 #include <stdlib.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <netdb.h>
20 #include <string.h>
21
22 #include <system.h>
23
24 #include "fake-getaddrinfo.h"
25
26 #ifndef HAVE_GAI_STRERROR
27 char *gai_strerror(int ecode)
28 {
29         switch (ecode) {
30                 case EAI_NODATA:
31                         return "no address associated with hostname.";
32                 case EAI_MEMORY:
33                         return "memory allocation failure.";
34                 default:
35                         return "unknown error.";
36         }
37 }    
38 #endif /* !HAVE_GAI_STRERROR */
39
40 #ifndef HAVE_FREEADDRINFO
41 void freeaddrinfo(struct addrinfo *ai)
42 {
43         struct addrinfo *next;
44
45         do {
46                 next = ai->ai_next;
47                 free(ai);
48         } while (NULL != (ai = next));
49 }
50 #endif /* !HAVE_FREEADDRINFO */
51
52 #ifndef HAVE_GETADDRINFO
53 static struct addrinfo *malloc_ai(int port, u_long addr)
54 {
55         struct addrinfo *ai;
56
57         ai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
58         if (ai == NULL)
59                 return(NULL);
60         
61         memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
62         
63         ai->ai_addr = (struct sockaddr *)(ai + 1);
64         /* XXX -- ssh doesn't use sa_len */
65         ai->ai_addrlen = sizeof(struct sockaddr_in);
66         ai->ai_addr->sa_family = ai->ai_family = AF_INET;
67
68         ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
69         ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
70         
71         return(ai);
72 }
73
74 int getaddrinfo(const char *hostname, const char *servname, 
75                 const struct addrinfo *hints, struct addrinfo **res)
76 {
77         struct addrinfo *cur, *prev = NULL;
78         struct hostent *hp;
79         struct in_addr in;
80         int i, port;
81
82         if (servname)
83                 port = htons(atoi(servname));
84         else
85                 port = 0;
86
87         if (hints && hints->ai_flags & AI_PASSIVE) {
88                 if (NULL != (*res = malloc_ai(port, htonl(0x00000000))))
89                         return 0;
90                 else
91                         return EAI_MEMORY;
92         }
93                 
94         if (!hostname) {
95                 if (NULL != (*res = malloc_ai(port, htonl(0x7f000001))))
96                         return 0;
97                 else
98                         return EAI_MEMORY;
99         }
100         
101 #ifdef HAVE_INET_ATON
102         if (inet_aton(hostname, &in)) {
103                 if (NULL != (*res = malloc_ai(port, in.s_addr)))
104                         return 0;
105                 else
106                         return EAI_MEMORY;
107         }
108 #endif
109         
110         hp = gethostbyname(hostname);
111         if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
112                 for (i = 0; hp->h_addr_list[i]; i++) {
113                         cur = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
114                         if (cur == NULL) {
115                                 if (*res)
116                                         freeaddrinfo(*res);
117                                 return EAI_MEMORY;
118                         }
119                         
120                         if (prev)
121                                 prev->ai_next = cur;
122                         else
123                                 *res = cur;
124
125                         prev = cur;
126                 }
127                 return 0;
128         }
129         
130         return EAI_NODATA;
131 }
132 #endif /* !HAVE_GETADDRINFO */