1*3b7b927dSMichael Lotz /* 2*3b7b927dSMichael Lotz * Copyright 2013-2015 Haiku, Inc. All rights reserved. 3*3b7b927dSMichael Lotz * Distributed under the terms of the MIT License. 4*3b7b927dSMichael Lotz */ 5*3b7b927dSMichael Lotz 6*3b7b927dSMichael Lotz #include <NetworkRoute.h> 7*3b7b927dSMichael Lotz 8*3b7b927dSMichael Lotz #include <errno.h> 9*3b7b927dSMichael Lotz #include <net/if.h> 10*3b7b927dSMichael Lotz #include <sys/sockio.h> 11*3b7b927dSMichael Lotz 12*3b7b927dSMichael Lotz #include <AutoDeleter.h> 13*3b7b927dSMichael Lotz 14*3b7b927dSMichael Lotz 15*3b7b927dSMichael Lotz BNetworkRoute::BNetworkRoute() 16*3b7b927dSMichael Lotz { 17*3b7b927dSMichael Lotz memset(&fRouteEntry, 0, sizeof(route_entry)); 18*3b7b927dSMichael Lotz } 19*3b7b927dSMichael Lotz 20*3b7b927dSMichael Lotz 21*3b7b927dSMichael Lotz BNetworkRoute::~BNetworkRoute() 22*3b7b927dSMichael Lotz { 23*3b7b927dSMichael Lotz UnsetDestination(); 24*3b7b927dSMichael Lotz UnsetMask(); 25*3b7b927dSMichael Lotz UnsetGateway(); 26*3b7b927dSMichael Lotz UnsetSource(); 27*3b7b927dSMichael Lotz } 28*3b7b927dSMichael Lotz 29*3b7b927dSMichael Lotz 30*3b7b927dSMichael Lotz status_t 31*3b7b927dSMichael Lotz BNetworkRoute::SetTo(const BNetworkRoute& other) 32*3b7b927dSMichael Lotz { 33*3b7b927dSMichael Lotz return SetTo(other.RouteEntry()); 34*3b7b927dSMichael Lotz } 35*3b7b927dSMichael Lotz 36*3b7b927dSMichael Lotz 37*3b7b927dSMichael Lotz status_t 38*3b7b927dSMichael Lotz BNetworkRoute::SetTo(const route_entry& routeEntry) 39*3b7b927dSMichael Lotz { 40*3b7b927dSMichael Lotz #define SET_ADDRESS(address, setFunction) \ 41*3b7b927dSMichael Lotz if (routeEntry.address != NULL) { \ 42*3b7b927dSMichael Lotz result = setFunction(*routeEntry.address); \ 43*3b7b927dSMichael Lotz if (result != B_OK) \ 44*3b7b927dSMichael Lotz return result; \ 45*3b7b927dSMichael Lotz } 46*3b7b927dSMichael Lotz 47*3b7b927dSMichael Lotz status_t result; 48*3b7b927dSMichael Lotz SET_ADDRESS(destination, SetDestination) 49*3b7b927dSMichael Lotz SET_ADDRESS(mask, SetMask) 50*3b7b927dSMichael Lotz SET_ADDRESS(gateway, SetGateway) 51*3b7b927dSMichael Lotz SET_ADDRESS(source, SetSource) 52*3b7b927dSMichael Lotz 53*3b7b927dSMichael Lotz SetFlags(routeEntry.flags); 54*3b7b927dSMichael Lotz SetMTU(routeEntry.mtu); 55*3b7b927dSMichael Lotz return B_OK; 56*3b7b927dSMichael Lotz } 57*3b7b927dSMichael Lotz 58*3b7b927dSMichael Lotz 59*3b7b927dSMichael Lotz void 60*3b7b927dSMichael Lotz BNetworkRoute::Adopt(BNetworkRoute& other) 61*3b7b927dSMichael Lotz { 62*3b7b927dSMichael Lotz memcpy(&fRouteEntry, &other.fRouteEntry, sizeof(route_entry)); 63*3b7b927dSMichael Lotz memset(&other.fRouteEntry, 0, sizeof(route_entry)); 64*3b7b927dSMichael Lotz } 65*3b7b927dSMichael Lotz 66*3b7b927dSMichael Lotz 67*3b7b927dSMichael Lotz const route_entry& 68*3b7b927dSMichael Lotz BNetworkRoute::RouteEntry() const 69*3b7b927dSMichael Lotz { 70*3b7b927dSMichael Lotz return fRouteEntry; 71*3b7b927dSMichael Lotz } 72*3b7b927dSMichael Lotz 73*3b7b927dSMichael Lotz 74*3b7b927dSMichael Lotz const sockaddr* 75*3b7b927dSMichael Lotz BNetworkRoute::Destination() const 76*3b7b927dSMichael Lotz { 77*3b7b927dSMichael Lotz return fRouteEntry.destination; 78*3b7b927dSMichael Lotz } 79*3b7b927dSMichael Lotz 80*3b7b927dSMichael Lotz 81*3b7b927dSMichael Lotz status_t 82*3b7b927dSMichael Lotz BNetworkRoute::SetDestination(const sockaddr& destination) 83*3b7b927dSMichael Lotz { 84*3b7b927dSMichael Lotz return _AllocateAndSetAddress(destination, fRouteEntry.destination); 85*3b7b927dSMichael Lotz } 86*3b7b927dSMichael Lotz 87*3b7b927dSMichael Lotz 88*3b7b927dSMichael Lotz void 89*3b7b927dSMichael Lotz BNetworkRoute::UnsetDestination() 90*3b7b927dSMichael Lotz { 91*3b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.destination); 92*3b7b927dSMichael Lotz } 93*3b7b927dSMichael Lotz 94*3b7b927dSMichael Lotz 95*3b7b927dSMichael Lotz const sockaddr* 96*3b7b927dSMichael Lotz BNetworkRoute::Mask() const 97*3b7b927dSMichael Lotz { 98*3b7b927dSMichael Lotz return fRouteEntry.mask; 99*3b7b927dSMichael Lotz } 100*3b7b927dSMichael Lotz 101*3b7b927dSMichael Lotz 102*3b7b927dSMichael Lotz status_t 103*3b7b927dSMichael Lotz BNetworkRoute::SetMask(const sockaddr& mask) 104*3b7b927dSMichael Lotz { 105*3b7b927dSMichael Lotz return _AllocateAndSetAddress(mask, fRouteEntry.mask); 106*3b7b927dSMichael Lotz } 107*3b7b927dSMichael Lotz 108*3b7b927dSMichael Lotz 109*3b7b927dSMichael Lotz void 110*3b7b927dSMichael Lotz BNetworkRoute::UnsetMask() 111*3b7b927dSMichael Lotz { 112*3b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.mask); 113*3b7b927dSMichael Lotz } 114*3b7b927dSMichael Lotz 115*3b7b927dSMichael Lotz 116*3b7b927dSMichael Lotz const sockaddr* 117*3b7b927dSMichael Lotz BNetworkRoute::Gateway() const 118*3b7b927dSMichael Lotz { 119*3b7b927dSMichael Lotz return fRouteEntry.gateway; 120*3b7b927dSMichael Lotz } 121*3b7b927dSMichael Lotz 122*3b7b927dSMichael Lotz 123*3b7b927dSMichael Lotz status_t 124*3b7b927dSMichael Lotz BNetworkRoute::SetGateway(const sockaddr& gateway) 125*3b7b927dSMichael Lotz { 126*3b7b927dSMichael Lotz return _AllocateAndSetAddress(gateway, fRouteEntry.gateway); 127*3b7b927dSMichael Lotz } 128*3b7b927dSMichael Lotz 129*3b7b927dSMichael Lotz 130*3b7b927dSMichael Lotz void 131*3b7b927dSMichael Lotz BNetworkRoute::UnsetGateway() 132*3b7b927dSMichael Lotz { 133*3b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.gateway); 134*3b7b927dSMichael Lotz } 135*3b7b927dSMichael Lotz 136*3b7b927dSMichael Lotz 137*3b7b927dSMichael Lotz const sockaddr* 138*3b7b927dSMichael Lotz BNetworkRoute::Source() const 139*3b7b927dSMichael Lotz { 140*3b7b927dSMichael Lotz return fRouteEntry.source; 141*3b7b927dSMichael Lotz } 142*3b7b927dSMichael Lotz 143*3b7b927dSMichael Lotz 144*3b7b927dSMichael Lotz status_t 145*3b7b927dSMichael Lotz BNetworkRoute::SetSource(const sockaddr& source) 146*3b7b927dSMichael Lotz { 147*3b7b927dSMichael Lotz return _AllocateAndSetAddress(source, fRouteEntry.source); 148*3b7b927dSMichael Lotz } 149*3b7b927dSMichael Lotz 150*3b7b927dSMichael Lotz 151*3b7b927dSMichael Lotz void 152*3b7b927dSMichael Lotz BNetworkRoute::UnsetSource() 153*3b7b927dSMichael Lotz { 154*3b7b927dSMichael Lotz _FreeAndUnsetAddress(fRouteEntry.source); 155*3b7b927dSMichael Lotz } 156*3b7b927dSMichael Lotz 157*3b7b927dSMichael Lotz 158*3b7b927dSMichael Lotz uint32 159*3b7b927dSMichael Lotz BNetworkRoute::Flags() const 160*3b7b927dSMichael Lotz { 161*3b7b927dSMichael Lotz return fRouteEntry.flags; 162*3b7b927dSMichael Lotz } 163*3b7b927dSMichael Lotz 164*3b7b927dSMichael Lotz 165*3b7b927dSMichael Lotz void 166*3b7b927dSMichael Lotz BNetworkRoute::SetFlags(uint32 flags) 167*3b7b927dSMichael Lotz { 168*3b7b927dSMichael Lotz fRouteEntry.flags = flags; 169*3b7b927dSMichael Lotz } 170*3b7b927dSMichael Lotz 171*3b7b927dSMichael Lotz 172*3b7b927dSMichael Lotz uint32 173*3b7b927dSMichael Lotz BNetworkRoute::MTU() const 174*3b7b927dSMichael Lotz { 175*3b7b927dSMichael Lotz return fRouteEntry.mtu; 176*3b7b927dSMichael Lotz } 177*3b7b927dSMichael Lotz 178*3b7b927dSMichael Lotz 179*3b7b927dSMichael Lotz void 180*3b7b927dSMichael Lotz BNetworkRoute::SetMTU(uint32 mtu) 181*3b7b927dSMichael Lotz { 182*3b7b927dSMichael Lotz fRouteEntry.mtu = mtu; 183*3b7b927dSMichael Lotz } 184*3b7b927dSMichael Lotz 185*3b7b927dSMichael Lotz 186*3b7b927dSMichael Lotz int 187*3b7b927dSMichael Lotz BNetworkRoute::AddressFamily() const 188*3b7b927dSMichael Lotz { 189*3b7b927dSMichael Lotz #define RETURN_FAMILY_IF_SET(address) \ 190*3b7b927dSMichael Lotz if (fRouteEntry.address != NULL \ 191*3b7b927dSMichael Lotz && fRouteEntry.address->sa_family != AF_UNSPEC) { \ 192*3b7b927dSMichael Lotz return fRouteEntry.address->sa_family; \ 193*3b7b927dSMichael Lotz } 194*3b7b927dSMichael Lotz 195*3b7b927dSMichael Lotz RETURN_FAMILY_IF_SET(destination) 196*3b7b927dSMichael Lotz RETURN_FAMILY_IF_SET(mask) 197*3b7b927dSMichael Lotz RETURN_FAMILY_IF_SET(gateway) 198*3b7b927dSMichael Lotz RETURN_FAMILY_IF_SET(source) 199*3b7b927dSMichael Lotz 200*3b7b927dSMichael Lotz return AF_UNSPEC; 201*3b7b927dSMichael Lotz } 202*3b7b927dSMichael Lotz 203*3b7b927dSMichael Lotz 204*3b7b927dSMichael Lotz status_t 205*3b7b927dSMichael Lotz BNetworkRoute::GetDefaultRoute(int family, const char* interfaceName, 206*3b7b927dSMichael Lotz BNetworkRoute& route) 207*3b7b927dSMichael Lotz { 208*3b7b927dSMichael Lotz BObjectList<BNetworkRoute> routes(1, true); 209*3b7b927dSMichael Lotz status_t result = GetRoutes(family, interfaceName, RTF_DEFAULT, routes); 210*3b7b927dSMichael Lotz if (result != B_OK) 211*3b7b927dSMichael Lotz return result; 212*3b7b927dSMichael Lotz 213*3b7b927dSMichael Lotz if (routes.CountItems() == 0) 214*3b7b927dSMichael Lotz return B_ENTRY_NOT_FOUND; 215*3b7b927dSMichael Lotz 216*3b7b927dSMichael Lotz route.Adopt(*routes.ItemAt(0)); 217*3b7b927dSMichael Lotz return B_OK; 218*3b7b927dSMichael Lotz } 219*3b7b927dSMichael Lotz 220*3b7b927dSMichael Lotz 221*3b7b927dSMichael Lotz status_t 222*3b7b927dSMichael Lotz BNetworkRoute::GetDefaultGateway(int family, const char* interfaceName, 223*3b7b927dSMichael Lotz sockaddr& gateway) 224*3b7b927dSMichael Lotz { 225*3b7b927dSMichael Lotz BNetworkRoute route; 226*3b7b927dSMichael Lotz status_t result = GetDefaultRoute(family, interfaceName, route); 227*3b7b927dSMichael Lotz if (result != B_OK) 228*3b7b927dSMichael Lotz return result; 229*3b7b927dSMichael Lotz 230*3b7b927dSMichael Lotz const sockaddr* defaultGateway = route.Gateway(); 231*3b7b927dSMichael Lotz if (defaultGateway == NULL) 232*3b7b927dSMichael Lotz return B_ENTRY_NOT_FOUND; 233*3b7b927dSMichael Lotz 234*3b7b927dSMichael Lotz memcpy(&gateway, defaultGateway, defaultGateway->sa_len); 235*3b7b927dSMichael Lotz return B_OK; 236*3b7b927dSMichael Lotz } 237*3b7b927dSMichael Lotz 238*3b7b927dSMichael Lotz 239*3b7b927dSMichael Lotz status_t 240*3b7b927dSMichael Lotz BNetworkRoute::GetRoutes(int family, BObjectList<BNetworkRoute>& routes) 241*3b7b927dSMichael Lotz { 242*3b7b927dSMichael Lotz return GetRoutes(family, NULL, 0, routes); 243*3b7b927dSMichael Lotz } 244*3b7b927dSMichael Lotz 245*3b7b927dSMichael Lotz 246*3b7b927dSMichael Lotz status_t 247*3b7b927dSMichael Lotz BNetworkRoute::GetRoutes(int family, const char* interfaceName, 248*3b7b927dSMichael Lotz BObjectList<BNetworkRoute>& routes) 249*3b7b927dSMichael Lotz { 250*3b7b927dSMichael Lotz return GetRoutes(family, interfaceName, 0, routes); 251*3b7b927dSMichael Lotz } 252*3b7b927dSMichael Lotz 253*3b7b927dSMichael Lotz 254*3b7b927dSMichael Lotz status_t 255*3b7b927dSMichael Lotz BNetworkRoute::GetRoutes(int family, const char* interfaceName, 256*3b7b927dSMichael Lotz uint32 filterFlags, BObjectList<BNetworkRoute>& routes) 257*3b7b927dSMichael Lotz { 258*3b7b927dSMichael Lotz int socket = ::socket(family, SOCK_DGRAM, 0); 259*3b7b927dSMichael Lotz if (socket < 0) 260*3b7b927dSMichael Lotz return errno; 261*3b7b927dSMichael Lotz 262*3b7b927dSMichael Lotz FileDescriptorCloser fdCloser(socket); 263*3b7b927dSMichael Lotz 264*3b7b927dSMichael Lotz ifconf config; 265*3b7b927dSMichael Lotz config.ifc_len = sizeof(config.ifc_value); 266*3b7b927dSMichael Lotz if (ioctl(socket, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0) 267*3b7b927dSMichael Lotz return errno; 268*3b7b927dSMichael Lotz 269*3b7b927dSMichael Lotz uint32 size = (uint32)config.ifc_value; 270*3b7b927dSMichael Lotz if (size == 0) 271*3b7b927dSMichael Lotz return B_OK; 272*3b7b927dSMichael Lotz 273*3b7b927dSMichael Lotz void* buffer = malloc(size); 274*3b7b927dSMichael Lotz if (buffer == NULL) 275*3b7b927dSMichael Lotz return B_NO_MEMORY; 276*3b7b927dSMichael Lotz 277*3b7b927dSMichael Lotz MemoryDeleter bufferDeleter(buffer); 278*3b7b927dSMichael Lotz config.ifc_len = size; 279*3b7b927dSMichael Lotz config.ifc_buf = buffer; 280*3b7b927dSMichael Lotz 281*3b7b927dSMichael Lotz if (ioctl(socket, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0) 282*3b7b927dSMichael Lotz return errno; 283*3b7b927dSMichael Lotz 284*3b7b927dSMichael Lotz ifreq* interface = (ifreq*)buffer; 285*3b7b927dSMichael Lotz ifreq* end = (ifreq*)((uint8*)buffer + size); 286*3b7b927dSMichael Lotz 287*3b7b927dSMichael Lotz while (interface < end) { 288*3b7b927dSMichael Lotz route_entry& routeEntry = interface->ifr_route; 289*3b7b927dSMichael Lotz 290*3b7b927dSMichael Lotz if ((interfaceName == NULL 291*3b7b927dSMichael Lotz || strcmp(interface->ifr_name, interfaceName) == 0) 292*3b7b927dSMichael Lotz && (filterFlags == 0 || (routeEntry.flags & filterFlags) != 0)) { 293*3b7b927dSMichael Lotz 294*3b7b927dSMichael Lotz BNetworkRoute* route = new(std::nothrow) BNetworkRoute; 295*3b7b927dSMichael Lotz if (route == NULL) 296*3b7b927dSMichael Lotz return B_NO_MEMORY; 297*3b7b927dSMichael Lotz 298*3b7b927dSMichael Lotz // Note that source is not provided in the buffer. 299*3b7b927dSMichael Lotz routeEntry.source = NULL; 300*3b7b927dSMichael Lotz 301*3b7b927dSMichael Lotz status_t result = route->SetTo(routeEntry); 302*3b7b927dSMichael Lotz if (result != B_OK) { 303*3b7b927dSMichael Lotz delete route; 304*3b7b927dSMichael Lotz return result; 305*3b7b927dSMichael Lotz } 306*3b7b927dSMichael Lotz 307*3b7b927dSMichael Lotz if (!routes.AddItem(route)) { 308*3b7b927dSMichael Lotz delete route; 309*3b7b927dSMichael Lotz return B_NO_MEMORY; 310*3b7b927dSMichael Lotz } 311*3b7b927dSMichael Lotz } 312*3b7b927dSMichael Lotz 313*3b7b927dSMichael Lotz size_t addressSize = 0; 314*3b7b927dSMichael Lotz if (routeEntry.destination != NULL) 315*3b7b927dSMichael Lotz addressSize += routeEntry.destination->sa_len; 316*3b7b927dSMichael Lotz if (routeEntry.mask != NULL) 317*3b7b927dSMichael Lotz addressSize += routeEntry.mask->sa_len; 318*3b7b927dSMichael Lotz if (routeEntry.gateway != NULL) 319*3b7b927dSMichael Lotz addressSize += routeEntry.gateway->sa_len; 320*3b7b927dSMichael Lotz 321*3b7b927dSMichael Lotz interface = (ifreq *)((addr_t)interface + IF_NAMESIZE 322*3b7b927dSMichael Lotz + sizeof(route_entry) + addressSize); 323*3b7b927dSMichael Lotz } 324*3b7b927dSMichael Lotz 325*3b7b927dSMichael Lotz return B_OK; 326*3b7b927dSMichael Lotz } 327*3b7b927dSMichael Lotz 328*3b7b927dSMichael Lotz 329*3b7b927dSMichael Lotz status_t 330*3b7b927dSMichael Lotz BNetworkRoute::_AllocateAndSetAddress(const sockaddr& from, 331*3b7b927dSMichael Lotz sockaddr*& to) 332*3b7b927dSMichael Lotz { 333*3b7b927dSMichael Lotz if (from.sa_len > sizeof(sockaddr_storage)) 334*3b7b927dSMichael Lotz return B_BAD_VALUE; 335*3b7b927dSMichael Lotz 336*3b7b927dSMichael Lotz if (to == NULL) { 337*3b7b927dSMichael Lotz to = (sockaddr*)malloc(sizeof(sockaddr_storage)); 338*3b7b927dSMichael Lotz if (to == NULL) 339*3b7b927dSMichael Lotz return B_NO_MEMORY; 340*3b7b927dSMichael Lotz } 341*3b7b927dSMichael Lotz 342*3b7b927dSMichael Lotz memcpy(to, &from, from.sa_len); 343*3b7b927dSMichael Lotz return B_OK; 344*3b7b927dSMichael Lotz } 345*3b7b927dSMichael Lotz 346*3b7b927dSMichael Lotz 347*3b7b927dSMichael Lotz void 348*3b7b927dSMichael Lotz BNetworkRoute::_FreeAndUnsetAddress(sockaddr*& address) 349*3b7b927dSMichael Lotz { 350*3b7b927dSMichael Lotz free(address); 351*3b7b927dSMichael Lotz address = NULL; 352*3b7b927dSMichael Lotz } 353