-------------------------------------------------------------------------------
以下內容可能還是存在問題,等之后有時間再進行進一步確認。
-------------------------------------------------------------------------------
原先一直使用TP-LINK路由器本身自帶的花生殼動態DNS加路由器的端口映射功能,可以從外網直接訪問到到內網電腦端口。
后來發現花生殼提供的解析IP不能訪問內網電腦了,經過一番檢查,發現路由器中的外網IP與訪問外網網頁時所顯示器的IP地址不一致,
使用訪問網頁時的IP測試不能訪問到內網,使用路由器上顯示器的外網IP倒是可以訪問到內網,
應該是ISP提供商(本人用的是聯通寬帶)使用了NAT轉換導致的。
又是一番調查,花生殼和其它的動態DNS服務提供商倒是提供了可能的解決方案,就是根據線路不同內部進行不同處理,
本人估計是可能可以解決NAT轉換導致的IP地址問題,但是,最重要一點,這種服務是收費服務,只能另想辦法了。
另外,在要映射端口的電腦上安裝新花生殼客戶端軟件,此軟件具有的內網映射功能應該可以實現對這種情況下對內網電腦端口的映射功能,只要付費1元就可以了,
不過這個功能實現可能是通過軟件本身的中轉實現,存在不少局限性,不過一般情況下的使用應該也沒多大問題。
本人還是希望通過真實IP來進行訪問,所以又進行調查,之后發現花生殼提供手動更新動態IP功能,也就是使用HTTP的GET方法來編程手動更新IP地址,
又調查發現應該可以從路由器的管理網頁中得到外網IP,所以經過調查測試,確實可以實現,再加上軟件中進行定時自動更新,可以實現類似花生殼客戶端的自動更新IP功能。
將使用的主要代碼【C#】記錄如下:
/// <summary>
/// 取得TP-LINK路由器的外網IP地址
/// 本函數假設路由器已處於連網狀態,不再對是否連網狀態進行判斷
/// </summary>
/// <param name="strTPIP">TP-LINK路由器的IP地址</param>
/// <param name="strUserName">TP-LINK路由器的管理用戶名</param>
/// <param name="strPassword">TP-LINK路由器的管理用戶密碼</param>
/// <returns>外網IP地址,為空表示獲取失敗</returns>
private string GetWanIP(string strTPIP, string strUserName, string strPassword)
{
// 包含TP-LINK路由器狀態信息的網頁URL
string strTPURL = "http://" + strTPIP + "/userRpm/StatusRpm.htm";
// 設置獲取狀態信息網頁內容的相關參數
System.Net.HttpWebRequest objRequest = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(strTPURL);
objRequest.Referer = strTPURL;
objRequest.Credentials = new System.Net.NetworkCredential(strUserName, strPassword);
// 取得結果信息內容
SetLogMessage(0, "嘗試獲取路由器狀態信息內容");
System.Net.HttpWebResponse objResponse = (System.Net.HttpWebResponse)objRequest.GetResponse();
SetLogMessage(1, "已取得路由器狀態信息");
// 取得結果內容文本
System.IO.StreamReader objResponseReader = new System.IO.StreamReader(objResponse.GetResponseStream(), Encoding.Default);
string strResponseText = objResponseReader.ReadToEnd();
objResponseReader.Close();
objResponse.Close();
// 查找包含外網IP地址的數據數組位置
SetLogMessage(1, "查找包含外網IP地址的數據數組位置");
int intPos = strResponseText.IndexOf("var wanPara = new Array");
if (intPos < 0)
{
SetLogMessage(0, "*** 查找包含外網IP地址的數據數組位置失敗");
return "";
}
// 查找外網IP地址位置
SetLogMessage(1, "查找外網IP地址位置");
int intPos2 = strResponseText.IndexOf("\",\n\"", intPos);
if (intPos2 < 0)
{
SetLogMessage(0, "*** 查找外網IP地址位置失敗");
return "";
}
// 查找外網IP地址結束位置
SetLogMessage(1, "查找外網IP地址結束位置");
int intPos3 = strResponseText.IndexOf("\"", intPos2 + 4);
if (intPos3 < 0)
{
SetLogMessage(0, "*** 查找外網IP地址結束位置失敗");
return "";
}
// 得到外網IP地址
int intIPPos = intPos2 + 4;
string strWanIP = strResponseText.Substring(intIPPos, intPos3 - intIPPos);
SetLogMessage(0, "得到結果外網IP地址:[" + strWanIP + "]");
return strWanIP;
}
/// <summary>
/// 更新動態IP地址到花生殼
/// </summary>
/// <param name="strOrayUserName">花生殼用戶名</param>
/// <param name="strOrayPassword">花生殼密碼</param>
/// <param name="strHostName">花生殼域名(多個域名時用逗號隔開)</param>
/// <param name="strWanIP">要更新的IP,也可為空,為空時由花生殼得到的IP地址為准</param>
/// <returns>是否成功</returns>
private bool UpdateOrayDdnsIP(string strOrayUserName, string strOrayPassword, string strHostName, string strWanIP)
{
// 更新DDNS的URL
string strUpdateURL = "http://ddns.oray.com/ph/update?hostname=" + strHostName + "&myip=" + strWanIP;
// 創建HTTP請求對象
System.Net.HttpWebRequest objRequest = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(strUpdateURL);
// 設置相關參數
objRequest.UserAgent = "Oray";
objRequest.Method = "GET";
//獲得用戶名密碼的Base64編碼
string strBase64Code = Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", strOrayUserName, strOrayPassword)));
//添加Authorization到HTTP頭
objRequest.Headers.Add("Authorization", "Basic " + strBase64Code);
// 嘗試更新並取得結果信息
SetLogMessage(0, "嘗試更新動態IP到花生殼");
System.Net.HttpWebResponse objResponse = (System.Net.HttpWebResponse)objRequest.GetResponse();
// 得到結果信息文本
SetLogMessage(1, "更新動態IP到花生殼完成");
System.IO.StreamReader objResponseReader = new System.IO.StreamReader(objResponse.GetResponseStream(), Encoding.Default);
string strResponseText = objResponseReader.ReadToEnd();
objResponseReader.Close();
objResponse.Close();
SetLogMessage(0, "更新結果信息:[" + strResponseText + "]");
// 檢查結果是否成功
if (strResponseText.IndexOf("good") >= 0 || strResponseText.IndexOf("nochg") >= 0)
{
SetLogMessage(1, "更新動態IP地址成功");
return true;
}
else
{
SetLogMessage(0, "*** 更新動態IP地址失敗");
return false;
}
}
以上代碼只適用於TP-LINK路由器,在TP-LINK路由器TL-WR845N型號上測試通過,因為沒有測試其它型號,所以不能保證其它型號的路由器可以正常使用。
如果TP-LINK其它型號路由器不能使用,可以查看狀態顯示器網頁URL是否與上面代碼中URL一致,並且使用HTTP抓包工具查看網頁Header內容及Response內容,
對URL、進行GET時的Header內容以及Response的內容中的外網IP所在位置查找字符串方法進行調整,應該是可以實現的。
同理,對於其它廠商的路由器,本人感覺也是可以同樣道理來實現,查看路由器狀態信息頁面源代碼以及使用HTTP抓包工具查看相關信息,應該可以實現類似功能。
花生殼返回代碼列表
| 參數 | 說明 | ||
| good | 更新成功,域名的IP地址已經更新,同時會返回本次更新成功的IP,用空格隔開,如:good 1.2.3.4 | ||
| nochg | 更新成功,但沒有改變IP。一般這種情況為本次提交的IP跟上一次的一樣 | ||
| notfqdn | 未有激活花生殼的域名 | ||
| nohost | 域名不存在或未激活花生殼 | ||
| nochg | 更新成功,但沒有改變IP。一般這種情況為本次提交的IP跟上一次的一樣 | ||
| abuse | 請求失敗,頻繁請求或驗證失敗時會出現 | ||
| !donator | 表示此功能需要付費用戶才能使用,如https | ||
| 911 | 系統錯誤 |
參考資料:
花生殼HTTP協議說明:
http://open.oray.com/wiki/doku.php?id=%E6%96%87%E6%A1%A3:%E8%8A%B1%E7%94%9F%E5%A3%B3:http%E5%8D%8F%E8%AE%AE%E8%AF%B4%E6%98%8E
