66import okhttp3 .OkHttpClient ;
77import okhttp3 .Request ;
88import okhttp3 .Response ;
9+ import java .net .InetAddress ;
10+ import java .net .UnknownHostException ;
11+ import java .net .Inet4Address ;
912
1013public 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