前段时间在调试IP摄像头时偶然发现铁通也能刷出独立IP,是183开头的,一开始以为只有铁通网络能够访问,后面发现跟myexternalip.com检测的IP一致,然后IP摄像头居然可以外网访问了,于是写了个python脚本来刷独立IP。
原理很简单,每次路由器重新拨号就能改变IP,然后将路由器的IP跟myexternalip.com检测的外网IP比较,如果一致就是独立IP。
我家路由器是水星MD898n(固件:V2.0_140216标准版,以下都是针对此固件,不同版本固件可能不一样),根据Chrome抓包得到每次点击 断线,都会向路由器提交 “[ACT_PPP_DISCONN#2,1,1,0,0,0#0,0,0,0,0,0]0,0\r\n”的指令,点击 连接则提交“[ACT_PPP_CONN#2,1,1,0,0,0#0,0,0,0,0,0]0,0\r\n”,这样就实现路由器重新拨号。路由器登录验证则是base验证,只不过不需要用户名而已。
路由器的IP则可以通过UPnP的方式得到,具体可以参考关于UPnP端口映射的文献。
upnp.py的实现,主要实现get_external_ip()这个函数用于获取路由器IP
import socket
import socket
import re
import urllib2
import httplib
import struct
import time
from xml.dom.minidom import parseString
from urlparse import urlparse
xmlLocation = ""
xmlString = ""
def _get_external_ip():
global xmlLocation
global xmlString
if xmlLocation == "" or xmlString == "":
ssdpRequest = "M-SEARCH * HTTP/1.1\r\n" + \
"MX: 3\r\n" + \
"HOST: 239.255.255.250:1900\r\n" + \
"MAN: \"ssdp:discover\"\r\n" + \
"ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n\r\n"
SSDP_ADDR = "239.255.255.250"
SSDP_PORT = 1900
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('192.168.1.5', 0))
sock.settimeout(10)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.sendto(ssdpRequest, (SSDP_ADDR, SSDP_PORT))
resp = sock.recv(1024)
lines = resp.splitlines()
for line in lines:
params = line.split(':', 1)
if len(params) == 2 and params[0].strip().lower() == "location":
xmlLocation = params[1].strip()
break
opened = urllib2.urlopen(xmlLocation)
xmlString = opened.read()
opened.close()
GetExternalIPAddress = "<?xml version=\"1.0\"?>" + \
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + \
"<s:Body>" + \
"<u:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:{0}:1\">" + \
"</u:GetExternalIPAddress>" + \
"</s:Body>" + \
"</s:Envelope>"
router_path = urlparse(xmlLocation)
dom = parseString(xmlString)
service_types = dom.getElementsByTagName('serviceType')
path = ""
action = ""
for service in service_types:
if service.childNodes[0].data.find('WANIPConnection') > 0:
path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data
action = "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"
elif service.childNodes[0].data.find('WANPPPConnection') > 0:
path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data
action = "urn:schemas-upnp-org:service:WANPPPConnection:1#GetExternalIPAddress"
else:
continue
conn = httplib.HTTPConnection(router_path.hostname, router_path.port)
conn.request('POST',
path,
GetExternalIPAddress,
{'SOAPAction': action,
'Content-Type': 'text/xml; charset="utf-8"'}
)
resp = conn.getresponse()
result = resp.read()
resp.close()
conn.close()
dom = parseString(result)
external_ip = dom.getElementsByTagName('NewExternalIPAddress')[0].childNodes[0].nodeValue
if external_ip != "0.0.0.0":
return external_ip
return ""
def get_external_ip():
while(1):
try:
ip = _get_external_ip()
if ip != "":
return ip
except Exception, e:
print e
time.sleep(3)
print get_external_ip() |
import socket
import socket
import re
import urllib2
import httplib
import struct
import time
from xml.dom.minidom import parseString
from urlparse import urlparse
xmlLocation = ""
xmlString = ""
def _get_external_ip():
global xmlLocation
global xmlString
if xmlLocation == "" or xmlString == "":
ssdpRequest = "M-SEARCH * HTTP/1.1\r\n" + \
"MX: 3\r\n" + \
"HOST: 239.255.255.250:1900\r\n" + \
"MAN: \"ssdp:discover\"\r\n" + \
"ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n\r\n"
SSDP_ADDR = "239.255.255.250"
SSDP_PORT = 1900
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('192.168.1.5', 0))
sock.settimeout(10)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.sendto(ssdpRequest, (SSDP_ADDR, SSDP_PORT))
resp = sock.recv(1024)
lines = resp.splitlines()
for line in lines:
params = line.split(':', 1)
if len(params) == 2 and params[0].strip().lower() == "location":
xmlLocation = params[1].strip()
break
opened = urllib2.urlopen(xmlLocation)
xmlString = opened.read()
opened.close()
GetExternalIPAddress = "<?xml version=\"1.0\"?>" + \
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + \
"<s:Body>" + \
"<u:GetExternalIPAddress xmlns:u=\"urn:schemas-upnp-org:service:{0}:1\">" + \
"</u:GetExternalIPAddress>" + \
"</s:Body>" + \
"</s:Envelope>"
router_path = urlparse(xmlLocation)
dom = parseString(xmlString)
service_types = dom.getElementsByTagName('serviceType')
path = ""
action = ""
for service in service_types:
if service.childNodes[0].data.find('WANIPConnection') > 0:
path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data
action = "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"
elif service.childNodes[0].data.find('WANPPPConnection') > 0:
path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data
action = "urn:schemas-upnp-org:service:WANPPPConnection:1#GetExternalIPAddress"
else:
continue
conn = httplib.HTTPConnection(router_path.hostname, router_path.port)
conn.request('POST',
path,
GetExternalIPAddress,
{'SOAPAction': action,
'Content-Type': 'text/xml; charset="utf-8"'}
)
resp = conn.getresponse()
result = resp.read()
resp.close()
conn.close()
dom = parseString(result)
external_ip = dom.getElementsByTagName('NewExternalIPAddress')[0].childNodes[0].nodeValue
if external_ip != "0.0.0.0":
return external_ip
return ""
def get_external_ip():
while(1):
try:
ip = _get_external_ip()
if ip != "":
return ip
except Exception, e:
print e
time.sleep(3)
print get_external_ip()
get_global_ip.py的实现
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import httplib
import urllib
import base64
import time
import re,urllib2
import traceback
import upnp
def Get_public_ip(): #获取真实的广域网IP
try:
opener = urllib2.urlopen("http://myexternalip.com/raw")
str = opener.read().strip()
return str
except Exception,ex:
print Exception,":",ex
return None
def _sendhttp(data):
conn = httplib.HTTPConnection('192.168.1.1') #注意路由器的IP,下同
conn.putrequest('POST', '/cgi?7')
conn.putheader("Accept", "*/*")
conn.putheader("Origin", "http://192.168.1.1")
conn.putheader("Referer", "http://192.168.1.1/")
conn.putheader("Content-Type", "text/plain")
conn.putheader("Content-Length", str(len(data)))
conn.putheader("Cookie", "Authorization=Basic " + base64.b64encode("123456")) # 123456为路由器登录密码
conn.endheaders()
conn.send(data)
return conn.getresponse()
def sendhttp(data):
httpres = _sendhttp(data)
while httpres.status != 200:
print httpres.status
time.sleep(2)
httpres = _sendhttp(data)
print httpres.status
print httpres.reason
print httpres.read()
if __name__ == '__main__':
try:
print "Global IP:" + Get_public_ip()
print "Router IP:" + upnp.get_external_ip()
print "Refreshing..."
while(1):
sendhttp("[ACT_PPP_DISCONN#2,1,1,0,0,0#0,0,0,0,0,0]0,0\r\n") #路由器断线
time.sleep(2)
sendhttp("[ACT_PPP_CONN#2,1,1,0,0,0#0,0,0,0,0,0]0,0\r\n") #路由器连接,完成一次重新拨号
time.sleep(1)
public_ip = Get_public_ip() #获取实际外网IP
external_ip = upnp.get_external_ip() #获取路由器IP
if(public_ip == external_ip): #比较
print "Global IP:" + public_ip
print "Refresh OK!"
break
else:
print "Router IP:" + external_ip
print "Global IP:" + public_ip
print "Continue refreshing..." #不是独立IP,继续刷
time.sleep(1000)
except Exception, e:
print e
print traceback.format_exc()
time.sleep(1000) |
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import httplib
import urllib
import base64
import time
import re,urllib2
import traceback
import upnp
def Get_public_ip(): #获取真实的广域网IP
try:
opener = urllib2.urlopen("http://myexternalip.com/raw")
str = opener.read().strip()
return str
except Exception,ex:
print Exception,":",ex
return None
def _sendhttp(data):
conn = httplib.HTTPConnection('192.168.1.1') #注意路由器的IP,下同
conn.putrequest('POST', '/cgi?7')
conn.putheader("Accept", "*/*")
conn.putheader("Origin", "http://192.168.1.1")
conn.putheader("Referer", "http://192.168.1.1/")
conn.putheader("Content-Type", "text/plain")
conn.putheader("Content-Length", str(len(data)))
conn.putheader("Cookie", "Authorization=Basic " + base64.b64encode("123456")) # 123456为路由器登录密码
conn.endheaders()
conn.send(data)
return conn.getresponse()
def sendhttp(data):
httpres = _sendhttp(data)
while httpres.status != 200:
print httpres.status
time.sleep(2)
httpres = _sendhttp(data)
print httpres.status
print httpres.reason
print httpres.read()
if __name__ == '__main__':
try:
print "Global IP:" + Get_public_ip()
print "Router IP:" + upnp.get_external_ip()
print "Refreshing..."
while(1):
sendhttp("[ACT_PPP_DISCONN#2,1,1,0,0,0#0,0,0,0,0,0]0,0\r\n") #路由器断线
time.sleep(2)
sendhttp("[ACT_PPP_CONN#2,1,1,0,0,0#0,0,0,0,0,0]0,0\r\n") #路由器连接,完成一次重新拨号
time.sleep(1)
public_ip = Get_public_ip() #获取实际外网IP
external_ip = upnp.get_external_ip() #获取路由器IP
if(public_ip == external_ip): #比较
print "Global IP:" + public_ip
print "Refresh OK!"
break
else:
print "Router IP:" + external_ip
print "Global IP:" + public_ip
print "Continue refreshing..." #不是独立IP,继续刷
time.sleep(1000)
except Exception, e:
print e
print traceback.format_exc()
time.sleep(1000)
将两个文件放置同一个目录,运行get_global_ip.py即可,确保跟路由器处于同一子网,并且路由器没有上级路由器,路由器要开启UPnP,切记!不同的路由器只要改一下拨号部分的代码即可。
当然还有粗暴的方式,把这代码弄到树莓派,再让树莓派控制继电器开关路由器电源,路由器每重启一次就能拨号一次,只是过于粗暴体验不佳……😂😂😂😂
本文地址 http://www.shenyaocn.com/2016/09/using_python_obtain_cmcc_global_ip/