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