summaryrefslogblamecommitdiffstats
path: root/src/fbgui/networkmanager.cpp
blob: 8a3e52957bd68c352e29eacbb7449689b08ccf4b (plain) (tree)
1
2
3
4
5
6
7
8



                                                                             
  

                                                                      
  



                           






                                                       


                                         

 


                                        

 






















                                                     








                                                                             
 

                                       
 

                                       
 

                                                             
 

                                        
                                                                               

                
 

                                    
 

                                                      
                                                                      
     
 
                                           
 



                                                 
 



                                                     
 
                                                        
                                                                                   
 


                            
 
                

 
















                                                                                
                                                      

                                               
 



























                                                                        
 


























                                                                               
 

                         
 





                                                                                   
 




                                                    
 
                           
 



                                           
 






                                                                    
 
                 

 









                                     



                                                

 









                                       



                                                  

 












                                                                             













                                                             
                                                                            

                
 

                                    
 










                                                      
                                                                    




                                          
                                                   



                                                         
                                                     
                  
                                                                                       







                            































                                                                          




                                                                             
 









                                                                    
 



                                                                         
 





                                   
 

                                                 
 

                                                   
 

                                                   
 

                                    
 

                                                      
                                                                   

                
 
                                           
 

                                  
                                                             

                
 




                                         
                                                                 
     
 
                                                         
                                                              
                                              
 




                                             
                                                                     
     
 
                                         
 


                                                  
                                                             

                      
 
                

 










                                                                   




                                                                    
 

                    
                                                               




                                                  
 

                
 












                                                                           
                                                                   

                
 
                                             
 






                                                      
 
                                                        

 
    




                                                           
 

                                  
 
                                                   
 




                          
 
              

 
    



                                                               
 




                                                           
 
             

 
    





                                                                
 


                                         
 
              

 





                                                                     














                                                                        
 

              
 











































































                                                                                        
                                                            































                                                             
                                                           







                                                           
                                                                           





                    














                                                         







                                                             
                                                                       









                                                                            
 
             
 
         

 
/**
 * @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"

#include <log4cxx/logger.h>
#include "qlog4cxx.h"

using namespace log4cxx;
using namespace log4cxx::helpers;
LoggerPtr ndnmLogger(Logger::getLogger("fbgui.nd.nm"));

NetworkManager::NetworkManager()
{
  // TODO Auto-generated constructor stub
}

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();

  LOG4CXX_DEBUG(ndnmLogger, "---doRoute() gwaddr" << gwaddr);
  //qDebug() << "---doRoute() gwaddr" << gwaddr;

  if (!(gw = nl_addr_parse(gwaddr, af)))
    {
	  LOG4CXX_DEBUG(ndnmLogger, "Invalid router address given:" << gwaddr);
      return -1;
    }

  rtsock = nl_handle_alloc();
  nl_connect(rtsock, NETLINK_ROUTE);

  if ((cache = rtnl_link_alloc_cache(rtsock)) == NULL)
    {
	  LOG4CXX_DEBUG(ndnmLogger, "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);
  LOG4CXX_DEBUG(ndnmLogger, "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() <<  "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()))
    {
	  LOG4CXX_DEBUG(ndnmLogger, "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)
    {
	  LOG4CXX_DEBUG(ndnmLogger, "error with link cache alloc ");
    }

  old = rtnl_link_get_by_name(cache, ifn);
  if (old)
    {
	  LOG4CXX_DEBUG(ndnmLogger, "change link");
      retval = rtnl_link_change(rtsock, old, request, 0);
    }
  else
    {
	  LOG4CXX_DEBUG(ndnmLogger, "change failed");
      retval = -1;
      LOG4CXX_DEBUG(ndnmLogger, "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)
    {
	  LOG4CXX_DEBUG(ndnmLogger, "error with link cache alloc");
      return -1;
    }

  iface_idx = rtnl_link_name2i(cache, ifn);

  if (!(addr = rtnl_addr_alloc()))
    {
	  LOG4CXX_DEBUG(ndnmLogger, "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)
    {
	  LOG4CXX_DEBUG(ndnmLogger, "error with set local addr");
    }

  prefixLength = ip4_netmaskToPrefix(ipAddress, netmask);
  LOG4CXX_DEBUG(ndnmLogger, "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)
    {
	  LOG4CXX_DEBUG(ndnmLogger, "error with set broadcast addr");
    }

  rtnl_addr_set_ifindex(addr, iface_idx);

  retval = sync_address(ifn, iface_idx, af, addr);
  if (retval < 0)
    {
	  LOG4CXX_DEBUG(ndnmLogger, "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 == "")
    {
	  LOG4CXX_DEBUG(ndnmLogger, "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)
    {
	  LOG4CXX_DEBUG(ndnmLogger, "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 ());
    	LOG4CXX_DEBUG(ndnmLogger, "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));
	LOG4CXX_DEBUG(ndnmLogger, "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 ());
	LOG4CXX_DEBUG(ndnmLogger, "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))
  {
	LOG4CXX_DEBUG(ndnmLogger, "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;
}