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 FileDescriptorCloser socket(::socket(family, SOCK_DGRAM, 0)); 260 if (!socket.IsSet()) 261 return errno; 262 263 ifconf config; 264 config.ifc_len = sizeof(config.ifc_value); 265 if (ioctl(socket.Get(), SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0) 266 return errno; 267 268 uint32 size = (uint32)config.ifc_value; 269 if (size == 0) 270 return B_OK; 271 272 void* buffer = malloc(size); 273 if (buffer == NULL) 274 return B_NO_MEMORY; 275 276 MemoryDeleter bufferDeleter(buffer); 277 config.ifc_len = size; 278 config.ifc_buf = buffer; 279 280 if (ioctl(socket.Get(), SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0) 281 return errno; 282 283 ifreq* interface = (ifreq*)buffer; 284 ifreq* end = (ifreq*)((uint8*)buffer + size); 285 286 while (interface < end) { 287 route_entry& routeEntry = interface->ifr_route; 288 289 if ((interfaceName == NULL 290 || strcmp(interface->ifr_name, interfaceName) == 0) 291 && (filterFlags == 0 || (routeEntry.flags & filterFlags) != 0)) { 292 293 BNetworkRoute* route = new(std::nothrow) BNetworkRoute; 294 if (route == NULL) 295 return B_NO_MEMORY; 296 297 // Note that source is not provided in the buffer. 298 routeEntry.source = NULL; 299 300 status_t result = route->SetTo(routeEntry); 301 if (result != B_OK) { 302 delete route; 303 return result; 304 } 305 306 if (!routes.AddItem(route)) { 307 delete route; 308 return B_NO_MEMORY; 309 } 310 } 311 312 size_t addressSize = 0; 313 if (routeEntry.destination != NULL) 314 addressSize += routeEntry.destination->sa_len; 315 if (routeEntry.mask != NULL) 316 addressSize += routeEntry.mask->sa_len; 317 if (routeEntry.gateway != NULL) 318 addressSize += routeEntry.gateway->sa_len; 319 320 interface = (ifreq *)((addr_t)interface + IF_NAMESIZE 321 + sizeof(route_entry) + addressSize); 322 } 323 324 return B_OK; 325 } 326 327 328 status_t 329 BNetworkRoute::_AllocateAndSetAddress(const sockaddr& from, 330 sockaddr*& to) 331 { 332 if (from.sa_len > sizeof(sockaddr_storage)) 333 return B_BAD_VALUE; 334 335 if (to == NULL) { 336 to = (sockaddr*)malloc(sizeof(sockaddr_storage)); 337 if (to == NULL) 338 return B_NO_MEMORY; 339 } 340 341 memcpy(to, &from, from.sa_len); 342 return B_OK; 343 } 344 345 346 void 347 BNetworkRoute::_FreeAndUnsetAddress(sockaddr*& address) 348 { 349 free(address); 350 address = NULL; 351 } 352