summaryrefslogtreecommitdiffstats
path: root/src/fbgui/networkmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/fbgui/networkmanager.cpp')
-rw-r--r--src/fbgui/networkmanager.cpp681
1 files changed, 681 insertions, 0 deletions
diff --git a/src/fbgui/networkmanager.cpp b/src/fbgui/networkmanager.cpp
new file mode 100644
index 0000000..2dc774f
--- /dev/null
+++ b/src/fbgui/networkmanager.cpp
@@ -0,0 +1,681 @@
+/**
+ * @class NetworkManager
+ *
+ * @brief Manages the network configurations like setting new default routes.
+ *
+ * Manages the network configurations like setting new default routes.
+ * It provides methods for ipv4 and some method for ipv6.
+ *
+ */
+
+
+
+#include "networkmanager.h"
+
+NetworkManager::NetworkManager() {
+ // TODO Auto-generated constructor stub
+ _tag = "[nd:NetworkManager]";
+}
+
+
+
+NetworkManager::~NetworkManager() {
+ // TODO Auto-generated destructor stub
+}
+
+
+
+/**
+ * This method adds /replaces the default route.
+ * This method adds /replaces the default route.
+ * To keep it modular, it is possible
+ * to specify an ip address family.
+ *
+ * @param ifName
+ * the interface name
+ *
+ * @param gateway
+ * the gateway address (e.g: 192.168.0.254)
+ * @param mss
+ * the mss.
+ * @param af
+ * specify the family type of the ip address.
+ * possible values are: AF_INET for an IPv4 address
+ * AF_INET6 for an IPv6 address
+ *
+
+ * @return
+ * return -1 if an error happened.
+ * return 0 if everything was ok.
+ */
+int NetworkManager::replaceDefaultRoute(QString ifname, QString gateway,
+ int mss, int af) {
+ struct nl_cache *cache;
+ struct nl_handle* rtsock;
+ struct nl_addr * gw;
+ struct rtnl_route * route;
+ int retval, iface_idx;
+
+ QByteArray ba_ifn = ifname.toAscii();
+ char * ifn = ba_ifn.data();
+
+ QByteArray ba_gw = gateway.toAscii();
+ char * gwaddr = ba_gw.data();
+
+ qDebug() << _tag << "---doRoute() gwaddr" << gwaddr;
+
+ if (!(gw = nl_addr_parse(gwaddr, af))) {
+ qDebug() << _tag << "Invalid router address given:" << gwaddr;
+ return -1;
+ }
+
+ rtsock = nl_handle_alloc();
+ nl_connect(rtsock, NETLINK_ROUTE);
+
+ if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) {
+ qDebug() << _tag << "error with link cache alloc \n";
+ }
+
+ iface_idx = rtnl_link_name2i(cache, ifn);
+
+ route = rtnl_route_alloc();
+ rtnl_route_set_scope(route, RT_SCOPE_UNIVERSE);
+ rtnl_route_set_gateway(route, gw);
+ rtnl_route_set_oif(route, iface_idx);
+
+ if (mss > 0) {
+ rtnl_route_set_metric(route, RTAX_ADVMSS, mss);
+ }
+
+ retval = rtnl_route_add(rtsock, route, NLM_F_REPLACE);
+ qDebug() << _tag << "return value:" << retval << ":" << strerror(-retval);
+
+ rtnl_route_put(route);
+ nl_addr_put(gw);
+ nl_handle_destroy(rtsock);
+
+ return retval;
+}
+
+
+
+/**/
+int NetworkManager::ip6_addRoute(const char *iface,
+ const struct in6_addr *ip6_dest, int ip6_prefix,
+ const struct in6_addr *ip6_gateway, int metric, int mss) {
+ struct nl_cache *cache;
+ struct nl_handle *nlh;
+ struct rtnl_route *route;
+ struct nl_addr *dest_addr;
+ struct nl_addr *gw_addr = NULL;
+ int err, iface_idx;
+
+ nlh = nl_handle_alloc();
+ nl_connect(nlh, NETLINK_ROUTE);
+
+ if ((cache = rtnl_link_alloc_cache(nlh)) == NULL) {
+ //qDebug() << _tag << "error with link cache alloc \n";
+ printf("error with link cache alloc \n");
+ }
+
+ iface_idx = rtnl_link_name2i(cache, iface);
+
+ route = rtnl_route_alloc();
+
+ /* Destination */
+ dest_addr = nl_addr_build(AF_INET6, (struct in6_addr *) ip6_dest,
+ sizeof(*ip6_dest));
+ nl_addr_set_prefixlen(dest_addr, (int) ip6_prefix);
+
+ rtnl_route_set_dst(route, dest_addr);
+ nl_addr_put(dest_addr);
+
+ /* Gateway */
+ if (ip6_gateway && !IN6_IS_ADDR_UNSPECIFIED (ip6_gateway)) {
+ gw_addr = nl_addr_build(AF_INET6, (struct in6_addr *) ip6_gateway,
+ sizeof(*ip6_gateway));
+ if (gw_addr) {
+ rtnl_route_set_gateway(route, gw_addr);
+ rtnl_route_set_scope(route, RT_SCOPE_UNIVERSE);
+ } else {
+ rtnl_route_put(route);
+ return -1;
+ }
+ }
+
+ /* Metric */
+ if (metric)
+ rtnl_route_set_prio(route, metric);
+
+ /* Add the route */
+ err = rtnl_route_add(nlh, route, 0);
+ if (err == -ESRCH && ip6_gateway) {
+ /* Gateway might be over a bridge; try adding a route to gateway first */
+ struct rtnl_route *route2;
+
+ route2 = create_route(iface_idx, mss);
+ if (route2) {
+ /* Add route to gateway over bridge */
+ rtnl_route_set_dst(route2, gw_addr);
+ err = rtnl_route_add(nlh, route2, 0);
+ if (!err) {
+ /* Try adding the route again */
+ err = rtnl_route_add(nlh, route, 0);
+ if (err)
+ rtnl_route_del(nlh, route2, 0);
+ }
+ rtnl_route_put(route2);
+ }
+ }
+
+ if (gw_addr)
+ nl_addr_put(gw_addr);
+
+ if (err) {
+ //nm_warning ("Failed to set IPv6 route on '%s': %s", iface, nl_geterror ());
+ rtnl_route_put(route);
+ route = NULL;
+ }
+
+ return 0;
+}
+
+
+
+struct rtnl_route * NetworkManager::create_route (int iface_idx, int mss)
+{
+ struct rtnl_route *route;
+
+ route = rtnl_route_alloc ();
+ if (route) {
+ rtnl_route_set_oif (route, iface_idx);
+
+ if (mss && rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0) {
+ //nm_warning ("Could not set mss");
+ }
+ } else
+ //nm_warning ("Could not allocate route");
+
+ return route;
+}
+
+
+
+/**
+ * The method brings an interface up.
+ *
+ * @param ifname
+ * the name of the interface
+ *
+ * @return
+ * 0 -> success
+ * -1 -> error
+ */
+int NetworkManager::bringInterfaceUP(QString ifname) {
+ return bringInterfaceUpDown(ifname, true);
+}
+
+
+
+/**
+ * The method brings an interface down.
+ *
+ * @param ifname
+ * the name of the interface
+ *
+ * @return
+ * 0 -> success
+ * -1 -> error
+ */
+int NetworkManager::bringInterfaceDown(QString ifname) {
+ return bringInterfaceUpDown(ifname, false);
+}
+
+
+
+/**
+ * This method brings an interface up or down.
+ *
+ * @param ifname
+ * is a string which contains the interface name which is going down or up.
+ *
+ * @param up
+ * is a bool. true means. we bring the interface up.
+ * false meand. we bring the interface down.
+ * @return
+ * 0 if everything is ok
+ * else an error
+ */
+int NetworkManager::bringInterfaceUpDown(QString ifname, bool up) {
+ struct nl_cache *cache;
+ struct nl_handle* rtsock;
+ struct rtnl_link* request = NULL;
+ struct rtnl_link* old = NULL;
+ int retval;
+
+ QByteArray ba_ifn = ifname.toAscii();
+ char * ifn = ba_ifn.data();
+
+ if (!(request = rtnl_link_alloc())) {
+ qDebug() << _tag << "error. couldn't allocate a rtnl link";
+ return -1;
+ }
+
+ rtsock = nl_handle_alloc();
+ nl_connect(rtsock, NETLINK_ROUTE);
+
+ if (up) {
+ rtnl_link_set_flags(request, IFF_UP);
+ } else {
+ rtnl_link_unset_flags(request, IFF_UP);
+ }
+
+ if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) {
+ qDebug() << _tag << "error with link cache alloc ";
+ }
+
+ old = rtnl_link_get_by_name(cache, ifn);
+ if (old) {
+ qDebug() << _tag << "change link";
+ retval = rtnl_link_change(rtsock, old, request, 0);
+ } else {
+ qDebug() << _tag << "change failed";
+ retval = -1;
+ qDebug() << _tag << "return value:" << retval << ":" << strerror(-retval);
+ }
+
+ rtnl_link_put(old);
+ rtnl_link_put(request);
+ nl_handle_destroy(rtsock);
+
+ return retval;
+}
+
+
+
+/**
+ * This method is used when the manual configuration is needed.
+ *
+ * This method is used when the manual configuration is needed.
+ * First we bring up the interface. Than we configure the interface with
+ * our manual entered configuration dates.
+ * After that we replace the old default route with the new and
+ * write a resolv.conf.
+ *
+ * @param ifname
+ * name of the interface which we are about to configure.
+ *
+ * @param ipAddress
+ * the new IP-Address.
+ *
+ * @param netmask
+ * the netmask of the IP-Address.
+ *
+ * @param broadcast
+ * the broadcast address.
+ * @param gateway
+ * the gateway address.
+ * @param metric
+ * do not exactly know why we need this. in most cases this should be 0.
+ * @param af
+ * the address type. Either AF_INET for IPv4 or AF_INET6 for IPv6.
+ * @param pathToResolvConf
+ * the path to the resolf.conf file. in most cases "/etc/".
+ * @param nameServer
+ * the name server addresses.
+ */
+int NetworkManager::ip4_setManualConfiguration(QString ifname, QString ipAddress, QString netmask,
+ QString broadcast, QString gateway, int metric, int af, QString pathToResolvConf, QList<QString> nameServer) {
+
+ //bring the interface up
+ bringInterfaceUP(ifname);
+ //set configuration
+ ip4_configureInterface(ifname, ipAddress, broadcast, netmask,af);
+ //set default route
+ replaceDefaultRoute(ifname, gateway, metric, af);
+ //write resolv.conf
+ writeResolvConf(pathToResolvConf, ifname, nameServer);
+ return 0;
+}
+
+
+
+int NetworkManager::ip4_configureInterface(QString ifname, QString ipAddress,
+ QString broadcast, QString netmask, int af) {
+
+ struct nl_cache *cache;
+ struct nl_handle* rtsock;
+ struct nl_addr * local;
+ struct rtnl_addr * addr = NULL;
+ int retval = 0;
+ int iface_idx, err, prefixLength;
+
+ QByteArray ba_ifn = ifname.trimmed().toAscii();
+ char * ifn = ba_ifn.data();
+
+ QByteArray ba_ip = ipAddress.trimmed().toAscii();
+ char * ipaddr = ba_ip.data();
+
+ QByteArray ba_bc = broadcast.trimmed().toAscii();
+ char * bcaddr = ba_bc.data();
+
+ rtsock = nl_handle_alloc();
+ nl_connect(rtsock, NETLINK_ROUTE);
+
+ if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) {
+ qDebug() << _tag << "error with link cache alloc";
+ return -1;
+ }
+
+ iface_idx = rtnl_link_name2i(cache, ifn);
+
+ if (!(addr = rtnl_addr_alloc())) {
+ qDebug() << _tag << "error with addr alloc";
+ return -1;
+ }
+
+ local = nl_addr_parse(ipaddr, af);
+ err = rtnl_addr_set_local(addr, local);
+ nl_addr_put(local);
+ if (err != 0) {
+ qDebug() << _tag << "error with set local addr";
+ }
+
+ prefixLength = ip4_netmaskToPrefix(ipAddress,netmask);
+ qDebug() << _tag << "prefix length:" << prefixLength;
+ rtnl_addr_set_prefixlen(addr, prefixLength);
+
+ local = nl_addr_parse(bcaddr, af);
+ err = rtnl_addr_set_broadcast(addr, local);
+ nl_addr_put(local);
+ if (err != 0) {
+ qDebug() << _tag << "error with set broadcast addr";
+ }
+
+ rtnl_addr_set_ifindex(addr, iface_idx);
+
+
+ retval = sync_address(ifn, iface_idx, af, addr);
+ if(retval < 0) {
+ qDebug() << _tag << "error in sync_address";
+ }
+ rtnl_addr_put(addr);
+
+ return retval;
+}
+
+
+
+/**
+ * This Method returns the length of the IP-Address netmask prefix.
+ *
+ * @param ipAddr
+ * the IP-address
+ *
+ * @param netmask
+ * the netmask of the IP-address.
+ * @return
+ * the length of the IP-Address netmask prefix
+ */
+int NetworkManager::ip4_netmaskToPrefix(QString ipAddr, QString netmask) {
+ int retval = -1;
+ QNetworkAddressEntry nae;
+
+ if (netmask == "") {
+ qDebug() << _tag << "error: netmask is empty";
+ return retval;
+ }
+ nae.setIp(QHostAddress(ipAddr));
+ nae.setNetmask(QHostAddress(netmask.trimmed()));
+ retval = nae.prefixLength();
+
+ return retval;
+}
+
+
+
+int NetworkManager::ip6_addAddress(struct ip6_addr* ip6Addr, const char *iface) {
+ int num_addrs, i, iface_idx;
+ struct rtnl_addr* addr = NULL;
+ struct nl_cache *cache;
+ struct nl_handle* rtsock;
+
+ rtsock = nl_handle_alloc();
+ nl_connect(rtsock, NETLINK_ROUTE);
+
+ if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL) {
+ qDebug() << _tag << "error with link cache alloc";
+ return -1;
+ }
+
+ iface_idx = rtnl_link_name2i(cache, iface);
+
+ addr = ip6AddrToRtnlAddr(ip6Addr);
+ if (!addr) {
+ //nm_warning("couldn't create rtnl address!\n");
+ return -1;
+ }
+ rtnl_addr_set_ifindex(addr, iface_idx);
+
+ return sync_address(iface, iface_idx, AF_INET6, addr);
+}
+
+
+
+/**/
+struct rtnl_addr* NetworkManager::ip6AddrToRtnlAddr(struct ip6_addr* ip6Addr) {
+ struct rtnl_addr *addr;
+ bool success = true;
+
+ if (!(addr = rtnl_addr_alloc()))
+ return NULL;
+
+ success = (nlAddrToRtnlAddr(ip6Addr, addr) >= 0);
+
+ if (!success) {
+ rtnl_addr_put(addr);
+ addr = NULL;
+ }
+
+ return addr;
+}
+
+
+
+/**/
+struct nl_addr* NetworkManager::ip6AddrToNlAddr(const struct ip6_addr *ip6Addr) {
+ struct nl_addr * nla = NULL;
+
+ if (!(nla = nl_addr_alloc(sizeof(struct in6_addr))))
+ return NULL;
+ nl_addr_set_family(nla, AF_INET6);
+ nl_addr_set_binary_addr(nla, (struct in6_addr *) ip6Addr, sizeof(struct in6_addr));
+
+ return nla;
+}
+
+
+
+/**/
+int NetworkManager::nlAddrToRtnlAddr(
+ const struct ip6_addr* ip6Addr, struct rtnl_addr* addr) {
+ struct nl_addr * local = NULL;
+ int err = 0;
+
+ local = ip6AddrToNlAddr(ip6Addr);
+ err = rtnl_addr_set_local(addr, local);
+ nl_addr_put(local);
+
+ return -err;
+}
+
+
+
+/**
+ * delete all addresses of this interface but not the one we just set
+ *
+ * @return
+ * -1 if something went wrong. else 0
+ */
+int NetworkManager::sync_address(const char *iface, int ifindex, int family,
+ struct rtnl_addr *addr) {
+
+ struct nl_handle *nlh;
+ struct nl_cache *addr_cache;
+ struct rtnl_addr *filter_addr, *match_addr;
+ struct nl_object *match;
+ struct nl_addr *nladdr;
+ int err;
+ char buf[INET6_ADDRSTRLEN + 1];
+
+ nlh = nl_handle_alloc();
+ nl_connect(nlh, NETLINK_ROUTE);
+
+ if (!nlh)
+ return -1;
+
+ addr_cache = rtnl_addr_alloc_cache(nlh);
+
+ if (!addr_cache)
+ return -1;
+
+ filter_addr = rtnl_addr_alloc();
+ if (!filter_addr) {
+ nl_cache_free(addr_cache);
+ return -1;
+ }
+ rtnl_addr_set_ifindex(filter_addr, ifindex);
+ if (family)
+ rtnl_addr_set_family(filter_addr, family);
+
+ //nm_log_dbg (log_domain, "(%s): syncing addresses (family %d)", iface, family);
+
+ /* Walk through the cache, comparing the addresses already on
+ * the interface to the addresses in addrs.
+ */
+ for (match = nl_cache_get_first(addr_cache); match; match
+ = nl_cache_get_next(match)) {
+ int buf_valid = -1;
+ match_addr = (struct rtnl_addr *) match;
+
+ /* Skip addresses not on our interface */
+ if (!nl_object_match_filter(match, (struct nl_object *) filter_addr))
+ continue;
+
+ if (addr) {
+ if (addr && nl_object_identical(match, (struct nl_object *) addr)) {
+ continue;
+ }
+ }
+
+ nladdr = rtnl_addr_get_local(match_addr);
+
+ /* Don't delete IPv6 link-local addresses; they don't belong to NM */
+ if (rtnl_addr_get_family(match_addr) == AF_INET6) {
+ struct in6_addr *tmp;
+
+ if (rtnl_addr_get_scope(match_addr) == RT_SCOPE_LINK) {
+ //nm_log_dbg (log_domain, "(%s): ignoring IPv6 link-local address", iface);
+ continue;
+ }
+
+ tmp = (in6_addr*) nl_addr_get_binary_addr(nladdr);
+ if (inet_ntop(AF_INET6, tmp, buf, sizeof(buf)))
+ buf_valid = 0;
+ } else if (rtnl_addr_get_family(match_addr) == AF_INET) {
+ struct in_addr *tmp;
+
+ tmp = (in_addr *) nl_addr_get_binary_addr(nladdr);
+ if (inet_ntop(AF_INET, tmp, buf, sizeof(buf)))
+ buf_valid = 0;
+ }
+
+ if (buf_valid == 0) {
+ //nm_log_dbg (log_domain, "(%s): removing address '%s/%d'",
+ // iface, buf, nl_addr_get_prefixlen (nladdr));
+ }
+
+ /* Otherwise, match_addr should be removed from the interface. */
+ err = rtnl_addr_delete(nlh, match_addr, 0);
+ if (err < 0) {
+ //nm_log_err (log_domain, "(%s): error %d returned from rtnl_addr_delete(): %s",
+ // iface, err, nl_geterror ());
+ qDebug() << _tag << "error with delete addr";
+ }
+ }
+
+ rtnl_addr_put(filter_addr);
+ nl_cache_free(addr_cache);
+
+ /* Now add the remaining new addresses */
+ if (!addr)
+ return -1;
+
+ struct in6_addr *in6tmp;
+ struct in_addr *in4tmp;
+ int buf_valid = -1;
+
+ nladdr = rtnl_addr_get_local(addr);
+ if (rtnl_addr_get_family(addr) == AF_INET6) {
+ in6tmp = (in6_addr*) nl_addr_get_binary_addr(nladdr);
+ if (inet_ntop(AF_INET6, in6tmp, buf, sizeof(buf)))
+ buf_valid = 0;
+ } else if (rtnl_addr_get_family(addr) == AF_INET) {
+ in4tmp = (in_addr*) nl_addr_get_binary_addr(nladdr);
+ if (inet_ntop(AF_INET, in4tmp, buf, sizeof(buf)))
+ buf_valid = 0;
+ }
+
+ if (buf_valid == 0) {
+ //nm_log_dbg (log_domain, "(%s): adding address '%s/%d'",
+ //iface, buf, nl_addr_get_prefixlen (nladdr));
+ qDebug() << _tag << "buf valid adding addr";
+ }
+
+ err = rtnl_addr_add(nlh, addr, 0);
+ if (err < 0) {
+ //nm_log_err (log_domain,
+ // "(%s): error %d returned from rtnl_addr_add():\n%s",
+ // iface, err, nl_geterror ());
+ qDebug() << _tag << "error with add addr"<< strerror(-err);
+ }
+
+ rtnl_addr_put(addr);
+
+ return err;
+}
+
+
+
+/**
+ * This method writes a resolv.conf file.
+ *
+ * @param path
+ * path to the resolv.conf file. (in most cases: /etc/)
+ * @param ifname
+ * name of the interface
+ * @param
+ * addresses of the nameserver
+ *
+ * @return
+ * return 0 if success
+ * else -1
+ */
+int NetworkManager::writeResolvConf(QString path, QString ifname, QList<QString> nameServer){
+
+ QFile file(path + "resolv.conf");
+ if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ qDebug() << _tag << "error couldn't open file:" << path;
+ return -1;
+ }
+ QTextStream out(&file);
+ out << "# Generated by networkdiscovery manual configuration for interface " + ifname +"\n";
+ foreach(QString ns, nameServer ) {
+ out << "nameserver " + ns +"\n";
+ }
+
+ file.close();
+
+ return 0;
+}
+