summaryrefslogtreecommitdiffstats
path: root/netlink-notify.c
diff options
context:
space:
mode:
Diffstat (limited to 'netlink-notify.c')
-rw-r--r--netlink-notify.c205
1 files changed, 122 insertions, 83 deletions
diff --git a/netlink-notify.c b/netlink-notify.c
index a3bdb8f..1417a12 100644
--- a/netlink-notify.c
+++ b/netlink-notify.c
@@ -54,30 +54,20 @@ struct addresses_seen {
struct addresses_seen *next;
};
-struct ifnames {
+struct ifs {
char *name;
unsigned char deleted;
+ struct addresses_seen *addresses_seen;
+ NotifyNotification *notification;
};
char *program;
unsigned int maxinterface = 0;
-NotifyNotification ** notifications = NULL;
-struct addresses_seen *addresses_seen = NULL;
-struct ifnames ** ifnames = NULL;
+struct ifs ** ifs = NULL;
-/*** free_chain ***/
-void free_chain(struct addresses_seen *addresses_seen) {
- struct addresses_seen *next;
-
- /* first struct is allocated by array, do not free */
- if (addresses_seen->address != NULL)
- free(addresses_seen->address);
- addresses_seen->address = NULL;
- addresses_seen->prefix = 0;
-
- next = addresses_seen->next;
- addresses_seen->next = NULL;
- addresses_seen = next;
+/*** free_addresses ***/
+void free_addresses(struct addresses_seen *addresses_seen) {
+ struct addresses_seen *next = NULL;
/* free everything else */
while (addresses_seen != NULL) {
@@ -89,54 +79,85 @@ void free_chain(struct addresses_seen *addresses_seen) {
}
}
-/*** init_address ***/
-void init_address(struct addresses_seen *next) {
- next->address = NULL;
- next->prefix = 0;
- next->next = NULL;
-}
-
/*** add_address ***/
-void add_address(struct addresses_seen *next, char *address, unsigned char prefix) {
- while (next->next != NULL) {
+struct addresses_seen * add_address(struct addresses_seen *addresses_seen, char *address, unsigned char prefix) {
+ struct addresses_seen *first = addresses_seen;
+
+ if (addresses_seen == NULL) {
+ addresses_seen = malloc(sizeof(struct addresses_seen));
+ addresses_seen->address = address;
+ addresses_seen->prefix = prefix;
+ addresses_seen->next = NULL;
+ return addresses_seen;
+ }
+
+ while (addresses_seen->next != NULL) {
/* just find the last one */
- next = next->next;
+ addresses_seen = addresses_seen->next;
}
- next->address = address;
- next->prefix = prefix;
- next->next = malloc(sizeof(struct addresses_seen));
- init_address(next->next);
+
+ addresses_seen->next = malloc(sizeof(struct addresses_seen));
+ addresses_seen = addresses_seen->next;
+ addresses_seen->address = address;
+ addresses_seen->prefix = prefix;
+ addresses_seen->next = NULL;
+
+ return first;
}
/*** remove_address ***/
-void remove_address(struct addresses_seen *next, char *address, unsigned char prefix) {
- while (next->next != NULL) {
- if (next->address != NULL /* next->address can be NULL if it has been removed from interface */ &&
- strcmp(next->address, address) == 0 && next->prefix == prefix) {
- free(next->address);
- next->address = NULL;
- next->prefix = 0;
+struct addresses_seen * remove_address(struct addresses_seen *addresses_seen, char *address, unsigned char prefix) {
+ struct addresses_seen *first = addresses_seen, *last = NULL;
+
+ /* no addresses, just return NULL */
+ if (addresses_seen == NULL)
+ return NULL;
+
+ /* first address matches, return new start */
+ if (strcmp(addresses_seen->address, address) == 0 && addresses_seen->prefix == prefix) {
+ first = addresses_seen->next;
+ free(addresses_seen->address);
+ free(addresses_seen);
+ return first;
+ }
+
+ /* find the address and remove it */
+ while (addresses_seen != NULL) {
+ if (strcmp(addresses_seen->address, address) == 0 && addresses_seen->prefix == prefix) {
+ free(addresses_seen->address);
+ last->next = addresses_seen->next;
+ free(addresses_seen);
+ break;
}
- next = next->next;
+ last = addresses_seen;
+ addresses_seen = addresses_seen->next;
}
+ return first;
}
/*** match_address ***/
-int match_address(struct addresses_seen *next, char *address, unsigned char prefix) {
- while (next->next != NULL) {
- if (next->address != NULL /* next->address can be NULL if it has been removed from interface */ &&
- strcmp(next->address, address) == 0 && next->prefix == prefix) {
-# if DEBUG
- printf("%s: Matched address: %s/%d\n", program, address, prefix);
-# endif
+int match_address(struct addresses_seen *addresses_seen, char *address, unsigned char prefix) {
+ while (addresses_seen != NULL) {
+ if (strcmp(addresses_seen->address, address) == 0 && addresses_seen->prefix == prefix) {
return 1;
}
- next = next->next;
+ addresses_seen = addresses_seen->next;
}
-
return 0;
}
+#if DEBUG
+/*** list_addresses ***/
+void list_addresses(struct addresses_seen *addresses_seen, char *interface) {
+ printf("%s: Addresses seen for interface %s:", program, interface);
+ while (addresses_seen != NULL) {
+ printf(" %s/%d", addresses_seen->address, addresses_seen->prefix);
+ addresses_seen = addresses_seen->next;
+ }
+ putchar('\n');
+}
+#endif
+
/*** newstr_link ***/
char * newstr_link(const char *text, char *interface, unsigned int flags) {
char *notifystr;
@@ -255,27 +276,31 @@ static int msg_handler (struct sockaddr_nl *nl, struct nlmsghdr *msg) {
/* make sure we have alloced memory for NotifyNotification and addresses_seen struct array */
if (maxinterface < ifi->ifi_index) {
- notifications = realloc(notifications, (ifi->ifi_index + 1) * sizeof(size_t));
- addresses_seen = realloc(addresses_seen, (ifi->ifi_index + 1) * sizeof(struct addresses_seen));
- ifnames = realloc(ifnames, (ifi->ifi_index + 1) * sizeof(size_t));
- do {
- maxinterface++; /* there is no interface with index 0, so this is safe */
+ ifs = realloc(ifs, (ifi->ifi_index + 1) * sizeof(size_t));
+ while(maxinterface < ifi->ifi_index) {
+ maxinterface++;
+
+# if DEBUG
+ printf("%s: Initializing interface %d.\n", program, maxinterface);
+# endif
+
+ ifs[maxinterface] = malloc(sizeof(struct ifs));
- notifications[maxinterface] =
+ ifs[maxinterface]->name = NULL;
+ ifs[maxinterface]->deleted = 0;
+
+ ifs[maxinterface]->notification =
# if NOTIFY_CHECK_VERSION(0, 7, 0)
notify_notification_new(TEXT_TOPIC, NULL, NULL);
# else
notify_notification_new(TEXT_TOPIC, NULL, NULL, NULL);
# endif
- notify_notification_set_category(notifications[maxinterface], PROGNAME);
- notify_notification_set_urgency(notifications[maxinterface], NOTIFY_URGENCY_NORMAL);
-
- init_address(&addresses_seen[maxinterface]);
- ifnames[maxinterface] = malloc(sizeof(struct ifnames));
- ifnames[maxinterface]->name = NULL;
- ifnames[maxinterface]->deleted = 0;
- } while (maxinterface < ifi->ifi_index);
- } else if (ifnames[ifi->ifi_index]->deleted == 1) {
+ notify_notification_set_category(ifs[maxinterface]->notification, PROGNAME);
+ notify_notification_set_urgency(ifs[maxinterface]->notification, NOTIFY_URGENCY_NORMAL);
+
+ ifs[maxinterface]->addresses_seen = NULL;
+ }
+ } else if (ifs[ifi->ifi_index]->deleted == 1) {
# if DEBUG
printf("%s: Ignoring event for deleted interface %d.\n", program, ifi->ifi_index);
# endif
@@ -284,18 +309,18 @@ static int msg_handler (struct sockaddr_nl *nl, struct nlmsghdr *msg) {
/* make notification point to the array element, will be overwritten
* later when needed for address notification */
- notification = notifications[ifi->ifi_index];
+ notification = ifs[ifi->ifi_index]->notification;
/* get interface name and store it */
- if (ifnames[ifi->ifi_index]->name == NULL) {
- ifnames[ifi->ifi_index]->name = realloc(ifnames[ifi->ifi_index]->name, IFNAMSIZ * sizeof(char));
- sprintf(ifnames[ifi->ifi_index]->name, "(unknown)");
+ if (ifs[ifi->ifi_index]->name == NULL) {
+ ifs[ifi->ifi_index]->name = realloc(ifs[ifi->ifi_index]->name, IFNAMSIZ * sizeof(char));
+ sprintf(ifs[ifi->ifi_index]->name, "(unknown)");
}
- if_indextoname(ifi->ifi_index, ifnames[ifi->ifi_index]->name);
+ if_indextoname(ifi->ifi_index, ifs[ifi->ifi_index]->name);
# if DEBUG
- printf("%s: Interface %s (%d), flags: %x, msg type: %d\n",
- program, ifnames[ifi->ifi_index]->name, ifi->ifi_index, ifa->ifa_flags, msg->nlmsg_type);
+ printf("%s: Event for interface %s (%d): flags = %x, msg type = %d\n",
+ program, ifs[ifi->ifi_index]->name, ifi->ifi_index, ifa->ifa_flags, msg->nlmsg_type);
# endif
switch (msg->nlmsg_type) {
@@ -312,14 +337,22 @@ static int msg_handler (struct sockaddr_nl *nl, struct nlmsghdr *msg) {
inet_ntop(ifa->ifa_family, RTA_DATA (rth), buf, sizeof(buf));
/* check if we already notified about this address */
- if (match_address(&addresses_seen[ifi->ifi_index], buf, ifa->ifa_prefixlen))
+ if (match_address(ifs[ifi->ifi_index]->addresses_seen, buf, ifa->ifa_prefixlen)) {
+# if DEBUG
+ printf("%s: Address %s/%d already known for %s, ignoring.\n", program, buf, ifa->ifa_prefixlen, ifs[ifi->ifi_index]->name);
+# endif
break;
+ }
/* add address to struct */
- add_address(&addresses_seen[ifi->ifi_index], strdup(buf), ifa->ifa_prefixlen);
+ ifs[ifi->ifi_index]->addresses_seen =
+ add_address(ifs[ifi->ifi_index]->addresses_seen, strdup(buf), ifa->ifa_prefixlen);
+# if DEBUG
+ list_addresses(ifs[ifi->ifi_index]->addresses_seen, ifs[ifi->ifi_index]->name);
+# endif
/* display notification */
- notifystr = newstr_addr(TEXT_NEWADDR, ifnames[ifi->ifi_index]->name,
+ notifystr = newstr_addr(TEXT_NEWADDR, ifs[ifi->ifi_index]->name,
ifa->ifa_family, buf, ifa->ifa_prefixlen);
/* we are done, no need to run more loops */
@@ -355,7 +388,11 @@ static int msg_handler (struct sockaddr_nl *nl, struct nlmsghdr *msg) {
|| rth->rta_type == IFA_ADDRESS /* IPv6 */)
&& ifa->ifa_scope == RT_SCOPE_UNIVERSE /* no IPv6 scope link */) {
inet_ntop(ifa->ifa_family, RTA_DATA (rth), buf, sizeof(buf));
- remove_address(&addresses_seen[ifi->ifi_index], buf, ifa->ifa_prefixlen);
+ ifs[ifi->ifi_index]->addresses_seen =
+ remove_address(ifs[ifi->ifi_index]->addresses_seen, buf, ifa->ifa_prefixlen);
+# if DEBUG
+ list_addresses(ifs[ifi->ifi_index]->addresses_seen, ifs[ifi->ifi_index]->name);
+# endif
/* we are done, no need to run more loops */
break;
@@ -369,30 +406,32 @@ static int msg_handler (struct sockaddr_nl *nl, struct nlmsghdr *msg) {
case RTM_DELROUTE:
return 0;
case RTM_NEWLINK:
- notifystr = newstr_link(TEXT_NEWLINK, ifnames[ifi->ifi_index]->name, ifi->ifi_flags);
+ notifystr = newstr_link(TEXT_NEWLINK, ifs[ifi->ifi_index]->name, ifi->ifi_flags);
icon = ifi->ifi_flags & CHECK_CONNECTED ? ICON_NETWORK_UP : ICON_NETWORK_DOWN;
/* free only if interface goes down */
- if (!(ifi->ifi_flags & CHECK_CONNECTED))
- free_chain(&addresses_seen[ifi->ifi_index]);
+ if (!(ifi->ifi_flags & CHECK_CONNECTED)) {
+ free_addresses(ifs[ifi->ifi_index]->addresses_seen);
+ ifs[ifi->ifi_index]->addresses_seen = NULL;
+ }
break;
case RTM_DELLINK:
- notifystr = newstr_away(TEXT_DELLINK, ifnames[ifi->ifi_index]->name);
+ notifystr = newstr_away(TEXT_DELLINK, ifs[ifi->ifi_index]->name);
icon = ICON_NETWORK_AWAY;
- free_chain(&addresses_seen[ifi->ifi_index]);
- free(ifnames[ifi->ifi_index]->name);
+ free_addresses(ifs[ifi->ifi_index]->addresses_seen);
+ free(ifs[ifi->ifi_index]->name);
/* marking interface deleted makes events for this interface to be ignored */
- ifnames[ifi->ifi_index]->deleted = 1;
+ ifs[ifi->ifi_index]->deleted = 1;
tmp_notification = notification;
break;
default:
/* we should not get here... */
- fprintf(stderr, "msg_handler: Unknown netlink nlmsg_type %d\n", msg->nlmsg_type);
+ fprintf(stderr, "msg_handler: Unknown netlink nlmsg_type %d.\n", msg->nlmsg_type);
return 0;
}
@@ -445,7 +484,7 @@ int main (int argc, char **argv) {
nls = open_netlink ();
if (nls < 0) {
- fprintf (stderr, "%s: Error opening netlin socket!", argv[0]);
+ fprintf (stderr, "%s: Error opening netlink socket!", argv[0]);
exit (EXIT_FAILURE);
}