summaryrefslogtreecommitdiff
path: root/src/starter/interfaces.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/starter/interfaces.c')
-rw-r--r--src/starter/interfaces.c246
1 files changed, 153 insertions, 93 deletions
diff --git a/src/starter/interfaces.c b/src/starter/interfaces.c
index 3fff65be7..92b2c74a4 100644
--- a/src/starter/interfaces.c
+++ b/src/starter/interfaces.c
@@ -1,5 +1,6 @@
/* strongSwan IPsec interfaces management
* Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
+ * 2009 Heiko Hund - Astaro AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -12,12 +13,6 @@
* for more details.
*/
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#ifdef HAVE_SYS_SOCKIO_H
-#include <sys/sockio.h>
-#endif
-
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -33,120 +28,185 @@
#include "exec.h"
#include "files.h"
+#ifdef START_PLUTO
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/rtnetlink.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+
/*
- * discover the default route via /proc/net/route
+ * Get the default route information via rtnetlink
*/
void
get_defaultroute(defaultroute_t *defaultroute)
{
- FILE *fd;
- char line[BUF_LEN];
- bool first = TRUE;
-
- memset(defaultroute, 0, sizeof(defaultroute_t));
+ union {
+ struct {
+ struct nlmsghdr nh;
+ struct rtmsg rt;
+ } m;
+ char buf[4096];
+ } rtu;
+
+ struct nlmsghdr *nh;
+ uint32_t best_metric = ~0;
+ ssize_t msglen;
+ int fd;
+
+ bzero(&rtu, sizeof(rtu));
+ rtu.m.nh.nlmsg_len = NLMSG_LENGTH(sizeof(rtu.m.rt));
+ rtu.m.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ rtu.m.nh.nlmsg_type = RTM_GETROUTE;
+ rtu.m.rt.rtm_family = AF_INET;
+ rtu.m.rt.rtm_table = RT_TABLE_UNSPEC;
+ rtu.m.rt.rtm_protocol = RTPROT_UNSPEC;
+ rtu.m.rt.rtm_type = RTN_UNICAST;
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd == -1)
+ {
+ plog("could not create rtnetlink socket");
+ return;
+ }
- fd = fopen("/proc/net/route", "r");
+ if (send(fd, &rtu, rtu.m.nh.nlmsg_len, 0) == -1)
+ {
+ plog("could not write to rtnetlink socket");
+ close(fd);
+ return;
+ }
- if (!fd)
+ msglen = recv(fd, &rtu, sizeof(rtu), MSG_WAITALL);
+ if (msglen == -1)
{
- plog("could not open 'proc/net/route'");
+ plog("could not read from rtnetlink socket");
+ close(fd);
return;
}
- while (fgets(line, sizeof(line), fd) != 0)
+ close(fd);
+
+ for (nh = &rtu.m.nh; NLMSG_OK(nh, msglen); nh = NLMSG_NEXT(nh, msglen))
{
- char iface[11];
- char destination[9];
- char gateway[11];
- char flags[5];
- char mask[9];
-
- int refcnt;
- int use;
- int metric;
- int items;
-
- /* proc/net/route returns IP addresses in host order */
- strcpy(gateway, "0h");
-
- /* skip the header line */
- if (first)
+ struct rtmsg *rt;
+ struct rtattr *rta;
+ uint32_t rtalen, metric = 0;
+ struct in_addr gw = { .s_addr = INADDR_ANY };
+ int iface_idx = -1;
+
+ if (nh->nlmsg_type == NLMSG_ERROR)
{
- first = FALSE;
- continue;
+ plog("error from rtnetlink");
+ return;
}
- /* parsing a single line of proc/net/route */
- items = sscanf(line, "%10s\t%8s\t%8s\t%5s\t%d\t%d\t%d\t%8s\t"
- , iface, destination, gateway+2, flags, &refcnt, &use, &metric, mask);
- if (items < 8)
- {
- plog("parsing error while scanning /proc/net/route");
+ if (nh->nlmsg_type == NLMSG_DONE)
+ break;
+
+ rt = NLMSG_DATA(nh);
+ if ( rt->rtm_dst_len != 0
+ || (rt->rtm_table != RT_TABLE_MAIN
+ && rt->rtm_table != RT_TABLE_DEFAULT) )
continue;
+
+ rta = RTM_RTA(rt);
+ rtalen = RTM_PAYLOAD(nh);
+ while ( RTA_OK(rta, rtalen) )
+ {
+ switch (rta->rta_type)
+ {
+ case RTA_GATEWAY:
+ gw = *(struct in_addr *) RTA_DATA(rta);
+ break;
+ case RTA_OIF:
+ iface_idx = *(int *) RTA_DATA(rta);
+ break;
+ case RTA_PRIORITY:
+ metric = *(uint32_t *) RTA_DATA(rta);
+ break;
+ }
+ rta = RTA_NEXT(rta, rtalen);
}
- /* check for defaultroute (destination 0.0.0.0 and mask 0.0.0.0) */
- if (streq(destination, "00000000") && streq(mask, "00000000"))
+ if (metric < best_metric
+ && iface_idx != -1)
{
- if (defaultroute->defined)
+ struct ifreq req;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0)
+ {
+ plog("could not open AF_INET socket");
+ break;
+ }
+ bzero(&req, sizeof(req));
+ req.ifr_ifindex = iface_idx;
+ if (ioctl(fd, SIOCGIFNAME, &req) < 0 ||
+ ioctl(fd, SIOCGIFADDR, &req) < 0)
{
- plog("multiple default routes - cannot cope with %%defaultroute!!!");
- defaultroute->defined = FALSE;
- fclose(fd);
- return;
+ plog("could not read interface data, ignoring route");
+ close(fd);
+ break;
}
- ttoaddr(gateway, strlen(gateway), AF_INET, &defaultroute->nexthop);
- strncpy(defaultroute->iface, iface, IFNAMSIZ);
+
+ strncpy(defaultroute->iface, req.ifr_name, IFNAMSIZ);
+ defaultroute->addr.u.v4 = *((struct sockaddr_in *) &req.ifr_addr);
+ defaultroute->nexthop.u.v4.sin_family = AF_INET;
+
+ if (gw.s_addr == INADDR_ANY)
+ {
+ if (ioctl(fd, SIOCGIFDSTADDR, &req) < 0 ||
+ ((struct sockaddr_in*) &req.ifr_dstaddr)->sin_addr.s_addr == INADDR_ANY)
+ {
+ DBG_log("Ignoring default route to device %s because we can't get it's destination",
+ req.ifr_name);
+ close(fd);
+ break;
+ }
+
+ defaultroute->nexthop.u.v4 = *((struct sockaddr_in *) &req.ifr_dstaddr);
+ }
+ else
+ defaultroute->nexthop.u.v4.sin_addr = gw;
+
+ close(fd);
+
+ DBG(DBG_CONTROL,
+ char addr[20];
+ char nexthop[20];
+ addrtot(&defaultroute->addr, 0, addr, sizeof(addr));
+ addrtot(&defaultroute->nexthop, 0, nexthop, sizeof(nexthop));
+
+ DBG_log(
+ ( !defaultroute->defined
+ ? "Default route found: iface=%s, addr=%s, nexthop=%s"
+ : "Better default route: iface=%s, addr=%s, nexthop=%s"
+ ), defaultroute->iface, addr, nexthop
+ )
+ );
+
+ best_metric = metric;
defaultroute->defined = TRUE;
}
}
- fclose(fd);
+ defaultroute->supported = TRUE;
if (!defaultroute->defined)
- {
plog("no default route - cannot cope with %%defaultroute!!!");
- }
- else
- {
- char addr_buf[20], nexthop_buf[20];
- struct ifreq physreq;
+}
- int sock = socket(AF_INET, SOCK_DGRAM, 0);
+#else /* !START_PLUTO */
- /* determine IP address of iface */
- if (sock < 0)
- {
- plog("could not open SOCK_DGRAM socket");
- defaultroute->defined = FALSE;
- return;
- }
- memset ((void*)&physreq, 0, sizeof(physreq));
- strncpy(physreq.ifr_name, defaultroute->iface, IFNAMSIZ);
- ioctl(sock, SIOCGIFADDR, &physreq);
- close(sock);
- defaultroute->addr.u.v4 = *((struct sockaddr_in *)&physreq.ifr_addr);
-
- addrtot(&defaultroute->addr, 0, addr_buf, sizeof(addr_buf));
- addrtot(&defaultroute->nexthop, 0, nexthop_buf, sizeof(nexthop_buf));
-
- DBG(DBG_CONTROL,
- DBG_log("Default route found: iface=%s, addr=%s, nexthop=%s"
- , defaultroute->iface, addr_buf, nexthop_buf)
- )
-
- /* for backwards-compatibility with the awk shell scripts
- * store the defaultroute in /var/run/ipsec.info
- */
- fd = fopen(INFO_FILE, "w");
-
- if (fd)
- {
- fprintf(fd, "defaultroutephys=%s\n", defaultroute->iface );
- fprintf(fd, "defaultroutevirt=ipsec0\n");
- fprintf(fd, "defaultrouteaddr=%s\n", addr_buf);
- fprintf(fd, "defaultroutenexthop=%s\n", nexthop_buf);
- fclose(fd);
- }
- }
- return;
+/**
+ * Pluto disabled, fall back to %any
+ */
+void
+get_defaultroute(defaultroute_t *defaultroute)
+{
+ defaultroute->supported = FALSE;
}
+#endif /* START_PLUTO */
+