2 * copyright (c) 2001-2012 Emil Mikulic.
4 * localip.c: determine local IPs of an interface
6 * You may use, modify and redistribute this file under the terms of the
7 * GNU General Public License version 2. (see COPYING.GPL)
11 #include "bsd.h" /* for strlcpy */
12 #include "config.h" /* for HAVE_IFADDRS_H */
18 #include <sys/socket.h>
30 # ifdef HAVE_SYS_SOCKIO_H
31 # include <sys/sockio.h> /* for SIOCGIFADDR, especially on Solaris */
33 # include <sys/ioctl.h>
36 void localip_init(struct local_ips
*ips
) {
38 ips
->last_update_mono
= 0;
43 void localip_free(struct local_ips
*ips
) {
44 if (ips
->addrs
!= NULL
)
48 static void add_ip(const char *iface
,
49 struct local_ips
*ips
,
52 if (ips
->num_addrs
<= *idx
) {
54 ips
->addrs
= xrealloc(ips
->addrs
, sizeof(*(ips
->addrs
)) * (*idx
+ 1));
56 assert(ips
->num_addrs
> *idx
);
57 verbosef("interface '%s' gained new address %s", iface
, addr_to_str(a
));
59 /* Warn about changed address. */
60 if (!addr_equal(ips
->addrs
+ *idx
, a
)) {
61 static char before
[INET6_ADDRSTRLEN
];
62 strncpy(before
, addr_to_str(ips
->addrs
+ *idx
), INET6_ADDRSTRLEN
);
63 verbosef("interface '%s' address %d/%d changed from %s to %s",
64 iface
, *idx
+1, ips
->num_addrs
, before
, addr_to_str(a
));
67 ips
->addrs
[*idx
] = *a
;
71 /* Returns 0 on failure. */
72 void localip_update(const char *iface
, struct local_ips
*ips
) {
77 /* reading from capfile */
82 if (ips
->last_update_mono
== now_mono()) {
83 /* Too soon, bail out. */
86 ips
->last_update_mono
= now_mono();
90 struct ifaddrs
*ifas
, *ifa
;
92 if (getifaddrs(&ifas
) < 0)
93 err(1, "getifaddrs() failed");
95 for (ifa
=ifas
; ifa
; ifa
=ifa
->ifa_next
) {
96 if (strncmp(ifa
->ifa_name
, iface
, IFNAMSIZ
))
97 continue; /* Wrong interface. */
100 continue; /* This can be NULL, e.g. for ppp0. */
102 if (ifa
->ifa_addr
->sa_family
== AF_INET
) {
104 a
.ip
.v4
= ((struct sockaddr_in
*)ifa
->ifa_addr
)->sin_addr
.s_addr
;
105 add_ip(iface
, ips
, &new_addrs
, &a
);
107 if (ifa
->ifa_addr
->sa_family
== AF_INET6
) {
108 struct sockaddr_in6
*sa6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
110 if ( IN6_IS_ADDR_LINKLOCAL(&(sa6
->sin6_addr
))
111 || IN6_IS_ADDR_SITELOCAL(&(sa6
->sin6_addr
)) )
115 memcpy(&(a
.ip
.v6
), &sa6
->sin6_addr
, sizeof(a
.ip
.v6
));
116 add_ip(iface
, ips
, &new_addrs
, &a
);
121 #else /* don't HAVE_IFADDRS_H */
123 int tmp
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_IP
);
127 strlcpy(ifr
.ifr_name
, iface
, IFNAMSIZ
);
128 ifr
.ifr_addr
.sa_family
= AF_INET
;
129 if (ioctl(tmp
, SIOCGIFADDR
, &ifr
) != -1) {
132 a
.ip
.v4
= ((struct sockaddr_in
*)(&ifr
.ifr_addr
))->sin_addr
.s_addr
;
133 add_ip(iface
, ips
, &new_addrs
, &a
);
138 if (new_addrs
== 0) {
140 verbosef("interface '%s' no longer has any addresses", iface
);
144 verbosef("interface '%s' now has addresses", iface
);
146 if (ips
->num_addrs
!= new_addrs
)
147 verbosef("interface '%s' number of addresses decreased from %d to %d",
148 iface
, ips
->num_addrs
, new_addrs
);
149 ips
->num_addrs
= new_addrs
;
153 int is_localip(const struct addr
* const a
,
154 const struct local_ips
* const ips
) {
157 for (i
=0; i
<ips
->num_addrs
; i
++) {
158 if (addr_equal(a
, ips
->addrs
+i
))
164 /* vim:set ts=3 sw=3 tw=80 et: */