]> gitweb.fperrin.net Git - iftop.git/blob - addrs_ioctl.c
Import iftop-1.0pre4
[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 __GLIBC__ && ! 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 __GLIBC__ && ! 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     }
94     else if (sysctl(sysctlparam, 6, NULL, &needed, NULL, 0) < 0) {
95       fprintf(stderr, "Error getting hardware address for interface: %s\n", interface);
96     }
97     else if ((buf = malloc(needed)) == NULL) {
98       fprintf(stderr, "Error getting hardware address for interface: %s\n", interface);
99     }
100     else if (sysctl(sysctlparam, 6, buf, &needed, NULL, 0) < 0) {
101       fprintf(stderr, "Error getting hardware address for interface: %s\n", interface);
102       free(buf);
103     }
104     else {
105       msghdr = (struct if_msghdr *) buf;
106       memcpy(if_hw_addr, LLADDR((struct sockaddr_dl *)(buf + sizeof(struct if_msghdr) - sizeof(struct if_data) + sizeof(struct if_data))), 6);
107       free(buf);
108       got_hw_addr = 1;
109     }
110   }
111 #else
112   fprintf(stderr, "Cannot obtain hardware address on this platform\n");
113 #endif
114 #endif
115   
116   /* Get the IP address of the interface */
117 #ifdef USE_GETIFADDRS
118   if (getifaddrs(&ifas) == -1) {
119     fprintf(stderr, "Unable to get IP address for interface: %s\n", interface); 
120     perror("getifaddrs()");
121   }
122   else {
123      for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
124         if (got_ip_addr && got_ip6_addr)
125            break; /* Search is already complete. */
126
127         if (strcmp(ifa->ifa_name, interface))
128            continue; /* Not our interface. */
129
130         if (ifa->ifa_addr == NULL)
131            continue; /* Skip NULL interface address. */
132
133         if ( (ifa->ifa_addr->sa_family != AF_INET)
134               && (ifa->ifa_addr->sa_family != AF_INET6) )
135            continue; /* AF_PACKET is beyond our scope. */
136
137         if ( (ifa->ifa_addr->sa_family == AF_INET)
138               && !got_ip_addr ) {
139            got_ip_addr = 2;
140            memcpy(if_ip_addr,
141                  &(((struct sockaddr_in *) ifa->ifa_addr)->sin_addr),
142                  sizeof(*if_ip_addr));
143            continue;
144         }
145         /* Must be a IPv6 address at this point. */
146         struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
147
148         if ( IN6_IS_ADDR_LINKLOCAL(&(sa6->sin6_addr))
149               || IN6_IS_ADDR_SITELOCAL(&(sa6->sin6_addr)) )
150            continue;
151
152         /* A useful IPv6 address. */
153         memcpy(if_ip6_addr, &(sa6->sin6_addr), sizeof(*if_ip6_addr));
154         got_ip6_addr = 4;
155      }
156      freeifaddrs(ifas);
157   } /* getifaddrs() */
158 #elif defined(SIOCGIFADDR)
159   (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = AF_INET;
160   if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
161     fprintf(stderr, "Unable to get IP address for interface: %s\n", interface); 
162     perror("ioctl(SIOCGIFADDR)");
163   }
164   else {
165     memcpy(if_ip_addr, &((*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr), sizeof(struct in_addr));
166     got_ip_addr = 2;
167   }
168 #else
169   fprintf(stderr, "Cannot obtain IP address on this platform\n");
170 #endif
171   
172   close(s);
173
174   return got_hw_addr + got_ip_addr + got_ip6_addr;
175 }