propagate from branch 'i2p.i2p' (head eb2151f9d804ec432bfe97214896ee62da08943e)

to branch 'i2p.i2p.zzz.test2' (head 2ea50c5f22fe1e24d37dff2f283b77feaa9190ee)
This commit is contained in:
zzz
2016-06-04 13:00:36 +00:00
564 changed files with 52737 additions and 24572 deletions

View File

@@ -16,6 +16,9 @@
<!-- Depend on classes instead of jars where available -->
<classpath>
<pathelement location="../../core/java/build/obj" />
<pathelement location="../../core/java/build/gnu-getopt.jar" />
<pathelement location="../../core/java/build/httpclient.jar" />
<pathelement location="../../core/java/build/httpcore.jar" />
</classpath>
</depend>
</target>
@@ -38,7 +41,7 @@
<javac srcdir="./src" debug="true" source="${javac.version}" target="${javac.version}" deprecation="on"
debuglevel="lines,vars,source"
includeAntRuntime="false"
destdir="./build/obj" classpath="../../core/java/build/obj:../../core/java/build/i2p.jar" >
destdir="./build/obj" classpath="../../core/java/build/obj:../../core/java/build/i2p.jar:../../core/java/build/gnu-getopt.jar:../../core/java/build/httpclient.jar:../../core/java/build/httpcore.jar" >
<compilerarg line="${javac.compilerargs}" />
</javac>
</target>

View File

@@ -0,0 +1,63 @@
/**
* Country.java
*
* Copyright (C) 2003 MaxMind LLC. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.maxmind.geoip;
/**
* Represents a country.
*
* @author Matt Tucker
*/
public class Country {
private String code;
private String name;
/**
* Creates a new Country.
*
* @param code
* the country code.
* @param name
* the country name.
*/
public Country(String code, String name) {
this.code = code;
this.name = name;
}
/**
* Returns the ISO two-letter country code of this country.
*
* @return the country code.
*/
public String getCode() {
return code;
}
/**
* Returns the name of this country.
*
* @return the country name.
*/
public String getName() {
return name;
}
}

View File

@@ -0,0 +1,128 @@
/**
* DatabaseInfo.java
*
* Copyright (C) 2003 MaxMind LLC. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.maxmind.geoip;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Encapsulates metadata about the GeoIP database. The database has a date, is a
* premium or standard version, and is one of the following types:
*
* <ul>
* <li>Country edition -- this is the most common version of the database. It
* includes the name of the country and it's ISO country code given an IP
* address.
* <li>Region edition -- includes the country information as well as what U.S.
* state or Canadian province the IP address is from if the IP address is from
* the U.S. or Canada.
* <li>City edition -- includes country, region, city, postal code, latitude,
* and longitude information.
* <li>Org edition -- includes netblock owner.
* <li>ISP edition -- ISP information.
* </ul>
*
* @see com.maxmind.geoip.LookupService#getDatabaseInfo()
* @author Matt Tucker
*/
public class DatabaseInfo {
public static final int COUNTRY_EDITION = 1;
public static final int REGION_EDITION_REV0 = 7;
public static final int REGION_EDITION_REV1 = 3;
public static final int CITY_EDITION_REV0 = 6;
public static final int CITY_EDITION_REV1 = 2;
public static final int ORG_EDITION = 5;
public static final int ISP_EDITION = 4;
public static final int PROXY_EDITION = 8;
public static final int ASNUM_EDITION = 9;
public static final int NETSPEED_EDITION = 10;
public static final int DOMAIN_EDITION = 11;
public static final int COUNTRY_EDITION_V6 = 12;
public static final int ASNUM_EDITION_V6 = 21;
public static final int ISP_EDITION_V6 = 22;
public static final int ORG_EDITION_V6 = 23;
public static final int DOMAIN_EDITION_V6 = 24;
public static final int CITY_EDITION_REV1_V6 = 30;
public static final int CITY_EDITION_REV0_V6 = 31;
public static final int NETSPEED_EDITION_REV1 = 32;
public static final int NETSPEED_EDITION_REV1_V6 = 33;
private static SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
private String info;
/**
* Creates a new DatabaseInfo object given the database info String.
*
* @param info
*/
public DatabaseInfo(String info) {
this.info = info;
}
public int getType() {
if (info == null || info.length() == 0) {
return COUNTRY_EDITION;
} else {
// Get the type code from the database info string and then
// subtract 105 from the value to preserve compatability with
// databases from April 2003 and earlier.
return Integer.parseInt(info.substring(4, 7)) - 105;
}
}
/**
* Returns true if the database is the premium version.
*
* @return true if the premium version of the database.
*/
public boolean isPremium() {
return !info.contains("FREE");
}
/**
* Returns the date of the database.
*
* @return the date of the database.
*/
public Date getDate() {
for (int i = 0; i < info.length() - 9; i++) {
if (Character.isWhitespace(info.charAt(i))) {
String dateString = info.substring(i + 1, i + 9);
try {
synchronized (formatter) {
return formatter.parse(dateString);
}
} catch (ParseException pe) {
}
break;
}
}
return null;
}
@Override
public String toString() {
return info;
}
}

View File

