d831732d71bd384bcc2b64167da4c88701934c11
[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 <netinet/in.h>
17 #include <sys/socket.h>
18 #include <netdb.h>
19 #include <string.h>
20
21 #include <system.h>
22
23 #include "fake-getaddrinfo.h"
24
25 #ifndef HAVE_GAI_STRERROR
26 char *gai_strerror(int ecode)
27 {
28         switch (ecode) {
29                 case EAI_NODATA:
30                         return "no address associated with hostname.";
31                 case EAI_MEMORY:
32                         return "memory allocation failure.";
33                 default:
34                         return "unknown error.";
35         }
36 }    
37 #endif /* !HAVE_GAI_STRERROR */
38
39 #ifndef HAVE_FREEADDRINFO
40 void freeaddrinfo(struct addrinfo *ai)
41 {
42         struct addrinfo *next;
43
44         do {
45                 next = ai->ai_next;
46                 free(ai);
47         } while (NULL != (ai = next));
48 }
49 #endif /* !HAVE_FREEADDRINFO */
50
51 #ifndef HAVE_GETADDRINFO
52 static struct addrinfo *malloc_ai(int port, u_long addr)
53 {
54         struct addrinfo *ai;
55
56         ai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
57         if (ai == NULL)
58                 return(NULL);
59         
60         memset(ai, 0, sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
61         
62         ai->ai_addr = (struct sockaddr *)(ai + 1);
63         /* XXX -- ssh doesn't use sa_len */
64         ai->ai_addrlen = sizeof(struct sockaddr_in);
65         ai->ai_addr->sa_family = ai->ai_family = AF_INET;
66
67         ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
68         ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
69         
70         return(ai);
71 }
72
73 int getaddrinfo(const char *hostname, const char *servname, 
74                 const struct addrinfo *hints, struct addrinfo **res)
75 {
76         struct addrinfo *cur, *prev = NULL;
77         struct hostent *hp;
78         struct in_addr in;
79         int i, port;
80
81         if (servname)
82                 port = htons(atoi(servname));
83         else
84                 port = 0;
85
86         if (hints && hints->ai_flags & AI_PASSIVE) {
87                 if (NULL != (*res = malloc_ai(port, htonl(0x00000000))))
88                         return 0;
89                 else
90                         return EAI_MEMORY;
91         }
92                 
93         if (!hostname) {
94                 if (NULL != (*res = malloc_ai(port, htonl(0x7f000001))))
95                         return 0;
96                 else
97                         return EAI_MEMORY;
98         }
99         
100         if (inet_aton(hostname, &in)) {
101                 if (NULL != (*res = malloc_ai(port, in.s_addr)))
102                         return 0;
103                 else
104                         return EAI_MEMORY;
105         }
106         
107         hp = gethostbyname(hostname);
108         if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
109                 for (i = 0; hp->h_addr_list[i]; i++) {
110                         cur = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
111                         if (cur == NULL) {
112                                 if (*res)
113                                         freeaddrinfo(*res);
114                                 return EAI_MEMORY;
115                         }
116                         
117                         if (prev)
118                                 prev->ai_next = cur;
119                         else
120                                 *res = cur;
121
122                         prev = cur;
123                 }
124                 return 0;
125         }
126         
127         return EAI_NODATA;
128 }
129 #endif /* !HAVE_GETADDRINFO */