diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2011-07-21 13:03:12 +0200 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2011-07-21 13:31:15 +0200 |
commit | 4e3d2e3093b9dcbb7d37ee3f18db8d6fa54f0deb (patch) | |
tree | 180f87fc5f167469fd66b7188cc611634ca50355 | |
parent | b1817e210a434bec5543c574c6846f6e114426a5 (diff) | |
download | pingu-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.c | 5 | ||||
-rw-r--r-- | pingu_host.h | 1 | ||||
-rw-r--r-- | pingu_iface.c | 9 | ||||
-rw-r--r-- | pingu_iface.h | 3 | ||||
-rw-r--r-- | pingu_netlink.c | 96 |
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: |