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