]> gitweb.fperrin.net Git - iftop.git/blob - addrs_ioctl.c
c68c50fafdbb50493ef3eaada5cd51a09eca060d
[iftop.git] / addrs_ioctl.c
1 /*
2  * addrs_ioctl.c:
3  *
4  * Provides the get_addrs_ioctl() function for use on systems that
5  * support a simple socket ioctl for acquiring low-level ethernet
6  * information about interfaces.
7  *
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14
15 #include <sys/types.h>
16 #include <sys/ioctl.h>
17 #include <sys/socket.h>
18 #include <net/if.h>
19 #include <netinet/in.h>
20
21 #if defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ \
22       || ( defined __GNUC__ && ! defined __linux__ )
23 #include <sys/param.h>
24 #include <sys/sysctl.h>
25 #include <net/if_dl.h>
26 #endif
27
28 #ifdef USE_GETIFADDRS
29 #include <ifaddrs.h>
30 #endif
31
32 #include "iftop.h"
33
34 /*
35  * This function identifies the IP address and ethernet address for the requested
36  * interface
37  *
38  * This function returns -1 on catastrophic failure, or a bitwise OR of the
39  * following values:
40  *
41  * 1 - Was able to get the ethernet address
42  * 2 - Was able to get the IP address
43  *
44  * This function should return 3 if all information was found
45  */
46
47 int
48 get_addrs_ioctl(char *interface, char if_hw_addr[], struct in_addr *if_ip_addr, struct in6_addr *if_ip6_addr)
49 {
50   int s;
51   struct ifreq ifr = {};
52   int got_hw_addr = 0;
53   int got_ip_addr = 0;
54   int got_ip6_addr = 0;
55 #ifdef USE_GETIFADDRS
56   struct ifaddrs *ifa, *ifas;
57 #endif
58
59   /* -- */
60
61   s = socket(AF_INET, SOCK_DGRAM, 0); /* any sort of IP socket will do */
62
63   if (s == -1) {
64     perror("socket");
65     return -1;
66   }
67
68   fprintf(stderr,"interface: %s\n", interface);
69
70   memset(if_hw_addr, 0, 6);
71   strncpy(ifr.ifr_name, interface, IFNAMSIZ);
72
73 #ifdef SIOCGIFHWADDR
74   if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) {
75     fprintf(stderr, "Error getting hardware address for interface: %s\n", interface); 
76     perror("ioctl(SIOCGIFHWADDR)");
77   }
78   else {
79     memcpy(if_hw_addr, ifr.ifr_hwaddr.sa_data, 6);
80     got_hw_addr = 1;
81   }
82 #else
83 #if defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__ \
84       || ( defined __GNUC__ && ! defined __linux__ )
85   {
86     int sysctlparam[6] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
87     size_t needed = 0;
88     char *buf = NULL;
89     struct if_msghdr *msghdr = NULL;
90     sysctlparam[5] = if_nametoindex(interface);
91     if (sysctlparam[5] == 0) {
92       fprintf(stderr, "Error getting hardware address for interface: %s\n", interface);
93       goto ENDHWADDR;
94     }
95     if (sysctl(sysctlparam, 6, NULL, &needed, NULL, 0) < 0) {
96       fprintf(stderr, "Error getting hardware address for interface: %s\n", interface);
97       goto ENDHWADDR;
98     }
99     if ((buf = malloc(needed)) == NULL) {
100       fprintf(stderr, "Error getting hardware address for interface: %s\n", interface);
101       goto ENDHWADDR;
102     }
103     if (sysctl(sysctlparam, 6, buf, &needed, NULL, 0) < 0) {
104       fprintf(stderr, "Error getting hardware address for interface: %s\n", interface);
105       free(buf);
106       goto ENDHWADDR;
107     }
108     msghdr = (struct if_msghdr *) buf;
109     memcpy(if_hw_addr, LLADDR((struct sockaddr_dl *)(buf + sizeof(struct if_msghdr) - sizeof(struct if_data) + sizeof(struct if_data))), 6);
110     free(buf);
111     got_hw_addr = 1;
112
113   ENDHWADDR:
114     1; /* compiler whines if there is a label at the end of a block...*/
115   }
116 #else
117   fprintf(stderr, "Cannot obtain hardware address on this platform\n");
118 #endif
119 #endif
120   
121   /* Get the IP address of the interface */
122 #ifdef USE_GETIFADDRS
123   if (getifaddrs(&ifas) == -1) {
124     fprintf(stderr, "Unable to get IP address for interface: %s\n", interface); 
125     perror("getifaddrs()");
126   }
127   else {
128      for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
129         if (got_ip_addr && got_ip6_addr)
130            break; /* Search is already complete. */
131
132         if (strcmp(ifa->ifa_name, interface))
133            continue; /* Not our interface. */
134
135         if ( (ifa->ifa_addr->sa_family != AF_INET)
136               && (ifa->ifa_addr->sa_family != AF_INET6) )
137            continue; /* AF_PACKET is beyond our scope. */
138
139         if ( (ifa->ifa_addr->sa_family == AF_INET)
140               && !got_ip_addr ) {
141            got_ip_addr = 2;
142            memcpy(if_ip_addr,
143                  &(((struct sockaddr_in *) ifa->ifa_addr)->sin_addr),
144                  sizeof(*if_ip_addr));
145            continue;
146         }
147         /* Must be a IPv6 address at this point. */
148         struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
149
150         if ( IN6_IS_ADDR_LINKLOCAL(&(sa6->sin6_addr))
151               || IN6_IS_ADDR_SITELOCAL(&(sa6->sin6_addr)) )
152            continue;
153
154         /* A useful IPv6 address. */
155         memcpy(if_ip6_addr, &(sa6->sin6_addr), sizeof(*if_ip6_addr));
156         got_ip6_addr = 4;
157      }
158      freeifaddrs(ifas);
159   } /* getifaddrs() */
160 #elif defined(SIOCGIFADDR)
161   (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = AF_INET;
162   if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
163     fprintf(stderr, "Unable to get IP address for interface: %s\n", interface); 
164     perror("ioctl(SIOCGIFADDR)");
165   }
166   else {
167     memcpy(if_ip_addr, &((*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr), sizeof(struct in_addr));
168     got_ip_addr = 2;
169   }
170 #else
171   fprintf(stderr, "Cannot obtain IP address on this platform\n");
172 #endif
173   
174   close(s);
175
176   return got_hw_addr + got_ip_addr + got_ip6_addr;
177 }