tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nrinterfaceprioritizer.cpp (7049B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 #include "nrinterfaceprioritizer.h"
      5 
      6 #include <algorithm>
      7 #include <map>
      8 #include <set>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "logging.h"
     13 #include "nr_api.h"
     14 
     15 MOZ_MTLOG_MODULE("mtransport")
     16 
     17 namespace {
     18 
     19 class LocalAddress {
     20 public:
     21  LocalAddress()
     22      : is_vpn_(-1),
     23        estimated_speed_(-1),
     24        type_preference_(-1),
     25        ip_version_(-1) {}
     26 
     27  bool Init(const nr_local_addr& local_addr) {
     28    ifname_ = local_addr.addr.ifname;
     29 
     30    char buf[MAXIFNAME + 47];
     31    int r = nr_transport_addr_fmt_ifname_addr_string(&local_addr.addr, buf,
     32                                                     sizeof(buf));
     33    if (r) {
     34      MOZ_MTLOG(ML_ERROR, "Error formatting interface key.");
     35      return false;
     36    }
     37    key_ = buf;
     38 
     39    r = nr_transport_addr_get_addrstring(&local_addr.addr, buf, sizeof(buf));
     40    if (r) {
     41      MOZ_MTLOG(ML_ERROR, "Error formatting address string.");
     42      return false;
     43    }
     44    addr_ = buf;
     45 
     46    is_vpn_ = (local_addr.iface.type & NR_INTERFACE_TYPE_VPN) != 0 ? 1 : 0;
     47    estimated_speed_ = local_addr.iface.estimated_speed;
     48    type_preference_ = GetNetworkTypePreference(local_addr.iface.type);
     49    ip_version_ = local_addr.addr.ip_version;
     50    return true;
     51  }
     52 
     53  bool operator<(const LocalAddress& rhs) const {
     54    // Interface that is "less" here is preferred.
     55    // If type preferences are different, we should simply sort by
     56    // |type_preference_|.
     57    if (type_preference_ != rhs.type_preference_) {
     58      return type_preference_ < rhs.type_preference_;
     59    }
     60 
     61    // If type preferences are the same, the next thing we use to sort is vpn.
     62    // If two LocalAddress are different in |is_vpn_|, the LocalAddress that is
     63    // not in vpn gets priority.
     64    if (is_vpn_ != rhs.is_vpn_) {
     65      return is_vpn_ < rhs.is_vpn_;
     66    }
     67 
     68    // Compare estimated speed.
     69    if (estimated_speed_ != rhs.estimated_speed_) {
     70      return estimated_speed_ > rhs.estimated_speed_;
     71    }
     72 
     73    // See if our hard-coded pref list helps us.
     74    auto thisindex = std::find(interface_preference_list().begin(),
     75                               interface_preference_list().end(), ifname_);
     76    auto rhsindex = std::find(interface_preference_list().begin(),
     77                              interface_preference_list().end(), rhs.ifname_);
     78    if (thisindex != rhsindex) {
     79      return thisindex < rhsindex;
     80    }
     81 
     82    // Prefer IPV6 over IPV4
     83    if (ip_version_ != rhs.ip_version_) {
     84      return ip_version_ > rhs.ip_version_;
     85    }
     86 
     87    // Now we start getting into arbitrary stuff
     88    if (ifname_ != rhs.ifname_) {
     89      return ifname_ < rhs.ifname_;
     90    }
     91 
     92    return addr_ < rhs.addr_;
     93  }
     94 
     95  const std::string& GetKey() const { return key_; }
     96 
     97 private:
     98  // Getting the preference corresponding to a type. Getting lower number here
     99  // means the type of network is preferred.
    100  static inline int GetNetworkTypePreference(int type) {
    101    if (type & NR_INTERFACE_TYPE_WIRED) {
    102      return 1;
    103    }
    104    if (type & NR_INTERFACE_TYPE_WIFI) {
    105      return 2;
    106    }
    107    if (type & NR_INTERFACE_TYPE_MOBILE) {
    108      return 3;
    109    }
    110    if (type & NR_INTERFACE_TYPE_TEREDO) {
    111      // Teredo gets penalty because it's IP relayed
    112      return 5;
    113    }
    114    return 4;
    115  }
    116 
    117  // TODO(bug 895790): Once we can get useful interface properties on Darwin,
    118  // we should remove this stuff.
    119  static const std::vector<std::string>& interface_preference_list() {
    120    static std::vector<std::string> list(build_interface_preference_list());
    121    return list;
    122  }
    123 
    124  static std::vector<std::string> build_interface_preference_list() {
    125    std::vector<std::string> result;
    126    result.push_back("rl0");
    127    result.push_back("wi0");
    128    result.push_back("en0");
    129    result.push_back("enp2s0");
    130    result.push_back("enp3s0");
    131    result.push_back("en1");
    132    result.push_back("en2");
    133    result.push_back("en3");
    134    result.push_back("eth0");
    135    result.push_back("eth1");
    136    result.push_back("eth2");
    137    result.push_back("em1");
    138    result.push_back("em0");
    139    result.push_back("ppp");
    140    result.push_back("ppp0");
    141    result.push_back("vmnet1");
    142    result.push_back("vmnet0");
    143    result.push_back("vmnet3");
    144    result.push_back("vmnet4");
    145    result.push_back("vmnet5");
    146    result.push_back("vmnet6");
    147    result.push_back("vmnet7");
    148    result.push_back("vmnet8");
    149    result.push_back("virbr0");
    150    result.push_back("wlan0");
    151    result.push_back("lo0");
    152    return result;
    153  }
    154 
    155  std::string ifname_;
    156  std::string addr_;
    157  std::string key_;
    158  int is_vpn_;
    159  int estimated_speed_;
    160  int type_preference_;
    161  int ip_version_;
    162 };
    163 
    164 class InterfacePrioritizer {
    165 public:
    166  InterfacePrioritizer() : sorted_(false) {}
    167 
    168  int add(const nr_local_addr* iface) {
    169    LocalAddress addr;
    170    if (!addr.Init(*iface)) {
    171      return R_FAILED;
    172    }
    173    std::pair<std::set<LocalAddress>::iterator, bool> r =
    174        local_addrs_.insert(addr);
    175    if (!r.second) {
    176      return R_ALREADY;  // This address is already in the set.
    177    }
    178    sorted_ = false;
    179    return 0;
    180  }
    181 
    182  int sort() {
    183    UCHAR tmp_pref = 127;
    184    preference_map_.clear();
    185    for (const auto& local_addr : local_addrs_) {
    186      if (tmp_pref == 0) {
    187        return R_FAILED;
    188      }
    189      preference_map_.insert(make_pair(local_addr.GetKey(), tmp_pref--));
    190    }
    191    sorted_ = true;
    192    return 0;
    193  }
    194 
    195  int getPreference(const char* key, UCHAR* pref) {
    196    if (!sorted_) {
    197      return R_FAILED;
    198    }
    199    std::map<std::string, UCHAR>::iterator i = preference_map_.find(key);
    200    if (i == preference_map_.end()) {
    201      return R_NOT_FOUND;
    202    }
    203    *pref = i->second;
    204    return 0;
    205  }
    206 
    207 private:
    208  std::set<LocalAddress> local_addrs_;
    209  std::map<std::string, UCHAR> preference_map_;
    210  bool sorted_;
    211 };
    212 
    213 }  // anonymous namespace
    214 
    215 static int add_interface(void* obj, nr_local_addr* iface) {
    216  InterfacePrioritizer* ip = static_cast<InterfacePrioritizer*>(obj);
    217  return ip->add(iface);
    218 }
    219 
    220 static int get_priority(void* obj, const char* key, UCHAR* pref) {
    221  InterfacePrioritizer* ip = static_cast<InterfacePrioritizer*>(obj);
    222  return ip->getPreference(key, pref);
    223 }
    224 
    225 static int sort_preference(void* obj) {
    226  InterfacePrioritizer* ip = static_cast<InterfacePrioritizer*>(obj);
    227  return ip->sort();
    228 }
    229 
    230 static int destroy(void** objp) {
    231  if (!objp || !*objp) {
    232    return 0;
    233  }
    234 
    235  InterfacePrioritizer* ip = static_cast<InterfacePrioritizer*>(*objp);
    236  *objp = nullptr;
    237  delete ip;
    238 
    239  return 0;
    240 }
    241 
    242 static nr_interface_prioritizer_vtbl priorizer_vtbl = {
    243    add_interface, get_priority, sort_preference, destroy};
    244 
    245 namespace mozilla {
    246 
    247 nr_interface_prioritizer* CreateInterfacePrioritizer() {
    248  nr_interface_prioritizer* ip;
    249  int r = nr_interface_prioritizer_create_int(new InterfacePrioritizer(),
    250                                              &priorizer_vtbl, &ip);
    251  if (r != 0) {
    252    return nullptr;
    253  }
    254  return ip;
    255 }
    256 
    257 }  // namespace mozilla