summaryrefslogtreecommitdiffstats
path: root/netlink-notify.c
diff options
context:
space:
mode:
Diffstat (limited to 'netlink-notify.c')
-rw-r--r--netlink-notify.c96
1 files changed, 82 insertions, 14 deletions
diff --git a/netlink-notify.c b/netlink-notify.c
index 00b3a4d..55fcfea 100644
--- a/netlink-notify.c
+++ b/netlink-notify.c
@@ -44,9 +44,30 @@
#define CHECK_CONNECTED IFF_LOWER_UP
+struct addresses_seen {
+ char *address;
+ unsigned char prefix;
+ struct addresses_seen *next;
+};
+
char *program;
unsigned int maxinterface = 0;
-NotifyNotification ** notification;
+NotifyNotification ** notification = NULL;
+struct addresses_seen *addresses_seen = NULL;
+
+/*** free_chain ***/
+void free_chain(struct addresses_seen *first) {
+ struct addresses_seen *addresses_seen = first->next;
+
+ while (addresses_seen != NULL) {
+ struct addresses_seen *next = addresses_seen->next;
+ free(addresses_seen->address);
+ free(addresses_seen);
+ addresses_seen = next;
+ }
+
+ first->next = NULL;
+}
/*** newstr_link ***/
char * newstr_link(char *text, char *interface, unsigned int flags) {
@@ -59,13 +80,11 @@ char * newstr_link(char *text, char *interface, unsigned int flags) {
}
/*** newstr_addr ***/
-char * newstr_addr(char *text, char *interface, unsigned char family, void *ipaddr, unsigned char prefix) {
+char * newstr_addr(char *text, char *interface, unsigned char family, char *ipaddr, unsigned char prefix) {
char *notifystr;
- char buf[64];
- inet_ntop(family, ipaddr, buf, sizeof(buf));
- notifystr = malloc(strlen(text) + strlen(interface) + strlen(buf));
- sprintf(notifystr, text, interface, family == AF_INET6 ? "IPv6" : "IP", buf, prefix);
+ notifystr = malloc(strlen(text) + strlen(interface) + strlen(ipaddr));
+ sprintf(notifystr, text, interface, family == AF_INET6 ? "IPv6" : "IP", ipaddr, prefix);
return notifystr;
}
@@ -160,20 +179,31 @@ static int msg_handler (struct sockaddr_nl *nl, struct nlmsghdr *msg) {
struct rtattr *rth;
int rtl;
char name[IFNAMSIZ];
- NotifyNotification * address = NULL;
+ char buf[64];
+ struct addresses_seen *next;
+ unsigned char seen;
+ NotifyNotification *address = NULL;
ifa = (struct ifaddrmsg *) NLMSG_DATA (msg);
ifi = (struct ifinfomsg *) NLMSG_DATA (msg);
if_indextoname(ifi->ifi_index, name);
-
- /* make sure we have alloced memory for the struct array */
+
+ /* make sure we have alloced memory for NotifyNotification and addresses_seen struct array */
if (maxinterface < ifi->ifi_index) {
- notification = realloc(notification, (ifi->ifi_index + 1) * sizeof(NotifyNotification));
- for(; maxinterface < ifi->ifi_index; maxinterface++)
+ notification = realloc(notification, (ifi->ifi_index + 1) * sizeof(size_t));
+ addresses_seen = realloc(addresses_seen, (ifi->ifi_index + 1) * sizeof(struct addresses_seen));
+ do {
+ maxinterface++; /* there is no interface with index 0, so this is safe */
notification[maxinterface] = NULL;
+ addresses_seen[maxinterface].next = NULL;
+ } while (maxinterface < ifi->ifi_index);
}
+#if DEBUG
+ printf("Interface %s, flags: %x, msg type: %d\n", name, ifa->ifa_flags, msg->nlmsg_type);
+#endif
+
switch (msg->nlmsg_type) {
/* just return for cases we want to ignore */
case RTM_NEWADDR:
@@ -183,9 +213,40 @@ static int msg_handler (struct sockaddr_nl *nl, struct nlmsghdr *msg) {
while (rtl && RTA_OK (rth, rtl)) {
if ((rth->rta_type == IFA_LOCAL /* IPv4 */
|| rth->rta_type == IFA_ADDRESS /* IPv6 */)
- && ifa->ifa_scope == RT_SCOPE_UNIVERSE /* no IPv6 scope link */)
+ && ifa->ifa_scope == RT_SCOPE_UNIVERSE /* no IPv6 scope link */) {
+ inet_ntop(ifa->ifa_family, RTA_DATA (rth), buf, sizeof(buf));
+
+ next = &(addresses_seen[ifi->ifi_index]);
+ seen = 0;
+
+ /* check if we already notified about this address */
+ while (next->next != NULL) {
+ if (strcmp(next->address, buf) == 0 && next->prefix == ifa->ifa_prefixlen) {
+#if DEBUG
+ printf("Already notified about address %s/%d, skipping.\n", buf, ifa->ifa_prefixlen);
+#endif
+ seen++;
+ break;
+ }
+ next = next->next;
+ }
+
+ if (seen)
+ break;
+
+ /* add address to struct */
+ next->address = strdup(buf);
+ next->prefix = ifa->ifa_prefixlen;
+ next->next = malloc(sizeof(struct addresses_seen));
+ next->next->next = NULL;
+
+ /* display notification */
notifystr = newstr_addr(TEXT_NEWADDR, name,
- ifa->ifa_family, RTA_DATA (rth), ifa->ifa_prefixlen);
+ ifa->ifa_family, buf, ifa->ifa_prefixlen);
+
+ /* we are done, no need to run more loops */
+ break;
+ }
rth = RTA_NEXT (rth, rtl);
}
if (notifystr == NULL) {
@@ -206,9 +267,12 @@ static int msg_handler (struct sockaddr_nl *nl, struct nlmsghdr *msg) {
return 0;
case RTM_NEWLINK:
notifystr = newstr_link(TEXT_NEWLINK, name, ifi->ifi_flags);
+ if (!(ifi->ifi_flags & CHECK_CONNECTED))
+ free_chain(&(addresses_seen[ifi->ifi_index]));
break;
case RTM_DELLINK:
notifystr = newstr_away(TEXT_DELLINK);
+ free_chain(&(addresses_seen[ifi->ifi_index]));
break;
default:
/* we should not get here... */
@@ -268,7 +332,11 @@ int main (int argc, char **argv) {
int nls;
program = argv[0];
- printf ("%s: %s v%s (compiled: " __DATE__ ", " __TIME__ ")\n", argv[0], PROGNAME, VERSION);
+ printf ("%s: %s v%s (compiled: " __DATE__ ", " __TIME__
+#if DEBUG
+ ", with debug output"
+#endif
+ ")\n", argv[0], PROGNAME, VERSION);
nls = open_netlink ();
if (nls < 0) {