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; } }