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
68bool 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
86if2ip_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#ifndef ENABLE_IPV6
93  (void) remote_scope;
94#endif
95
96  if(getifaddrs(&head) >= 0) {
97    for(iface=head; iface != NULL; iface=iface->ifa_next) {
98      if(iface->ifa_addr != NULL) {
99        if(iface->ifa_addr->sa_family == af) {
100          if(curl_strequal(iface->ifa_name, interf)) {
101            void *addr;
102            char *ip;
103            char scope[12]="";
104            char ipstr[64];
105#ifdef ENABLE_IPV6
106            if(af == AF_INET6) {
107              unsigned int scopeid = 0;
108              addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr;
109#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
110              /* Include the scope of this interface as part of the address */
111              scopeid =
112                ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id;
113#endif
114              if(scopeid != remote_scope) {
115                /* We are interested only in interface addresses whose
116                   scope ID matches the remote address we want to
117                   connect to: global (0) for global, link-local for
118                   link-local, etc... */
119                if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED;
120                continue;
121              }
122              if(scopeid)
123                snprintf(scope, sizeof(scope), "%%%u", scopeid);
124            }
125            else
126#endif
127              addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr;
128            res = IF2IP_FOUND;
129            ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
130            snprintf(buf, buf_size, "%s%s", ip, scope);
131            break;
132          }
133        }
134        else if((res == IF2IP_NOT_FOUND) &&
135                curl_strequal(iface->ifa_name, interf)) {
136          res = IF2IP_AF_NOT_SUPPORTED;
137        }
138      }
139    }
140    freeifaddrs(head);
141  }
142  return res;
143}
144
145#elif defined(HAVE_IOCTL_SIOCGIFADDR)
146
147bool Curl_if_is_interface_name(const char *interf)
148{
149  /* This is here just to support the old interfaces */
150  char buf[256];
151
152  return (Curl_if2ip(AF_INET, 0, interf, buf, sizeof(buf)) ==
153          IF2IP_NOT_FOUND) ? FALSE : TRUE;
154}
155
156if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
157                          const char *interf, char *buf, int buf_size)
158{
159  struct ifreq req;
160  struct in_addr in;
161  struct sockaddr_in *s;
162  curl_socket_t dummy;
163  size_t len;
164
165  (void)remote_scope;
166
167  if(!interf || (af != AF_INET))
168    return IF2IP_NOT_FOUND;
169
170  len = strlen(interf);
171  if(len >= sizeof(req.ifr_name))
172    return IF2IP_NOT_FOUND;
173
174  dummy = socket(AF_INET, SOCK_STREAM, 0);
175  if(CURL_SOCKET_BAD == dummy)
176    return IF2IP_NOT_FOUND;
177
178  memset(&req, 0, sizeof(req));
179  memcpy(req.ifr_name, interf, len+1);
180  req.ifr_addr.sa_family = AF_INET;
181
182  if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
183    sclose(dummy);
184    /* With SIOCGIFADDR, we cannot tell the difference between an interface
185       that does not exist and an interface that has no address of the
186       correct family. Assume the interface does not exist */
187    return IF2IP_NOT_FOUND;
188  }
189
190  s = (struct sockaddr_in *)&req.ifr_addr;
191  memcpy(&in, &s->sin_addr, sizeof(in));
192  Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
193
194  sclose(dummy);
195  return IF2IP_FOUND;
196}
197
198#else
199
200bool Curl_if_is_interface_name(const char *interf)
201{
202  (void) interf;
203
204  return FALSE;
205}
206
207if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
208                          const char *interf, char *buf, int buf_size)
209{
210    (void) af;
211    (void) remote_scope;
212    (void) interf;
213    (void) buf;
214    (void) buf_size;
215    return IF2IP_NOT_FOUND;
216}
217
218#endif
219