def GetNetworkName(): """Return network name (SSID for WLANs) a device is connected to. Returns: name of the matching network name if possible, None otherwise. """ this_platform = _GetPlatform() if this_platform == LINUX: cmdline = '/usr/bin/nmcli -t -f NAME,DEVICES conn status' # Ignore "Auto " prefix on automatically connecting networks. ssid_re = re.compile(r'^(Auto )?([^:]*):.*$') try: return_code, out, _ = flight_common.Exec(cmdline) except OSError: logging.exception('Error executing nmcli') return if out and not return_code: for l in out.splitlines(): res = ssid_re.match(l) if res: return res.groups()[1] elif this_platform == DARWIN: cmdline = ( '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/' 'Current/Resources/airport -I | ' 'awk \'/ SSID/ {print substr($0, index($0, $2))}\'') try: return_code, out, _ = flight_common.Exec(cmdline) except OSError: logging.exception('Error executing airport') return if out and not return_code: return out.strip() or None
def GetAllInterfaceNames(): """Get network interfaces info for this host. Note that this list may include all types of interfaces that are not normally interesting to this script, e.g. fw0. Returns: list, e.g. ['en0', 'en1', 'fw0', 'eth0'] """ this_platform = _GetPlatform() # Note slight difference in regex. # BSD ifconfig writes "interface_name:\s+" # while Linux writes "interface_name\s+" if this_platform == LINUX: intf_header = re.compile(r'^([a-z]+(?:[0-9]+)?)\s+') elif this_platform == DARWIN: intf_header = re.compile(r'^([a-z]+(?:[0-9]+)?):\s+') return_code, stdout, stderr = flight_common.Exec('/sbin/ifconfig') if return_code != 0 or stderr: return [] interfaces = [] if stdout: for l in stdout.splitlines(): # pylint: disable=maybe-no-member m = intf_header.search(str(l)) if m: interfaces.append(m.group(1)) return interfaces
def IsOnWwan(): """"Checks WWAN device connection status. Note: this may produce false-positives, and may not catch all WWAN devices. Several Sprint and Verizon devices were tested, all of which create ppp0 upon connection. However, L2TP VPN also creates ppp0 (Google no longer uses this as of Q2-2010 in favor of SSLVPN). A stronger check is probably needed at some point. As of 2011-12-6 OpenVPN interface is tun0 on Linux and Darwin. Returns: Boolean. True if WWAN device is active, False otherwise. """ wwan_ifaces = GetInterfaceNames(INTERFACE_WWAN) for wwan_iface in wwan_ifaces: try: return_code, unused_out, unused_err = flight_common.Exec( [IFCONFIG, wwan_iface]) except OSError: return_code = None # ifconfig exits with 1 if interface doesn't exist. if return_code == 0: return True return False
def GetNetworkName(dev): """Return network name (SSID for WLANs) seen by nmcli. If dev is set: Find network name (SSID) associated with device dev. Otherwise return first connected network name. Args: dev: network device name as seen by NetworkManager. Returns: name of the matching network name if possible, None otherwise. """ cmdline = '/usr/bin/nmcli -t -f NAME,DEVICES conn status' # Ignore "Auto " prefix on automatically connecting networks. ssid_re = re.compile(r'^(Auto )?([^:]*):(.*)$') try: return_code, out, _ = flight_common.Exec(cmdline) except OSError: return_code = -1 if out and not return_code: for l in out.splitlines(): res = ssid_re.match(l) if res: if not dev or res.groups()[2] == dev: return res.groups()[1] return None
def IsOnAndroidWap(): """Checks if connected to Android WAP tether, WiFi or Bluetooth. Returns: Booelan. True if WAP is providing connection, False otherwise. """ iface_regex = re.compile( r'inet\s+192\.168\.(43|44)\.\d{1,3}\s+netmask\s+0xffffff00\s+') # Android tethering uses very specific subnets (192.168.43.0/24 for WiFi and # 192.168.44.0/24 for Bluetooth) as well as dnsmasq. for iface in NETWORK_INTERFACES: try: return_code, stdout, unused_err = flight_common.Exec([IFCONFIG, iface]) except OSError, e: logging.error('Exec(%s) error: %s %s', IFCONFIG, iface, e) return_code = -1 if return_code != 0: # interface was likely not found. continue # 0xffffff00 is a hex representation of /24. android_wap_match = iface_regex.search(stdout) if android_wap_match is not None: default_gateway = '192.168.%s.1' % android_wap_match.group(1) # IP and netmask look like Android WAP, so check dnsmasq. cmd = ['host', '-W', '5', '-c', 'CHAOS', '-t', 'txt', 'VERSION.BIND', default_gateway] try: return_code, stdout, unused_err = flight_common.Exec(cmd) except OSError, e: logging.error('Exec(%s) error: %s', cmd, e) return_code = -1 if return_code != 0: continue dnsmasq_match = re.search( r'VERSION\.BIND descriptive text "dnsmasq-.*"', stdout) if dnsmasq_match is not None: # IP, netmask and dnsmasq all match Android WAP tethering. return True
def main(): optparser = optparse.OptionParser() optparser.add_option('-r', '--reason', dest='reason', default='Unknown', help='Reason for brokenness.') optparser.add_option('-d', '--detail-file', dest='detail_file', help='File with error details.') options, _ = optparser.parse_args() detail_parts = [] if options.detail_file: try: detail_parts.append('Failure detail:\n%s' % open(options.detail_file, 'r').read()) except IOError as e: detail_parts.append('Could not read detail file %r:\n%s' % (options.detail_file, e)) return_code, stdout, stderr = flight_common.Exec(['facter', '-p'], timeout=60, waitfor=0.5) facter_parts = [ 'Facter Return Code: %s' % return_code, 'Facter StdOut:\n%s' % stdout, ] if stderr: facter_parts.append('Facter StdErr:\n%s' % stderr) detail_parts.append('\n\n'.join(facter_parts)) details = ('\n\n' + ('*' * 60) + '\n\n').join( [part.strip() for part in detail_parts]) params = {'details': details, 'reason': options.reason} url = flight_common.GetServerURL() c = client.SimianAuthClient( flight_common.GetClientIdentifier('auto')['uuid'], hostname=url) c.GetAuthToken() c.PostReport('broken_client', params) print 'Reported broken client to server.'
def IsOnWwan(): """"Checks WWAN device connection status. Note: this may produce false-positives, and may not catch all WWAN devices. Several Sprint and Verizon devices were tested, all of which create ppp0 upon connection. However, L2TP VPN also creates ppp0 (Google no longer uses this as of Q2-2010 in favor of SSLVPN). A stronger check is probably needed at some point. Returns: Boolean. True if WWAN device is active, False otherwise. """ wwan_iface = 'ppp0' try: return_code, unused_out, unused_err = flight_common.Exec( [IFCONFIG, wwan_iface]) except OSError, e: logging.error('Exec(%s) error: %s', IFCONFIG, e) return_code = -1
def GetNetworkGateway(network): """Get the gateway for a network. Uses "netstat -nr" on Darwin and "ip route" on Linux to read the routing table. It searches for a route with destination exactly matching the network parameter! Args: network: str, likely in CIDR format or default gateway, e.g. "1.2.3/24" or "0.0.0.0" Returns: a string like "1.2.3.4" or "link#1" or "01:02:03:04:05:06" or "dev wlan0", depending on the type of route and platform. """ route = ROUTE.get(_GetPlatform(), None) logging.debug('Route: %s', str(route)) if not route: return try: return_code, stdout, stderr = flight_common.Exec(route) except OSError: return_code = None if return_code != 0 or stderr or not stdout: return gateway_pattern = (r'^%s\s+(via[\s\t])?' r'([\d\.]+|[0-9a-f:]+|link#\d+|dev [a-z\d]+)[\s\t]+' % network) gateway = re.search(gateway_pattern, str(stdout), re.MULTILINE) if gateway: return gateway.group(2) return
def IsOnAndroidWap(): """Checks if Android WiFi or Bluetooth tethering is connected. Returns: Boolean. True if Android tethering is connected, False otherwise. """ # ifconfig output looks a little bit different on Darwin vs Linux. # # Darwin: # inet 169.254.135.20 netmask 0xffff0000 broadcast 169.254.255.255 # Linux: # inet addr:172.26.113.45 Bcast:172.26.115.255 Mask:255.255.252.0 android_wap_match_regex = re.compile( r'inet[\w\s]*[\s:]+192\.168\.(42|43|44)\.\d{1,3}\s+' r'.*(?:netmask\s+0xffffff00\s+|Mask:255\.255\.255\.0)') ifaces = GetInterfaceNames(INTERFACE_ANDROID_WAP) for wifi_iface in ifaces: # Android tethering uses very specific subnets*, as well as dnsmasq which # reveals itself via the TXT VERSION.BIND record. # * 192.168.42.0/24 for wired, 192.168.43.0/24 for WiFi, and # 192.168.44.0/24 for Bluetooth. try: return_code, stdout, stderr = flight_common.Exec( [IFCONFIG, wifi_iface]) except OSError: return_code = None if return_code != 0 or stderr: # interface was likely not found. continue android_wap_match = android_wap_match_regex.search(stdout) # Look for an interface on 192.168.4[2-4].0/24. if android_wap_match is not None: # If the default gateway is not through a likely Android WAN interface, # tethering may be active but is not likely to be used. default_gateway = GetDefaultGateway() logging.debug('Default gateway: %s', str(default_gateway)) default_gateway_prefix = '192.168.%s.' % android_wap_match.group(1) if not default_gateway.startswith(default_gateway_prefix): return False # IP, netmask, gateway look like Android WAP, so check dnsmasq. # Request needs to be explicitly top level, as Linux uses # ndots:2 which would turn VERSION.BIND (without trailing dot) into # VERSION.BIND.foo.example.com in some cases. cmd = [ HOST, '-W', '5', '-c', 'CHAOS', '-t', 'txt', 'VERSION.BIND.', default_gateway ] try: return_code, stdout, unused_err = flight_common.Exec(cmd) except OSError: return_code = None if return_code != 0: continue dnsmasq_match = re.search( r'VERSION\.BIND descriptive text "dnsmasq-.*"', stdout) if dnsmasq_match is not None: # IP, netmask and dnsmasq all match Android WAP tethering. return True return False