rev |
line source |
yuuji@0
|
1 /* ========================================================================
|
yuuji@0
|
2 * Copyright 1988-2006 University of Washington
|
yuuji@0
|
3 *
|
yuuji@0
|
4 * Licensed under the Apache License, Version 2.0 (the "License");
|
yuuji@0
|
5 * you may not use this file except in compliance with the License.
|
yuuji@0
|
6 * You may obtain a copy of the License at
|
yuuji@0
|
7 *
|
yuuji@0
|
8 * http://www.apache.org/licenses/LICENSE-2.0
|
yuuji@0
|
9 *
|
yuuji@0
|
10 *
|
yuuji@0
|
11 * ========================================================================
|
yuuji@0
|
12 */
|
yuuji@0
|
13
|
yuuji@0
|
14 /*
|
yuuji@0
|
15 * Program: UNIX IPv6 routines
|
yuuji@0
|
16 *
|
yuuji@0
|
17 * Author: Mark Crispin
|
yuuji@0
|
18 * Networks and Distributed Computing
|
yuuji@0
|
19 * Computing & Communications
|
yuuji@0
|
20 * University of Washington
|
yuuji@0
|
21 * Administration Building, AG-44
|
yuuji@0
|
22 * Seattle, WA 98195
|
yuuji@0
|
23 * Internet: MRC@CAC.Washington.EDU
|
yuuji@0
|
24 *
|
yuuji@0
|
25 * Date: 18 December 2003
|
yuuji@0
|
26 * Last Edited: 30 August 2006
|
yuuji@0
|
27 */
|
yuuji@0
|
28
|
yuuji@0
|
29
|
yuuji@0
|
30 /*
|
yuuji@0
|
31 * There is some amazingly bad design in IPv6 sockets.
|
yuuji@0
|
32 *
|
yuuji@0
|
33 * Supposedly, the new getnameinfo() and getaddrinfo() functions create an
|
yuuji@0
|
34 * abstraction that is not dependent upon IPv4 or IPv6. However, the
|
yuuji@0
|
35 * definition of getnameinfo() requires that the caller pass the length of
|
yuuji@0
|
36 * the sockaddr instead of deriving it from sa_family. The man page says
|
yuuji@0
|
37 * that there's an sa_len member in the sockaddr, but actually there isn't.
|
yuuji@0
|
38 * This means that any caller to getnameinfo() and getaddrinfo() has to know
|
yuuji@0
|
39 * the size for the protocol family used by that sockaddr.
|
yuuji@0
|
40 *
|
yuuji@0
|
41 * The new sockaddr_in6 is bigger than the generic sockaddr (which is what
|
yuuji@0
|
42 * connect(), accept(), bind(), getpeername(), getsockname(), etc. expect).
|
yuuji@0
|
43 * Rather than increase the size of sockaddr, there's a new sockaddr_storage
|
yuuji@0
|
44 * which is only usable for allocating space.
|
yuuji@0
|
45 */
|
yuuji@0
|
46
|
yuuji@0
|
47 #define SADRLEN sizeof (struct sockaddr_storage)
|
yuuji@0
|
48
|
yuuji@0
|
49 #define SADR4(sadr) ((struct sockaddr_in *) sadr)
|
yuuji@0
|
50 #define SADR4LEN sizeof (struct sockaddr_in)
|
yuuji@0
|
51 #define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
|
yuuji@0
|
52 #define ADR4LEN sizeof (struct in_addr)
|
yuuji@0
|
53 #define SADR4PORT(sadr) SADR4 (sadr)->sin_port
|
yuuji@0
|
54
|
yuuji@0
|
55 #define SADR6(sadr) ((struct sockaddr_in6 *) sadr)
|
yuuji@0
|
56 #define SADR6LEN sizeof (struct sockaddr_in6)
|
yuuji@0
|
57 #define SADR6ADR(sadr) SADR6 (sadr)->sin6_addr
|
yuuji@0
|
58 #define ADR6LEN sizeof (struct in6_addr)
|
yuuji@0
|
59 #define SADR6PORT(sadr) SADR6 (sadr)->sin6_port
|
yuuji@0
|
60
|
yuuji@0
|
61
|
yuuji@0
|
62 /* IP abstraction layer */
|
yuuji@0
|
63
|
yuuji@0
|
64 char *ip_sockaddrtostring (struct sockaddr *sadr);
|
yuuji@0
|
65 long ip_sockaddrtoport (struct sockaddr *sadr);
|
yuuji@0
|
66 void *ip_stringtoaddr (char *text,size_t *len,int *family);
|
yuuji@0
|
67 struct sockaddr *ip_newsockaddr (size_t *len);
|
yuuji@0
|
68 struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
|
yuuji@0
|
69 unsigned short port,size_t *len);
|
yuuji@0
|
70 char *ip_sockaddrtoname (struct sockaddr *sadr);
|
yuuji@0
|
71 void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
|
yuuji@0
|
72 void **next);
|
yuuji@0
|
73
|
yuuji@0
|
74 /* Return IP address string from socket address
|
yuuji@0
|
75 * Accepts: socket address
|
yuuji@0
|
76 * Returns: IP address as name string
|
yuuji@0
|
77 */
|
yuuji@0
|
78
|
yuuji@0
|
79 char *ip_sockaddrtostring (struct sockaddr *sadr)
|
yuuji@0
|
80 {
|
yuuji@0
|
81 static char tmp[NI_MAXHOST];
|
yuuji@0
|
82 switch (sadr->sa_family) {
|
yuuji@0
|
83 case PF_INET: /* IPv4 */
|
yuuji@0
|
84 if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
|
yuuji@0
|
85 return tmp;
|
yuuji@0
|
86 break;
|
yuuji@0
|
87 case PF_INET6: /* IPv6 */
|
yuuji@0
|
88 if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
|
yuuji@0
|
89 return tmp;
|
yuuji@0
|
90 break;
|
yuuji@0
|
91 }
|
yuuji@0
|
92 return "NON-IP";
|
yuuji@0
|
93 }
|
yuuji@0
|
94
|
yuuji@0
|
95
|
yuuji@0
|
96 /* Return port from socket address
|
yuuji@0
|
97 * Accepts: socket address
|
yuuji@0
|
98 * Returns: port number or -1 if can't determine it
|
yuuji@0
|
99 */
|
yuuji@0
|
100
|
yuuji@0
|
101 long ip_sockaddrtoport (struct sockaddr *sadr)
|
yuuji@0
|
102 {
|
yuuji@0
|
103 switch (sadr->sa_family) {
|
yuuji@0
|
104 case PF_INET:
|
yuuji@0
|
105 return ntohs (SADR4PORT (sadr));
|
yuuji@0
|
106 case PF_INET6:
|
yuuji@0
|
107 return ntohs (SADR6PORT (sadr));
|
yuuji@0
|
108 }
|
yuuji@0
|
109 return -1;
|
yuuji@0
|
110 }
|
yuuji@0
|
111
|
yuuji@0
|
112 /* Return IP address from string
|
yuuji@0
|
113 * Accepts: name string
|
yuuji@0
|
114 * pointer to returned length
|
yuuji@0
|
115 * pointer to returned address family
|
yuuji@0
|
116 * Returns: address if valid, length and family updated, or NIL
|
yuuji@0
|
117 */
|
yuuji@0
|
118
|
yuuji@0
|
119 void *ip_stringtoaddr (char *text,size_t *len,int *family)
|
yuuji@0
|
120
|
yuuji@0
|
121 {
|
yuuji@0
|
122 char tmp[MAILTMPLEN];
|
yuuji@0
|
123 static struct addrinfo *hints;
|
yuuji@0
|
124 struct addrinfo *ai;
|
yuuji@0
|
125 void *adr = NIL;
|
yuuji@0
|
126 if (!hints) { /* hints set up yet? */
|
yuuji@0
|
127 hints = (struct addrinfo *) /* one-time setup */
|
yuuji@0
|
128 memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
|
yuuji@0
|
129 hints->ai_family = AF_UNSPEC;/* allow any address family */
|
yuuji@0
|
130 hints->ai_socktype = SOCK_STREAM;
|
yuuji@0
|
131 /* numeric name only */
|
yuuji@0
|
132 hints->ai_flags = AI_NUMERICHOST;
|
yuuji@0
|
133 }
|
yuuji@0
|
134 /* case-independent lookup */
|
yuuji@0
|
135 if (text && (strlen (text) < MAILTMPLEN) &&
|
yuuji@0
|
136 (!getaddrinfo (lcase (strcpy (tmp,text)),NIL,hints,&ai))) {
|
yuuji@0
|
137 switch (*family = ai->ai_family) {
|
yuuji@0
|
138 case AF_INET: /* IPv4 */
|
yuuji@0
|
139 adr = fs_get (*len = ADR4LEN);
|
yuuji@0
|
140 memcpy (adr,(void *) &SADR4ADR (ai->ai_addr),*len);
|
yuuji@0
|
141 break;
|
yuuji@0
|
142 case AF_INET6: /* IPv6 */
|
yuuji@0
|
143 adr = fs_get (*len = ADR6LEN);
|
yuuji@0
|
144 memcpy (adr,(void *) &SADR6ADR (ai->ai_addr),*len);
|
yuuji@0
|
145 break;
|
yuuji@0
|
146 }
|
yuuji@0
|
147 freeaddrinfo (ai); /* free addrinfo */
|
yuuji@0
|
148 }
|
yuuji@0
|
149 return adr;
|
yuuji@0
|
150 }
|
yuuji@0
|
151
|
yuuji@0
|
152 /* Create a maximum-size socket address
|
yuuji@0
|
153 * Accepts: pointer to return maximum socket address length
|
yuuji@0
|
154 * Returns: new, empty socket address of maximum size
|
yuuji@0
|
155 */
|
yuuji@0
|
156
|
yuuji@0
|
157 struct sockaddr *ip_newsockaddr (size_t *len)
|
yuuji@0
|
158 {
|
yuuji@0
|
159 return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
|
yuuji@0
|
160 }
|
yuuji@0
|
161
|
yuuji@0
|
162
|
yuuji@0
|
163 /* Stuff a socket address
|
yuuji@0
|
164 * Accepts: address family
|
yuuji@0
|
165 * IPv4 address
|
yuuji@0
|
166 * length of address
|
yuuji@0
|
167 * port number
|
yuuji@0
|
168 * pointer to return socket address length
|
yuuji@0
|
169 * Returns: socket address
|
yuuji@0
|
170 */
|
yuuji@0
|
171
|
yuuji@0
|
172 struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
|
yuuji@0
|
173 unsigned short port,size_t *len)
|
yuuji@0
|
174 {
|
yuuji@0
|
175 struct sockaddr *sadr = ip_newsockaddr (len);
|
yuuji@0
|
176 switch (family) { /* build socket address based upon family */
|
yuuji@0
|
177 case AF_INET: /* IPv4 */
|
yuuji@0
|
178 sadr->sa_family = PF_INET;
|
yuuji@0
|
179 /* copy host address */
|
yuuji@0
|
180 memcpy (&SADR4ADR (sadr),adr,adrlen);
|
yuuji@0
|
181 /* copy port number in network format */
|
yuuji@0
|
182 SADR4PORT (sadr) = htons (port);
|
yuuji@0
|
183 *len = SADR4LEN;
|
yuuji@0
|
184 break;
|
yuuji@0
|
185 case AF_INET6: /* IPv6 */
|
yuuji@0
|
186 sadr->sa_family = PF_INET6;
|
yuuji@0
|
187 /* copy host address */
|
yuuji@0
|
188 memcpy (&SADR6ADR (sadr),adr,adrlen);
|
yuuji@0
|
189 /* copy port number in network format */
|
yuuji@0
|
190 SADR6PORT (sadr) = htons (port);
|
yuuji@0
|
191 *len = SADR6LEN;
|
yuuji@0
|
192 break;
|
yuuji@0
|
193 default: /* non-IP?? */
|
yuuji@0
|
194 sadr->sa_family = PF_UNSPEC;
|
yuuji@0
|
195 break;
|
yuuji@0
|
196 }
|
yuuji@0
|
197 return sadr;
|
yuuji@0
|
198 }
|
yuuji@0
|
199
|
yuuji@0
|
200 /* Return name from socket address
|
yuuji@0
|
201 * Accepts: socket address
|
yuuji@0
|
202 * Returns: canonical name for that address or NIL if none
|
yuuji@0
|
203 */
|
yuuji@0
|
204
|
yuuji@0
|
205 char *ip_sockaddrtoname (struct sockaddr *sadr)
|
yuuji@0
|
206 {
|
yuuji@0
|
207 static char tmp[NI_MAXHOST];
|
yuuji@0
|
208 switch (sadr->sa_family) {
|
yuuji@0
|
209 case PF_INET: /* IPv4 */
|
yuuji@0
|
210 if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
|
yuuji@0
|
211 return tmp;
|
yuuji@0
|
212 break;
|
yuuji@0
|
213 case PF_INET6: /* IPv6 */
|
yuuji@0
|
214 if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
|
yuuji@0
|
215 return tmp;
|
yuuji@0
|
216 break;
|
yuuji@0
|
217 }
|
yuuji@0
|
218 return NIL;
|
yuuji@0
|
219 }
|
yuuji@0
|
220
|
yuuji@0
|
221 /* Return address from name
|
yuuji@0
|
222 * Accepts: name or NIL to return next address
|
yuuji@0
|
223 * pointer to previous/returned length
|
yuuji@0
|
224 * pointer to previous/returned address family
|
yuuji@0
|
225 * pointer to previous/returned canonical name
|
yuuji@0
|
226 * pointer to previous/return state for next-address calls
|
yuuji@0
|
227 * Returns: address with length/family/canonical updated if needed, or NIL
|
yuuji@0
|
228 */
|
yuuji@0
|
229
|
yuuji@0
|
230 void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
|
yuuji@0
|
231 void **next)
|
yuuji@0
|
232 {
|
yuuji@0
|
233 struct addrinfo *cur = NIL;
|
yuuji@0
|
234 static struct addrinfo *hints;
|
yuuji@0
|
235 static struct addrinfo *ai = NIL;
|
yuuji@0
|
236 static char lcname[MAILTMPLEN];
|
yuuji@0
|
237 if (!hints) { /* hints set up yet? */
|
yuuji@0
|
238 hints = (struct addrinfo *) /* one-time setup */
|
yuuji@0
|
239 memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
|
yuuji@0
|
240 /* allow any address family */
|
yuuji@0
|
241 hints->ai_family = AF_UNSPEC;
|
yuuji@0
|
242 hints->ai_socktype = SOCK_STREAM;
|
yuuji@0
|
243 /* need canonical name */
|
yuuji@0
|
244 hints->ai_flags = AI_CANONNAME;
|
yuuji@0
|
245 }
|
yuuji@0
|
246 if (name) { /* name supplied? */
|
yuuji@0
|
247 if (ai) {
|
yuuji@0
|
248 freeaddrinfo (ai); /* free old addrinfo */
|
yuuji@0
|
249 ai = NIL;
|
yuuji@0
|
250 }
|
yuuji@0
|
251 /* case-independent lookup */
|
yuuji@0
|
252 if ((strlen (name) < MAILTMPLEN) &&
|
yuuji@0
|
253 (!getaddrinfo (lcase (strcpy (lcname,name)),NIL,hints,&ai))) {
|
yuuji@0
|
254 cur = ai; /* current block */
|
yuuji@0
|
255 if (canonical) /* set canonical name */
|
yuuji@0
|
256 *canonical = cur->ai_canonname ? cur->ai_canonname : lcname;
|
yuuji@0
|
257 /* remember as next block */
|
yuuji@0
|
258 if (next) *next = (void *) ai;
|
yuuji@0
|
259 }
|
yuuji@0
|
260 else { /* error */
|
yuuji@0
|
261 cur = NIL;
|
yuuji@0
|
262 if (len) *len = 0;
|
yuuji@0
|
263 if (family) *family = 0;
|
yuuji@0
|
264 if (canonical) *canonical = NIL;
|
yuuji@0
|
265 if (next) *next = NIL;
|
yuuji@0
|
266 }
|
yuuji@0
|
267 }
|
yuuji@0
|
268 /* return next in series */
|
yuuji@0
|
269 else if (next && (cur = ((struct addrinfo *) *next)->ai_next)) {
|
yuuji@0
|
270 *next = cur; /* set as last address */
|
yuuji@0
|
271 /* set canonical in case changed */
|
yuuji@0
|
272 if (canonical && cur->ai_canonname) *canonical = cur->ai_canonname;
|
yuuji@0
|
273 }
|
yuuji@0
|
274
|
yuuji@0
|
275 if (cur) { /* got data? */
|
yuuji@0
|
276 if (family) *family = cur->ai_family;
|
yuuji@0
|
277 switch (cur->ai_family) {
|
yuuji@0
|
278 case AF_INET:
|
yuuji@0
|
279 if (len) *len = ADR4LEN;
|
yuuji@0
|
280 return (void *) &SADR4ADR (cur->ai_addr);
|
yuuji@0
|
281 case AF_INET6:
|
yuuji@0
|
282 if (len) *len = ADR6LEN;
|
yuuji@0
|
283 return (void *) &SADR6ADR (cur->ai_addr);
|
yuuji@0
|
284 }
|
yuuji@0
|
285 }
|
yuuji@0
|
286 if (len) *len = 0; /* error return */
|
yuuji@0
|
287 return NIL;
|
yuuji@0
|
288 }
|