2 * copyright (c) 2001-2011 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
, struct local_ips
*ips
,
49 int *index
, struct addr
*a
) {
50 if (ips
->num_addrs
<= *index
) {
52 ips
->addrs
= xrealloc(ips
->addrs
, sizeof(*(ips
->addrs
)) * (*index
+ 1));
54 assert(ips
->num_addrs
> *index
);
55 verbosef("interface '%s' gained new address %s", iface
, addr_to_str(a
));
57 /* Warn about changed address. */
58 if (!addr_equal(ips
->addrs
+ *index
, a
)) {
59 static char before
[INET6_ADDRSTRLEN
];
60 strncpy(before
, addr_to_str(ips
->addrs
+ *index
), INET6_ADDRSTRLEN
);
61 verbosef("interface '%s' address %d/%d changed from %s to %s",
62 iface
, *index
+1, ips
->num_addrs
, before
, addr_to_str(a
));
65 ips
->addrs
[*index
] = *a
;
69 /* Returns 0 on failure. */
70 void localip_update(const char *iface
, struct local_ips
*ips
) {
75 /* reading from capfile */
80 if (ips
->last_update_mono
== now_mono()) {
81 /* Too soon, bail out. */
84 ips
->last_update_mono
= now_mono();
88 struct ifaddrs
*ifas
, *ifa
;
90 if (getifaddrs(&ifas
) < 0)
91 err(1, "getifaddrs() failed");
93 for (ifa
=ifas
; ifa
; ifa
=ifa
->ifa_next
) {
94 if (strncmp(ifa
->ifa_name
, iface
, IFNAMSIZ
))
95 continue; /* Wrong interface. */
98 continue; /* This can be NULL, e.g. for ppp0. */
100 if (ifa
->ifa_addr
->sa_family
== AF_INET
) {
102 a
.ip
.v4
= ((struct sockaddr_in
*)ifa
->ifa_addr
)->sin_addr
.s_addr
;
103 add_ip(iface
, ips
, &new_addrs
, &a
);
104 } else if (ifa
->ifa_addr
->sa_family
== AF_INET6
) {
105 struct sockaddr_in6
*sa6
= (struct sockaddr_in6
*)ifa
->ifa_addr
;
107 if ( IN6_IS_ADDR_LINKLOCAL(&(sa6
->sin6_addr
))
108 || IN6_IS_ADDR_SITELOCAL(&(sa6
->sin6_addr
)) )
112 memcpy(&(a
.ip
.v6
), &sa6
->sin6_addr
, sizeof(a
.ip
.v6
));
113 add_ip(iface
, ips
, &new_addrs
, &a
);
115 } else if (ifa
->ifa_addr
->sa_family
== AF_PACKET
) {
119 verbosef("unknown sa_family=%d on interface '%s'",
120 (int)ifa
->ifa_addr
->sa_family
, iface
);
124 #else /* don't HAVE_IFADDRS_H */
126 int tmp
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_IP
);
130 strlcpy(ifr
.ifr_name
, iface
, IFNAMSIZ
);
131 ifr
.ifr_addr
.sa_family
= AF_INET
;
132 if (ioctl(tmp
, SIOCGIFADDR
, &ifr
) != -1) {
135 a
.ip
.v4
= ((struct sockaddr_in
*)(&ifr
.ifr_addr
))->sin_addr
.s_addr
;
136 add_ip(iface
, ips
, &new_addrs
, &a
);
141 if (new_addrs
== 0) {
143 verbosef("interface '%s' no longer has any addresses", iface
);
147 verbosef("interface '%s' now has addresses", iface
);
149 if (ips
->num_addrs
!= new_addrs
)
150 verbosef("interface '%s' number of addresses decreased from %d to %d",
151 iface
, ips
->num_addrs
, new_addrs
);
152 ips
->num_addrs
= new_addrs
;
156 int is_localip(const struct addr
* const a
,
157 const struct local_ips
* const ips
) {
160 for (i
=0; i
<ips
->num_addrs
; i
++) {
161 if (addr_equal(a
, ips
->addrs
+i
))
167 /* vim:set ts=3 sw=3 tw=80 et: */