⬆️ ⬇️

Getting a list of Internet connections of the router DIR-615 in a readable form

I live in a big family with a lot of computers. The need for Internet access for these computers satisfies the D-link DIR-615 router. In the web interface of this device there is always an interesting record about all current Internet connections passing through the device. Looking at this huge number of records, I was always worried, and what are my family members doing so creepy about, and have they not become victims of some creepy botnet? All entries in this table of connections operate only with IP addresses of computers on the local network and on the Internet. Rejecting the ethical side of the issue, I will explain in this article my script Kiddiv way to solve the problem of converting the list of connections into a human-readable form.



The list of connections looks like this:







Of course, you can sit and painstakingly copy the value of the 'Internet' field into any reverse DNS lookup service, but this is a terribly useless exercise. Therefore, first we will find a way to get the list at least in this form in our program. In my router, in its performance E4, there is no telnet as in the older models, and it does not flash any DD-WRT to get the list of connections in any decent way. Therefore, we will receive data directly from the web interface. To access this page, you must first log in to the router. Let's see how this process happens when you connect via a browser, for this we use the Mozilla Firefox browser plugin called HTTPFox.

Pressing the record of all HTTP requests in the plugin, we try to log in to the router, and see what happened. It should be noted that the router in the local network is located at 192.168.0.1.

')





We see that the authorization process is a simple POST request to the address for login.cgi. The request body basically consists of various variations of our login and password. Only they look strange, but their new appearance becomes clear. The script on the login page they are from the text fields of the interface elements are encoded in base64. Encoding script written directly on the login page. But bad luck, the function on the page gave different results when encoding the password with the urlsafe_b64encode function from the base64 Python library. The difference was that the page script sometimes changed the last character from '=' to 'A'. So I just ripped both the headers and POST Data from HTTPFox and wrote the login function. Hereinafter, to communicate with the router using the HTTP protocol, the Python module httplib will be used.

def LoginRouter(): headers = { '(Request-Line)': 'POST /login.cgi HTTP/1.1', 'Host': '192.168.0.1', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3', 'Accept-Encoding': 'gzip, deflate', 'Referer': 'http://192.168.0.1/login_auth.asp', 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': '144', } post_data = 'html_response_page=login_fail.asp&login_name=YWRtaW4A&login_pass=ZmFrZXB3ZA%3D%3D&graph_id=f1b37&login_n=admin&log_pass=ZmFrZXB3ZA%3D%3D&graph_code=&login=Login' conn = httplib.HTTPConnection('192.168.0.1:80') conn.request("POST", "/login.cgi", post_data, headers) response = conn.getresponse() 


No cookies come back to us, so apparently the router remembers us by IP address, which even simplifies everything.

Next, looking at the source text of the Internet connection page, we see that all the necessary data is set to the interface element with the input tag. And he is also one on the page. So the page parser will look simple, it will take the value field of the input tag parameters. To solve the problem, I did not want to install any third-party libraries, because I deliberately refused to use LXML, realizing that of course it would be more beautiful and simpler. To parse the web page, use the Python HTMLParser module. Using the module implies the creation of a class inherited from HTMLParser with the methods defined in it, which will be called when the parser finds certain data. We need only the methods handle_data and handle_starttag, which are called accordingly when the parser finds the data and the beginning of the tag. The data will look like a line of approximately the following type: ”TCP / 7767 / EST / OUT / 192.168.0.100 / 52751 / 64.12.30.3 / 5190/52751”, but we will easily cut it into a dict of a beautiful, convenient look. Getting a page will be a simple GET request. If in the response page we find a record of the form “function redirect ()”, it means we are not authorized on the router.



 def GetInternetSessionsPage(): class ConnectionsParser(HTMLParser): def __init__(self): HTMLParser.__init__(self) self.saved_data = [] def handle_starttag(self, tag, attrs): if tag == 'input': attr = dict(attrs) connections_str = attr['value'] connections_list = connections_str.split(',') for connection_entry in connections_list: data_entry_keywords = ['Protocol', 'Time out', 'State', 'Direction', 'Local IP', 'Local Port', 'Destination IP', 'Destination Port', 'NAT'] data_entry_values = connection_entry.split('/') data_entry = dict(zip(data_entry_keywords, data_entry_values)) self.saved_data.append(data_entry) conn = httplib.HTTPConnection('192.168.0.1:80') conn.request("GET", "/internet_sessions.asp") response = conn.getresponse() if response.status == httplib.OK: responce_text = response.read() if responce_text.find('function redirect()') >=0: return None parser = ConnectionsParser() parser.feed(responce_text) return parser.saved_data 




Now it remains only to turn the ip address into a domain name. On request, Google has a bunch of sites for reverse search. On the first one I find the API section, and I understand that the API is paid. But through the web interface, you can use as much as you like. Well, it will be perverted. But on this site, everything turned out to be simpler, the desired IP address is simply added to the URL, and the result page is displayed. We connect to the compiled address, and the parsing is all the same HTMLParser result. The truth came out somewhat stupid and ugly, because in the parser in the method of finding data, we write the following five records of data fields after the line "Resolve Host:". Well, it looks like a table of results on this site.



 def GetHostNameByIP(address): class DNSParser(HTMLParser): NUM_DATA_TO_SAVE = 5 def __init__(self): HTMLParser.__init__(self) self.next_data_save = 0 self.saved_data = [] def handle_data(self, data): if data.find('Resolve Host:') >= 0: self.next_data_save = self.NUM_DATA_TO_SAVE if self.next_data_save>0: self.saved_data.append(data) self.next_data_save -= 1 conn = httplib.HTTPConnection('domaintz.com:80') conn.request("GET", "/tools/overview/" + address) response = conn.getresponse() if response.status == httplib.OK: parser = DNSParser() parser.feed(response.read()) return parser.saved_data else: return 'Error ' + str(response.status) 




Next, we write a simple function that receives a list of connections, if not received, it logs into the router and tries again. And then it runs each destination address through reverse DNS. We fasten to it a simple filter so that information is displayed only at a specific address of the local network.



 def LookupRouterConnections(looking_ip = None): sessions = GetInternetSessionsPage() if sessions is None: LoginRouter() sessions = GetInternetSessionsPage() if sessions is None: print 'Cant login to router, check Login/Password' return for entry in sessions: if entry.has_key('Destination IP'): if looking_ip is not None: if entry.get('Local IP') != looking_ip: continue print '{0} : {1}'.format(entry['Local IP'],GetHostNameByIP(entry['Destination IP'])) 




We try:



 LookupRouterConnections('192.168.0.100') 192.168.0.100 : ['Resolve Host:', '212-36-249-250.rdtc.ru', ' (212.36.249.250)', 'IP Location:', 'Russian Federation, Novokuznetsk, Regional Digital Telecommunication Company (212.36.249.250)'] 192.168.0.100 : ['Resolve Host:', 'Debian-60-squeeze-64-minimal', ' (5.9.145.232)', 'IP Location:', 'Germany, RIPE Network Coordination Center (5.9.145.232)'] 192.168.0.100 : ['Resolve Host:', 'server15033.teamviewer.com', ' (178.255.155.21)', 'IP Location:', 'Italy, ANEXIA Internetdienstleistungs GmbH (178.255.155.21)'] 192.168.0.100 : ['Resolve Host:', 'cm-04.lux.valve.net', ' (146.66.152.15)', 'IP Location:', 'Luxembourg, Valve Corporation (146.66.152.15)'] 




and so on, a lot of records.



Used sources:



http://ru.wikipedia.org/wiki/HTTP

http://www.python.org/doc/

Source: https://habr.com/ru/post/166417/



All Articles