aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2011-07-21 13:03:12 +0200
committerNatanael Copa <ncopa@alpinelinux.org>2011-07-21 13:31:15 +0200
commit4e3d2e3093b9dcbb7d37ee3f18db8d6fa54f0deb (patch)
tree180f87fc5f167469fd66b7188cc611634ca50355
parentb1817e210a434bec5543c574c6846f6e114426a5 (diff)
downloadpingu-4e3d2e3093b9dcbb7d37ee3f18db8d6fa54f0deb.tar.bz2
pingu-4e3d2e3093b9dcbb7d37ee3f18db8d6fa54f0deb.tar.xz
pingu: add initial code to modify routing tables
For now we just create the alternate routing tables from table 10 and +1 for each new interface. First interface is 10, second is 11 etc.
-rw-r--r--pingu_host.c5
-rw-r--r--pingu_host.h1
-rw-r--r--pingu_iface.c9
-rw-r--r--pingu_iface.h3
-rw-r--r--pingu_netlink.c96
5 files changed, 105 insertions, 9 deletions
diff --git a/pingu_host.c b/pingu_host.c
index 50aa914..da14858 100644
--- a/pingu_host.c
+++ b/pingu_host.c
@@ -22,6 +22,7 @@ int default_required_replies = 2;
char *default_up_action = NULL;
char *default_down_action = NULL;
char *default_route_script = NULL;
+int default_route_table = 10;
/* note: this overwrite the line buffer */
static void parse_line(char *line, char **key, char **value)
@@ -112,6 +113,8 @@ int pingu_host_read_config(const char *file)
default_down_action = xstrdup(value);
} else if (strcmp(key, "route-script") == 0) {
default_route_script = xstrdup(value);
+ } else if (strcmp(key, "route-table") == 0) {
+ default_route_table = atoi(value);
} else
log_error("host not specified");
} else if (strcmp(key, "interface") == 0) {
@@ -136,6 +139,8 @@ int pingu_host_read_config(const char *file)
p->source_ip = xstrdup(value);
} else if (strcmp(key, "interval") == 0) {
p->burst_interval = atof(value);
+ } else if (strcmp(key, "route-table") == 0) {
+ p->iface_route_table = atoi(value);
} else {
log_error("Unknown keyword '%s' on line %i", key,
lineno);
diff --git a/pingu_host.h b/pingu_host.h
index ba142a6..f19c461 100644
--- a/pingu_host.h
+++ b/pingu_host.h
@@ -15,6 +15,7 @@ struct pingu_host {
char *up_action;
char *down_action;
int status;
+ int iface_route_table;
int max_retries;
int required_replies;
ev_tstamp timeout;
diff --git a/pingu_iface.c b/pingu_iface.c
index 4de0bc6..689d36b 100644
--- a/pingu_iface.c
+++ b/pingu_iface.c
@@ -85,7 +85,7 @@ struct pingu_iface *pingu_iface_get_by_index(int index)
return NULL;
}
-struct pingu_iface *pingu_iface_find_or_create(struct ev_loop *loop, const char *name)
+struct pingu_iface *pingu_iface_new(struct ev_loop *loop, const char *name)
{
struct pingu_iface *iface = pingu_iface_get_by_name(name);
if (iface != NULL)
@@ -132,8 +132,13 @@ int pingu_iface_init(struct ev_loop *loop, struct list_head *host_list)
{
struct pingu_host *host;
struct pingu_iface *iface;
+ int autotbl = 10;
list_for_each_entry(host, host_list, host_list_entry) {
- iface = pingu_iface_find_or_create(loop, host->interface);
+ iface = pingu_iface_get_by_name(host->interface);
+ if (iface == NULL) {
+ iface = pingu_iface_new(loop, host->interface);
+ iface->route_table = autotbl++;
+ }
if (iface == NULL)
return -1;
host->iface = iface;
diff --git a/pingu_iface.h b/pingu_iface.h
index 84145a8..b44415d 100644
--- a/pingu_iface.h
+++ b/pingu_iface.h
@@ -11,15 +11,14 @@ struct pingu_iface {
int has_link;
int fd;
struct sockaddr primary_addr;
+ int route_table;
struct list_head iface_list_entry;
-// struct list_head burst_list;
struct list_head ping_list;
struct ev_io socket_watcher;
};
struct pingu_iface *pingu_iface_get_by_name(const char *name);
struct pingu_iface *pingu_iface_get_by_index(int index);
-struct pingu_iface *pingu_iface_find_or_create(struct ev_loop *loop, const char *name);
int pingu_iface_bind_socket(struct pingu_iface *iface, int log_error);
int pingu_iface_usable(struct pingu_iface *iface);
int pingu_iface_init(struct ev_loop *loop, struct list_head *host_list);
diff --git a/pingu_netlink.c b/pingu_netlink.c
index 98a7b6b..cd63c76 100644
--- a/pingu_netlink.c
+++ b/pingu_netlink.c
@@ -18,6 +18,7 @@
#include <linux/rtnetlink.h>
#include <linux/ip.h>
#include <linux/if.h>
+#include <netinet/in.h>
#include <time.h>
#include <stdio.h>
@@ -27,6 +28,7 @@
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
+#include <stdint.h>
#include <ev.h>
@@ -84,6 +86,23 @@ static void netlink_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rt
}
}
+static int netlink_add_rtattr_l(struct nlmsghdr *n, int maxlen, int type,
+ const void *data, int alen)
+{
+ int len = RTA_LENGTH(alen);
+ struct rtattr *rta;
+
+ if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
+ return FALSE;
+
+ rta = NLMSG_TAIL(n);
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy(RTA_DATA(rta), data, alen);
+ n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
+ return TRUE;
+}
+
static int netlink_receive(struct netlink_fd *fd, struct nlmsghdr *reply)
{
struct sockaddr_nl nladdr;
@@ -166,6 +185,40 @@ static int netlink_enumerate(struct netlink_fd *fd, int family, int type)
(struct sockaddr *) &addr, sizeof(addr)) >= 0;
}
+int netlink_route_add_or_replace(struct netlink_fd *fd,
+ in_addr_t destination, uint32_t masklen, in_addr_t gateway, int iface_index, int table)
+{
+ struct {
+ struct nlmsghdr nlh;
+ struct rtmsg msg;
+ char buf[1024];
+ } req;
+ struct sockaddr_nl addr;
+
+ memset(&req, 0, sizeof(req));
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+
+ req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE;
+ req.nlh.nlmsg_type = RTM_NEWROUTE;
+
+ req.msg.rtm_family = AF_INET;
+ req.msg.rtm_table = table;
+ req.msg.rtm_dst_len = masklen;
+ req.msg.rtm_protocol = RTPROT_BOOT;
+ req.msg.rtm_scope = RT_SCOPE_UNIVERSE;
+ req.msg.rtm_type = RTN_UNICAST;
+
+ netlink_add_rtattr_l(&req.nlh, sizeof(req), RTA_DST, &destination, 4);
+ netlink_add_rtattr_l(&req.nlh, sizeof(req), RTA_OIF, &iface_index, 4);
+ netlink_add_rtattr_l(&req.nlh, sizeof(req), RTA_GATEWAY, &gateway, 4);
+
+ return sendto(fd->fd, (void *) &req, sizeof(req), 0,
+ (struct sockaddr *) &addr, sizeof(addr));
+
+}
+
static void netlink_link_new(struct nlmsghdr *msg)
{
struct pingu_iface *iface;
@@ -259,14 +312,47 @@ static void netlink_addr_del(struct nlmsghdr *nlmsg)
}
+static void netlink_route_new(struct nlmsghdr *msg)
+{
+ struct pingu_iface *iface;
+ struct rtmsg *rtm = NLMSG_DATA(msg);
+ struct rtattr *rta[RTA_MAX+1];
+
+ in_addr_t destination = 0;
+ in_addr_t gateway = 0;
+ char deststr[64], gwstr[64];
+
+ netlink_parse_rtattr(rta, RTA_MAX, RTM_RTA(rtm), RTM_PAYLOAD(msg));
+ if (rta[RTA_OIF] == NULL || rta[RTA_GATEWAY] == NULL
+ || rtm->rtm_family != PF_INET || rtm->rtm_table != RT_TABLE_MAIN)
+ return;
+
+ if (rta[RTA_DST] != NULL)
+ destination = *(in_addr_t *)RTA_DATA(rta[RTA_DST]);
+
+ iface = pingu_iface_get_by_index(*(int*)RTA_DATA(rta[RTA_OIF]));
+ if (iface == NULL)
+ return;
+
+ gateway = *(in_addr_t *)RTA_DATA(rta[RTA_GATEWAY]);
+
+ inet_ntop(rtm->rtm_family, &destination, deststr, sizeof(deststr));
+ inet_ntop(rtm->rtm_family, &gateway, gwstr, sizeof(gwstr));
+
+ log_debug("New route to %s via %s dev %s table %i", deststr, gwstr,
+ iface->name, iface->route_table);
+
+ netlink_route_add_or_replace(&talk_fd, destination, rtm->rtm_dst_len,
+ gateway, iface->index, iface->route_table);
+}
+
static const netlink_dispatch_f route_dispatch[RTM_MAX] = {
[RTM_NEWLINK] = netlink_link_new,
[RTM_DELLINK] = netlink_link_del,
[RTM_NEWADDR] = netlink_addr_new,
-/* [RTM_DELADDR] = netlink_addr_del,
+ [RTM_DELADDR] = netlink_addr_del,
[RTM_NEWROUTE] = netlink_route_new,
- [RTM_DELROUTE] = netlink_route_del,
-*/
+// [RTM_DELROUTE] = netlink_route_del,
};
static void netlink_read_cb(struct ev_loop *loop, struct ev_io *w, int revents)
@@ -328,6 +414,7 @@ error:
return FALSE;
}
+
int kernel_init(struct ev_loop *loop)
{
int i;
@@ -346,10 +433,9 @@ int kernel_init(struct ev_loop *loop)
netlink_enumerate(&talk_fd, PF_UNSPEC, RTM_GETADDR);
netlink_read_cb(loop, &talk_fd.io, EV_READ);
-/*
netlink_enumerate(&talk_fd, PF_UNSPEC, RTM_GETROUTE);
netlink_read_cb(loop, &talk_fd.io, EV_READ);
-*/
+
return TRUE;
err_close_all: