import java.net.*; //InetAddress利用のため
import java.util.*;
import java.io.*; //streamのバッファリングなど
/*
UPnPを使ってグローバルIPを取得する。
(なお、このプログラムは、このソースファイル単体で動作します)
*/
public class SetMyHomeGlobalIP2 {
//引数による動作指定記憶用
static boolean debugFlag;
static boolean locationFlag; // -location
static boolean wanPPPFlag;
static boolean addTCPFlag;
static boolean delTCPFlag;
static boolean entryFlag;
//以上のFlagが設定されていなければ、ルータのWAN側IPアドレスを表示
//UPNPで使われるパラメータを、文字列から取得して記憶する
static String serviceType; //例→urn:schemas-upnp-org:service:WANPPPConnection:1
static String serviceId; //例→urn:upnp-org:serviceId:WANPPPConn1
static String SCPDURL; //例→WANPPPConnection.xml
static String controlURL; //例→/EmWeb/UPnP/Control/4
static String eventSubURL; //例→/EmWeb/UPnP/Eventing/4
static void showUsage(){
System.out.println("Usag example.");
System.out.println(" SetMyHomeGlobalIP2 [-debug]");
System.out.println(" show external IP address of router.");
System.out.println(" SetMyHomeGlobalIP2 [-debug] -addTCP wan_port localhost_port [-out]");
System.out.println(" add PortMapping by port of WAN , port of localhost.");
System.out.println(" SetMyHomeGlobalIP2 [-debug] -addTCP2 wan_port lan_ip lan_port [-out]");
System.out.println(" add PortMapping by port of WAN , IP address of LAN, port of LAN.");
System.out.println(" SetMyHomeGlobalIP2 [-debug] -delTCP lan_port [-out]");
System.out.println(" delete PortMapping by port of WAN , IP address of LAN, port of LAN.");
System.out.println(" SetMyHomeGlobalIP2 [-debug] -getEntry index");
System.out.println(" show Generic Port Mapping Entry.");
System.out.println(" SetMyHomeGlobalIP2 [-debug] -getLocation");
System.out.println(" show UPnP Globale Device Location.");
System.out.println(" SetMyHomeGlobalIP2 [-debug] -setUPnPInf");
System.out.println(" show UPnP information.");
System.out.println(" SetMyHomeGlobalIP2 [-debug] -getWANPPP");
System.out.println(" show WANPPPConnection information.");
System.out.println(" SetMyHomeGlobalIP2 [-debug] -getLocalhost");
System.out.println(" show localhost IP Address.");
System.exit(1);
}
public static void main(String args[])throws Exception{
String localhost=null;//ローカルマシンのIPアドレス
String newPortMappingIndex="0";
String newExternalPort=null;
String newProtocol="TCP";
String newInternalClient=null;
String newInternalPort=null;
String getEntryIdx = null;//マッピングエントリ情報指定用
// localhost のプライベートアドレスを取得
if(localhost == null){
localhost = getLocalHost(1);
}//System.exit(1);
for(int i=0; i < args.length; i++){
if(args[i].toLowerCase().equals("-?")) {
showUsage();
}
if(args[i].toLowerCase().equals("-debug")) debugFlag = true;
if(args[i].toLowerCase().equals("-getlocalhost")) {
getLocalHost(1);
System.out.println(localhost);
System.exit(0);
}
if(args[i].toLowerCase().equals("-getlocation")) {
System.out.println(getGlobaleDeviceLocation());
System.exit(0);
}
if(args[i].toLowerCase().equals("-getupnpinf")) {
String uri = getGlobaleDeviceLocation();
System.out.println(getHttpGet(uri));
System.exit(0);
}
if(args[i].toLowerCase().equals("-getwanppp")) {
wanPPPFlag = true;
break;
}
if(args[i].toLowerCase().equals("-addtcp")) {
addTCPFlag = true;
newExternalPort=args[++i];
newInternalClient=localhost;
newInternalPort=args[++i];
}
if(args[i].toLowerCase().equals("-addtcp2")) {
addTCPFlag = true;
newExternalPort=args[++i];
newInternalClient=args[++i];
newInternalPort=args[++i];
}
if(args[i].toLowerCase().equals("-deltcp")) {
delTCPFlag = true;
newExternalPort=args[++i];
}
if(args[i].toLowerCase().equals("-getentry")) {
entryFlag = true;
getEntryIdx = args[++i];
}
}
//グローバルIPコネクションを持つUPnp対応のルータを探す
String uri = getGlobaleDeviceLocation();
if(uri == null) System.exit(1);
if(debugFlag) System.out.println("getGlobaleDeviceLocation() return value:"+uri);
//取得したルータのサービス情報源より、ルータのLAN側のIPアドレスとポート番号の文字列を得る→ip_Port
String ip_Port = uri.substring("http://".length());
int idx = ip_Port.indexOf("/");
ip_Port = ip_Port.substring(0, idx);
if(debugFlag) System.out.println("ip_Port="+ip_Port);
//--------------Device Description のxmlの取得----------------
String queryResponse = getHttpGet(uri);
if(debugFlag) {
System.out.println(queryResponse);
System.out.println("==========================");
}
//内で、がWANPPPConnectionの所を探して各パラメタをセットする
SetMyHomeGlobalIP2.getParameter(queryResponse, "WANPPPConnection");
//WANPPPConnection の操作の詳細情報を取得
if( wanPPPFlag ) {
queryResponse= getHttpGet("http://" + ip_Port + "/" + SCPDURL);
System.out.println(queryResponse);
if(debugFlag) {
System.exit(1);
}
}
if( addTCPFlag ){
boolean rtnval =post_AddPortMapping(ip_Port, newExternalPort, newInternalClient, newInternalPort);
if(debugFlag) {
System.out.println("-----------------------------");
System.out.println("AddPortMapping:"+rtnval);
}
if(rtnval == false) {
System.out.println("failure");
System.exit(1);
}
}
if( delTCPFlag ){
boolean rtnval =post_DeletePortMapping(ip_Port,newExternalPort);
if(debugFlag) {
System.out.println("-----------------------------");
System.out.println("post_DeletePortMapping:"+rtnval);
}
if(rtnval == false) {
System.out.println("failure");
System.exit(1);
}
}
if( entryFlag ){
queryResponse = post_GetGenericPortMappingEntry(ip_Port,getEntryIdx);
System.out.println(queryResponse);
System.exit(0);
}
queryResponse = post_GetExternalIPAddress(ip_Port);
if(debugFlag) {
System.out.println("-----------------------------");
}
System.out.println("ExternalIPAddress:"+queryResponse);
}
//グローバルIPコネクションを持つUPnp対応のルータを探す
public static String getGlobaleDeviceLocation() throws Exception{
String queryResponse=null;
//グローバルIPコネクションを持つUPnp対応のルータを探す文字列
String query = "M-SEARCH * HTTP/1.1\n"+
"HOST: 239.255.255.250:1900\n"+
"MX: 3\n"+
"MAN: \"ssdp:discover\"\n"+
"ST: urn:schemas-upnp-org:service:WANIPConnection:1\n\n";
//UnpnマルチキャストのIPアドレスとポート
InetAddress inet = InetAddress.getByName("239.255.255.250");
int portNumber = 1900;//ポート番号
MulticastSocket multSock = new MulticastSocket();//マルチキャスト送信用
multSock.setTimeToLive(10);//寿命設定
byte[] buf = query.getBytes("UTF-8");//バイト列に変換
DatagramPacket packet;//マルチキャストソケット生成
multSock.joinGroup(inet); //指定のマルチキャストアドレスのグループに参加★
packet = new DatagramPacket(buf, buf.length, inet, portNumber);//IPアドレス、ポート番号も指定
if(debugFlag) System.out.println(new String(buf , "UTF-8"));
multSock.send(packet);//送信
byte[] data = new byte[1024];
packet = new DatagramPacket(data, data.length);
multSock.setSoTimeout(20000);
multSock.receive(packet);//受信& wait
multSock.close();
int len = packet.getLength();//受信バイト数取得
queryResponse = new String(data, 0, len,"UTF-8");//受信バイト列のデコード
if(debugFlag) {
System.out.println("-----------------------------");
System.out.println(queryResponse);
}
//上記で得られたqueryResponse から、「LOCATION: 」以降の1行を取得します。
// 例えば『Location: http://192.168.0.1:80/DeviceDescription.xml』の行が取得されます。
int idx = queryResponse.toUpperCase().indexOf("LOCATION: ");
if(idx == -1){
if(debugFlag) System.out.println("「LOCATION: 」の取得に失敗しました。");
return null;
}
String loacation = queryResponse.substring(idx + "LOCATION: ".length());
idx = loacation.indexOf("\n");
loacation = loacation.substring(0, idx).trim();
return loacation;
}
//uriをHTTPのGETで取得し,得た文字列を返す。
public static String getHttpGet(String uri) throws Exception {
if(debugFlag) System.out.println("============HTTP GET "+uri);
String str="";
URL url = new URL(uri);
HttpURLConnection huc = (HttpURLConnection) url.openConnection();
huc.setRequestMethod("GET");
huc.connect();
InputStreamReader isr = new InputStreamReader(huc.getInputStream(),"UTF-8");
int c;
while((c = isr.read()) != -1){
str+=(char)c;
}
huc.disconnect();
return str;
}
//引数に群がある文字列を指定する。その中に含まれるserviceTypeNameのサービスの各上記情報を取得して設定する。
public static boolean getParameter(String services_Str, String serviceTypeName){
if(debugFlag) System.out.println("++++++++++++++++++++ getParameter( ,"+ serviceTypeName + ")");
serviceTypeName = serviceTypeName.toUpperCase();
//serviceTypeNameがあるを探し、それを基準とする。
int idx = services_Str.toUpperCase().indexOf(serviceTypeName);
if(idx == -1)return false;
//この内で、を取得する。
idx = services_Str.toUpperCase().lastIndexOf("", idx);
services_Str = services_Str.substring(idx);//このの文字列を先頭になる文字列を得る
//この内で、を取得する。
idx = services_Str.toUpperCase().indexOf("");
serviceType = services_Str.substring("".length()+idx);
idx = serviceType.toUpperCase().indexOf("");
serviceType = serviceType.substring(0,idx);
if(debugFlag) System.out.println(":"+serviceType);
//この内で、を取得する。
idx = services_Str.toUpperCase().indexOf("");
if(idx != -1){
serviceId = services_Str.substring( "".length()+idx);
idx = serviceId.toUpperCase().indexOf("");
serviceId = serviceId.substring(0,idx);
if(debugFlag) System.out.println(":"+serviceId);
}
//この内で、を取得する。
idx = services_Str.toUpperCase().indexOf("");
if(idx != -1){
SCPDURL = services_Str.substring("".length()+idx);
idx = SCPDURL.toUpperCase().indexOf("");
SCPDURL = SCPDURL.substring(0,idx);
if(debugFlag) System.out.println(":"+SCPDURL);
}
//この内で、を取得する。
idx = services_Str.toUpperCase().indexOf("");
if(idx != -1){
controlURL = services_Str.substring("".length()+idx);
idx = controlURL.toUpperCase().indexOf("");
controlURL = controlURL.substring(0,idx);
if(debugFlag) System.out.println(":"+controlURL);
}
//この内で、を取得する。
idx = services_Str.toUpperCase().indexOf( "");
if(idx != -1){
eventSubURL = services_Str.substring("".length()+idx);
idx = eventSubURL.toUpperCase().indexOf("");
eventSubURL = eventSubURL.substring(0,idx);
if(debugFlag) System.out.println(":"+eventSubURL);
}
if(debugFlag) System.out.println("++++++++++++++++++++++++++++++++++++++++++++\n\n");
return true;
}
public static String post_UPnP_Message(String ip_Port, String acctionName,String postMsg)throws Exception
{
byte []postMsgBuf = postMsg.getBytes("UTF-8");
String str = "";//戻り値
String post = "POST "+controlURL+"/WANPPPConnection HTTP/1.1\r\n"+
"SoapAction: " + serviceType + "#"+acctionName+"\r\n"+
"Host: "+ip_Port+"\r\n"+
"Content-Type: text/xml\r\n"+
"Content-Length: " + postMsgBuf.length + "\r\n\r\n";
String uriPath = "http://" + ip_Port + controlURL;
URL url = new URL(uriPath);
if(debugFlag) {
System.out.println("-----URL:"+uriPath);
System.out.println("-----post_UPnP_Message:\n"+post);
System.out.println(postMsg);
}
String ip = null;
int port=80;
int idx = ip_Port.indexOf(":");
if(idx != -1){
ip= ip_Port.substring(0,idx);
port = Integer.parseInt(ip_Port.substring(idx+1));
}
Socket soket = new Socket(ip, port);
OutputStream outStream = soket.getOutputStream();
InputStream is = soket.getInputStream();
byte []buf = post.getBytes();
outStream.write(buf);
outStream.write(postMsgBuf);
outStream.flush();
InputStreamReader isr = new InputStreamReader(is);
int c;
while((c = isr.read()) != -1){
str+=(char)c;
}
soket.close();
if(debugFlag)System.out.println("------------------------ that over.\n");
return str;
}
public static String post_GetExternalIPAddress(String ip_Port) throws Exception{
String postMsg = "\r\n"+
"\r\n"+
"\r\n"+
"\r\n"+
"\r\n"+
"\r\n"+
"\r\n";
String resposeMsg = post_UPnP_Message(ip_Port, "GetExternalIPAddress", postMsg);
if(debugFlag) System.out.println("-----GetExternalIPAddress:"+resposeMsg);
int idx = resposeMsg.toUpperCase().indexOf("");
resposeMsg = resposeMsg.substring(idx + "".length());
idx = resposeMsg.indexOf("<");
resposeMsg = resposeMsg.substring(0, idx);
return resposeMsg;
}
public static boolean post_AddPortMapping(String ip_Port, String newExternalPort,
String newInternalClient, String newInternalPort) throws Exception{
String postMsg = "\r\n"+
"\r\n"+
"\r\n"+
"\r\n"+
"\r\n"+
""+newExternalPort+"\r\n"+
"TCP\r\n"+
""+newInternalPort+"\r\n"+
""+newInternalClient+"\r\n"+
"1\r\n"+
"UPnP "+newExternalPort+" port Mapping\r\n"+
"0\r\n"+
"\r\n"+
"\r\n"+
"\r\n";
String resposeMsg = post_UPnP_Message(ip_Port, "AddPortMapping", postMsg);
if(debugFlag) System.out.println("-----AddPortMapping:"+resposeMsg);
int idx = resposeMsg.toUpperCase().indexOf("\n");
if(idx != -1) resposeMsg = resposeMsg.substring(0,idx).toUpperCase();
idx = resposeMsg.toUpperCase().indexOf("200");//成功の番号がレスポンス先頭行にあるか
return idx != -1;
}
public static boolean post_DeletePortMapping(String ip_Port, String newExternalPort) throws Exception{
String postMsg = "\r\n"+
"\r\n"+
"\r\n"+
"\r\n"+
"\r\n"+
""+newExternalPort+"\r\n"+
"TCP\r\n"+
"\r\n"+
"\r\n"+
"\r\n";
String resposeMsg = post_UPnP_Message(ip_Port, "DeletePortMapping", postMsg);
if(debugFlag) System.out.println("-----DeletePortMapping:"+resposeMsg);
int idx = resposeMsg.toUpperCase().indexOf("\n");
if(idx != -1) resposeMsg = resposeMsg.substring(0,idx).toUpperCase();
idx = resposeMsg.toUpperCase().indexOf("200");//成功の番号がレスポンス先頭行にあるか
return idx != -1;
}
public static String post_GetGenericPortMappingEntry(String ip_Port,String strIndex) throws Exception{
String postMsg = "\r\n"+
"\r\n"+
"\r\n"+
"\r\n"+
""+strIndex+"\r\n"+
"\r\n"+
"\r\n"+
"\r\n";
String resposeMsg = post_UPnP_Message(ip_Port, "GetGenericPortMappingEntry", postMsg);
if(debugFlag) System.out.println("-----GetGenericPortMappingEntry:"+resposeMsg);
return resposeMsg;
}
public static String getLocalHost(int number) throws Exception {
String host = null;
Enumeration netSet = NetworkInterface.getNetworkInterfaces();
LOOP: while(netSet.hasMoreElements()){
NetworkInterface netinterface = (NetworkInterface) netSet.nextElement();
Enumeration inetSet = netinterface.getInetAddresses();
InetAddress inet = InetAddress.getByName("localhost");
while(inetSet.hasMoreElements()){
inet = (InetAddress) inetSet.nextElement();
host = inet.getHostAddress();
if(debugFlag){
System.out.println("--------"+inet.getClass().getName());
System.out.println("IPアドレス:" + host);
System.out.println("IPアドレス:" + inet);
} else if(inet.getClass().getName().equals("java.net.Inet4Address")){
if(--number <= 0) break LOOP;
}
}
}
return host;
}
static String getDisplayTime(){
Calendar colender = Calendar.getInstance();
String s = "";
s += colender.get(Calendar.YEAR);
String m = "" +( colender.get(Calendar.MONTH) + 1);
if(m.length() == 1) m = "0" + m;
String dd = "" + colender.get(Calendar.DATE);
if(dd.length() == 1) dd = "0" + dd;
String hh = "" + colender.get(Calendar.HOUR_OF_DAY);
if(hh.length() == 1) hh = "0" + hh;
String mm = "" + colender.get(Calendar.MINUTE);
if(mm.length() == 1) mm = "0" + mm;
s += " " + m+ "/" + dd + " " + hh + ":" + mm ;
return s;
}
}