@@ -0,0 +1,26 @@
package com.maxmind.geoip;
import java.io.IOException;
/**
* Signals that there was an issue reading from the database file due to
* unexpected data formatting. This generally suggests that the database is
* corrupt or otherwise not in a format supported by the reader.
*/
public final class InvalidDatabaseException extends RuntimeException {
/**
* @param message A message describing the reason why the exception was thrown.
*/
public InvalidDatabaseException(String message) {
super(message);
}
/**
* @param message A message describing the reason why the exception was thrown.
* @param cause The cause of the exception.
*/
public InvalidDatabaseException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,62 @@
/**
* Location.java
*
* Copyright (C) 2004 MaxMind LLC. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Lesser Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.maxmind.geoip;
public class Location {
public String countryCode;
public String countryName;
public String region;
public String city;
public String postalCode;
public float latitude;
public float longitude;
public int dma_code;
public int area_code;
public int metro_code;
private final static double EARTH_DIAMETER = 2 * 6378.2;
private final static double PI = 3.14159265;
private final static double RAD_CONVERT = PI / 180;
public double distance(Location loc) {
double delta_lat, delta_lon;
double temp;
float lat1 = latitude;
float lon1 = longitude;
float lat2 = loc.latitude;
float lon2 = loc.longitude;
// convert degrees to radians
lat1 *= RAD_CONVERT;
lat2 *= RAD_CONVERT;
// find the deltas
delta_lat = lat2 - lat1;
delta_lon = (lon2 - lon1) * RAD_CONVERT;
// Find the great circle distance
temp = Math.pow(Math.sin(delta_lat / 2), 2) + Math.cos(lat1)
* Math.cos(lat2) * Math.pow(Math.sin(delta_lon / 2), 2);
return EARTH_DIAMETER
* Math.atan2(Math.sqrt(temp), Math.sqrt(1 - temp));
}
}

View File

@@ -0,0 +1,988 @@
/*
* LookupService.java
*
* Copyright (C) 2003 MaxMind LLC. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option) any
* later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.maxmind.geoip;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Arrays;
import java.util.List;
/**
* Provides a lookup service for information based on an IP address. The
* location of a database file is supplied when creating a lookup service
* instance. The edition of the database determines what information is
* available about an IP address. See the DatabaseInfo class for further
* details.
* <p>
*
* The following code snippet demonstrates looking up the country that an IP
* address is from:
*
* <pre>
* // First, create a LookupService instance with the location of the database.
* LookupService lookupService = new LookupService(&quot;c:\\geoip.dat&quot;);
* // Assume we have a String ipAddress (in dot-decimal form).
* Country country = lookupService.getCountry(ipAddress);
* System.out.println(&quot;The country is: &quot; + country.getName());
* System.out.println(&quot;The country code is: &quot; + country.getCode());
* </pre>
*
* In general, a single LookupService instance should be created and then reused
* repeatedly.
* <p>
*
* <i>Tip:</i> Those deploying the GeoIP API as part of a web application may
* find it difficult to pass in a File to create the lookup service, as the
* location of the database may vary per deployment or may even be part of the
* web-application. In this case, the database should be added to the classpath
* of the web-app. For example, by putting it into the WEB-INF/classes directory
* of the web application. The following code snippet demonstrates how to create
* a LookupService using a database that can be found on the classpath:
*
* <pre>
* String fileName = getClass().getResource(&quot;/GeoIP.dat&quot;).toExternalForm()
* .substring(6);
* LookupService lookupService = new LookupService(fileName);
* </pre>
*
* @author Matt Tucker (matt@jivesoftware.com)
*/
public class LookupService {
/**
* Database file.
*/
private RandomAccessFile file;
private final File databaseFile;
/**
* Information about the database.
*/
private DatabaseInfo databaseInfo;
private static final Charset charset = Charset.forName("ISO-8859-1");
private final CharsetDecoder charsetDecoder = charset.newDecoder();
/**
* The database type. Default is the country edition.
*/
private byte databaseType = DatabaseInfo.COUNTRY_EDITION;
private int[] databaseSegments;
private int recordLength;
private int dboptions;
private byte[] dbbuffer;
private byte[] index_cache;
private long mtime;
private int last_netmask;
private static final int US_OFFSET = 1;
private static final int CANADA_OFFSET = 677;
private static final int WORLD_OFFSET = 1353;
private static final int FIPS_RANGE = 360;
private static final int COUNTRY_BEGIN = 16776960;
private static final int STATE_BEGIN_REV0 = 16700000;
private static final int STATE_BEGIN_REV1 = 16000000;
private static final int STRUCTURE_INFO_MAX_SIZE = 20;
private static final int DATABASE_INFO_MAX_SIZE = 100;
public static final int GEOIP_STANDARD = 0;
public static final int GEOIP_MEMORY_CACHE = 1;
public static final int GEOIP_CHECK_CACHE = 2;
public static final int GEOIP_INDEX_CACHE = 4;
public static final int GEOIP_UNKNOWN_SPEED = 0;
public static final int GEOIP_DIALUP_SPEED = 1;
public static final int GEOIP_CABLEDSL_SPEED = 2;
public static final int GEOIP_CORPORATE_SPEED = 3;
private static final int SEGMENT_RECORD_LENGTH = 3;
private static final int STANDARD_RECORD_LENGTH = 3;
private static final int ORG_RECORD_LENGTH = 4;
private static final int MAX_RECORD_LENGTH = 4;
private static final int MAX_ORG_RECORD_LENGTH = 300;
private static final int FULL_RECORD_LENGTH = 60;
private final Country UNKNOWN_COUNTRY = new Country("--", "N/A");
private static final String[] countryCode = { "--", "AP", "EU", "AD", "AE",
"AF", "AG", "AI", "AL", "AM", "CW", "AO", "AQ", "AR", "AS", "AT",
"AU", "AW", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI",
"BJ", "BM", "BN", "BO", "BR", "BS", "BT", "BV", "BW", "BY", "BZ",
"CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN",
"CO", "CR", "CU", "CV", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM",
"DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ",
"FK", "FM", "FO", "FR", "SX", "GA", "GB", "GD", "GE", "GF", "GH",
"GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", "GW",
"GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN",
"IO", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH",
"KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC",
"LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD",
"MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS",
"MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF",
"NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE",
"PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW",
"PY", "QA", "RE", "RO", "RU", "RW", "SA", "SB", "SC", "SD", "SE",
"SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "ST",
"SV", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", "TJ", "TK", "TM",
"TN", "TO", "TL", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM",
"US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF",
"WS", "YE", "YT", "RS", "ZA", "ZM", "ME", "ZW", "A1", "A2", "O1",
"AX", "GG", "IM", "JE", "BL", "MF", "BQ", "SS", "O1" };
private static final String[] countryName = { "N/A", "Asia/Pacific Region",
"Europe", "Andorra", "United Arab Emirates", "Afghanistan",
"Antigua and Barbuda", "Anguilla", "Albania", "Armenia", "Curacao",
"Angola", "Antarctica", "Argentina", "American Samoa", "Austria",
"Australia", "Aruba", "Azerbaijan", "Bosnia and Herzegovina",
"Barbados", "Bangladesh", "Belgium", "Burkina Faso", "Bulgaria",
"Bahrain", "Burundi", "Benin", "Bermuda", "Brunei Darussalam",
"Bolivia", "Brazil", "Bahamas", "Bhutan", "Bouvet Island",
"Botswana", "Belarus", "Belize", "Canada",
"Cocos (Keeling) Islands", "Congo, The Democratic Republic of the",
"Central African Republic", "Congo", "Switzerland",
"Cote D'Ivoire", "Cook Islands", "Chile", "Cameroon", "China",
"Colombia", "Costa Rica", "Cuba", "Cape Verde", "Christmas Island",
"Cyprus", "Czech Republic", "Germany", "Djibouti", "Denmark",
"Dominica", "Dominican Republic", "Algeria", "Ecuador", "Estonia",
"Egypt", "Western Sahara", "Eritrea", "Spain", "Ethiopia",
"Finland", "Fiji", "Falkland Islands (Malvinas)",
"Micronesia, Federated States of", "Faroe Islands", "France",
"Sint Maarten (Dutch part)", "Gabon", "United Kingdom", "Grenada",
"Georgia", "French Guiana", "Ghana", "Gibraltar", "Greenland",
"Gambia", "Guinea", "Guadeloupe", "Equatorial Guinea", "Greece",
"South Georgia and the South Sandwich Islands", "Guatemala",
"Guam", "Guinea-Bissau", "Guyana", "Hong Kong",
"Heard Island and McDonald Islands", "Honduras", "Croatia",
"Haiti", "Hungary", "Indonesia", "Ireland", "Israel", "India",
"British Indian Ocean Territory", "Iraq",
"Iran, Islamic Republic of", "Iceland", "Italy", "Jamaica",
"Jordan", "Japan", "Kenya", "Kyrgyzstan", "Cambodia", "Kiribati",
"Comoros", "Saint Kitts and Nevis",
"Korea, Democratic People's Republic of", "Korea, Republic of",
"Kuwait", "Cayman Islands", "Kazakhstan",
"Lao People's Democratic Republic", "Lebanon", "Saint Lucia",
"Liechtenstein", "Sri Lanka", "Liberia", "Lesotho", "Lithuania",
"Luxembourg", "Latvia", "Libya", "Morocco", "Monaco",
"Moldova, Republic of", "Madagascar", "Marshall Islands",
"Macedonia", "Mali", "Myanmar", "Mongolia", "Macau",
"Northern Mariana Islands", "Martinique", "Mauritania",
"Montserrat", "Malta", "Mauritius", "Maldives", "Malawi", "Mexico",
"Malaysia", "Mozambique", "Namibia", "New Caledonia", "Niger",
"Norfolk Island", "Nigeria", "Nicaragua", "Netherlands", "Norway",
"Nepal", "Nauru", "Niue", "New Zealand", "Oman", "Panama", "Peru",
"French Polynesia", "Papua New Guinea", "Philippines", "Pakistan",
"Poland", "Saint Pierre and Miquelon", "Pitcairn Islands",
"Puerto Rico", "Palestinian Territory", "Portugal", "Palau",
"Paraguay", "Qatar", "Reunion", "Romania", "Russian Federation",
"Rwanda", "Saudi Arabia", "Solomon Islands", "Seychelles", "Sudan",
"Sweden", "Singapore", "Saint Helena", "Slovenia",
"Svalbard and Jan Mayen", "Slovakia", "Sierra Leone", "San Marino",
"Senegal", "Somalia", "Suriname", "Sao Tome and Principe",
"El Salvador", "Syrian Arab Republic", "Swaziland",
"Turks and Caicos Islands", "Chad", "French Southern Territories",
"Togo", "Thailand", "Tajikistan", "Tokelau", "Turkmenistan",
"Tunisia", "Tonga", "Timor-Leste", "Turkey", "Trinidad and Tobago",
"Tuvalu", "Taiwan", "Tanzania, United Republic of", "Ukraine",
"Uganda", "United States Minor Outlying Islands", "United States",
"Uruguay", "Uzbekistan", "Holy See (Vatican City State)",
"Saint Vincent and the Grenadines", "Venezuela",
"Virgin Islands, British", "Virgin Islands, U.S.", "Vietnam",
"Vanuatu", "Wallis and Futuna", "Samoa", "Yemen", "Mayotte",
"Serbia", "South Africa", "Zambia", "Montenegro", "Zimbabwe",
"Anonymous Proxy", "Satellite Provider", "Other", "Aland Islands",
"Guernsey", "Isle of Man", "Jersey", "Saint Barthelemy",
"Saint Martin", "Bonaire, Saint Eustatius and Saba", "South Sudan",
"Other" };
/* init the hashmap once at startup time */
static {
if (countryCode.length != countryName.length) {
throw new AssertionError("countryCode.length!=countryName.length");
}
}
/**
* Create a new lookup service using the specified database file.
*
* @param databaseFile
* String representation of the database file.
* @throws IOException
* if an error occured creating the lookup service from the
* database file.
*/
public LookupService(String databaseFile) throws IOException {
this(new File(databaseFile));
}
/**
* Create a new lookup service using the specified database file.
*
* @param databaseFile
* the database file.
* @throws IOException
* if an error occured creating the lookup service from the
* database file.
*/
public LookupService(File databaseFile) throws IOException {
this.databaseFile = databaseFile;
file = new RandomAccessFile(databaseFile, "r");
init();
}
/**
* Create a new lookup service using the specified database file.
*
* @param databaseFile
* String representation of the database file.
* @param options
* database flags to use when opening the database GEOIP_STANDARD
* read database from disk GEOIP_MEMORY_CACHE cache the database
* in RAM and read it from RAM
* @throws IOException
* if an error occured creating the lookup service from the
* database file.
*/
public LookupService(String databaseFile, int options) throws IOException {
this(new File(databaseFile), options);
}
/**
* Create a new lookup service using the specified database file.
*
* @param databaseFile
* the database file.
* @param options
* database flags to use when opening the database GEOIP_STANDARD
* read database from disk GEOIP_MEMORY_CACHE cache the database
* in RAM and read it from RAM
* @throws IOException
* if an error occured creating the lookup service from the
* database file.
*/
public LookupService(File databaseFile, int options) throws IOException {
this.databaseFile = databaseFile;
file = new RandomAccessFile(databaseFile, "r");
dboptions = options;
init();
}
/**
* Reads meta-data from the database file.
*
* @throws IOException
* if an error occurs reading from the database file.
*/
private synchronized void init() throws IOException {
byte[] delim = new byte[3];
byte[] buf = new byte[SEGMENT_RECORD_LENGTH];
if (file == null) {
return;
}
if ((dboptions & GEOIP_CHECK_CACHE) != 0) {
mtime = databaseFile.lastModified();
}
file.seek(file.length() - 3);
for (int i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
file.readFully(delim);
if (delim[0] == -1 && delim[1] == -1 && delim[2] == -1) {
databaseType = file.readByte();
if (databaseType >= 106) {
// Backward compatibility with databases from April 2003 and
// earlier
databaseType -= 105;
}
// Determine the database type.
if (databaseType == DatabaseInfo.REGION_EDITION_REV0) {
databaseSegments = new int[1];
databaseSegments[0] = STATE_BEGIN_REV0;
recordLength = STANDARD_RECORD_LENGTH;
} else if (databaseType == DatabaseInfo.REGION_EDITION_REV1) {
databaseSegments = new int[1];
databaseSegments[0] = STATE_BEGIN_REV1;
recordLength = STANDARD_RECORD_LENGTH;
} else if (databaseType == DatabaseInfo.CITY_EDITION_REV0
|| databaseType == DatabaseInfo.CITY_EDITION_REV1
|| databaseType == DatabaseInfo.ORG_EDITION
|| databaseType == DatabaseInfo.ORG_EDITION_V6
|| databaseType == DatabaseInfo.ISP_EDITION
|| databaseType == DatabaseInfo.ISP_EDITION_V6
|| databaseType == DatabaseInfo.DOMAIN_EDITION
|| databaseType == DatabaseInfo.DOMAIN_EDITION_V6
|| databaseType == DatabaseInfo.ASNUM_EDITION
|| databaseType == DatabaseInfo.ASNUM_EDITION_V6
|| databaseType == DatabaseInfo.NETSPEED_EDITION_REV1
|| databaseType == DatabaseInfo.NETSPEED_EDITION_REV1_V6
|| databaseType == DatabaseInfo.CITY_EDITION_REV0_V6
|| databaseType == DatabaseInfo.CITY_EDITION_REV1_V6) {
databaseSegments = new int[1];
databaseSegments[0] = 0;
if (databaseType == DatabaseInfo.CITY_EDITION_REV0
|| databaseType == DatabaseInfo.CITY_EDITION_REV1
|| databaseType == DatabaseInfo.ASNUM_EDITION_V6
|| databaseType == DatabaseInfo.NETSPEED_EDITION_REV1
|| databaseType == DatabaseInfo.NETSPEED_EDITION_REV1_V6
|| databaseType == DatabaseInfo.CITY_EDITION_REV0_V6
|| databaseType == DatabaseInfo.CITY_EDITION_REV1_V6
|| databaseType == DatabaseInfo.ASNUM_EDITION) {
recordLength = STANDARD_RECORD_LENGTH;
} else {
recordLength = ORG_RECORD_LENGTH;
}
file.readFully(buf);
for (int j = 0; j < SEGMENT_RECORD_LENGTH; j++) {
databaseSegments[0] += (unsignedByteToInt(buf[j]) << (j * 8));
}
}
break;
} else {
file.seek(file.getFilePointer() - 4);
}
}
if ((databaseType == DatabaseInfo.COUNTRY_EDITION)
|| (databaseType == DatabaseInfo.COUNTRY_EDITION_V6)
|| (databaseType == DatabaseInfo.PROXY_EDITION)
|| (databaseType == DatabaseInfo.NETSPEED_EDITION)) {
databaseSegments = new int[1];
databaseSegments[0] = COUNTRY_BEGIN;
recordLength = STANDARD_RECORD_LENGTH;
}
if ((dboptions & GEOIP_MEMORY_CACHE) == 1) {
int l = (int) file.length();
dbbuffer = new byte[l];
file.seek(0);
file.readFully(dbbuffer, 0, l);
databaseInfo = getDatabaseInfo();
file.close();
}
if ((dboptions & GEOIP_INDEX_CACHE) != 0) {
int l = databaseSegments[0] * recordLength * 2;
index_cache = new byte[l];
file.seek(0);
file.readFully(index_cache, 0, l);
} else {
index_cache = null;
}
}
/**
* Closes the lookup service.
*/
public synchronized void close() {
try {
if (file != null) {
file.close();
}
file = null;
} catch (IOException e) {
// Here for backward compatibility.
}
}
/**
* @return The list of all known country names
*/
public List<String> getAllCountryNames() {
return Arrays.asList(Arrays.copyOf(countryName, countryName.length));
}
/**
* @return The list of all known country codes
*/
public List<String> getAllCountryCodes() {
return Arrays.asList(Arrays.copyOf(countryCode, countryCode.length));
}
/**
* Returns the country the IP address is in.
*
* @param ipAddress
* String version of an IPv6 address, i.e. "::127.0.0.1"
* @return the country the IP address is from.
*/
public Country getCountryV6(String ipAddress) {
InetAddress addr;
try {
addr = InetAddress.getByName(ipAddress);
} catch (UnknownHostException e) {
return UNKNOWN_COUNTRY;
}
return getCountryV6(addr);
}
/**
* Returns the country the IP address is in.
*
* @param ipAddress
* String version of an IP address, i.e. "127.0.0.1"
* @return the country the IP address is from.
*/
public Country getCountry(String ipAddress) {
InetAddress addr;
try {
addr = InetAddress.getByName(ipAddress);
} catch (UnknownHostException e) {
return UNKNOWN_COUNTRY;
}
return getCountry(addr);
}
/**
* Returns the country the IP address is in.
*
* @param ipAddress
* the IP address.
* @return the country the IP address is from.
*/
public synchronized Country getCountry(InetAddress ipAddress) {
return getCountry(bytesToLong(ipAddress.getAddress()));
}
/**
* Returns the country the IP address is in.
*
* @param addr
* the IP address as Inet6Address.
* @return the country the IP address is from.
*/
public synchronized Country getCountryV6(InetAddress addr) {
if (file == null && (dboptions & GEOIP_MEMORY_CACHE) == 0) {
throw new IllegalStateException("Database has been closed.");
}
int ret = seekCountryV6(addr) - COUNTRY_BEGIN;
if (ret == 0) {
return UNKNOWN_COUNTRY;
} else {
return new Country(countryCode[ret], countryName[ret]);
}
}
/**
* Returns the country the IP address is in.
*
* @param ipAddress
* the IP address in long format.
* @return the country the IP address is from.
*/
public synchronized Country getCountry(long ipAddress) {
if (file == null && (dboptions & GEOIP_MEMORY_CACHE) == 0) {
throw new IllegalStateException("Database has been closed.");
}
int ret = seekCountry(ipAddress) - COUNTRY_BEGIN;
if (ret == 0) {
return UNKNOWN_COUNTRY;
} else {
return new Country(countryCode[ret], countryName[ret]);
}
}
public int getID(String ipAddress) {
InetAddress addr;
try {
addr = InetAddress.getByName(ipAddress);
} catch (UnknownHostException e) {
return 0;
}
return getID(bytesToLong(addr.getAddress()));
}
public int getID(InetAddress ipAddress) {
return getID(bytesToLong(ipAddress.getAddress()));
}
public synchronized int getID(long ipAddress) {
if (file == null && (dboptions & GEOIP_MEMORY_CACHE) == 0) {
throw new IllegalStateException("Database has been closed.");
}
return seekCountry(ipAddress) - databaseSegments[0];
}
public int last_netmask() {
return last_netmask;
}
public void netmask(int nm) {
last_netmask = nm;
}
/**
* Returns information about the database.
*
* @return database info.
*/
public synchronized DatabaseInfo getDatabaseInfo() {
if (databaseInfo != null) {
return databaseInfo;
}
try {
_check_mtime();
boolean hasStructureInfo = false;
byte[] delim = new byte[3];
// Advance to part of file where database info is stored.
file.seek(file.length() - 3);
for (int i = 0; i < STRUCTURE_INFO_MAX_SIZE; i++) {
int read = file.read(delim);
if (read == 3 && (delim[0] & 0xFF) == 255
&& (delim[1] & 0xFF) == 255 && (delim[2] & 0xFF) == 255) {
hasStructureInfo = true;
break;
}
file.seek(file.getFilePointer() - 4);
}
if (hasStructureInfo) {
file.seek(file.getFilePointer() - 6);
} else {
// No structure info, must be pre Sep 2002 database, go back to
// end.
file.seek(file.length() - 3);
}
// Find the database info string.
for (int i = 0; i < DATABASE_INFO_MAX_SIZE; i++) {
file.readFully(delim);
if (delim[0] == 0 && delim[1] == 0 && delim[2] == 0) {
byte[] dbInfo = new byte[i];
file.readFully(dbInfo);
// Create the database info object using the string.
databaseInfo = new DatabaseInfo(new String(dbInfo, charset));
return databaseInfo;
}
file.seek(file.getFilePointer() - 4);
}
} catch (IOException e) {
throw new InvalidDatabaseException("Error reading database info", e);
}
return new DatabaseInfo("");
}
synchronized void _check_mtime() {
try {
if ((dboptions & GEOIP_CHECK_CACHE) != 0) {
long t = databaseFile.lastModified();
if (t != mtime) {
/* GeoIP Database file updated */
/* refresh filehandle */
close();
file = new RandomAccessFile(databaseFile, "r");
databaseInfo = null;
init();
}
}
} catch (IOException e) {
throw new InvalidDatabaseException("Database not found", e);
}
}
// for GeoIP City only
public Location getLocationV6(String str) {
InetAddress addr;
try {
addr = InetAddress.getByName(str);
} catch (UnknownHostException e) {
return null;
}
return getLocationV6(addr);
}
// for GeoIP City only
public Location getLocation(InetAddress addr) {
return getLocation(bytesToLong(addr.getAddress()));
}
// for GeoIP City only
public Location getLocation(String str) {
InetAddress addr;
try {
addr = InetAddress.getByName(str);
} catch (UnknownHostException e) {
return null;
}
return getLocation(addr);
}
public synchronized Region getRegion(String str) {
InetAddress addr;
try {
addr = InetAddress.getByName(str);
} catch (UnknownHostException e) {
return null;
}
return getRegion(bytesToLong(addr.getAddress()));
}
public synchronized Region getRegion(InetAddress addr) {
return getRegion(bytesToLong(addr.getAddress()));
}
public synchronized Region getRegion(long ipnum) {
Region record = new Region();
int seek_region;
if (databaseType == DatabaseInfo.REGION_EDITION_REV0) {
seek_region = seekCountry(ipnum) - STATE_BEGIN_REV0;
char[] ch = new char[2];
if (seek_region >= 1000) {
record.countryCode = "US";
record.countryName = "United States";
ch[0] = (char) (((seek_region - 1000) / 26) + 65);
ch[1] = (char) (((seek_region - 1000) % 26) + 65);
record.region = new String(ch);
} else {
record.countryCode = countryCode[seek_region];
record.countryName = countryName[seek_region];
record.region = "";
}
} else if (databaseType == DatabaseInfo.REGION_EDITION_REV1) {
seek_region = seekCountry(ipnum) - STATE_BEGIN_REV1;
char[] ch = new char[2];
if (seek_region < US_OFFSET) {
record.countryCode = "";
record.countryName = "";
record.region = "";
} else if (seek_region < CANADA_OFFSET) {
record.countryCode = "US";
record.countryName = "United States";
ch[0] = (char) (((seek_region - US_OFFSET) / 26) + 65);
ch[1] = (char) (((seek_region - US_OFFSET) % 26) + 65);
record.region = new String(ch);
} else if (seek_region < WORLD_OFFSET) {
record.countryCode = "CA";
record.countryName = "Canada";
ch[0] = (char) (((seek_region - CANADA_OFFSET) / 26) + 65);
ch[1] = (char) (((seek_region - CANADA_OFFSET) % 26) + 65);
record.region = new String(ch);
} else {
record.countryCode = countryCode[(seek_region - WORLD_OFFSET)
/ FIPS_RANGE];
record.countryName = countryName[(seek_region - WORLD_OFFSET)
/ FIPS_RANGE];
record.region = "";
}
}
return record;
}
public synchronized Location getLocationV6(InetAddress addr) {
int seek_country;
try {
seek_country = seekCountryV6(addr);
return readCityRecord(seek_country);
} catch (IOException e) {
throw new InvalidDatabaseException("Error while seting up segments", e);
}
}
public synchronized Location getLocation(long ipnum) {
int seek_country;
try {
seek_country = seekCountry(ipnum);
return readCityRecord(seek_country);
} catch (IOException e) {
throw new InvalidDatabaseException("Error while seting up segments", e);
}
}
private Location readCityRecord(int seekCountry) throws IOException {
if (seekCountry == databaseSegments[0]) {
return null;
}
ByteBuffer buffer = readRecordBuf(seekCountry, FULL_RECORD_LENGTH);
Location record = new Location();
int country = unsignedByteToInt(buffer.get());
// get country
record.countryCode = countryCode[country];
record.countryName = countryName[country];
record.region = readString(buffer);
record.city = readString(buffer);
record.postalCode = readString(buffer);
record.latitude = readAngle(buffer);
record.longitude = readAngle(buffer);
if (databaseType == DatabaseInfo.CITY_EDITION_REV1) {
// get DMA code
if ("US".equals(record.countryCode)) {
int metroarea_combo = readMetroAreaCombo(buffer);
record.metro_code = record.dma_code = metroarea_combo / 1000;
record.area_code = metroarea_combo % 1000;
}
}
return record;
}
private ByteBuffer readRecordBuf(int seek, int maxLength) throws IOException {
int recordPointer = seek + (2 * recordLength - 1)
* databaseSegments[0];
ByteBuffer buffer;
if ((dboptions & GEOIP_MEMORY_CACHE) == 1) {
buffer = ByteBuffer.wrap(dbbuffer, recordPointer, Math
.min(dbbuffer.length - recordPointer, maxLength));
} else {
byte[] recordBuf = new byte[maxLength];
// read from disk
file.seek(recordPointer);
file.read(recordBuf);
buffer = ByteBuffer.wrap(recordBuf);
}
return buffer;
}
private String readString(ByteBuffer buffer) throws CharacterCodingException {
int start = buffer.position();
int oldLimit = buffer.limit();
while (buffer.hasRemaining() && buffer.get() != 0) {}
int end = buffer.position() - 1;
String str = null;
if (end > start) {
buffer.position(start);
buffer.limit(end);
str = charsetDecoder.decode(buffer).toString();
buffer.limit(oldLimit);
}
buffer.position(end + 1);
return str;
}
private static float readAngle(ByteBuffer buffer) {
if (buffer.remaining() < 3) {
throw new InvalidDatabaseException("Unexpected end of data record when reading angle");
}
double num = 0;
for (int j = 0; j < 3; j++) {
num += unsignedByteToInt(buffer.get()) << (j * 8);
}
return (float) num / 10000 - 180;
}
private static int readMetroAreaCombo(ByteBuffer buffer) {
if (buffer.remaining() < 3) {
throw new InvalidDatabaseException("Unexpected end of data record when reading metro area");
}
int metroareaCombo = 0;
for (int j = 0; j < 3; j++) {
metroareaCombo += unsignedByteToInt(buffer.get()) << (j * 8);
}
return metroareaCombo;
}
public String getOrg(InetAddress addr) {
return getOrg(bytesToLong(addr.getAddress()));
}
public String getOrg(String str) {
InetAddress addr;
try {
addr = InetAddress.getByName(str);
} catch (UnknownHostException e) {
return null;
}
return getOrg(addr);
}
// GeoIP Organization and ISP Edition methods
public synchronized String getOrg(long ipnum) {
try {
int seekOrg = seekCountry(ipnum);
return readOrgRecord(seekOrg);
} catch (IOException e) {
throw new InvalidDatabaseException("Error while reading org", e);
}
}
public String getOrgV6(String str) {
InetAddress addr;
try {
addr = InetAddress.getByName(str);
} catch (UnknownHostException e) {
return null;
}
return getOrgV6(addr);
}
// GeoIP Organization and ISP Edition methods
public synchronized String getOrgV6(InetAddress addr) {
try {
int seekOrg = seekCountryV6(addr);
return readOrgRecord(seekOrg);
} catch (IOException e) {
throw new InvalidDatabaseException("Error while reading org", e);
}
}
private String readOrgRecord(int seekOrg) throws IOException {
if (seekOrg == databaseSegments[0]) {
return null;
}
ByteBuffer buf = readRecordBuf(seekOrg, MAX_ORG_RECORD_LENGTH);
return readString(buf);
}
/**
* Finds the country index value given an IPv6 address.
*
* @param addr
* the ip address to find in long format.
* @return the country index.
*/
private synchronized int seekCountryV6(InetAddress addr) {
byte[] v6vec = addr.getAddress();
if (v6vec.length == 4) {
// sometimes java returns an ipv4 address for IPv6 input
// we have to work around that feature
// It happens for ::ffff:24.24.24.24
byte[] t = new byte[16];
System.arraycopy(v6vec, 0, t, 12, 4);
v6vec = t;
}
byte[] buf = new byte[2 * MAX_RECORD_LENGTH];
int[] x = new int[2];
int offset = 0;
_check_mtime();
for (int depth = 127; depth >= 0; depth--) {
readNode(buf, x, offset);
int bnum = 127 - depth;
int idx = bnum >> 3;
int b_mask = 1 << (bnum & 7 ^ 7);
if ((v6vec[idx] & b_mask) > 0) {
if (x[1] >= databaseSegments[0]) {
last_netmask = 128 - depth;
return x[1];
}
offset = x[1];
} else {
if (x[0] >= databaseSegments[0]) {
last_netmask = 128 - depth;
return x[0];
}
offset = x[0];
}
}
throw new InvalidDatabaseException("Error seeking country while searching for "
+ addr.getHostAddress());
}
/**
* Finds the country index value given an IP address.
*
* @param ipAddress
* the ip address to find in long format.
* @return the country index.
*/
private synchronized int seekCountry(long ipAddress) {
byte[] buf = new byte[2 * MAX_RECORD_LENGTH];
int[] x = new int[2];
int offset = 0;
_check_mtime();
for (int depth = 31; depth >= 0; depth--) {
readNode(buf, x, offset);
if ((ipAddress & (1 << depth)) > 0) {
if (x[1] >= databaseSegments[0]) {
last_netmask = 32 - depth;
return x[1];
}
offset = x[1];
} else {
if (x[0] >= databaseSegments[0]) {
last_netmask = 32 - depth;
return x[0];
}
offset = x[0];
}
}
throw new InvalidDatabaseException("Error seeking country while searching for "
+ ipAddress);
}
private void readNode(byte[] buf, int[] x, int offset) {
if ((dboptions & GEOIP_MEMORY_CACHE) == 1) {
// read from memory
System.arraycopy(dbbuffer, (2 * recordLength * offset), buf, 0, 2 * recordLength);
} else if ((dboptions & GEOIP_INDEX_CACHE) != 0) {
// read from index cache
System.arraycopy(index_cache, (2 * recordLength * offset), buf, 0, 2 * recordLength);
} else {
// read from disk
try {
file.seek(2 * recordLength * offset);
file.read(buf);
} catch (IOException e) {
throw new InvalidDatabaseException("Error seeking in database", e);
}
}
for (int i = 0; i < 2; i++) {
x[i] = 0;
for (int j = 0; j < recordLength; j++) {
int y = buf[i * recordLength + j];
if (y < 0) {
y += 256;
}
x[i] += (y << (j * 8));
}
}
}
/**
* Returns the long version of an IP address given an InetAddress object.
*
* @param address
* the InetAddress.
* @return the long form of the IP address.
*/
private static long bytesToLong(byte[] address) {
long ipnum = 0;
for (int i = 0; i < 4; ++i) {
long y = address[i];
if (y < 0) {
y += 256;
}
ipnum += y << ((3 - i) * 8);
}
return ipnum;
}
private static int unsignedByteToInt(byte b) {
return (int) b & 0xFF;
}
}

View File

@@ -0,0 +1,7 @@
package com.maxmind.geoip;
public class Region {
public String countryCode;
public String countryName;
public String region;
}

View File

@@ -0,0 +1,15 @@
<html>
<body>
<p>
This is geoip-api-java release 1.3.1 2016-02-08
retrieved from <a href="https://github.com/maxmind/geoip-api-java">github</a>.
It is used only on Debian-based systems where the geoip-database package
is installed, with the files in /usr/share/GeoIP/ .
See net.i2p.router.transport.GeoIP.
</p><p>
Unmodified, except that
regionName.java and timeZone.java are omitted.
LGPL v2.1.
</p>
</body>
</html>

View File

@@ -503,8 +503,8 @@ public class RouterInfo extends DatabaseEntry {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(RouterInfo.class);
if (log.shouldWarn()) {
log.warn("Sig verify fail: " + toString(), new Exception("from"));
} else {
log.error("RI Sig verify fail: " + _identity.getHash());
//} else {
// log.error("RI Sig verify fail: " + _identity.getHash());
}
}
}

