def _enableStaticProvisioning_GXP1450(self, vars): try: # Login into interface opener = urllib2.build_opener(urllib2.HTTPCookieProcessor()) response = opener.open( 'http://' + self._ip + '/cgi-bin/dologin', urllib.urlencode({ 'Login': '******', 'P2': self._http_password, 'gnkey': '0b82' })) body = response.read() if 'dologin' in body: logging.error('Endpoint %s@%s GXP1450 - dologin failed login' % (self._vendorname, self._ip)) return False response = opener.open('http://' + self._ip + '/cgi-bin/update', urllib.urlencode(vars) + '&gnkey=0b82') body = response.read() if 'dologin' in body: logging.error( 'Endpoint %s@%s GXP1450 - dologin failed to keep session' % (self._vendorname, self._ip)) return False return True except socket.error, e: logging.error('Endpoint %s@%s GXP1450 failed to connect - %s' % (self._vendorname, self._ip, str(e))) return False
def register(client, fetch): # Agree Page agree_page = fetch("/ucp.php?mode=register", step="Agree Page") form_token = agree_page.find("input", {"name": "form_token"}) if form_token is not None: form_token = form_token['value'] else: return form_data = {'form_token': form_token, 'agreed': 'I agree to these terms'} params = urllib.urlencode(form_data) # Register Page register_page = fetch("/ucp.php?mode=register", params, step="Register Page") form_token = register_page.find("input", {"name": "form_token"}) if form_token is not None: form_token = form_token.get('value', "") else: return creation_time = register_page.find("input", {"name": "creation_time"}).get('value', "") form_data = {'username': client.name, 'email': client.email, 'new_password': client.password, 'password_confirm': client.password, 'lang': 'en', 'tz': 'America/Creston', 'tz_date': 'GMT-07:00 - 24 Apr 2013, 20:29', 'tz_copy': 'UTC', 'form_token': form_token, 'creation_time': creation_time, 'agreed': 'true', 'change_lang': '0', 'submit': 'Submit'} params = urllib.urlencode(form_data) # Save Registration fetch("/ucp.php?mode=register", params, step="Save User")
def _enableStaticProvisioning_GXP140x(self, vars): try: # Login into interface and get SID. Check proper Content-Type cookiejar = cookielib.CookieJar( cookielib.DefaultCookiePolicy(rfc2965=True)) opener = urllib2.build_opener( urllib2.HTTPCookieProcessor(cookiejar)) # response = urllib2.urlopen('http://' + self._ip + '/cgi-bin/dologin', response = opener.open( 'http://' + self._ip + '/cgi-bin/dologin', urllib.urlencode({'password': self._http_password})) body = response.read() content_type = response.info()['Content-Type'].rsplit(';', 1)[0] if content_type <> 'application/json': logging.error( 'Endpoint %s@%s GXP140x - dologin answered not application/json but %s' % (self._vendorname, self._ip, response.info()['Content-Type'])) return False # Check successful login and get sid jsonvars = cjson.decode(body) if not ('body' in jsonvars and 'sid' in jsonvars['body']): logging.error('Endpoint %s@%s GXP140x - dologin failed login' % (self._vendorname, self._ip)) return False sid = jsonvars['body']['sid'] # Post vars with sid vars.update({'sid': sid}) # response = urllib2.urlopen('http://' + self._ip + '/cgi-bin/api.values.post', response = opener.open( 'http://' + self._ip + '/cgi-bin/api.values.post', urllib.urlencode(vars)) jsonvars = self._parseBotchedJSONResponse(response) if jsonvars == None: logging.error( 'jsonvars vacio %s@%s GXP140x - vars rejected by interface - %s - %s - %s' % (self._vendorname, self._ip, urllib.urlencode(vars), jsonvars['body'], sid)) return False if not ('response' in jsonvars and jsonvars['response'] == 'success' \ and 'body' in jsonvars and 'status' in jsonvars['body'] and jsonvars['body']['status'] == 'right' ): logging.error( 'Endpoint %s@%s GXP140x - vars rejected by interface - %s - %s - %s' % (self._vendorname, self._ip, urllib.urlencode(vars), jsonvars['body'], sid)) return False return True except cjson.DecodeError, e: logging.error('Endpoint %s@%s GXP140x received invalid JSON - %s' % (self._vendorname, self._ip, str(e))) return False
def _send_email(self, check): check_name = check['check'] hostname = check['hostname'] if check['status'] is True: status = 'UP' else: status = 'DOWN' subject = "[stalker] %s on %s is %s" % (check_name, hostname, status) data = { "from": "Stalker <%s>" % self.from_addr, "to": self.recipients, "subject": subject, "text": "%s" % check } headers = { 'Authorization': 'Basic %s' % self.basic_auth_creds, 'Content-Type': 'application/x-www-form-urlencoded' } try: post_data = urllib.urlencode(data) req = urllib2.Request(self.url, post_data, headers) response = urllib2.urlopen(req) result = response.read() response.close() self.logger.info('Mailgun: %s' % result) return True except Exception: self.logger.exception('Mailgun notification error.') return False
def _send_email(self, check): check_name = check['check'] hostname = check['hostname'] if check['status'] is True: status = 'UP' else: status = 'DOWN' subject = "[stalker] %s on %s is %s" % (check_name, hostname, status) data = {"from": "Stalker <%s>" % self.from_addr, "to": self.recipients, "subject": subject, "text": "%s" % check} headers = { 'Authorization': 'Basic %s' % self.basic_auth_creds, 'Content-Type': 'application/x-www-form-urlencoded' } try: post_data = urllib.urlencode(data) req = urllib2.Request(self.url, post_data, headers) response = urllib2.urlopen(req) result = response.read() response.close() self.logger.info('Mailgun: %s' % result) return True except Exception: self.logger.exception('Mailgun notification error.') return False
def _getAuthOpener_LXP150(self, http_user, http_pass): ''' Create an authenticated opener for the LXPx50 series. The LXPx50 HTTP authentication is again weird. First, a request must be sent to the phone with a Cookie with a SessionId set to a random number between 0 and 99999. Sending 0 works just as well. The first request must be a GET that asks the phone to calculate a hash for a specified username and password. The hash is embedded inside a HTML fragment in the response. Next the hash must be sent as a new Cookie in a POST request that also includes the original SessionId number and the UserName as cookies. A successful login returns a response with the phone status, including the phone model. Additionally, the response after a successful login includes a brand new SessionId that must be replaced in the opener cookie. ''' cookiejar = cookielib.CookieJar(cookielib.DefaultCookiePolicy(rfc2965=True)) sesscookie = cookielib.Cookie(None, 'SessionId', '0', None, False, self._ip, False, False, '/', False, False, str((int)(time.time() + 3600)), False, 'SessionId', None, None) cookiejar.set_cookie(sesscookie) opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar)) response = opener.open('http://' + self._ip + '/fcgi/do?' + urllib.urlencode({ 'action': 'Encrypt', 'UserName' : http_user, 'Password' : http_pass})) body = response.read() m = re.search(r"id=hcSingleResult type=hidden value='(.+?)'", body) if m is None: return (None, None) encrypted_password = m.group(1) sesscookie = cookielib.Cookie(None, 'UserName', http_user, None, False, self._ip, False, False, '/', False, False, str((int)(time.time() + 3600)), False, 'UserName', None, None) cookiejar.set_cookie(sesscookie) sesscookie = cookielib.Cookie(None, 'Password', encrypted_password, None, False, self._ip, False, False, '/', False, False, str((int)(time.time() + 3600)), False, 'Password', None, None) cookiejar.set_cookie(sesscookie) response = opener.open('http://' + self._ip + '/fcgi/do?id=1', 'SubmitData=begin%26Operation%3DCreateSession%26DestURL%3Did%6021%26SubmitData%3Dend') # Find new SessionId value. What, no Set-Cookie header? body = response.read() m = re.search(r"id=hcSessionIdNow type=hidden value='(.+?)'", body) if m != None: sesscookie = cookielib.Cookie(None, 'SessionId', m.group(1), None, False, self._ip, False, False, '/', False, False, str((int)(time.time() + 3600)), False, 'SessionId', None, None) cookiejar.set_cookie(sesscookie) else: logging.error('Endpoint %s@%s LXPx50 failed to authenticate - new session ID not found in response' % (self._vendorname, self._ip)) return (None, None) # Subsequent requests must NOT have the UserName/Password cookies cookiejar.clear(self._ip, '/', 'UserName') cookiejar.clear(self._ip, '/', 'Password') return (opener, body)
def _build_url(self, method, **args): """Call the Eventful API's METHOD with ARGS.""" # Build up the request args['app_key'] = self.app_key if hasattr(self, 'user_key'): args['user'] = self.user args['user_key'] = self.user_key args = urllib.urlencode(args) return "http://%s/json/%s?%s" % (self.server, method, args)
def _enableStaticProvisioning_GXP140x(self, vars): try: # Login into interface and get SID. Check proper Content-Type response = urllib2.urlopen( 'http://' + self._ip + '/cgi-bin/dologin', urllib.urlencode({'password': self._http_password})) body = response.read() if response.info()['Content-Type'] <> 'application/json': logging.error( 'Endpoint %s@%s GXP140x - dologin answered not application/json but %s' % (self._vendorname, self._ip, response.info()['Content-Type'])) return False # Check successful login and get sid jsonvars = cjson.decode(body) if not ('body' in jsonvars and 'sid' in jsonvars['body']): logging.error('Endpoint %s@%s GXP140x - dologin failed login' % (self._vendorname, self._ip)) return False sid = jsonvars['body']['sid'] # Post vars with sid vars.update({'sid': sid}) response = urllib2.urlopen( 'http://' + self._ip + '/cgi-bin/api.values.post', urllib.urlencode(vars)) jsonvars = self._parseBotchedJSONResponse(response) if jsonvars == None: return False if not ('response' in jsonvars and jsonvars['response'] == 'success' \ and 'body' in jsonvars and 'status' in jsonvars['body'] and jsonvars['body']['status'] == 'right' ): logging.error( 'Endpoint %s@%s GXP140x - vars rejected by interface - %s' % (self._vendorname, self._ip, body)) return False return True except cjson.DecodeError, e: logging.error('Endpoint %s@%s GXP140x received invalid JSON - %s' % (self._vendorname, self._ip, str(e))) return False
def _enableStaticProvisioning_BT200(self, vars): try: # Login into interface cookiejar = cookielib.CookieJar( cookielib.DefaultCookiePolicy(rfc2965=True)) opener = urllib2.build_opener( urllib2.HTTPCookieProcessor(cookiejar)) response = opener.open( 'http://' + self._ip + '/dologin.htm', urllib.urlencode({ 'Login': '******', 'P2': self._http_password, 'gnkey': '0b82' })) body = response.read() if 'dologin.htm' in body: logging.error('Endpoint %s@%s BT200 - dologin failed login' % (self._vendorname, self._ip)) return False # Force cookie version to 0 for cookie in cookiejar: cookie.version = 0 response = opener.open('http://' + self._ip + '/update.htm', urllib.urlencode(vars) + '&gnkey=0b82') body = response.read() if 'dologin.htm' in body: logging.error( 'Endpoint %s@%s BT200 - dologin failed to keep session' % (self._vendorname, self._ip)) return False return True except urllib2.HTTPError, e: logging.error( 'Endpoint %s@%s BT200 failed to send vars to interface - %s' % (self._vendorname, self._ip, str(e))) return False
def _setNetworkConfig_V1(self): try: if self._dhcp: postvars = { 'dhcp': 'on', 'Settings': 'Save', 'ignore_dhcp_findings': '', } else: postvars = { 'dhcp': 'off', 'ip_adr': self._static_ip, 'netmask': self._static_mask, 'gateway': self._static_gw, 'dns_server1': self._static_dns1, 'dns_server2': self._static_dns2, 'Settings': 'Save', 'ignore_dhcp_findings': 'dns_server1 dns_server2 gateway ip_adr netmask', } response = urllib2.urlopen( 'http://' + self._ip + '/advanced_network.htm', urllib.urlencode(postvars)) htmlbody = response.read() if 'CONFIRM_REBOOT' in htmlbody: response = urllib2.urlopen( 'http://' + self._ip + '/advanced_network.htm', 'CONFIRM_REBOOT=Reboot') htmlbody = response.read() response = urllib2.urlopen( 'http://' + self._ip + '/confirm.htm', 'REBOOT=Yes') htmlbody = response.read() logging.info('Endpoint %s@%s set network config - rebooting' % (self._vendorname, self._ip)) return (True, True) else: logging.info( 'Endpoint %s@%s set network config - not yet rebooting' % (self._vendorname, self._ip)) return (True, False) except urllib2.URLError, e: logging.error('Endpoint %s@%s failed to connect - %s' % (self._vendorname, self._ip, str(e))) return (False, False)
def _setupAtcomAuthentication(self): http = httplib.HTTPConnection(self._ip) noncesources = ('/', '/right.htm') for noncesource in noncesources: http.request('GET', noncesource, None, {'Connection' : 'keep-alive'}) resp = http.getresponse() htmlbody = resp.read() if not resp.status in (200, 404): logging.error('Endpoint %s@%s failed to fetch nonce for HTTP configuration - got response code %s' % (self._vendorname, self._ip, resp.status)) http.close() return (None, None) elif resp.status == 200: m = re.search(r'<input type="hidden" name="nonce" value="([0-9a-zA-Z]+)">', htmlbody) if m != None: break if m == None: logging.error('Endpoint %s@%s failed to locate nonce in HTTP response' % (self._vendorname, self._ip)) http.close() return (None, None) nonce = m.group(1) # Identify firmware if noncesource == '/right.htm': self._firmware = 1 # Old firmware # Simulate POST to allow fetching rest of content extraheaders = { 'Connection' : 'keep-alive', 'Cookie' : 'auth=' + nonce, 'Content-Type' : 'application/x-www-form-urlencoded' } postvars = { 'encoded' : self._http_username + ':' + md5.new(':'.join((self._http_username, self._http_password, nonce))).hexdigest(), 'nonce' : nonce, 'goto' : 'Logon', 'URL' : '/' } postdata = urllib.urlencode(postvars) http.request('POST', noncesource, postdata, extraheaders) resp = http.getresponse() if resp.status != 200: logging.error('Endpoint %s@%s failed to fetch login result - got response code %s' % (self._vendorname, self._ip, resp.status)) http.close() return (None, None) htmlbody = resp.read() return (http, nonce)
def _loginHttp_V2(self): try: # Do HTTP login and save session cookie postvars = { 'username': self._http_username, 'password': self._http_password, 'link': 'index.htm', 'submit': 'Login' } response = urllib2.urlopen('http://' + self._ip + '/index.htm', urllib.urlencode(postvars)) htmlbody = response.read() if not 'Set-Cookie' in response.headers: logging.error('Endpoint %s@%s invalid username or password' % (self._vendorname, self._ip)) return False self._cookie_v2 = response.headers['Set-Cookie'] # If the phone is used for the first time, it will show an EULA that # must be accepted in order to continue. m = re.search(r'<input type="radio" name="eula" value="(.+?)">', htmlbody) if m != None: logging.warning('Endpoint %s@%s accepting EULA...' % (self._vendorname, self._ip)) postvars = {'eula': m.group(1), 'save': 'Submit'} response = urllib2.urlopen( urllib2.Request('http://' + self._ip + '/index.htm', urllib.urlencode(postvars), {'Cookie': self._cookie_v2})) htmlbody = response.read() return True except urllib2.URLError, e: logging.error('Endpoint %s@%s failed to connect - %s' % (self._vendorname, self._ip, str(e))) return False
def _setProvisionServer_V1(self): try: postvars = { 'setting_server': 'tftp://' + self._serverip, 'Settings': 'Save' } response = urllib2.urlopen( 'http://' + self._ip + '/advanced_update.htm', urllib.urlencode(postvars)) htmlbody = response.read() return True except urllib2.URLError, e: logging.error('Endpoint %s@%s failed to connect - %s' % (self._vendorname, self._ip, str(e))) return False
def _rebootbyhttp_V2(self): try: response = urllib2.urlopen( urllib2.Request('http://' + self._ip + '/update.htm', urllib.urlencode({'reboot': 'Reboot'}), {'Cookie': self._cookie_v2})) htmlbody = response.read() if response.code == 200: return True else: logging.error( 'Endpoint %s@%s failed to reboot phone - got error code %d' % (self._vendorname, self._ip, response.code)) except urllib2.URLError, e: logging.error('Endpoint %s@%s failed to connect - %s' % (self._vendorname, self._ip, str(e))) return False
def _encodeGrandstreamConfig(self, vars): # Encode configuration variables. The gnkey must be the last item in # order to prevent other variables from being followed by a null byte. payload = urllib.urlencode(vars) + '&gnkey=0b82' if (len(payload) & 1) != 0: payload = payload + '\x00' # Calculate block length in words, plus checksum length = 8 + len(payload) / 2 binmac = self._mac.replace(':', '').lower().decode('hex') bindata = struct.pack('>LH6s', length, 0, binmac) + '\x0d\x0a\x0d\x0a' + payload wordsize = len(bindata) / 2 checksum = 0x10000 - ( sum(struct.unpack('>' + str(wordsize) + 'H', bindata)) & 0xFFFF) bindata = struct.pack('>LH6s', length, checksum, binmac) + '\x0d\x0a\x0d\x0a' + payload return bindata
def _doAuthPost(self, urlpath, postvars): '''Perform an HTTP POST on a particular URL using the HTTP credentials This method is frequently used to make the phone use the Elastix server as the TFTP source for autoprovisioning. ''' password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm() password_manager.add_password(None, 'http://' + self._ip + '/', self._http_username, self._http_password) basic_auth_handler = urllib2.HTTPBasicAuthHandler(password_manager) digest_auth_handler = urllib2.HTTPDigestAuthHandler(password_manager) opener = urllib2.build_opener(basic_auth_handler, digest_auth_handler) if postvars != None: opener.addheaders = [('Content-Type', 'application/x-www-form-urlencoded')] if not isinstance(postvars, str): postvars = urllib.urlencode(postvars) try: opener.open('http://' + self._ip + urlpath, postvars) except urllib2.HTTPError, e: logging.error('Endpoint %s@%s failed to authenticate - %s' % (self._vendorname, self._ip, str(e))) return False
def _setupAtcomAuthentication(self): http = httplib.HTTPConnection(self._ip) nonce, noncesource = self._getNonce(http) if nonce == None: http.close() return (None, None) # Simulate POST to allow fetching rest of content extraheaders = { 'Connection': 'keep-alive', 'Cookie': 'auth=' + nonce, 'Content-Type': 'application/x-www-form-urlencoded' } postvars = { 'encoded': self._http_username + ':' + md5.new(':'.join( (self._http_username, self._http_password, nonce))).hexdigest(), 'nonce': nonce, 'goto': 'Logon', 'URL': '/' } postdata = urllib.urlencode(postvars) http.request('POST', noncesource, postdata, extraheaders) resp = http.getresponse() if resp.status != 200: logging.error( 'Endpoint %s@%s failed to fetch login result - got response code %s' % (self._vendorname, self._ip, resp.status)) http.close() return (None, None) htmlbody = resp.read() return (http, nonce)
def _sendPhoneConfiguration(self, xmlcontent): try: # Login into interface opener = urllib2.build_opener(urllib2.HTTPCookieProcessor()) response = opener.open( 'http://' + self._ip + '/console/j_security_check', urllib.urlencode({ 'submit': 'Login', 'j_username': self._http_username, 'j_password': self._http_password })) body = response.read() if not '/console/start' in body: logging.error( 'Endpoint %s@%s - j_security_check failed login' % (self._vendorname, self._ip)) return False # Build a custom request with form data boundary = '------------------ENDPOINTCONFIG' postdata = '--' + boundary + '\r\n' +\ 'Content-Disposition: form-data; name="COMMAND"\r\n' +\ '\r\n' +\ 'RX' + '\r\n' +\ '--' + boundary + '\r\n' +\ 'Content-Disposition: form-data; name="RX"; filename="config.xml"\r\n' +\ 'Content-Type: text/xml\r\n' +\ '\r\n' +\ xmlcontent + '\r\n' +\ '--' + boundary + '--\r\n' filerequest = urllib2.Request( 'http://' + self._ip + '/console/configuration', postdata, {'Content-Type': 'multipart/form-data; boundary=' + boundary}) # The phone configuration restore is known to hang for 25-30 seconds oldtimeout = socket.getdefaulttimeout() socket.setdefaulttimeout(40) try: response = opener.open(filerequest) finally: socket.setdefaulttimeout(oldtimeout) body = response.read() if not 'Configuration restore complete' in body: logging.error('Endpoint %s@%s - configuration post failed' % (self._vendorname, self._ip)) return False # Attempt to set just the provisioning server response = opener.open( 'http://' + self._ip + '/console/general', urllib.urlencode({ 'COMMAND': 'AP', '@p.provisioningServer': self._serverip, '@dhcp_option_protocol': 'TFTP' })) body = response.read() # Since the web interface will NOT immediately apply the network # changes, we need to go raw and ssh into the phone. Additionally, # if we are changing the network setting from DHCP to static or # viceversa, we expect the SSH connection to be disconnected in the # middle of the update. A timeout of 5 seconds should do it. if self._dhcp: command = '/root/dhcp-configure.sh' else: dns2 = 'none' if self._static_dns2 != None: dns2 = self._static_dns2 command = '/root/staticip-configure.sh %s %s %s %s %s' %\ (self._static_ip, self._static_mask, self._static_gw, self._static_dns1, dns2) ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.WarningPolicy()) ssh.connect(self._ip, username=self._ssh_username, password=self._ssh_password, timeout=5) stdin, stdout, stderr = ssh.exec_command(command) logging.info( 'Endpoint %s@%s - about to set timeout of %d on stdout' % ( self._vendorname, self._ip, oldtimeout, )) stdout.channel.settimeout(5) try: s = stdout.read() logging.info('Endpoint %s@%s - answer follows:\n%s' % ( self._vendorname, self._ip, s, )) except socket.error, e: pass ssh.close() return True
def _enableStaticProvisioning_GXV(self, vars): try: # Login into interface opener = urllib2.build_opener(urllib2.HTTPCookieProcessor()) headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36', } opener.addheaders = headers.items() response = opener.open('http://' + self._ip + '/manager?' + urllib.urlencode({ 'action': 'login', 'Username': self._http_username, 'Secret': self._http_password, 'time': (int)(time.time()) })) body = response.read() if 'Error' in body: logging.error('Endpoint %s@%s GXV - dologin failed login' % (self._vendorname, self._ip)) return False # For this interface, the variables are translated as follows: The # source key of the form Pxxxx produces a variable var-dddd where # dddd is a counter. The corresponding value produces a variable # val-dddd with the same counter varcount = 0 submitvars = {'action': 'put', 'time': (int)(time.time())} for pk in vars: varkey = 'var-' + ('%04d' % (varcount, )) varval = 'val-' + ('%04d' % (varcount, )) submitvars[varkey] = pk[1:] submitvars[varval] = vars[pk] varcount += 1 response = opener.open('http://' + self._ip + '/manager?' + urllib.urlencode(submitvars)) body = response.read() if not ('Success' in body): logging.error( 'Endpoint %s@%s GXV - dologin failed to keep session' % (self._vendorname, self._ip)) return False # Phonebook programming is a special case. submitvars = { 'action': 'putdownphbk', 'time': (int)(time.time()), 'url': vars['P331'], 'mode': 2, # HTTP 'clear-old': 1, 'flag': 1, # 1 forces download right now 'interval': vars['P332'], 'rm-redup': 1 } # This generates problems with GXV3240 # logging.info('Endpoint %s@%s GXV failed to send vars to interface - %s' % # (self._vendorname, self._ip, 'http://' + self._ip + '/manager?' + urllib.urlencode(submitvars))) # response = opener.open('http://' + self._ip + '/manager?' + urllib.urlencode(submitvars)) # body = response.read() # if not ('Success' in body): # logging.error('Endpoint %s@%s GXV - could not reprogram phonebook' % # (self._vendorname, self._ip)) return True except httplib.HTTPException as e: logging.info( 'Endpoint %s@%s GXV failed to send vars to interface - %s' % (self._vendorname, self._ip, str(e))) return True except urllib2.HTTPError, e: logging.error( 'Endpoint %s@%s GXV failed to send vars to interface - %s' % (self._vendorname, self._ip, str(e))) return False
def _enableStaticProvisioning_GXV(self, vars): try: # Login into interface opener = urllib2.build_opener(urllib2.HTTPCookieProcessor()) response = opener.open('http://' + self._ip + '/manager?' + urllib.urlencode({ 'action': 'login', 'Username': self._http_username, 'Secret': self._http_password, 'time': (int)(time.time()) })) body = response.read() if 'Error' in body: logging.error('Endpoint %s@%s GXV - dologin failed login' % (self._vendorname, self._ip)) return False # For this interface, the variables are translated as follows: The # source key of the form Pxxxx produces a variable var-dddd where # dddd is a counter. The corresponding value produces a variable # val-dddd with the same counter varcount = 0 submitvars = {'action': 'put', 'time': (int)(time.time())} for pk in vars: varkey = 'var-' + ('%04d' % (varcount, )) varval = 'val-' + ('%04d' % (varcount, )) submitvars[varkey] = pk[1:] submitvars[varval] = vars[pk] varcount += 1 response = opener.open('http://' + self._ip + '/manager?' + urllib.urlencode(submitvars)) body = response.read() if not ('Success' in body): logging.error( 'Endpoint %s@%s GXV - dologin failed to keep session' % (self._vendorname, self._ip)) return False # Phonebook programming is a special case. submitvars = { 'action': 'putdownphbk', 'time': (int)(time.time()), 'url': vars['P331'], 'mode': 2, # HTTP 'clear-old': 1, 'flag': 1, # 1 forces download right now 'interval': vars['P332'], 'rm-redup': 1 } response = opener.open('http://' + self._ip + '/manager?' + urllib.urlencode(submitvars)) body = response.read() if not ('Success' in body): logging.error( 'Endpoint %s@%s GXV - could not reprogram phonebook' % (self._vendorname, self._ip)) return True except urllib2.HTTPError, e: logging.error( 'Endpoint %s@%s GXV failed to send vars to interface - %s' % (self._vendorname, self._ip, str(e))) return False
def _setProvisionServer_V2(self): sConfigFile = 'snom-' + self._model + '-' + (self._mac.replace( ':', '').upper()) + '.xml' try: ''' base_name=snom-at-192.168.254.254-reg-192.168.254.1& asset_id=& dhcp=true& ip_adr=& netmask=& gateway=& dns_server1=& dns_server2=& dns_server3=& dns_server4=& dns_domain=& vlan_id=0& vlan_prio=0& setting_server=192.168.254.2& settings_refresh_timer=86400& sip_port=0& retry_t1=500& tos_rtp=160& tos_sip=160& allow_check_sync=false& stun_server=& stun_interval=5& ethernet_replug=reregister& network=true& save=Save ''' postvars = { 'setting_server': 'tftp://' + self._serverip, 'base_name': 'snom-at-' + self._ip + '-reg-' + self._serverip, 'dhcp': 'true', 'ip_adr': '', 'netmask': '', 'gateway': '', 'dns_server1': '', 'dns_server2': '', 'dns_server3': '', 'dns_server4': '', 'allow_check_sync': 'true', # Needed for sip notify to work 'save': 'Save', 'network': 'true', 'asset_id': '', 'vlan_id': 0, 'vlan_prio': 0, 'settings_refresh_timer': 86400, 'sip_port': 0, 'retry_t1': 500, 'tos_rtp': 160, 'tos_sip': 160, 'stun_server': '', 'stun_interval': 5, 'ethernet_replug': 'reregister', } if not self._dhcp: postvars.update({ 'dhcp': 'false', 'ip_adr': self._static_ip, 'netmask': self._static_mask, 'gateway': self._static_gw, 'dns_server1': self._static_dns1, 'dns_server2': self._static_dns2, }) response = urllib2.urlopen( urllib2.Request('http://' + self._ip + '/network.htm', urllib.urlencode(postvars), {'Cookie': self._cookie_v2})) htmlbody = response.read() if not 'Please reboot the device' in htmlbody: logging.error( 'Endpoint %s@%s failed to save provisioning or network settings' % (self._vendorname, self._ip)) return False return True except urllib2.URLError, e: logging.error('Endpoint %s@%s failed to connect - %s' % (self._vendorname, self._ip, str(e))) return False
def _enableStaticProvisioning(self): # The Aastra firmware is stateful, in an annoying way. Just submitting # a POST to the autoprovisioning URL from the factory-default setting will # only get a 200 OK with a message to visit sysinfo.html, and the settings # will NOT be applied. # To actually apply the settings, it is required to perform a dummy GET # to /sysinfo.html, discard anything returned, and only then # perform the POST. # Additionally, the TCP/IP and HTTP stack of the Aastra 6739i is buggy. # When performing a POST, the firmware wants the end of the headers and # the start of the body in the same TCP/IP packet. If they are on # different packets, the request hangs. Due to the way urllib2 works, # it introduces a flush between the two, which triggers said hang. # Therefore, the full POST request must be assembled and sent manually # as a single write. if not self._doAuthGet('/sysinfo.html'): return False # Set the Elastix server as the provisioning server postvars = { 'protocol': 'TFTP', 'tftp': self._serverip, 'tftppath': '', 'alttftp': self._serverip, 'alttftppath': '', 'usealttftp': '1', 'ftpserv': '', 'ftppath': '', 'ftpuser': '', 'ftppass': '', 'httpserv': '', 'httppath': '', 'httpport': 80, 'httpsserv': '', 'httpspath': '', 'httpsport': 80, 'autoResyncMode': 0, 'autoResyncTime': '00:00', 'maxDelay': 15, 'days': 0, 'postList': self._serverip, } postbody = urllib.urlencode(postvars) urlpath = '/configurationServer.html' postrequest = (\ 'POST %s HTTP/1.1\r\n' +\ 'Host: %s\r\n' +\ 'Connection: close\r\n' +\ 'Accept-Encoding: identity\r\n' +\ 'Authorization: Basic %s\r\n' +\ 'Content-length: %d\r\n' +\ 'Content-type: application/x-www-form-urlencoded\r\n' +\ '\r\n%s') % (urlpath, self._ip, base64.encodestring('%s:%s' % (self._http_username, self._http_password)).strip(), len(postbody), postbody) try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((self._ip, 80)) sock.sendall(postrequest) # Rather than parse the response myself, I create an instance of # HTTPResponse. However, begin() is an internal method, and not # guaranteed to exist in future versions of the library. resp = httplib.HTTPResponse(sock, strict=1, method='POST') resp.begin() htmlbody = resp.read() if resp.status <> 200: logging.error( 'Endpoint %s@%s failed to post configuration - %s' % (self._vendorname, self._ip, r)) return False if not 'Provisioning complete' in htmlbody: logging.error( 'Endpoint %s@%s failed to set configuration server - not provisioned' % (self._vendorname, self._ip)) return False except socket.error, e: logging.error('Endpoint %s@%s failed to connect - %s' % (self._vendorname, self._ip, str(e))) return False
def parse_rest(self,url,data={}): html_json=self.fetch(url,False)[1] next_page=str(int(data['current_page'])+1) self.requests.put((self.parse_rest,self.domain_url+self.search_other_pages%next_page+"&"+urllib.urlencode({'location':self.full_city})+"&"+data['query'],{'current_page':next_page,"query":data['query']})) try: html=json.loads(html_json) xs=HtmlXPathSelector(text=html['results']) for link in xs.select("//div[@class='listing-outer']//a[@class='target-details']/@href").extract(): self.requests.put((self.parse_room,self.domain_url+link,{})) except: #ADD LOGGER self.scrape_finished=True
def _transmit(self, command, data): enc_data = urllib.urlencode(data) self.conn.request('POST', '/web/%s'%command, enc_data, self.headers) resp = self.conn.getresponse() return resp.read()
def updateLocalConfig(self): '''Configuration for INCOM endpoints (local): The following procedure was developed for the ICW-1000 wireless phone. All interaction must be done on unencrypted HTTP protocol on port 8080. The phone interface requires an administrator login on /s_login.htm . The POST is unusual in that it apparently needs the question mark that would normally separate a GET request from its parameters. However, tests show that a GET works just as well for login. The session is IP-based with a timeout. 200 OK for success, 500 for error. The query /xpdb.uds?mode=list&db=config lists the entire catalog of known configuration variables, as a JSON structure. This structure consists of an object with a "section" member and an "entry" member. The "section" member is an array of objects that describe one section each, with a "name" member and a "sid" member. The "sid" value for a given section must be picked for a later POST. The top-level "entry" member is an array of objects that describe one scalar configuration variable each. Each variable has a "sid" number, an "eid" number and a "name" description. The "eid" value for a given variable must be picked for a later POST. To change a set of variables, a POST to /xpdb.uds must be done with the following variables: ?mode=change&db=config&... Each variable to update must set sidN=###&eidN=###&valN=### for each N counting from 0. Additionally, a "cnt" variable must be set at the end with the number of modified variables. If successful, 200 OK and a listing of updated variables. USER ACCOUNT/Displayname USER ACCOUNT/Phone Number USER ACCOUNT/User ID USER ACCOUNT/User Password USER ACCOUNT/URL Scheme SERVER SETTINGS/1st Proxy SERVER SETTINGS/Domain Realm To reboot the phone, it is necessary to POST to /s_reboot.htm while authenticated. ''' # Check that there is at least one account to configure if len(self._accounts) <= 0: logging.error('Endpoint %s@%s has no accounts to configure' % (self._vendorname, self._ip)) return False try: # Login into interface response = urllib2.urlopen('http://' + self._ip + ':8080/s_login.htm', urllib.urlencode({'id' : self._http_username, 'password' : self._http_password})) body = response.read() # The body is JSON but Content-Type is set to text/plain response = urllib2.urlopen('http://' + self._ip + ':8080/xpdb.uds?mode=list&db=config') body = response.read() jsonvars = cjson.decode(body) # Use the JSON map to find out values for sid and eid varmap = { 'USER ACCOUNT': { 'Displayname' : None, 'Phone Number' : None, 'User ID' : None, 'User Password' : None, 'URL Scheme' : None, }, 'SERVER SETTINGS': { '1st Proxy' : None, 'Domain Realm' : None, }, } # The ICW-1000 has up to 12 network configurations, labeled NETWORK1 to # NETWORK12. The one that should be configured is the one that contains # the current IP being used to access the device. for i in range(1,13): k_sid = 'NETWORK' + str(i) varmap[k_sid] = { 'Enable DHCP' : None, 'Address' : None, 'Netmask' : None, 'Gateway' : None, 'DNS1' : None, 'DNS2' : None, } for k_sid in varmap: v_sid = self._sectionFromName(jsonvars, k_sid) if v_sid == None: logging.error('Endpoint %s@%s received invalid JSON - cannot locate sid for %s' % (self._vendorname, self._ip, k_sid)) return False for k_entry in varmap[k_sid]: v_entry = self._entryFromName(jsonvars, v_sid, k_entry) if v_entry == None: logging.error('Endpoint %s@%s received invalid JSON - cannot locate eid for %s' % (self._vendorname, self._ip, k_entry)) return False varmap[k_sid][k_entry] = v_entry current_network = None for i in range(1,13): k_sid = 'NETWORK' + str(i) #logging.info('Endpoint %s@%s - %s Address %s looking for %s' % # (self._vendorname, self._ip, k_sid, varmap[k_sid]['Address'], self._ip)) if varmap[k_sid]['Address']['value'] == self._ip: current_network = k_sid break if current_network == None: logging.warning('Endpoint %s@%s - cannot locate network for %s, cannot update network settings' % (self._vendorname, self._ip, self._ip)) return False vars = self._prepareVarList() postvars = {'mode': 'change', 'db': 'config'} postvars.update(self._createPOSTVar(varmap, 0, 'SERVER SETTINGS', '1st Proxy', vars['server_ip'])) postvars.update(self._createPOSTVar(varmap, 1, 'SERVER SETTINGS', 'Domain Realm', vars['server_ip'])) postvars.update(self._createPOSTVar(varmap, 2, 'USER ACCOUNT', 'Displayname', vars['sip'][0].description)) postvars.update(self._createPOSTVar(varmap, 3, 'USER ACCOUNT', 'Phone Number', vars['sip'][0].extension)) postvars.update(self._createPOSTVar(varmap, 4, 'USER ACCOUNT', 'User ID', vars['sip'][0].account)) postvars.update(self._createPOSTVar(varmap, 5, 'USER ACCOUNT', 'User Password', vars['sip'][0].secret)) postvars.update(self._createPOSTVar(varmap, 6, 'USER ACCOUNT', 'URL Scheme', 'SIP')) postvar_count = 7 postvars.update({'cnt': postvar_count}) # Send updated variables response = urllib2.urlopen('http://' + self._ip + ':8080/xpdb.uds', urllib.urlencode(postvars)) body = response.read() # Apparently the ICW-1000 does not support setting the phone account # and the network settings in a single request if current_network != None: postvars = {'mode': 'change', 'db': 'config'} postvars.update(self._createPOSTVar(varmap, 0, current_network, 'Enable DHCP', vars['enable_dhcp'])) postvar_count = 1 if not self._dhcp: postvars.update(self._createPOSTVar(varmap, 1, current_network, 'Address', vars['static_ip'])) postvars.update(self._createPOSTVar(varmap, 2, current_network, 'Netmask', vars['static_mask'])) postvars.update(self._createPOSTVar(varmap, 3, current_network, 'Gateway', vars['static_gateway'])) postvars.update(self._createPOSTVar(varmap, 4, current_network, 'DNS1', vars['static_dns1'])) postvars.update(self._createPOSTVar(varmap, 5, current_network, 'DNS1', vars['static_dns2'])) postvar_count += 5 postvars.update({'cnt': postvar_count}) # Send updated variables response = urllib2.urlopen('http://' + self._ip + ':8080/xpdb.uds', urllib.urlencode(postvars)) body = response.read() # Reiniciar el teléfono response = urllib2.urlopen('http://' + self._ip + ':8080/s_reboot.htm', '') body = response.read() self._unregister() self._setConfigured() return True except cjson.DecodeError, e: logging.error('Endpoint %s@%s received invalid JSON - %s' % (self._vendorname, self._ip, str(e))) return False
def parse_first(self,url,data={}): """Fetch url for scraping and parsing the data with a right function""" xs=self.fetch(url)[1] for link in xs.select("//div[@class='listing-outer']//a[@class='target-details']/@href").extract(): self.requests.put((self.parse_room,self.domain_url+link,{})) self.full_city=xs.select("//input[@name='location']/@value").extract()[0] query=urllib.splitquery(url) if len(query)>1: query=query[1].replace("&source=bb","") else: query="" self.requests.put((self.parse_rest,self.domain_url+self.search_other_pages%"2&"+urllib.urlencode({"location":self.full_city})+"&"+query,{'current_page':'2','query':query}))