Returns the IPv4 routes to a host. :param dst: the IPv4 of the destination host :param dev: (optional) filtering is performed to limit search to route associated to that interface. :returns: tuple (iface, output_ip, gateway_ip) where - ``ifac
(self, dst=None, dev=None, verbose=conf.verb, _internal=False)
| 166 | self.routes.append((the_net, the_msk, '0.0.0.0', iff, the_addr, 1)) |
| 167 | |
| 168 | def route(self, dst=None, dev=None, verbose=conf.verb, _internal=False): |
| 169 | # type: (Optional[str], Optional[str], int, bool) -> Tuple[str, str, str] |
| 170 | """Returns the IPv4 routes to a host. |
| 171 | |
| 172 | :param dst: the IPv4 of the destination host |
| 173 | :param dev: (optional) filtering is performed to limit search to route |
| 174 | associated to that interface. |
| 175 | |
| 176 | :returns: tuple (iface, output_ip, gateway_ip) where |
| 177 | - ``iface``: the interface used to connect to the host |
| 178 | - ``output_ip``: the outgoing IP that will be used |
| 179 | - ``gateway_ip``: the gateway IP that will be used |
| 180 | """ |
| 181 | dst = dst or "0.0.0.0" # Enable route(None) to return default route |
| 182 | if isinstance(dst, bytes): |
| 183 | try: |
| 184 | dst = plain_str(dst) |
| 185 | except UnicodeDecodeError: |
| 186 | raise TypeError("Unknown IP address input (bytes)") |
| 187 | if (dst, dev) in self.cache: |
| 188 | return self.cache[(dst, dev)] |
| 189 | # Transform "192.168.*.1-5" to one IP of the set |
| 190 | _dst = dst.split("/")[0].replace("*", "0") |
| 191 | while True: |
| 192 | idx = _dst.find("-") |
| 193 | if idx < 0: |
| 194 | break |
| 195 | m = (_dst[idx:] + ".").find(".") |
| 196 | _dst = _dst[:idx] + _dst[idx + m:] |
| 197 | |
| 198 | atol_dst = atol(_dst) |
| 199 | paths = [] |
| 200 | for d, m, gw, i, a, me in self.routes: |
| 201 | if not a: # some interfaces may not currently be connected |
| 202 | continue |
| 203 | if dev is not None and i != dev: |
| 204 | continue |
| 205 | aa = atol(a) |
| 206 | if aa == atol_dst and aa != 0: |
| 207 | paths.append( |
| 208 | (0xffffffff, 1, (conf.loopback_name, a, "0.0.0.0")) # noqa: E501 |
| 209 | ) |
| 210 | if (atol_dst & m) == (d & m): |
| 211 | paths.append((m, me, (i, a, gw))) |
| 212 | |
| 213 | if not paths: |
| 214 | if verbose: |
| 215 | warning("No route found for IPv4 destination %s " |
| 216 | "(no default route?)", dst) |
| 217 | return (dev or conf.loopback_name, "0.0.0.0", "0.0.0.0") |
| 218 | # Choose the more specific route |
| 219 | # Sort by greatest netmask and use metrics as a tie-breaker |
| 220 | paths.sort(key=lambda x: (-x[0], x[1])) |
| 221 | # Return interface |
| 222 | ret = paths[0][2] |
| 223 | # Check if source is 0.0.0.0. This is a 'via' route with no src. |
| 224 | if ret[1] == "0.0.0.0" and not _internal: |
| 225 | # Then get the source from route(gw) |
no test coverage detected