connect: treat an interface bindlocal() problem as a non-fatal error
[platform/upstream/curl.git] / lib / if2ip.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23 #include "curl_setup.h"
24
25 #ifdef HAVE_NETINET_IN_H
26 #  include <netinet/in.h>
27 #endif
28 #ifdef HAVE_ARPA_INET_H
29 #  include <arpa/inet.h>
30 #endif
31 #ifdef HAVE_NET_IF_H
32 #  include <net/if.h>
33 #endif
34 #ifdef HAVE_SYS_IOCTL_H
35 #  include <sys/ioctl.h>
36 #endif
37 #ifdef HAVE_NETDB_H
38 #  include <netdb.h>
39 #endif
40 #ifdef HAVE_SYS_SOCKIO_H
41 #  include <sys/sockio.h>
42 #endif
43 #ifdef HAVE_IFADDRS_H
44 #  include <ifaddrs.h>
45 #endif
46 #ifdef HAVE_STROPTS_H
47 #  include <stropts.h>
48 #endif
49 #ifdef __VMS
50 #  include <inet.h>
51 #endif
52
53 #include "inet_ntop.h"
54 #include "strequal.h"
55 #include "if2ip.h"
56
57 #define _MPRINTF_REPLACE /* use our functions only */
58 #include <curl/mprintf.h>
59
60 #include "curl_memory.h"
61 /* The last #include file should be: */
62 #include "memdebug.h"
63
64 /* ------------------------------------------------------------------ */
65
66 #if defined(HAVE_GETIFADDRS)
67
68 bool Curl_if_is_interface_name(const char *interf)
69 {
70   bool result = FALSE;
71
72   struct ifaddrs *iface, *head;
73
74   if(getifaddrs(&head) >= 0) {
75     for(iface=head; iface != NULL; iface=iface->ifa_next) {
76       if(curl_strequal(iface->ifa_name, interf)) {
77         result = TRUE;
78         break;
79       }
80     }
81     freeifaddrs(head);
82   }
83   return result;
84 }
85
86 if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
87                           const char *interf, char *buf, int buf_size)
88 {
89   struct ifaddrs *iface, *head;
90   if2ip_result_t res = IF2IP_NOT_FOUND;
91
92   if(getifaddrs(&head) >= 0) {
93     for(iface=head; iface != NULL; iface=iface->ifa_next) {
94       if(iface->ifa_addr != NULL) {
95         if(iface->ifa_addr->sa_family == af) {
96           if(curl_strequal(iface->ifa_name, interf)) {
97             void *addr;
98             char *ip;
99             char scope[12]="";
100             char ipstr[64];
101 #ifdef ENABLE_IPV6
102             if(af == AF_INET6) {
103               unsigned int scopeid = 0;
104               addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr;
105 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
106               /* Include the scope of this interface as part of the address */
107               scopeid =
108                 ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id;
109 #endif
110               if(scopeid != remote_scope) {
111                 /* We are interested only in interface addresses whose
112                    scope ID matches the remote address we want to
113                    connect to: global (0) for global, link-local for
114                    link-local, etc... */
115                 if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED;
116                 continue;
117               }
118               if(scopeid)
119                 snprintf(scope, sizeof(scope), "%%%u", scopeid);
120             }
121             else
122 #endif
123               addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr;
124             res = IF2IP_FOUND;
125             ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
126             snprintf(buf, buf_size, "%s%s", ip, scope);
127             break;
128           }
129         }
130         else if((res == IF2IP_NOT_FOUND) &&
131                 curl_strequal(iface->ifa_name, interf)) {
132           res = IF2IP_AF_NOT_SUPPORTED;
133         }
134       }
135     }
136     freeifaddrs(head);
137   }
138   return res;
139 }
140
141 #elif defined(HAVE_IOCTL_SIOCGIFADDR)
142
143 bool Curl_if_is_interface_name(const char *interf)
144 {
145   /* This is here just to support the old interfaces */
146   char buf[256];
147
148   return (Curl_if2ip(AF_INET, 0, interf, buf, sizeof(buf)) ==
149           IF2IP_NOT_FOUND) ? FALSE : TRUE;
150 }
151
152 if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
153                           const char *interf, char *buf, int buf_size)
154 {
155   struct ifreq req;
156   struct in_addr in;
157   struct sockaddr_in *s;
158   curl_socket_t dummy;
159   size_t len;
160
161   if(!interf || (af != AF_INET))
162     return IF2IP_NOT_FOUND;
163
164   len = strlen(interf);
165   if(len >= sizeof(req.ifr_name))
166     return IF2IP_NOT_FOUND;
167
168   dummy = socket(AF_INET, SOCK_STREAM, 0);
169   if(CURL_SOCKET_BAD == dummy)
170     return IF2IP_NOT_FOUND;
171
172   memset(&req, 0, sizeof(req));
173   memcpy(req.ifr_name, interf, len+1);
174   req.ifr_addr.sa_family = AF_INET;
175
176   if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
177     sclose(dummy);
178     /* With SIOCGIFADDR, we cannot tell the difference between an interface
179        that does not exist and an interface that has no address of the
180        correct family. Assume the interface does not exist */
181     return IF2IP_NOT_FOUND;
182   }
183
184   s = (struct sockaddr_in *)&req.ifr_addr;
185   memcpy(&in, &s->sin_addr, sizeof(in));
186   Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
187
188   sclose(dummy);
189   return IF2IP_FOUND;
190 }
191
192 #else
193
194 bool Curl_if_is_interface_name(const char *interf)
195 {
196   (void) interf;
197
198   return FALSE;
199 }
200
201 if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
202                           const char *interf, char *buf, int buf_size)
203 {
204     (void) af;
205     (void) interf;
206     (void) buf;
207     (void) buf_size;
208     return IF2IP_NOT_FOUND;
209 }
210
211 #endif