forked from Qortal/qortal
Added optional "senderPeerAddress" string to HELLO messages, to allow external IP changes to be detected without using a centralized service.
This commit is contained in:
parent
b1c1634950
commit
f007f9a86d
@ -48,6 +48,9 @@ public enum Handshake {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make a note of the senderPeerAddress, as this should be our public IP
|
||||||
|
Network.getInstance().ourPeerAddressUpdated(helloMessage.getSenderPeerAddress());
|
||||||
|
|
||||||
String versionString = helloMessage.getVersionString();
|
String versionString = helloMessage.getVersionString();
|
||||||
|
|
||||||
Matcher matcher = peer.VERSION_PATTERN.matcher(versionString);
|
Matcher matcher = peer.VERSION_PATTERN.matcher(versionString);
|
||||||
@ -87,8 +90,9 @@ public enum Handshake {
|
|||||||
public void action(Peer peer) {
|
public void action(Peer peer) {
|
||||||
String versionString = Controller.getInstance().getVersionString();
|
String versionString = Controller.getInstance().getVersionString();
|
||||||
long timestamp = NTP.getTime();
|
long timestamp = NTP.getTime();
|
||||||
|
String senderPeerAddress = peer.getPeerData().getAddress().toString();
|
||||||
|
|
||||||
Message helloMessage = new HelloMessage(timestamp, versionString);
|
Message helloMessage = new HelloMessage(timestamp, versionString, senderPeerAddress);
|
||||||
if (!peer.sendMessage(helloMessage))
|
if (!peer.sendMessage(helloMessage))
|
||||||
peer.disconnect("failed to send HELLO");
|
peer.disconnect("failed to send HELLO");
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
|
|||||||
import org.qortal.block.BlockChain;
|
import org.qortal.block.BlockChain;
|
||||||
import org.qortal.controller.Controller;
|
import org.qortal.controller.Controller;
|
||||||
import org.qortal.controller.arbitrary.ArbitraryDataFileManager;
|
import org.qortal.controller.arbitrary.ArbitraryDataFileManager;
|
||||||
import org.qortal.controller.arbitrary.ArbitraryDataManager;
|
|
||||||
import org.qortal.crypto.Crypto;
|
import org.qortal.crypto.Crypto;
|
||||||
import org.qortal.data.block.BlockData;
|
import org.qortal.data.block.BlockData;
|
||||||
import org.qortal.data.network.PeerData;
|
import org.qortal.data.network.PeerData;
|
||||||
@ -117,6 +116,9 @@ public class Network {
|
|||||||
|
|
||||||
private final Lock mergePeersLock = new ReentrantLock();
|
private final Lock mergePeersLock = new ReentrantLock();
|
||||||
|
|
||||||
|
private List<String> ourExternalIpAddressHistory = new ArrayList<>();
|
||||||
|
private String ourExternalIpAddress = null;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
private Network() {
|
private Network() {
|
||||||
@ -1102,6 +1104,65 @@ public class Network {
|
|||||||
return new GetUnconfirmedTransactionsMessage();
|
return new GetUnconfirmedTransactionsMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// External IP / peerAddress tracking
|
||||||
|
|
||||||
|
public void ourPeerAddressUpdated(String peerAddress) {
|
||||||
|
if (peerAddress == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] parts = peerAddress.split(":");
|
||||||
|
if (parts.length != 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String host = parts[0];
|
||||||
|
try {
|
||||||
|
InetAddress addr = InetAddress.getByName(host);
|
||||||
|
if (addr.isAnyLocalAddress() || addr.isSiteLocalAddress()) {
|
||||||
|
// Ignore local addresses
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ourExternalIpAddressHistory.add(host);
|
||||||
|
|
||||||
|
// Limit to 10 entries
|
||||||
|
while (this.ourExternalIpAddressHistory.size() > 10) {
|
||||||
|
this.ourExternalIpAddressHistory.remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've had 3 consecutive matching addresses, and they're different from
|
||||||
|
// our stored IP address value, treat it as updated.
|
||||||
|
|
||||||
|
int size = this.ourExternalIpAddressHistory.size();
|
||||||
|
if (size < 3) {
|
||||||
|
// Need at least 3 readings
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ip1 = this.ourExternalIpAddressHistory.get(size - 1);
|
||||||
|
String ip2 = this.ourExternalIpAddressHistory.get(size - 2);
|
||||||
|
String ip3 = this.ourExternalIpAddressHistory.get(size - 3);
|
||||||
|
|
||||||
|
if (!Objects.equals(ip1, this.ourExternalIpAddress)) {
|
||||||
|
// Latest reading doesn't match our known value
|
||||||
|
if (Objects.equals(ip1, ip2) && Objects.equals(ip1, ip3)) {
|
||||||
|
// Last 3 readings were the same - i.e. more than one peer agreed on the new IP address
|
||||||
|
this.ourExternalIpAddress = ip1;
|
||||||
|
this.onExternalIpUpdate(ip1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onExternalIpUpdate(String ipAddress) {
|
||||||
|
LOGGER.info("External IP address updated to {}", ipAddress);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Peer-management calls
|
// Peer-management calls
|
||||||
|
|
||||||
public void noteToSelf(Peer peer) {
|
public void noteToSelf(Peer peer) {
|
||||||
|
@ -13,16 +13,18 @@ public class HelloMessage extends Message {
|
|||||||
|
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final String versionString;
|
private final String versionString;
|
||||||
|
private final String senderPeerAddress;
|
||||||
|
|
||||||
private HelloMessage(int id, long timestamp, String versionString) {
|
private HelloMessage(int id, long timestamp, String versionString, String senderPeerAddress) {
|
||||||
super(id, MessageType.HELLO);
|
super(id, MessageType.HELLO);
|
||||||
|
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.versionString = versionString;
|
this.versionString = versionString;
|
||||||
|
this.senderPeerAddress = senderPeerAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HelloMessage(long timestamp, String versionString) {
|
public HelloMessage(long timestamp, String versionString, String senderPeerAddress) {
|
||||||
this(-1, timestamp, versionString);
|
this(-1, timestamp, versionString, senderPeerAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getTimestamp() {
|
public long getTimestamp() {
|
||||||
@ -33,12 +35,22 @@ public class HelloMessage extends Message {
|
|||||||
return this.versionString;
|
return this.versionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSenderPeerAddress() {
|
||||||
|
return this.senderPeerAddress;
|
||||||
|
}
|
||||||
|
|
||||||
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws TransformationException {
|
public static Message fromByteBuffer(int id, ByteBuffer byteBuffer) throws TransformationException {
|
||||||
long timestamp = byteBuffer.getLong();
|
long timestamp = byteBuffer.getLong();
|
||||||
|
|
||||||
String versionString = Serialization.deserializeSizedString(byteBuffer, 255);
|
String versionString = Serialization.deserializeSizedString(byteBuffer, 255);
|
||||||
|
|
||||||
return new HelloMessage(id, timestamp, versionString);
|
// Sender peer address added in v3.0, so is an optional field. Older versions won't send it.
|
||||||
|
String senderPeerAddress = null;
|
||||||
|
if (byteBuffer.hasRemaining()) {
|
||||||
|
senderPeerAddress = Serialization.deserializeSizedString(byteBuffer, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HelloMessage(id, timestamp, versionString, senderPeerAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -49,6 +61,8 @@ public class HelloMessage extends Message {
|
|||||||
|
|
||||||
Serialization.serializeSizedString(bytes, this.versionString);
|
Serialization.serializeSizedString(bytes, this.versionString);
|
||||||
|
|
||||||
|
Serialization.serializeSizedString(bytes, this.senderPeerAddress);
|
||||||
|
|
||||||
return bytes.toByteArray();
|
return bytes.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user