View File

@@ -14,6 +14,7 @@ import java.util.List;
public class CommandLine extends net.i2p.util.CommandLine {
protected static final List<String> RCLASSES = Arrays.asList(new String[] {
"net.i2p.data.router.RouterInfo",
"net.i2p.router.MultiRouter",
"net.i2p.router.Router",
"net.i2p.router.RouterLaunch",

View File

@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 13;
public final static long BUILD = 17;
/** for example "-test" */
public final static String EXTRA = "-rc";

View File

@@ -10,6 +10,8 @@ package net.i2p.router.client;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -123,10 +125,30 @@ class ClientManager {
protected void startListeners() {
ClientListenerRunner listener;
if (SystemVersion.isAndroid()) {
listener = new DomainClientListenerRunner(_ctx, this);
Thread t = new I2PThread(listener, "DomainClientListener", true);
t.start();
_listeners.add(listener);
try {
Class<? extends ClientListenerRunner> clazz = Class.forName(
"net.i2p.router.client.DomainClientListenerRunner"
).asSubclass(ClientListenerRunner.class);
Constructor<? extends ClientListenerRunner> ctor =
clazz.getDeclaredConstructor(RouterContext.class,
ClientManager.class);
listener = ctor.newInstance(_ctx, this);
Thread t = new I2PThread(listener, "DomainClientListener", true);
t.start();
_listeners.add(listener);
} catch (ClassNotFoundException e) {
_log.warn("Could not find DomainClientListenerRunner class", e);
} catch (ClassCastException e) {
_log.error("Error creating DomainClientListenerRunner", e);
} catch (NoSuchMethodException e) {
_log.error("Error creating DomainClientListenerRunner", e);
} catch (InstantiationException e) {
_log.error("Error creating DomainClientListenerRunner", e);
} catch (IllegalAccessException e) {
_log.error("Error creating DomainClientListenerRunner", e);
} catch (InvocationTargetException e) {
_log.error("Error creating DomainClientListenerRunner", e);
}
}
if (!_ctx.getBooleanProperty(PROP_DISABLE_EXTERNAL)) {
// there's no option to start both an SSL and non-SSL listener

View File

@@ -407,6 +407,8 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
/**
* The client asked for a message, so we send it to them.
*
* This is only when not in fast receive mode.
* In the default fast receive mode, data is sent in MessageReceivedJob.
*/
private void handleReceiveBegin(ReceiveMessageBeginMessage message) {
if (_runner.isDead()) return;
@@ -427,8 +429,11 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
try {
_runner.doSend(msg);
} catch (I2CPMessageException ime) {
if (_log.shouldLog(Log.WARN))
_log.warn("Error delivering the payload", ime);
String emsg = "Error sending data to client " + _runner.getDestHash();
if (_log.shouldWarn())
_log.warn(emsg, ime);
else
_log.logAlways(Log.WARN, emsg);
_runner.removePayload(new MessageId(message.getMessageId()));
}
}

View File

@@ -1,31 +0,0 @@
package net.i2p.router.client;
import java.io.IOException;
import java.net.ServerSocket;
import net.i2p.client.DomainSocketFactory;
import net.i2p.router.RouterContext;
/**
* Unix domain socket version of ClientListenerRunner.
* <p/>
* This is a stub that does nothing.
* This class is replaced in the Android build.
*
* @author str4d
* @since 0.9.14
*/
public class DomainClientListenerRunner extends ClientListenerRunner {
public DomainClientListenerRunner(RouterContext context, ClientManager manager) {
super(context, manager, -1);
}
/**
* @throws IOException
*/
@Override
protected ServerSocket getServerSocket() throws IOException {
final DomainSocketFactory fact = new DomainSocketFactory(_context);
return fact.createServerSocket(DomainSocketFactory.I2CP_SOCKET_ADDRESS);
}
}

View File

@@ -60,8 +60,11 @@ class MessageReceivedJob extends JobImpl {
messageAvailable(id, _payload.getSize());
}
} catch (I2CPMessageException ime) {
if (_log.shouldLog(Log.WARN))
_log.warn("Error writing out the message", ime);
String msg = "Error sending data to client " + _runner.getDestHash();
if (_log.shouldWarn())
_log.warn(msg, ime);
else
_log.logAlways(Log.WARN, msg);
if (id != null && !_sendDirect)
_runner.removePayload(id);
}

View File

@@ -63,6 +63,8 @@ public class Reseeder {
private static final boolean ENABLE_SU3 = true;
/** if false, use su3 only, and disable fallback reading directory index and individual dat files */
private static final boolean ENABLE_NON_SU3 = false;
private static final int MIN_RI_WANTED = 100;
private static final int MIN_RESEED_SERVERS = 2;
/**
* NOTE - URLs that are in both the standard and SSL groups must use the same hostname,
@@ -83,19 +85,39 @@ public class Reseeder {
//"http://netdb.i2p2.no/"; // Only SU3 (v3) support
"";
/** @since 0.8.2 */
/**
* The I2P reseed servers are managed by backup (backup@mail.i2p).
* Please contact him for support, change requests, or issues.
* See also the reseed forum http://zzz.i2p/forums/18
* and the reseed setup and testing guide
* https://geti2p.net/en/get-involved/guides/reseed
*
* All supported reseed hosts need a corresponding reseed (SU3)
* signing certificate installed in the router.
*
* All supported reseed hosts with selfsigned SSL certificates
* need the corresponding SSL certificate installed in the router.
*
* While this implementation supports SNI, others may not, so
* SNI requirements are noted.
*
* @since 0.8.2
*/
public static final String DEFAULT_SSL_SEED_URL =
"https://reseed.i2p-projekt.de/" + "," + // Only HTTPS
"https://i2p.mooo.com/netDb/" + "," +
"https://netdb.i2p2.no/" + "," + // Only SU3 (v3) support, SNI required
"https://us.reseed.i2p2.no:444/" + "," +
"https://uk.reseed.i2p2.no:444/" + "," +
//"https://www.torontocrypto.org:8443/" + "," +
"https://i2p.manas.ca:8443/" + "," +
"https://i2p-0.manas.ca:8443/" + "," +
"https://reseed.i2p.vzaws.com:8443/" + ", " + // Only SU3 (v3) support
"https://user.mx24.eu/" + "," + // Only HTTPS and SU3 (v3) support
"https://download.xxlspeed.com/"; // Only HTTPS and SU3 (v3) support
// newest first, please add new ones at the top
//
// https url:port, ending with "/" // certificates/reseed/ // certificates/ssl/ // notes
// ---------------------------------- ------------------------ ------------------------- ---------------
"https://i2p.manas.ca:8443/" + ',' + // zmx_at_mail.i2p.crt // CA // SNI required
"https://i2p-0.manas.ca:8443/" + ',' + // zmx_at_mail.i2p.crt // CA // SNI required
"https://reseed.i2p.vzaws.com:8443/" + ',' + // parg_at_mail.i2p.crt // reseed.i2p.vzaws.com.crt
"https://i2p.mooo.com/netDb/" + ',' + // bugme_at_mail.i2p.crt // i2p.mooo.com.crt
"https://user.mx24.eu/" + ',' + // backup_at_mail.i2p.crt // user.mx24.eu.crt
"https://download.xxlspeed.com/" + ',' + // backup_at_mail.i2p.crt // download.xxlspeed.com.crt // SNI required
"https://netdb.i2p2.no/" + ',' + // meeh_at_mail.i2p.crt // netdb.i2p2.no.crt // SNI required
"https://us.reseed.i2p2.no:444/" + ',' + // meeh_at_mail.i2p.crt // us.reseed.i2p2.no.crt
"https://uk.reseed.i2p2.no:444/" + ',' + // meeh_at_mail.i2p.crt // uk.reseed.i2p2.no.crt
"https://reseed.i2p-projekt.de/"; // echelon_at_mail.i2p.crt // reseed.i2p-projekt.de.crt
private static final String SU3_FILENAME = "i2pseeds.su3";
@@ -221,6 +243,9 @@ public class Reseeder {
* Since Java 7 or Android 2.3 (API 9),
* which is the lowest Android we support anyway.
*
* Not guaranteed to be correct, e.g. FreeBSD:
* https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=201446
*
* @since 0.9.20
*/
private static boolean isSNISupported() {
@@ -480,6 +505,9 @@ public class Reseeder {
}
if (!isSNISupported()) {
try {
URLList.remove(new URI("https://i2p.manas.ca:8443/"));
URLList.remove(new URI("https://i2p-0.manas.ca:8443/"));
URLList.remove(new URI("https://download.xxlspeed.com/"));
URLList.remove(new URI("https://netdb.i2p2.no/"));
} catch (URISyntaxException mue) {}
}
@@ -501,6 +529,7 @@ public class Reseeder {
*/
private int reseed(List<URI> URLList, boolean echoStatus) {
int total = 0;
int fetched_reseed_servers = 0;
for (int i = 0; i < URLList.size() && _isRunning; i++) {
if (_context.router().gracefulShutdownInProgress()) {
System.out.println("Reseed aborted, shutdown in progress");
@@ -519,8 +548,9 @@ public class Reseeder {
}
if (dl > 0) {
total += dl;
fetched_reseed_servers++;
// Don't go on to the next URL if we have enough
if (total >= 100)
if (total >= MIN_RI_WANTED && fetched_reseed_servers >= MIN_RESEED_SERVERS)
break;
// remove alternate versions if we haven't tried them yet
for (int j = i + 1; j < URLList.size(); ) {

View File

@@ -135,36 +135,39 @@ public class InstallUpdate {
boolean goodOS = isWin || isMac ||
osName.contains("linux") || osName.contains("freebsd");
// only do this on these x86
File jbigiJar = new File(context.getBaseDir(), "lib/jbigi.jar");
if (isX86 && goodOS && jbigiJar.exists()) {
if (goodOS && jbigiJar.exists()) {
String libPrefix = (isWin ? "" : "lib");
String libSuffix = (isWin ? ".dll" : isMac ? ".jnilib" : ".so");
File jcpuidLib = new File(context.getBaseDir(), libPrefix + "jcpuid" + libSuffix);
if (jcpuidLib.canWrite() && jbigiJar.lastModified() > jcpuidLib.lastModified()) {
String path = jcpuidLib.getAbsolutePath();
boolean success = FileUtil.copy(path, path + ".bak", true, true);
if (success) {
boolean success2 = jcpuidLib.delete();
if (success2) {
System.out.println("New jbigi.jar detected, moved jcpuid library to " +
path + ".bak");
System.out.println("Check logs for successful installation of new library");
if (isX86) {
File jcpuidLib = new File(context.getBaseDir(), libPrefix + "jcpuid" + libSuffix);
if (jcpuidLib.canWrite() && jbigiJar.lastModified() > jcpuidLib.lastModified()) {
String path = jcpuidLib.getAbsolutePath();
boolean success = FileUtil.copy(path, path + ".bak", true, true);
if (success) {
boolean success2 = jcpuidLib.delete();
if (success2) {
System.out.println("New jbigi.jar detected, moved jcpuid library to " +
path + ".bak");
System.out.println("Check logs for successful installation of new library");
}
}
}
}
File jbigiLib = new File(context.getBaseDir(), libPrefix + "jbigi" + libSuffix);
if (jbigiLib.canWrite() && jbigiJar.lastModified() > jbigiLib.lastModified()) {
String path = jbigiLib.getAbsolutePath();
boolean success = FileUtil.copy(path, path + ".bak", true, true);
if (success) {
boolean success2 = jbigiLib.delete();
if (success2) {
System.out.println("New jbigi.jar detected, moved jbigi library to " +
path + ".bak");
System.out.println("Check logs for successful installation of new library");
if (isX86 || SystemVersion.isARM()) {
File jbigiLib = new File(context.getBaseDir(), libPrefix + "jbigi" + libSuffix);
if (jbigiLib.canWrite() && jbigiJar.lastModified() > jbigiLib.lastModified()) {
String path = jbigiLib.getAbsolutePath();
boolean success = FileUtil.copy(path, path + ".bak", true, true);
if (success) {
boolean success2 = jbigiLib.delete();
if (success2) {
System.out.println("New jbigi.jar detected, moved jbigi library to " +
path + ".bak");
System.out.println("Check logs for successful installation of new library");
}
}
}
}

View File

@@ -36,6 +36,9 @@ import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import net.i2p.data.DataHelper;
import net.i2p.util.HexDump;
import net.i2p.util.Log;
/**
* NtpClient - an NTP client for Java. This program connects to an NTP server
@@ -53,9 +56,12 @@ import java.util.Collections;
*/
class NtpClient {
/** difference between the unix epoch and jan 1 1900 (NTP uses that) */
private final static double SECONDS_1900_TO_EPOCH = 2208988800.0;
public final static double SECONDS_1900_TO_EPOCH = 2208988800.0;
private final static int NTP_PORT = 123;
private static final int DEFAULT_TIMEOUT = 10*1000;
private static final int OFF_ORIGTIME = 24;
private static final int OFF_TXTIME = 40;
private static final int MIN_PKT_LEN = 48;
/**
* Query the ntp servers, returning the current time from first one we find
@@ -63,6 +69,7 @@ class NtpClient {
* @return milliseconds since january 1, 1970 (UTC)
* @throws IllegalArgumentException if none of the servers are reachable
*/
/****
public static long currentTime(String serverNames[]) {
if (serverNames == null)
throw new IllegalArgumentException("No NTP servers specified");
@@ -77,15 +84,18 @@ class NtpClient {
}
throw new IllegalArgumentException("No reachable NTP servers specified");
}
****/
/**
* Query the ntp servers, returning the current time from first one we find
* Hack to return time and stratum
*
* @param log may be null
* @return time in rv[0] and stratum in rv[1]
* @throws IllegalArgumentException if none of the servers are reachable
* @since 0.7.12
*/
public static long[] currentTimeAndStratum(String serverNames[], int perServerTimeout) {
public static long[] currentTimeAndStratum(String serverNames[], int perServerTimeout, Log log) {
if (serverNames == null)
throw new IllegalArgumentException("No NTP servers specified");
ArrayList<String> names = new ArrayList<String>(serverNames.length);
@@ -93,7 +103,7 @@ class NtpClient {
names.add(serverNames[i]);
Collections.shuffle(names);
for (int i = 0; i < names.size(); i++) {
long[] rv = currentTimeAndStratum(names.get(i), perServerTimeout);
long[] rv = currentTimeAndStratum(names.get(i), perServerTimeout, log);
if (rv != null && rv[0] > 0)
return rv;
}
@@ -105,19 +115,23 @@ class NtpClient {
*
* @return milliseconds since january 1, 1970 (UTC), or -1 on error
*/
/****
public static long currentTime(String serverName) {
long[] la = currentTimeAndStratum(serverName, DEFAULT_TIMEOUT);
if (la != null)
return la[0];
return -1;
}
****/
/**
* Hack to return time and stratum
*
* @param log may be null
* @return time in rv[0] and stratum in rv[1], or null for error
* @since 0.7.12
*/
private static long[] currentTimeAndStratum(String serverName, int timeout) {
private static long[] currentTimeAndStratum(String serverName, int timeout, Log log) {
DatagramSocket socket = null;
try {
// Send request
@@ -125,14 +139,19 @@ class NtpClient {
InetAddress address = InetAddress.getByName(serverName);
byte[] buf = new NtpMessage().toByteArray();
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, NTP_PORT);
byte[] txtime = new byte[8];
// Set the transmit timestamp *just* before sending the packet
// ToDo: Does this actually improve performance or not?
NtpMessage.encodeTimestamp(packet.getData(), 40,
NtpMessage.encodeTimestamp(packet.getData(), OFF_TXTIME,
(System.currentTimeMillis()/1000.0)
+ SECONDS_1900_TO_EPOCH);
socket.send(packet);
// save for check
System.arraycopy(packet.getData(), OFF_TXTIME, txtime, 0, 8);
if (log != null && log.shouldDebug())
log.debug("Sent:\n" + HexDump.dump(buf));
// Get response
packet = new DatagramPacket(buf, buf.length);
@@ -142,28 +161,51 @@ class NtpClient {
// Immediately record the incoming timestamp
double destinationTimestamp = (System.currentTimeMillis()/1000.0) + SECONDS_1900_TO_EPOCH;
if (packet.getLength() < MIN_PKT_LEN) {
if (log != null && log.shouldWarn())
log.warn("Short packet length " + packet.getLength());
return null;
}
// Process response
NtpMessage msg = new NtpMessage(packet.getData());
//double roundTripDelay = (destinationTimestamp-msg.originateTimestamp) -
// (msg.receiveTimestamp-msg.transmitTimestamp);
double localClockOffset = ((msg.receiveTimestamp - msg.originateTimestamp) +
(msg.transmitTimestamp - destinationTimestamp)) / 2;
if (log != null && log.shouldDebug())
log.debug("Received from: " + packet.getAddress().getHostAddress() +
'\n' + msg + '\n' + HexDump.dump(packet.getData()));
// Stratum must be between 1 (atomic) and 15 (maximum defined value)
// Anything else is right out, treat such responses like errors
if ((msg.stratum < 1) || (msg.stratum > 15)) {
//System.out.println("Response from NTP server of unacceptable stratum " + msg.stratum + ", failing.");
if (log != null && log.shouldWarn())
log.warn("Response from NTP server of unacceptable stratum " + msg.stratum + ", failing.");
return null;
}
if (!DataHelper.eq(txtime, 0, packet.getData(), OFF_ORIGTIME, 8)) {
if (log != null && log.shouldWarn())
log.warn("Origin time mismatch sent:\n" + HexDump.dump(txtime) +
"rcvd:\n" + HexDump.dump(packet.getData(), OFF_ORIGTIME, 8));
return null;
}
double localClockOffset = ((msg.receiveTimestamp - msg.originateTimestamp) +
(msg.transmitTimestamp - destinationTimestamp)) / 2;
long[] rv = new long[2];
rv[0] = (long)(System.currentTimeMillis() + localClockOffset*1000);
rv[1] = msg.stratum;
//System.out.println("host: " + address.getHostAddress() + " rtt: " + roundTripDelay + " offset: " + localClockOffset + " seconds");
if (log != null && log.shouldInfo()) {
double roundTripDelay = (destinationTimestamp-msg.originateTimestamp) -
(msg.receiveTimestamp-msg.transmitTimestamp);
log.info("host: " + packet.getAddress().getHostAddress() + " rtt: " +
roundTripDelay + " offset: " + localClockOffset + " seconds");
}
return rv;
} catch (IOException ioe) {
//ioe.printStackTrace();
if (log != null && log.shouldWarn())
log.warn("NTP failure from " + serverName, ioe);
return null;
} finally {
if (socket != null)
@@ -171,20 +213,19 @@ class NtpClient {
}
}
/****
public static void main(String[] args) throws IOException {
// Process command-line args
if(args.length <= 0) {
printUsage();
return;
// args = new String[] { "ntp1.sth.netnod.se", "ntp2.sth.netnod.se" };
args = new String[] { "pool.ntp.org" };
}
long now = currentTime(args);
System.out.println("Current time: " + new java.util.Date(now));
Log log = new Log(NtpClient.class);
long[] rv = currentTimeAndStratum(args, DEFAULT_TIMEOUT, log);
System.out.println("Current time: " + new java.util.Date(rv[0]) + " (stratum " + rv[1] + ')');
}
static void printUsage() {
/****
private static void printUsage() {
System.out.println(
"NtpClient - an NTP client for Java.\n" +
"\n" +

View File

@@ -31,6 +31,7 @@ package net.i2p.router.time;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import net.i2p.util.RandomSource;
@@ -117,7 +118,7 @@ class NtpMessage {
* in the request and the server sets it to 4 (server) in the reply. In
* multicast mode, the server sets this field to 5 (broadcast).
*/
public byte mode = 0;
public final byte mode;
/**
@@ -233,12 +234,14 @@ class NtpMessage {
* This is the time at which the reply departed the server for the client,
* in seconds since 00:00 1-Jan-1900.
*/
public double transmitTimestamp = 0;
public final double transmitTimestamp;
/**
* Constructs a new NtpMessage from an array of bytes.
*
* @param array 48 bytes minimum
*/
public NtpMessage(byte[] array) {
// See the packet format diagram in RFC 2030 for details
@@ -280,13 +283,15 @@ class NtpMessage {
// Note that all the other member variables are already set with
// appropriate default values.
this.mode = 3;
this.transmitTimestamp = (System.currentTimeMillis()/1000.0) + 2208988800.0;
this.transmitTimestamp = (System.currentTimeMillis()/1000.0) + NtpClient.SECONDS_1900_TO_EPOCH;
}
/**
* This method constructs the data bytes of a raw NTP packet.
*
* @return 48 bytes
*/
public byte[] toByteArray() {
// All bytes are automatically set to 0
@@ -368,6 +373,10 @@ class NtpMessage {
* Will read 8 bytes of a message beginning at <code>pointer</code>
* and return it as a double, according to the NTP 64-bit timestamp
* format.
*
* @param array 8 bytes starting at pointer
* @param pointer the offset
* @return the time since 1900 (NOT Java time)
*/
public static double decodeTimestamp(byte[] array, int pointer) {
double r = 0.0;
@@ -383,10 +392,21 @@ class NtpMessage {
/**
* Encodes a timestamp in the specified position in the message
*
* @param array output 8 bytes starting at pointer
* @param pointer the offset
* @param timestamp the time to encode (since 1900, NOT Java time)
*/
public static void encodeTimestamp(byte[] array, int pointer, double timestamp) {
if (timestamp == 0.0) {
// don't put in random data
Arrays.fill(array, pointer, pointer + 8, (byte) 0);
return;
}
// Converts a double into a 64-bit fixed point
for(int i=0; i<8; i++) {
// 6 bytes of real data
for(int i=0; i<7; i++) {
// 2^24, 2^16, 2^8, .. 2^-32
double base = Math.pow(2, (3-i)*8);
@@ -401,7 +421,8 @@ class NtpMessage {
// low order bits of the timestamp with a random, unbiased
// bitstring, both to avoid systematic roundoff errors and as
// a means of loop detection and replay detection.
array[7+pointer] = (byte) (RandomSource.getInstance().nextInt());
// 2 bytes of random data
RandomSource.getInstance().nextBytes(array, pointer + 6, 2);
}
@@ -415,7 +436,7 @@ class NtpMessage {
// timestamp is relative to 1900, utc is used by Java and is relative
// to 1970
double utc = timestamp - (2208988800.0);
double utc = timestamp - NtpClient.SECONDS_1900_TO_EPOCH;
// milliseconds
long ms = (long) (utc * 1000.0);
@@ -425,7 +446,7 @@ class NtpMessage {
// fraction
double fraction = timestamp - ((long) timestamp);
String fractionSting = new DecimalFormat(".000000").format(fraction);
String fractionSting = new DecimalFormat(".000000000").format(fraction);
return date + fractionSting;
}

View File

@@ -273,7 +273,7 @@ public class RouterTimestamper extends Timestamper {
// // this delays startup when net is disconnected or the timeserver list is bad, don't make it too long
// try { Thread.sleep(2*1000); } catch (InterruptedException ie) {}
//}
long[] timeAndStratum = NtpClient.currentTimeAndStratum(serverList, perServerTimeout);
long[] timeAndStratum = NtpClient.currentTimeAndStratum(serverList, perServerTimeout, _log);
now = timeAndStratum[0];
stratum = (int) timeAndStratum[1];
long delta = now - _context.clock().now();

View File

@@ -16,6 +16,9 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import com.maxmind.geoip.InvalidDatabaseException;
import com.maxmind.geoip.LookupService;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
@@ -24,6 +27,7 @@ import net.i2p.router.RouterContext;
import net.i2p.util.Addresses;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.Log;
import net.i2p.util.SystemVersion;
/**
* Manage geoip lookup in a file with the Tor geoip format.
@@ -56,6 +60,20 @@ public class GeoIP {
private final AtomicBoolean _lock;
private int _lookupRunCount;
static final String PROP_GEOIP_ENABLED = "routerconsole.geoip.enable";
public static final String PROP_GEOIP_DIR = "geoip.dir";
public static final String GEOIP_DIR_DEFAULT = "geoip";
static final String GEOIP_FILE_DEFAULT = "geoip.txt";
static final String COUNTRY_FILE_DEFAULT = "countries.txt";
public static final String PROP_IP_COUNTRY = "i2np.lastCountry";
public static final String PROP_DEBIAN_GEOIP = "geoip.dat";
public static final String PROP_DEBIAN_GEOIPV6 = "geoip.v6.dat";
private static final String DEBIAN_GEOIP_FILE = "/usr/share/GeoIP/GeoIP.dat";
private static final String DEBIAN_GEOIPV6_FILE = "/usr/share/GeoIP/GeoIPv6.dat";
private static final boolean ENABLE_DEBIAN = !(SystemVersion.isWindows() || SystemVersion.isAndroid());
/** maxmind API */
private static final String UNKNOWN_COUNTRY_CODE = "--";
/**
* @param context RouterContext in production, I2PAppContext for testing only
*/
@@ -71,13 +89,6 @@ public class GeoIP {
_lock = new AtomicBoolean();
readCountryFile();
}
static final String PROP_GEOIP_ENABLED = "routerconsole.geoip.enable";
public static final String PROP_GEOIP_DIR = "geoip.dir";
public static final String GEOIP_DIR_DEFAULT = "geoip";
static final String GEOIP_FILE_DEFAULT = "geoip.txt";
static final String COUNTRY_FILE_DEFAULT = "countries.txt";
public static final String PROP_IP_COUNTRY = "i2np.lastCountry";
/**
* @since 0.9.3
@@ -145,12 +156,39 @@ public class GeoIP {
_pendingSearch.clear();
if (search.length > 0) {
Arrays.sort(search);
String[] countries = readGeoIPFile(search);
for (int i = 0; i < countries.length; i++) {
if (countries[i] != null)
_IPToCountry.put(search[i], countries[i]);
else
_notFound.add(search[i]);
File f = new File(_context.getProperty(PROP_DEBIAN_GEOIP, DEBIAN_GEOIP_FILE));
if (ENABLE_DEBIAN && f.exists()) {
// Maxmind database
LookupService ls = null;
try {
ls = new LookupService(f, LookupService.GEOIP_STANDARD);
for (int i = 0; i < search.length; i++) {
long ip = search[i].longValue();
// returns upper case or "--"
String uc = ls.getCountry(ip).getCode();
if (!uc.equals(UNKNOWN_COUNTRY_CODE)) {
String cached = _codeCache.get(uc.toLowerCase(Locale.US));
_IPToCountry.put(search[i], cached);
} else {
_notFound.add(search[i]);
}
}
} catch (IOException ioe) {
_log.error("GeoIP failure", ioe);
} catch (InvalidDatabaseException ide) {
_log.error("GeoIP failure", ide);
} finally {
if (ls != null) ls.close();
}
} else {
// Tor-style database
String[] countries = readGeoIPFile(search);
for (int i = 0; i < countries.length; i++) {
if (countries[i] != null)
_IPToCountry.put(search[i], countries[i]);
else
_notFound.add(search[i]);
}
}
}
// IPv6
@@ -158,12 +196,40 @@ public class GeoIP {
_pendingIPv6Search.clear();
if (search.length > 0) {
Arrays.sort(search);
String[] countries = GeoIPv6.readGeoIPFile(_context, search, _codeCache);
for (int i = 0; i < countries.length; i++) {
if (countries[i] != null)
_IPToCountry.put(search[i], countries[i]);
else
_notFound.add(search[i]);
File f = new File(_context.getProperty(PROP_DEBIAN_GEOIPV6, DEBIAN_GEOIPV6_FILE));
if (ENABLE_DEBIAN && f.exists()) {
// Maxmind database
LookupService ls = null;
try {
ls = new LookupService(f, LookupService.GEOIP_STANDARD);
for (int i = 0; i < search.length; i++) {
long ip = search[i].longValue();
String ipv6 = toV6(ip);
// returns upper case or "--"
String uc = ls.getCountryV6(ipv6).getCode();
if (!uc.equals(UNKNOWN_COUNTRY_CODE)) {
String cached = _codeCache.get(uc.toLowerCase(Locale.US));
_IPToCountry.put(search[i], cached);
} else {
_notFound.add(search[i]);
}
}
} catch (IOException ioe) {
_log.error("GeoIP failure", ioe);
} catch (InvalidDatabaseException ide) {
_log.error("GeoIP failure", ide);
} finally {
if (ls != null) ls.close();
}
} else {
// Tor-style database
String[] countries = GeoIPv6.readGeoIPFile(_context, search, _codeCache);
for (int i = 0; i < countries.length; i++) {
if (countries[i] != null)
_IPToCountry.put(search[i], countries[i]);
else
_notFound.add(search[i]);
}
}
}
} finally {
@@ -404,6 +470,20 @@ public class GeoIP {
}
}
/**
* @return e.g. aabb:ccdd:eeff:1122::
* @since 0.9.26 for maxmind
*/
private static String toV6(long ip) {
StringBuilder buf = new StringBuilder(21);
for (int i = 0; i < 4; i++) {
buf.append(Long.toHexString((ip >> ((3-i)*16)) & 0xffff));
buf.append(':');
}
buf.append(':');
return buf.toString();
}
/**
* Get the country for a country code
* @param code two-letter lower case code

View File

@@ -3,12 +3,14 @@ package net.i2p.router.transport.udp;
import java.io.IOException;
import java.io.Writer;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -325,6 +327,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
System.arraycopy(_context.routerHash().getData(), 0, _introKey.getData(), 0, SessionKey.KEYSIZE_BYTES);
// bind host
// This is not exposed in the UI and in practice is always null.
// We use PROP_EXTERNAL_HOST instead. See below.
String bindTo = _context.getProperty(PROP_BIND_INTERFACE);
if (bindTo == null) {
@@ -333,17 +337,66 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// bind only to that.
String fixedHost = _context.getProperty(PROP_EXTERNAL_HOST);
if (fixedHost != null && fixedHost.length() > 0) {
try {
// TODO getAllByName(), bind to each
String testAddr = InetAddress.getByName(fixedHost).getHostAddress();
if (Addresses.getAddresses().contains(testAddr))
bindTo = testAddr;
} catch (UnknownHostException uhe) {}
// Generate a comma-separated list of valid IP addresses
// that we can bind to,
// from the comma-separated PROP_EXTERNAL_HOST config.
// The config may contain IPs or hostnames; expand each
// hostname to one or more (v4 or v6) IPs.
TransportUtil.IPv6Config cfg = getIPv6Config();
Set<String> myAddrs;
if (cfg == IPV6_DISABLED)
myAddrs = Addresses.getAddresses(false, false);
else
myAddrs = Addresses.getAddresses(false, true);
StringBuilder buf = new StringBuilder();
String[] bta = DataHelper.split(fixedHost, "[,; \r\n\t]");
for (int i = 0; i < bta.length; i++) {
String bt = bta[i];
if (bt.length() <= 0)
continue;
try {
InetAddress[] all = InetAddress.getAllByName(bt);
for (int j = 0; j < all.length; j++) {
InetAddress ia = all[j];
if (cfg == IPV6_ONLY && (ia instanceof Inet4Address)) {
if (_log.shouldWarn())
_log.warn("Configured for IPv6 only, not binding to configured IPv4 host " + bt);
continue;
}
String testAddr = ia.getHostAddress();
if (myAddrs.contains(testAddr)) {
if (buf.length() > 0)
buf.append(',');
buf.append(testAddr);
} else {
if (_log.shouldWarn())
_log.warn("Not a local address, not binding to configured IP " + testAddr);
}
}
} catch (UnknownHostException uhe) {
if (_log.shouldWarn())
_log.warn("Not binding to configured host " + bt + " - " + uhe);
}
}
if (buf.length() > 0) {
bindTo = buf.toString();
if (_log.shouldWarn() && !fixedHost.equals(bindTo))
_log.warn("Expanded external host config \"" + fixedHost + "\" to \"" + bindTo + '"');
}
}
}
List<InetAddress> bindToAddrs = new ArrayList<InetAddress>(4);
// construct a set of addresses
Set<InetAddress> bindToAddrs = new HashSet<InetAddress>(4);
if (bindTo != null) {
// Generate a set IP addresses
// that we can bind to,
// from the comma-separated PROP_BIND_INTERFACE config,
// or as generated from the PROP_EXTERNAL_HOST config.
// In theory, the config may contain IPs and/or hostnames.
// However, in practice, it's only IPs, because any hostnames
// in PROP_EXTERNAL_HOST were expanded above to one or more (v4 or v6) IPs.
// PROP_BIND_INTERFACE is not exposed in the UI and is never set.
String[] bta = DataHelper.split(bindTo, "[,; \r\n\t]");
for (int i = 0; i < bta.length; i++) {
String bt = bta[i];
@@ -500,6 +553,11 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
}
rebuildExternalAddress(ia.getHostAddress(), newPort, false);
}
// TODO
// If we are bound only to v4 addresses,
// force _haveIPv6Address to false, or else we get 'no endpoint' errors
// If we are bound only to v6 addresses,
// override getIPv6Config() ?
}
if (isIPv4Firewalled()) {
if (_lastInboundIPv6 > 0)

View File

@@ -68,6 +68,10 @@ class BuildExecutor implements Runnable {
//_context.statManager().createRateStat("tunnel.pendingRemaining", "How many inbound requests are pending after a pass (period is how long the pass takes)?", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.buildFailFirstHop", "How often we fail to build a OB tunnel because we can't contact the first hop", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.buildReplySlow", "Build reply late, but not too late", "Tunnels", new long[] { 10*60*1000 });
//ctx.statManager().createRateStat("tunnel.buildClientExpireIB", "", "Tunnels", new long[] { 60*60*1000 });
//ctx.statManager().createRateStat("tunnel.buildClientExpireOB", "", "Tunnels", new long[] { 60*60*1000 });
//ctx.statManager().createRateStat("tunnel.buildExploratoryExpireIB", "", "Tunnels", new long[] { 60*60*1000 });
//ctx.statManager().createRateStat("tunnel.buildExploratoryExpireOB", "", "Tunnels", new long[] { 60*60*1000 });
// Get stat manager, get recognized bandwidth tiers
StatManager statMgr = _context.statManager();
@@ -184,7 +188,7 @@ class BuildExecutor implements Runnable {
String bwTier = "Unknown";
if (ri != null) bwTier = ri.getBandwidthTier(); // Returns "Unknown" if none recognized
// Record that a peer of the given tier expired
_context.statManager().addRateData("tunnel.tierExpire" + bwTier, 1, 0);
_context.statManager().addRateData("tunnel.tierExpire" + bwTier, 1);
didNotReply(cfg.getReplyMessageId(), peer);
// Blame everybody since we don't know whose fault it is.
// (it could be our exploratory tunnel's fault too...)
@@ -194,10 +198,19 @@ class BuildExecutor implements Runnable {
TunnelPool pool = cfg.getTunnelPool();
if (pool != null)
pool.buildComplete(cfg);
if (cfg.getDestination() == null)
_context.statManager().addRateData("tunnel.buildExploratoryExpire", 1, 0);
else
_context.statManager().addRateData("tunnel.buildClientExpire", 1, 0);
if (cfg.getDestination() == null) {
_context.statManager().addRateData("tunnel.buildExploratoryExpire", 1);
//if (cfg.isInbound())
// _context.statManager().addRateData("tunnel.buildExploratoryExpireIB", 1);
//else
// _context.statManager().addRateData("tunnel.buildExploratoryExpireOB", 1);
} else {
_context.statManager().addRateData("tunnel.buildClientExpire", 1);
//if (cfg.isInbound())
// _context.statManager().addRateData("tunnel.buildClientExpireIB", 1);
//else
// _context.statManager().addRateData("tunnel.buildClientExpireOB", 1);
}
}
}

View File

@@ -497,8 +497,16 @@ class BuildHandler implements Runnable {
// limit concurrent next-hop lookups to prevent job queue overload attacks
int numTunnels = _context.tunnelManager().getParticipatingCount();
int limit = Math.max(MIN_LOOKUP_LIMIT, Math.min(MAX_LOOKUP_LIMIT, numTunnels * PERCENT_LOOKUP_LIMIT / 100));
int current = _currentLookups.incrementAndGet();
int current;
// leaky counter, since it isn't reliable
if (_context.random().nextInt(16) > 0)
current = _currentLookups.incrementAndGet();
else
current = 1;
if (current <= limit) {
// don't let it go negative
if (current <= 0)
_currentLookups.set(1);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Request " + req
+ " handled, lookup next peer " + nextPeer
@@ -510,9 +518,9 @@ class BuildHandler implements Runnable {
if (_log.shouldLog(Log.WARN))
_log.warn("Drop next hop lookup, limit " + limit + ": " + req);
_context.statManager().addRateData("tunnel.dropLookupThrottle", 1);
if (from != null)
_context.commSystem().mayDisconnect(from);
}
if (from != null)
_context.commSystem().mayDisconnect(from);
return -1;
} else {
long beforeHandle = System.currentTimeMillis();