Skip to content

Commit 964a526

Browse files
authored
Merge pull request #34 from ipinfo/talha/be-578
Check for bogon IPs without API call & give more info
2 parents 3b93e95 + 3ffc078 commit 964a526

File tree

3 files changed

+206
-21
lines changed

3 files changed

+206
-21
lines changed

src/main/java/io/ipinfo/api/model/IPResponse.java

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
public class IPResponse {
66
private final String ip;
77
private final String hostname;
8+
private final boolean bogon;
89
private final boolean anycast;
910
private final String city;
1011
private final String region;
@@ -24,6 +25,7 @@ public class IPResponse {
2425
public IPResponse(
2526
String ip,
2627
String hostname,
28+
boolean bogon,
2729
boolean anycast,
2830
String city,
2931
String region,
@@ -41,6 +43,7 @@ public IPResponse(
4143
) {
4244
this.ip = ip;
4345
this.hostname = hostname;
46+
this.bogon = bogon;
4447
this.anycast = anycast;
4548
this.city = city;
4649
this.region = region;
@@ -55,7 +58,13 @@ public IPResponse(
5558
this.privacy = privacy;
5659
this.abuse = abuse;
5760
this.domains = domains;
61+
}
5862

63+
public IPResponse(
64+
String ip,
65+
boolean bogon
66+
) {
67+
this(ip, null, bogon, false, null, null, null, null, null, null, null, null, null, null, null, null, null);
5968
}
6069

6170
/**
@@ -75,6 +84,10 @@ public String getHostname() {
7584
return hostname;
7685
}
7786

87+
public boolean getBogon() {
88+
return bogon;
89+
}
90+
7891
public boolean getAnycast() {
7992
return anycast;
8093
}
@@ -157,23 +170,29 @@ public Domains getDomains() {
157170

158171
@Override
159172
public String toString() {
160-
return "IPResponse{" +
161-
"ip='" + ip + '\'' +
162-
", hostname='" + hostname + '\'' +
163-
", anycast=" + anycast +
164-
", city='" + city + '\'' +
165-
", region='" + region + '\'' +
166-
", country='" + country + '\'' +
167-
", loc='" + loc + '\'' +
168-
", org='" + org + '\'' +
169-
", postal='" + postal + '\'' +
170-
", timezone='" + timezone + '\'' +
171-
", asn=" + asn +
172-
", company=" + company +
173-
", carrier=" + carrier +
174-
", privacy=" + privacy +
175-
", abuse=" + abuse +
176-
", domains=" + domains +
177-
'}';
173+
return (bogon ?
174+
"IPResponse{" +
175+
"ip='" + ip + '\'' +
176+
", bogon='" + bogon + '\'' +
177+
"}"
178+
:
179+
"IPResponse{" +
180+
"ip='" + ip + '\'' +
181+
", hostname='" + hostname + '\'' +
182+
", anycast=" + anycast +
183+
", city='" + city + '\'' +
184+
", region='" + region + '\'' +
185+
", country='" + country + '\'' +
186+
", loc='" + loc + '\'' +
187+
", org='" + org + '\'' +
188+
", postal='" + postal + '\'' +
189+
", timezone='" + timezone + '\'' +
190+
", asn=" + asn +
191+
", company=" + company +
192+
", carrier=" + carrier +
193+
", privacy=" + privacy +
194+
", abuse=" + abuse +
195+
", domains=" + domains +
196+
'}');
178197
}
179198
}

src/main/java/io/ipinfo/api/request/IPRequest.java

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import okhttp3.OkHttpClient;
77
import okhttp3.Request;
88
import okhttp3.Response;
9+
import java.net.InetAddress;
10+
import java.net.UnknownHostException;
911

1012
public class IPRequest extends BaseRequest<IPResponse> {
1113
private final static String URL_FORMAT = "https://ipinfo.io/%s";
@@ -18,6 +20,14 @@ public IPRequest(OkHttpClient client, String token, String ip) {
1820

1921
@Override
2022
public IPResponse handle() throws RateLimitedException {
23+
if (isBogon(ip)) {
24+
try {
25+
return new IPResponse(ip, true);
26+
} catch (Exception ex) {
27+
throw new ErrorResponseException(ex);
28+
}
29+
}
30+
2131
String url = String.format(URL_FORMAT, ip);
2232
Request.Builder request = new Request.Builder().url(url).get();
2333

@@ -33,4 +43,147 @@ public IPResponse handle() throws RateLimitedException {
3343
}
3444
}
3545
}
46+
47+
static IpAddressMatcher[] IpAddressMatcherList = {
48+
// IPv4
49+
new IpAddressMatcher("0.0.0.0/8"),
50+
new IpAddressMatcher("10.0.0.0/8"),
51+
new IpAddressMatcher("100.64.0.0/10"),
52+
new IpAddressMatcher("127.0.0.0/8"),
53+
new IpAddressMatcher("169.254.0.0/16"),
54+
new IpAddressMatcher("172.16.0.0/12"),
55+
new IpAddressMatcher("192.0.0.0/24"),
56+
new IpAddressMatcher("192.0.2.0/24"),
57+
new IpAddressMatcher("192.168.0.0/16"),
58+
new IpAddressMatcher("198.18.0.0/15"),
59+
new IpAddressMatcher("198.51.100.0/24"),
60+
new IpAddressMatcher("203.0.113.0/24"),
61+
new IpAddressMatcher("224.0.0.0/4"),
62+
new IpAddressMatcher("240.0.0.0/4"),
63+
new IpAddressMatcher("255.255.255.255/32"),
64+
// IPv6
65+
new IpAddressMatcher("::/128"),
66+
new IpAddressMatcher("::1/128"),
67+
new IpAddressMatcher("::ffff:0:0/96"),
68+
new IpAddressMatcher("::/96"),
69+
new IpAddressMatcher("100::/64"),
70+
new IpAddressMatcher("2001:10::/28"),
71+
new IpAddressMatcher("2001:db8::/32"),
72+
new IpAddressMatcher("fc00::/7"),
73+
new IpAddressMatcher("fe80::/10"),
74+
new IpAddressMatcher("fec0::/10"),
75+
new IpAddressMatcher("ff00::/8"),
76+
// 6to4
77+
new IpAddressMatcher("2002::/24"),
78+
new IpAddressMatcher("2002:a00::/24"),
79+
new IpAddressMatcher("2002:7f00::/24"),
80+
new IpAddressMatcher("2002:a9fe::/32"),
81+
new IpAddressMatcher("2002:ac10::/28"),
82+
new IpAddressMatcher("2002:c000::/40"),
83+
new IpAddressMatcher("2002:c000:200::/40"),
84+
new IpAddressMatcher("2002:c0a8::/32"),
85+
new IpAddressMatcher("2002:c612::/31"),
86+
new IpAddressMatcher("2002:c633:6400::/40"),
87+
new IpAddressMatcher("2002:cb00:7100::/40"),
88+
new IpAddressMatcher("2002:e000::/20"),
89+
new IpAddressMatcher("2002:f000::/20"),
90+
new IpAddressMatcher("2002:ffff:ffff::/48"),
91+
// Teredo
92+
new IpAddressMatcher("2001::/40"),
93+
new IpAddressMatcher("2001:0:a00::/40"),
94+
new IpAddressMatcher("2001:0:7f00::/40"),
95+
new IpAddressMatcher("2001:0:a9fe::/48"),
96+
new IpAddressMatcher("2001:0:ac10::/44"),
97+
new IpAddressMatcher("2001:0:c000::/56"),
98+
new IpAddressMatcher("2001:0:c000:200::/56"),
99+
new IpAddressMatcher("2001:0:c0a8::/48"),
100+
new IpAddressMatcher("2001:0:c612::/47"),
101+
new IpAddressMatcher("2001:0:c633:6400::/56"),
102+
new IpAddressMatcher("2001:0:cb00:7100::/56"),
103+
new IpAddressMatcher("2001:0:e000::/36"),
104+
new IpAddressMatcher("2001:0:f000::/36"),
105+
new IpAddressMatcher("2001:0:ffff:ffff::/64")
106+
};
107+
108+
static boolean isBogon(String ip) {
109+
for (int i = 0; i < IpAddressMatcherList.length; i++) {
110+
IpAddressMatcher ipAddressMatcher = IpAddressMatcherList[i];
111+
if (ipAddressMatcher.matches(ip)) {
112+
return true;
113+
}
114+
}
115+
return false;
116+
}
117+
118+
static InetAddress parseAddress(String address) {
119+
try {
120+
return InetAddress.getByName(address);
121+
}
122+
catch (UnknownHostException e) {
123+
throw new IllegalArgumentException("Failed to parse address: " + address, e);
124+
}
125+
}
126+
127+
/*
128+
* Copyright 2002-2019 the original author or authors.
129+
*
130+
* Licensed under the Apache License, Version 2.0 (the "License");
131+
* you may not use this file except in compliance with the License.
132+
* You may obtain a copy of the License at
133+
*
134+
* https://www.apache.org/licenses/LICENSE-2.0
135+
*
136+
* Unless required by applicable law or agreed to in writing, software
137+
* distributed under the License is distributed on an "AS IS" BASIS,
138+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139+
* See the License for the specific language governing permissions and
140+
* limitations under the License.
141+
*/
142+
public static class IpAddressMatcher {
143+
private final int nMaskBits;
144+
private final InetAddress requiredAddress;
145+
146+
public IpAddressMatcher(String ipAddress) {
147+
148+
if (ipAddress.indexOf('/') > 0) {
149+
String[] addressAndMask = ipAddress.split("/");
150+
ipAddress = addressAndMask[0];
151+
nMaskBits = Integer.parseInt(addressAndMask[1]);
152+
}
153+
else {
154+
nMaskBits = -1;
155+
}
156+
requiredAddress = parseAddress(ipAddress);
157+
}
158+
159+
public boolean matches(String address) {
160+
InetAddress remoteAddress = parseAddress(address);
161+
162+
if (!requiredAddress.getClass().equals(remoteAddress.getClass())) {
163+
return false;
164+
}
165+
166+
if (nMaskBits < 0) {
167+
return remoteAddress.equals(requiredAddress);
168+
}
169+
170+
byte[] remAddr = remoteAddress.getAddress();
171+
byte[] reqAddr = requiredAddress.getAddress();
172+
173+
int nMaskFullBytes = nMaskBits / 8;
174+
byte finalByte = (byte) (0xFF00 >> (nMaskBits & 0x07));
175+
176+
for (int i = 0; i < nMaskFullBytes; i++) {
177+
if (remAddr[i] != reqAddr[i]) {
178+
return false;
179+
}
180+
}
181+
182+
if (finalByte != 0) {
183+
return (remAddr[nMaskFullBytes] & finalByte) == (reqAddr[nMaskFullBytes] & finalByte);
184+
}
185+
186+
return true;
187+
}
188+
}
36189
}

src/test/java/io/ipinfo/IPinfoTest.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,16 @@ public void testGoogleDNS() {
3939
() -> assertFalse(response.getPrivacy().getVpn()),
4040
() -> assertFalse(response.getPrivacy().getTor()),
4141
() -> assertFalse(response.getPrivacy().getRelay()),
42-
() -> assertFalse(response.getPrivacy().getHosting()),
42+
() -> assertTrue(response.getPrivacy().getHosting()),
4343
() -> assertEquals(response.getPrivacy().getService(), ""),
4444
() -> assertEquals(response.getDomains().getDomains().size(), 5)
4545
);
46+
47+
IPResponse bogonResp = ii.lookupIP("2001:0:c000:200::0:255:1");
48+
assertAll("",
49+
() -> assertEquals(bogonResp.getIp(), "2001:0:c000:200::0:255:1"),
50+
() -> assertTrue(bogonResp.getBogon())
51+
);
4652
} catch (RateLimitedException e) {
4753
fail(e);
4854
}
@@ -72,6 +78,7 @@ public void testGetBatch() {
7278
urls.add("AS123");
7379
urls.add("8.8.8.8");
7480
urls.add("9.9.9.9/hostname");
81+
urls.add("239.0.0.0");
7582
ConcurrentHashMap<String, Object> result = ii.getBatch(urls);
7683

7784
assertAll("keys exist",
@@ -107,13 +114,19 @@ public void testGetBatch() {
107114
() -> assertFalse(ipResp.getPrivacy().getVpn()),
108115
() -> assertFalse(ipResp.getPrivacy().getTor()),
109116
() -> assertFalse(ipResp.getPrivacy().getRelay()),
110-
() -> assertFalse(ipResp.getPrivacy().getHosting()),
117+
() -> assertTrue(ipResp.getPrivacy().getHosting()),
111118
() -> assertEquals(ipResp.getPrivacy().getService(), ""),
112119
() -> assertEquals(ipResp.getDomains().getDomains().size(), 5)
113120
);
114121

115122
String hostname = (String)result.get("9.9.9.9/hostname");
116123
assertEquals(hostname, "dns9.quad9.net");
124+
125+
IPResponse bogonResp = (IPResponse)result.get("239.0.0.0");
126+
assertAll("239.0.0.0",
127+
() -> assertEquals(bogonResp.getIp(), "239.0.0.0"),
128+
() -> assertTrue(bogonResp.getBogon())
129+
);
117130
} catch (RateLimitedException e) {
118131
fail(e);
119132
}
@@ -171,7 +184,7 @@ public void testGetBatchIps() {
171184
() -> assertFalse(res2.getPrivacy().getVpn()),
172185
() -> assertFalse(res2.getPrivacy().getTor()),
173186
() -> assertFalse(res2.getPrivacy().getRelay()),
174-
() -> assertFalse(res2.getPrivacy().getHosting()),
187+
() -> assertTrue(res2.getPrivacy().getHosting()),
175188
() -> assertEquals(res2.getPrivacy().getService(), ""),
176189
() -> assertEquals(res2.getDomains().getDomains().size(), 5)
177190
);

0 commit comments

Comments
 (0)