Use struct addr - big cleanup.
[darkstat] / localip.c
1 /* darkstat 3
2 * copyright (c) 2001-2008 Emil Mikulic.
3 *
4 * localip.c: determine local IP of our capture interface
5 *
6 * You may use, modify and redistribute this file under the terms of the
7 * GNU General Public License version 2. (see COPYING.GPL)
8 */
9
10 #include "darkstat.h"
11 #include "addr.h"
12 #include "conv.h" /* for strlcpy */
13 #include "err.h"
14 #include "localip.h"
15
16 #include <sys/socket.h>
17 #include <net/if.h>
18 #include <ifaddrs.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <unistd.h>
22
23 static const char *iface = NULL;
24 struct addr localip4, localip6;
25 static struct addr last_localip4, last_localip6;
26
27 void
28 localip_init(const char *interface)
29 {
30 iface = interface;
31 localip_update();
32 }
33
34 void
35 localip_update(void)
36 {
37 struct ifaddrs *ifas, *ifa;
38 int got_v4 = 0, got_v6 = 0;
39
40 localip4.family = IPv4;
41 localip6.family = IPv6;
42
43 if (iface == NULL) {
44 /* reading from capfile */
45 localip4.ip.v4 = 0;
46 memset(&(localip6.ip.v6), 0, sizeof(localip6.ip.v6));
47 return;
48 }
49
50 if (getifaddrs(&ifas) < 0)
51 err(1, "can't get own IP address on interface \"%s\"", iface);
52
53 for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
54 if (got_v4 && got_v6)
55 break; /* Task is already complete. */
56
57 if (strncmp(ifa->ifa_name, iface, IFNAMSIZ))
58 continue; /* Wrong interface. */
59
60 /* The first IPv4 name is always functional. */
61 if ((ifa->ifa_addr->sa_family == AF_INET) && !got_v4)
62 {
63 /* Good IPv4 address. */
64 localip4.ip.v4 =
65 ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
66 got_v4 = 1;
67 continue;
68 }
69
70 /* IPv6 needs some obvious exceptions. */
71 if ( ifa->ifa_addr->sa_family == AF_INET6 ) {
72 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
73
74 if ( IN6_IS_ADDR_LINKLOCAL(&(sa6->sin6_addr))
75 || IN6_IS_ADDR_SITELOCAL(&(sa6->sin6_addr)) )
76 continue;
77
78 /* Only standard IPv6 can reach this point. */
79 memcpy(&(localip6.ip.v6), &sa6->sin6_addr, sizeof(localip6.ip.v6));
80 got_v6 = 1;
81 }
82 }
83
84 freeifaddrs(ifas);
85
86 /* Report an error if IPv4 address could not be found. */
87 if (!got_v4)
88 err(1, "can't get own IPv4 address on interface \"%s\"", iface);
89
90 if (!addr_equal(&last_localip4, &localip4)) {
91 verbosef("localip4 update(%s) = %s", iface, addr_to_str(&localip4));
92 last_localip4 = localip4;
93 }
94 if (!addr_equal(&last_localip6, &localip6)) {
95 verbosef("localip6 update(%s) = %s", iface, addr_to_str(&localip6));
96 last_localip6 = localip6;
97 }
98 }
99
100 /* vim:set ts=3 sw=3 tw=78 expandtab: */