Skip to content

Commit d910490

Browse files
committed
Check for bogon IPs without API call & give more info
1 parent 3b93e95 commit d910490

File tree

2 files changed

+229
-18
lines changed

2 files changed

+229
-18
lines changed

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

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
public class IPResponse {
66
private final String ip;
77
private final String hostname;
8+
private final boolean bogon;
9+
private final String bogonType;
810
private final boolean anycast;
911
private final String city;
1012
private final String region;
@@ -24,6 +26,8 @@ public class IPResponse {
2426
public IPResponse(
2527
String ip,
2628
String hostname,
29+
boolean bogon,
30+
String bogonType,
2731
boolean anycast,
2832
String city,
2933
String region,
@@ -41,6 +45,8 @@ public IPResponse(
4145
) {
4246
this.ip = ip;
4347
this.hostname = hostname;
48+
this.bogon = bogon;
49+
this.bogonType = bogonType;
4450
this.anycast = anycast;
4551
this.city = city;
4652
this.region = region;
@@ -75,6 +81,14 @@ public String getHostname() {
7581
return hostname;
7682
}
7783

84+
public boolean getBogon() {
85+
return bogon;
86+
}
87+
88+
public String getBogonType() {
89+
return bogonType;
90+
}
91+
7892
public boolean getAnycast() {
7993
return anycast;
8094
}
@@ -157,23 +171,30 @@ public Domains getDomains() {
157171

158172
@Override
159173
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-
'}';
174+
return (bogon ?
175+
"IPResponse{" +
176+
"ip='" + ip + '\'' +
177+
", bogon='" + bogon + '\'' +
178+
", bogonType='" + bogonType + '\'' +
179+
"}"
180+
:
181+
"IPResponse{" +
182+
"ip='" + ip + '\'' +
183+
", hostname='" + hostname + '\'' +
184+
", anycast=" + anycast +
185+
", city='" + city + '\'' +
186+
", region='" + region + '\'' +
187+
", country='" + country + '\'' +
188+
", loc='" + loc + '\'' +
189+
", org='" + org + '\'' +
190+
", postal='" + postal + '\'' +
191+
", timezone='" + timezone + '\'' +
192+
", asn=" + asn +
193+
", company=" + company +
194+
", carrier=" + carrier +
195+
", privacy=" + privacy +
196+
", abuse=" + abuse +
197+
", domains=" + domains +
198+
'}');
178199
}
179200
}

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

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

1013
public class IPRequest extends BaseRequest<IPResponse> {
1114
private final static String URL_FORMAT = "https://ipinfo.io/%s";
@@ -18,6 +21,17 @@ public IPRequest(OkHttpClient client, String token, String ip) {
1821

1922
@Override
2023
public IPResponse handle() throws RateLimitedException {
24+
String bogonType = handleBogon(ip);
25+
if (bogonType != null) {
26+
String bogonResponse = "{ip='" + ip + "', bogon='true', bogonType='" + bogonType + "'}";
27+
try {
28+
return gson.fromJson(bogonResponse.toString(), IPResponse.class);
29+
} catch (Exception ex) {
30+
System.out.println("inException");
31+
throw new ErrorResponseException(ex);
32+
}
33+
}
34+
2135
String url = String.format(URL_FORMAT, ip);
2236
Request.Builder request = new Request.Builder().url(url).get();
2337

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

0 commit comments

Comments
 (0)