├── .gitignore
├── IPTools.sln
├── LICENSE
├── README.md
├── README_zh-CN.md
├── assets
├── 1534995762038.png
└── 1534995856116.png
├── build
├── common.props
├── package.props
└── version.props
├── db
├── GeoLite2-City.mmdb
└── ip2region.db
├── publish.bat
├── sample
└── IPTools.ConsoleApp
│ ├── IPTools.ConsoleApp.csproj
│ └── Program.cs
└── src
├── IP2Region.Ex
├── DBSearcher.cs
├── IP2Region.Ex.csproj
├── IP2Region.LICENSE.md
├── Models
│ ├── DataBlock.cs
│ ├── DbConfig.cs
│ ├── HeaderBlock.cs
│ └── IndexBlock.cs
├── README.md
└── Utils.cs
├── IPTools.China
├── IPTools.China.csproj
└── IpSimpleSearcher.cs
├── IPTools.Core
├── Exception
│ └── IpToolException.cs
├── Extensions
│ └── IpToolExtension.cs
├── IIpSearcher.cs
├── IPTools.Core.csproj
├── IpInfo.cs
├── IpSearcherType.cs
├── IpTool.cs
└── IpToolSettings.cs
└── IPTools.International
├── IPTools.International.csproj
└── IpComplexSearcher.cs
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
332 | # custome
333 | publish
334 |
--------------------------------------------------------------------------------
/IPTools.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27703.2035
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IPTools.China", "src\IPTools.China\IPTools.China.csproj", "{000D6998-5162-441A-9D46-0AE0C3B065B0}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "02 src", "02 src", "{CD01804A-493A-4931-BC22-BA5C8E595F27}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "03 sample", "03 sample", "{2CBAB9C6-386B-4ABB-95C4-0A89364E6B4A}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IPTools.ConsoleApp", "sample\IPTools.ConsoleApp\IPTools.ConsoleApp.csproj", "{69B5FEAE-804F-43B3-8618-D08A959B52BD}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IP2Region.Ex", "src\IP2Region.Ex\IP2Region.Ex.csproj", "{2EA0CDB8-CD6C-4903-8DD6-FEB32BEF6CD3}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IPTools.Core", "src\IPTools.Core\IPTools.Core.csproj", "{3B7E6696-D71B-47A5-9381-2AC5DC0DCAD0}"
17 | EndProject
18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IPTools.International", "src\IPTools.International\IPTools.International.csproj", "{E6211F8A-23CA-4F7D-856F-D54905E91519}"
19 | EndProject
20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "01 Solution Items", "01 Solution Items", "{8A343EF0-8803-4986-92C1-D4CA7D364ADE}"
21 | ProjectSection(SolutionItems) = preProject
22 | .gitignore = .gitignore
23 | build\common.props = build\common.props
24 | global.json = global.json
25 | build\package.props = build\package.props
26 | README.md = README.md
27 | README_zh-CN.md = README_zh-CN.md
28 | build\version.props = build\version.props
29 | EndProjectSection
30 | EndProject
31 | Global
32 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
33 | Debug|Any CPU = Debug|Any CPU
34 | Release|Any CPU = Release|Any CPU
35 | EndGlobalSection
36 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
37 | {000D6998-5162-441A-9D46-0AE0C3B065B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {000D6998-5162-441A-9D46-0AE0C3B065B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {000D6998-5162-441A-9D46-0AE0C3B065B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {000D6998-5162-441A-9D46-0AE0C3B065B0}.Release|Any CPU.Build.0 = Release|Any CPU
41 | {69B5FEAE-804F-43B3-8618-D08A959B52BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 | {69B5FEAE-804F-43B3-8618-D08A959B52BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 | {69B5FEAE-804F-43B3-8618-D08A959B52BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {69B5FEAE-804F-43B3-8618-D08A959B52BD}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {2EA0CDB8-CD6C-4903-8DD6-FEB32BEF6CD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46 | {2EA0CDB8-CD6C-4903-8DD6-FEB32BEF6CD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
47 | {2EA0CDB8-CD6C-4903-8DD6-FEB32BEF6CD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 | {2EA0CDB8-CD6C-4903-8DD6-FEB32BEF6CD3}.Release|Any CPU.Build.0 = Release|Any CPU
49 | {3B7E6696-D71B-47A5-9381-2AC5DC0DCAD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50 | {3B7E6696-D71B-47A5-9381-2AC5DC0DCAD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
51 | {3B7E6696-D71B-47A5-9381-2AC5DC0DCAD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
52 | {3B7E6696-D71B-47A5-9381-2AC5DC0DCAD0}.Release|Any CPU.Build.0 = Release|Any CPU
53 | {E6211F8A-23CA-4F7D-856F-D54905E91519}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
54 | {E6211F8A-23CA-4F7D-856F-D54905E91519}.Debug|Any CPU.Build.0 = Debug|Any CPU
55 | {E6211F8A-23CA-4F7D-856F-D54905E91519}.Release|Any CPU.ActiveCfg = Release|Any CPU
56 | {E6211F8A-23CA-4F7D-856F-D54905E91519}.Release|Any CPU.Build.0 = Release|Any CPU
57 | EndGlobalSection
58 | GlobalSection(SolutionProperties) = preSolution
59 | HideSolutionNode = FALSE
60 | EndGlobalSection
61 | GlobalSection(NestedProjects) = preSolution
62 | {000D6998-5162-441A-9D46-0AE0C3B065B0} = {CD01804A-493A-4931-BC22-BA5C8E595F27}
63 | {69B5FEAE-804F-43B3-8618-D08A959B52BD} = {2CBAB9C6-386B-4ABB-95C4-0A89364E6B4A}
64 | {2EA0CDB8-CD6C-4903-8DD6-FEB32BEF6CD3} = {CD01804A-493A-4931-BC22-BA5C8E595F27}
65 | {3B7E6696-D71B-47A5-9381-2AC5DC0DCAD0} = {CD01804A-493A-4931-BC22-BA5C8E595F27}
66 | {E6211F8A-23CA-4F7D-856F-D54905E91519} = {CD01804A-493A-4931-BC22-BA5C8E595F27}
67 | EndGlobalSection
68 | GlobalSection(ExtensibilityGlobals) = postSolution
69 | SolutionGuid = {0AFF8D31-D253-4AC4-B9BA-207064A17DFD}
70 | EndGlobalSection
71 | EndGlobal
72 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Zhiqiang Li
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # IPTools | [中文文档](README_zh-CN.md)
2 | Quickly query IP information, support domestic and foreign IP information query, support query latitude and longitude, and support geographical location to the city.
3 |
4 | IPTools.China: [](https://www.nuget.org/packages/IPTools.China/)
5 |
6 | IPTools.International: [](https://www.nuget.org/packages/IPTools.International/)
7 |
8 | ## 1. IPTools.China
9 |
10 | Quickly query China IP information, country, province, city and network operators. Non China IP can only query national information.
11 |
12 | ### (1) Install
13 |
14 | ````shell
15 | Install-Package IPTools.China
16 | ````
17 |
18 | ### (2) Download database file
19 |
20 | ```shell
21 | https://github.com/stulzq/IPTools/raw/master/db/ip2region.db
22 | ```
23 |
24 | After the database file is downloaded, put it in your project root directory (same level as the *.csprj file), and **set the copy to the output directory**.
25 |
26 | 
27 |
28 | > At the beginning of version 1.2.0, the database file was unembedded into the assembly, which is convenient for updating and reduces the size of the assembly.
29 |
30 | ### (3) Usage
31 |
32 | ````shell
33 | IpTool.Search("your ip address");
34 | ````
35 |
36 | eg.
37 |
38 | ````csharp
39 | var ipinfo = IpTool.Search("171.210.12.163");
40 | Console.WriteLine(ipinfo.Country); // 中国
41 | Console.WriteLine(ipinfo.Province); // 四川省
42 | Console.WriteLine(ipinfo.City); // 成都市
43 | Console.WriteLine(ipinfo.NetworkOperator);// 电信
44 | ````
45 |
46 | ### (4) I18N
47 |
48 | Not support . So you can't use `IpTool.SearchWithI18NAsync()`.
49 |
50 | ### (5) performance testing
51 |
52 | Single thread double for loop queries 65025 IP, takes 170 ms.
53 |
54 | ### (6) Custom DB path
55 |
56 | ````csharp
57 | IpToolSettings.ChinaDbPath="";
58 | ````
59 |
60 | ## 2. IPTools.International
61 |
62 | Quickly query global IP information, support i18n, country, province, city, post code, longitude and latitude.
63 |
64 | ### (1) Install
65 |
66 | ```shell
67 | Install-Package IPTools.International
68 | ```
69 |
70 | ### (2) Download database file
71 |
72 | ```shell
73 | https://github.com/stulzq/IPTools/raw/master/db/GeoLite2-City.mmdb
74 | ```
75 |
76 | After the database file is downloaded, put it in your project root directory (same level as the *.csprj file), and **set the copy to the output directory**.
77 |
78 | 
79 |
80 | > At the beginning of version 1.2.0, the database file was unembedded into the assembly, which is convenient for updating and reduces the size of the assembly.
81 |
82 | ### (3) Usage
83 |
84 | ````csharp
85 | IpTool.Search("your ip address");
86 | ````
87 |
88 | eg.
89 |
90 | ````csharp
91 | var ipinfo = IpTool.SearchWithI18N("171.210.12.163");
92 | Console.WriteLine(ipinfo.Country); // 中国
93 | Console.WriteLine(ipinfo.CountryCode); // CN
94 | Console.WriteLine(ipinfo.Province); // 四川省
95 | Console.WriteLine(ipinfo.ProvinceCode); // SC
96 | Console.WriteLine(ipinfo.City); // 成都
97 | Console.WriteLine(ipinfo.Latitude); // 30.6667
98 | Console.WriteLine(ipinfo.Longitude); // 104.6667
99 | Console.WriteLine(ipinfo.AccuracyRadius);// 50
100 | ````
101 |
102 | ### (4) I18N
103 |
104 | ````csharp
105 | IpTool.SearchWithI18N("your ip address");
106 | ````
107 |
108 | eg.
109 |
110 | ````csharp
111 | var ipinfo = IpTool.SearchWithI18N("171.210.12.163","en");//If language code is not set, Chinese will be used by default.
112 | Console.WriteLine(ipinfo.Country); // China
113 | Console.WriteLine(ipinfo.CountryCode); // CN
114 | Console.WriteLine(ipinfo.Province); // Sichuan
115 | Console.WriteLine(ipinfo.ProvinceCode); // SC
116 | Console.WriteLine(ipinfo.City); // Chengdu
117 | Console.WriteLine(ipinfo.Latitude); // 30.6667
118 | Console.WriteLine(ipinfo.Longitude); // 104.6667
119 | Console.WriteLine(ipinfo.AccuracyRadius);// 50
120 | ````
121 |
122 | Default language is chinese(zh-CN), How to change?
123 |
124 | ````csharp
125 | IpToolSettings.DefaultLanguage = "en";// set default language is english.
126 | ````
127 |
128 | ### (5) Increase query speed
129 |
130 | With the following settings, will double the query speed, the principle is to fully load the database file into the memory, the price is that the memory will increase 60-70M, space for time, this should be noted.
131 |
132 | ```csharp
133 | IpToolSettings.LoadInternationalDbToMemory = true;
134 | ```
135 |
136 | > Version >= 1.2.0
137 |
138 | ### (6) performance testing
139 |
140 | Single thread double for loop queries 65025 IP, takes 1500 ms(Memory).
141 |
142 | ### (7) Custom DB path
143 |
144 | ````csharp
145 | IpToolSettings.InternationalDbPath="";
146 | ````
147 |
148 | ## 3. ASP.NET Core Support
149 |
150 | IPTools provides an extension method for `HttpContext`.
151 |
152 | usage:
153 |
154 | ````csharp
155 | HttpContext.GetRemoteIpInfo();
156 | HttpContext.GetRemoteIpInfo(headerKey); // Get ip from header if you use nginx, haproxy etc.
157 | ````
158 |
159 | ## 4. Use both IPTools.China and IPTools.International
160 |
161 | Both IPTools.China and IPTools.International implement `IIpSearcher`. The `IpTool` class will detect the package you installed during initialization and initialize it only once. `IpTool` has three static read-only properties, namely `DefaultSearcher`, `IpChinaSearcher`, `IpAllSearcher`.
162 |
163 | - `DefaultSearcher`. `IpTool.Search()` and `IpTool.SearchWithI18N()` will use the default Ip searcher.
164 | - `IpChinaSearcher`. IPTools.China Implemented searcher.
165 | - `IpAllSearcher`. IPTools.International Implemented searcher.
166 |
167 | If you just installed IPTools.China then `DefaultSearcher` will be `IpChinaSearcher` and `IpAllSearcher` will be null.
168 |
169 | If you just installed IPTools.International then `DefaultSearcher` will be `IpAllSearcher` and `IpChinaSearcher` will be null.
170 |
171 | If you have both components installed at the same time, by default `DefaultSearcher` will be `IpChinaSearcher`, `IpChinaSearcher` and `IpAllSearcher` will not be null.
172 |
173 | To change the default Searcher used by `DefaultSearcher`, please use the following code, if you have two components installed at the same time, it will take effect.
174 |
175 | ```csharp
176 | IpToolSettings.DefalutSearcherType = IpSearcherType.China;
177 | IpToolSettings.DefalutSearcherType = IpSearcherType.International;
178 | ```
179 |
180 | ## 5. Referencing project
181 |
182 | [**ip2region**](https://github.com/lionsoul2014/ip2region) by [lionsoul2014](https://github.com/lionsoul2014).
183 |
184 | [**GeoIP2-dotnet**](https://github.com/maxmind/GeoIP2-dotnet) by [maxmind](https://github.com/maxmind).
--------------------------------------------------------------------------------
/README_zh-CN.md:
--------------------------------------------------------------------------------
1 | # IPTools
2 | 快速查询IP信息,支持国内和国外IP信息查询,支持查询经纬度,地理位置最高支持到城市。
3 |
4 | ## 1. IPTools.China
5 |
6 | 快速查询中国IP地址信息,包含国家、省份、城市、和网络运营商。非中国IP只支持查询国家。
7 |
8 | ### (1) 安装
9 |
10 | ````shell
11 | Install-Package IPTools.China
12 | ````
13 |
14 | ### (2) 下载数据库文件
15 |
16 | ````shell
17 | https://github.com/stulzq/IPTools/raw/master/db/ip2region.db
18 | ````
19 | 将数据库文件下载完成以后,放到你的项目根目录(与*.csprj文件同级),并**设置复制到输出目录**
20 |
21 | 
22 |
23 |
24 | >1.2.0版本开始就取消了将数据库文件嵌入到程序集,方便更新,且减少程序集大小。
25 | ### (3) 使用
26 |
27 | ````shell
28 | IpTool.Search("你的ip地址");
29 | ````
30 |
31 | 示例.
32 |
33 | ````csharp
34 | var ipinfo = IpTool.Search("171.210.12.163");
35 | Console.WriteLine(ipinfo.Country); // 中国
36 | Console.WriteLine(ipinfo.Province); // 四川省
37 | Console.WriteLine(ipinfo.City); // 成都市
38 | Console.WriteLine(ipinfo.NetworkOperator);// 电信
39 | ````
40 |
41 | ### (4) 国际化
42 |
43 | 不支持国际化,所以不能使用`IpTool.SearchWithI18NAsync()`。
44 |
45 | ### (5) 性能测试
46 |
47 | 单线程,双重for循环,查询65025个IP,花费170毫秒。
48 |
49 | ### (6) 自定义ip数据库文件
50 |
51 | ````csharp
52 | IpToolSettings.ChinaDbPath="";
53 | ````
54 |
55 | ## 2. IPTools.International
56 |
57 | 快速查询全球IP信息,支持多语言,地理信息包括国家、省份、城市、邮政编码、纬度和精度。
58 |
59 | ### (1) 安装
60 |
61 | ```shell
62 | Install-Package IPTools.International
63 | ```
64 |
65 | ### (2) 下载数据库文件
66 |
67 | ```shell
68 | https://github.com/stulzq/IPTools/raw/master/db/GeoLite2-City.mmdb
69 | ```
70 |
71 | 将数据库文件下载完成以后,放到你的项目根目录(与*.csprj文件同级),并**设置复制到输出目录**
72 |
73 | 
74 |
75 | > 1.2.0版本开始就取消了将数据库文件嵌入到程序集,方便更新,且减少程序集大小。
76 |
77 | ### (3) 使用
78 |
79 | ````csharp
80 | IpTool.Search("你的ip地址");
81 | ````
82 |
83 | 示例.
84 |
85 | ````csharp
86 | var ipinfo = IpTool.SearchWithI18N("171.210.12.163");
87 | Console.WriteLine(ipinfo.Country); // 中国
88 | Console.WriteLine(ipinfo.CountryCode); // CN
89 | Console.WriteLine(ipinfo.Province); // 四川省
90 | Console.WriteLine(ipinfo.ProvinceCode); // SC
91 | Console.WriteLine(ipinfo.City); // 成都
92 | Console.WriteLine(ipinfo.Latitude); // 30.6667
93 | Console.WriteLine(ipinfo.Longitude); // 104.6667
94 | Console.WriteLine(ipinfo.AccuracyRadius);// 50
95 | ````
96 |
97 | ### (4) 国际化
98 |
99 | ````csharp
100 | IpTool.SearchWithI18N("你的ip地址");
101 | ````
102 |
103 | 示例.
104 |
105 | ````csharp
106 | var ipinfo = IpTool.SearchWithI18N("171.210.12.163","en");//如果不设置 language code, 默认将会使用中文
107 | Console.WriteLine(ipinfo.Country); // China
108 | Console.WriteLine(ipinfo.CountryCode); // CN
109 | Console.WriteLine(ipinfo.Province); // Sichuan
110 | Console.WriteLine(ipinfo.ProvinceCode); // SC
111 | Console.WriteLine(ipinfo.City); // Chengdu
112 | Console.WriteLine(ipinfo.Latitude); // 30.6667
113 | Console.WriteLine(ipinfo.Longitude); // 104.6667
114 | Console.WriteLine(ipinfo.AccuracyRadius);// 50
115 | ````
116 |
117 | 默认语言为中文,如何改变?使用下面的代码进行设置。中文为 `zh-CN`,英文为`en`
118 |
119 | ````csharp
120 | IpToolSettings.DefaultLanguage = "en";
121 | ````
122 |
123 | ### (5) 提升查询速度
124 |
125 | 通过以下设置,将会**提升一倍的查询速度**,其原理是将数据库文件完全加载到内存,付出的代价是内存将会增加60-70M,以空间换时间,这点需要注意。
126 |
127 | ````csharp
128 | IpToolSettings.LoadInternationalDbToMemory = true;
129 | ````
130 |
131 | > 版本要求 >= 1.2.0
132 |
133 | ### (6) 性能测试
134 |
135 | 单线程,双重for循环,查询65025个IP,花费1500毫秒(Memory)。
136 |
137 | ### (7) 自定义ip数据库文件
138 |
139 | ````csharp
140 | IpToolSettings.InternationalDbPath="";
141 | ````
142 |
143 | ## 3. ASP.NET Core 支持
144 |
145 | IPTools 提供了 `HttpContext`对象的扩展方法。
146 |
147 | 使用:
148 |
149 | ````csharp
150 | HttpContext.GetRemoteIpInfo();
151 | HttpContext.GetRemoteIpInfo(headerKey); // 从请求头获取ip地址信息,如果你使用了nginx、haproxy等代理
152 | ````
153 |
154 | ## 4. 同时使用 IPTools.China 和 IPTools.International
155 |
156 | IPTools.China 和 IPTools.International 都实现了` IIpSearcher`,`IpTool`类在加载时会检测你所安装的程序包进行初始化,且仅仅初始化一次。`IpTool`具有三个静态只读属性,分别是 `DefaultSearcher`、`IpChinaSearcher`、`IpAllSearcher`。
157 |
158 | - `DefaultSearcher`。`IpTool.Search()` 和 `IpTool.SearchWithI18N()` 将会使用的默认Ip搜索器。
159 | - `IpChinaSearcher`。对应 IPTools.China 实现的搜索器。
160 | - `IpAllSearcher`。对应 IPTools.International 实现的搜索器。
161 |
162 | 如果你只是安装了 IPTools.China 那么,`DefaultSearcher` 将会是 `IpChinaSearcher`,`IpAllSearcher`将会为 null。
163 |
164 | 如果你只是安装了 IPTools.International 那么,`DefaultSearcher` 将会是 `IpAllSearcher`,`IpChinaSearcher`将会为 null。
165 |
166 | 如果你同时安装了以上两个组件,那么默认情况下 `DefaultSearcher` 将会是 `IpChinaSearcher`,`IpChinaSearcher` 和 `IpAllSearcher` 都不会为null。
167 |
168 | 改变`DefaultSearcher` 所使用的默认 Searcher 请使用下面的代码,如果你同时安装了两个组件才会生效。
169 |
170 | ````csharp
171 | IpToolSettings.DefalutSearcherType = IpSearcherType.China;
172 | IpToolSettings.DefalutSearcherType = IpSearcherType.International;
173 | ````
174 |
175 | ## 5. 使用的开源项目
176 |
177 | [**ip2region**](https://github.com/lionsoul2014/ip2region) by [lionsoul2014](https://github.com/lionsoul2014).
178 |
179 | [**GeoIP2-dotnet**](https://github.com/maxmind/GeoIP2-dotnet) by [maxmind](https://github.com/maxmind).
--------------------------------------------------------------------------------
/assets/1534995762038.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/IPTools/d0edda0531ba8c542912cf7cee749de3bdbd912e/assets/1534995762038.png
--------------------------------------------------------------------------------
/assets/1534995856116.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/IPTools/d0edda0531ba8c542912cf7cee749de3bdbd912e/assets/1534995856116.png
--------------------------------------------------------------------------------
/build/common.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/build/package.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | https://github.com/stulzq/IPTools/blob/master/LICENSE
5 | https://github.com/stulzq/IPTools
6 | https://github.com/stulzq/IPTools.git
7 | git
8 | ip
9 | stulzq
10 | stulzq
11 |
12 |
13 |
--------------------------------------------------------------------------------
/build/version.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1
4 | 5
5 | 0
6 |
7 | $(VersionMajor).$(VersionMinor).$(VersionPatch)
8 |
9 |
10 |
--------------------------------------------------------------------------------
/db/GeoLite2-City.mmdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/IPTools/d0edda0531ba8c542912cf7cee749de3bdbd912e/db/GeoLite2-City.mmdb
--------------------------------------------------------------------------------
/db/ip2region.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stulzq/IPTools/d0edda0531ba8c542912cf7cee749de3bdbd912e/db/ip2region.db
--------------------------------------------------------------------------------
/publish.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | set publishdir=%cd%\publish
3 |
4 | echo "pack IP2Region.Ex..."
5 | dotnet pack src/IP2Region.Ex/IP2Region.Ex.csproj -c Release -o %publishdir%
6 | echo "pack IP2Region.Ex success"
7 |
8 | echo "pack IPTools.Core..."
9 | dotnet pack src/IPTools.Core/IPTools.Core.csproj -c Release -o %publishdir%
10 | echo "pack IPTools.Core success"
11 |
12 | echo "pack IPTools.China..."
13 | dotnet pack src/IPTools.China/IPTools.China.csproj -c Release -o %publishdir%
14 | echo "pack IPTools.China success"
15 |
16 | echo "pack IPTools.International..."
17 | dotnet pack src/IPTools.International/IPTools.International.csproj -c Release -o %publishdir%
18 | echo "pack IPTools.International success"
19 | pause
--------------------------------------------------------------------------------
/sample/IPTools.ConsoleApp/IPTools.ConsoleApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.1
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/sample/IPTools.ConsoleApp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using IPTools.Core;
4 |
5 | namespace IPTools.ConsoleApp
6 | {
7 | class Program
8 | {
9 | static void Main(string[] args)
10 | {
11 |
12 | IpToolSettings.LoadInternationalDbToMemory = true;
13 |
14 | Console.WriteLine("Default Searcher:"+ IpTool.Search("171.210.12.163").City);
15 |
16 | Console.WriteLine("IPTools.International Searcher:" + IpTool.IpAllSearcher.Search("171.210.12.163").City);
17 | Console.WriteLine("IPTools.International Searcher with i18n:" + IpTool.IpAllSearcher.SearchWithI18N("171.210.12.163").City);
18 |
19 | Console.WriteLine("IPTools.China Searcher:" + IpTool.IpChinaSearcher.Search("171.210.12.163").City);
20 |
21 | Stopwatch sw = new Stopwatch();
22 | sw.Start();
23 | for (int i = 0; i < 255; i++)
24 | {
25 |
26 | for (int j = 0; j < 255; j++)
27 | {
28 | var info = IpTool.Search($"171.{i}.{j}.163");
29 | }
30 | }
31 | sw.Stop();
32 | Console.WriteLine("Query 65025 ip spend "+sw.ElapsedMilliseconds +" ms.");
33 |
34 | sw.Restart();
35 | for (int i = 0; i < 255; i++)
36 | {
37 |
38 | for (int j = 0; j < 255; j++)
39 | {
40 | var info = IpTool.IpAllSearcher.Search($"171.{i}.{j}.163");
41 | }
42 | }
43 | sw.Stop();
44 | Console.WriteLine("Complex query 65025 ip spend " + sw.ElapsedMilliseconds + " ms.");
45 | Console.Read();
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/IP2Region.Ex/DBSearcher.cs:
--------------------------------------------------------------------------------
1 | //*******************************
2 | // Created By Rocher Kong
3 | // Github https://github.com/RocherKong
4 | // Date 2018.02.09
5 | //*******************************
6 |
7 | using System;
8 | using System.IO;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using IP2Region.Ex.Models;
12 |
13 | namespace IP2Region.Ex
14 | {
15 | public class DbSearcher : IDisposable
16 | {
17 | const int BTREE_ALGORITHM = 1;
18 | const int BINARY_ALGORITHM = 2;
19 | const int MEMORY_ALGORITYM = 3;
20 |
21 | private DbConfig _dbConfig = null;
22 |
23 | ///
24 | /// db file access handler
25 | ///
26 | private Stream _raf = null;
27 |
28 | ///
29 | /// header blocks buffer
30 | ///
31 | private long[] _headerSip = null;
32 | private int[] _headerPtr = null;
33 | private int _headerLength;
34 |
35 | ///
36 | /// super blocks info
37 | ///
38 | private long _firstIndexPtr = 0;
39 | private long _lastIndexPtr = 0;
40 | private int _totalIndexBlocks = 0;
41 |
42 | ///
43 | /// for memory mode
44 | /// the original db binary string
45 | ///
46 | private byte[] _dbBinStr = null;
47 |
48 | ///
49 | /// Get by index ptr.
50 | ///
51 | private DataBlock GetByIndexPtr(long ptr)
52 | {
53 | _raf.Seek(ptr, SeekOrigin.Begin);
54 | byte[] buffer = new byte[12];
55 | _raf.Read(buffer, 0, buffer.Length);
56 | long extra = Utils.GetIntLong(buffer, 8);
57 | int dataLen = (int)((extra >> 24) & 0xFF);
58 | int dataPtr = (int)((extra & 0x00FFFFFF));
59 | _raf.Seek(dataPtr, SeekOrigin.Begin);
60 | byte[] data = new byte[dataLen];
61 | _raf.Read(data, 0, data.Length);
62 | int city_id = (int)Utils.GetIntLong(data, 0);
63 | string region = Encoding.UTF8.GetString(data, 4, data.Length - 4);
64 | return new DataBlock(city_id, region, dataPtr);
65 | }
66 |
67 | public DbSearcher(DbConfig dbConfig, Stream dbFileStream)
68 | {
69 | if (_dbConfig == null)
70 | {
71 | _dbConfig = dbConfig;
72 | }
73 |
74 | _raf = dbFileStream;
75 | }
76 |
77 | public DbSearcher( Stream dbFileStream) : this(null, dbFileStream) { }
78 |
79 | public DbSearcher(DbConfig dbConfig, string dbFile)
80 | {
81 | if (_dbConfig == null)
82 | {
83 | _dbConfig = dbConfig;
84 | }
85 | _raf = new FileStream(dbFile, FileMode.Open, FileAccess.Read, FileShare.Read);
86 | }
87 |
88 | public DbSearcher(string dbFile) : this(null, dbFile) { }
89 |
90 | #region Sync Methods
91 | ///
92 | /// Get the region with a int ip address with memory binary search algorithm.
93 | ///
94 | private DataBlock MemorySearch(long ip)
95 | {
96 | int blen = IndexBlock.LENGTH;
97 | if (_dbBinStr == null)
98 | {
99 | _dbBinStr = new byte[(int)_raf.Length];
100 | _raf.Seek(0L, SeekOrigin.Begin);
101 | _raf.Read(_dbBinStr, 0, _dbBinStr.Length);
102 |
103 | //initialize the global vars
104 | _firstIndexPtr = Utils.GetIntLong(_dbBinStr, 0);
105 | _lastIndexPtr = Utils.GetIntLong(_dbBinStr, 4);
106 | _totalIndexBlocks = (int)((_lastIndexPtr - _firstIndexPtr) / blen) + 1;
107 | }
108 |
109 | //search the index blocks to define the data
110 | int l = 0, h = _totalIndexBlocks;
111 | long sip = 0;
112 |
113 | while (l <= h)
114 | {
115 | int m = (l + h) >> 1;
116 | int p = (int)(_firstIndexPtr + m * blen);
117 |
118 | sip = Utils.GetIntLong(_dbBinStr, p);
119 |
120 | if (ip < sip)
121 | {
122 | h = m - 1;
123 | }
124 | else
125 | {
126 | sip = Utils.GetIntLong(_dbBinStr, p + 4);
127 | if (ip > sip)
128 | {
129 | l = m + 1;
130 | }
131 | else
132 | {
133 | sip = Utils.GetIntLong(_dbBinStr, p + 8);
134 | break;
135 | }
136 | }
137 | }
138 |
139 | //not matched
140 | if (sip == 0) return null;
141 |
142 | //get the data
143 | int dataLen = (int)((sip >> 24) & 0xFF);
144 | int dataPtr = (int)((sip & 0x00FFFFFF));
145 | int city_id = (int)Utils.GetIntLong(_dbBinStr, dataPtr);
146 | string region = Encoding.UTF8.GetString(_dbBinStr, dataPtr + 4, dataLen - 4);//new String(dbBinStr, dataPtr + 4, dataLen - 4, Encoding.UTF8);
147 |
148 | return new DataBlock(city_id, region, dataPtr);
149 | }
150 |
151 | ///
152 | /// Get the region throught the ip address with memory binary search algorithm.
153 | ///
154 | public DataBlock MemorySearch(string ip)
155 | {
156 | return MemorySearch(Utils.Ip2long(ip));
157 | }
158 |
159 | ///
160 | /// Get the region with a int ip address with b-tree algorithm.
161 | ///
162 | private DataBlock BtreeSearch(long ip)
163 | {
164 | //check and load the header
165 | if (_headerSip == null)
166 | {
167 | _raf.Seek(8L, SeekOrigin.Begin); //pass the super block
168 | byte[] b = new byte[4096];
169 | _raf.Read(b, 0, b.Length);
170 | //fill the header
171 | int len = b.Length >> 3, idx = 0; //b.lenght / 8
172 | _headerSip = new long[len];
173 | _headerPtr = new int[len];
174 | long startIp, dataPtrTemp;
175 | for (int i = 0; i < b.Length; i += 8)
176 | {
177 | startIp = Utils.GetIntLong(b, i);
178 | dataPtrTemp = Utils.GetIntLong(b, i + 4);
179 | if (dataPtrTemp == 0) break;
180 |
181 | _headerSip[idx] = startIp;
182 | _headerPtr[idx] = (int)dataPtrTemp;
183 | idx++;
184 | }
185 | _headerLength = idx;
186 | }
187 |
188 | //1. define the index block with the binary search
189 | if (ip == _headerSip[0])
190 | {
191 | return GetByIndexPtr(_headerPtr[0]);
192 | }
193 | else if (ip == _headerPtr[_headerLength - 1])
194 | {
195 | return GetByIndexPtr(_headerPtr[_headerLength - 1]);
196 | }
197 | int l = 0, h = _headerLength, sptr = 0, eptr = 0;
198 | int m = 0;
199 | while (l <= h)
200 | {
201 | m = (l + h) >> 1;
202 | //perfectly matched, just return it
203 | if (ip == _headerSip[m])
204 | {
205 | if (m > 0)
206 | {
207 | sptr = _headerPtr[m - 1];
208 | eptr = _headerPtr[m];
209 | }
210 | else
211 | {
212 | sptr = _headerPtr[m];
213 | eptr = _headerPtr[m + 1];
214 | }
215 | }
216 | //less then the middle value
217 | else if (ip < _headerSip[m])
218 | {
219 | if (m == 0)
220 | {
221 | sptr = _headerPtr[m];
222 | eptr = _headerPtr[m + 1];
223 | break;
224 | }
225 | else if (ip > _headerSip[m - 1])
226 | {
227 | sptr = _headerPtr[m - 1];
228 | eptr = _headerPtr[m];
229 | break;
230 | }
231 | h = m - 1;
232 | }
233 | else
234 | {
235 | if (m == _headerLength - 1)
236 | {
237 | sptr = _headerPtr[m - 1];
238 | eptr = _headerPtr[m];
239 | break;
240 | }
241 | else if (ip <= _headerSip[m + 1])
242 | {
243 | sptr = _headerPtr[m];
244 | eptr = _headerPtr[m + 1];
245 | break;
246 | }
247 | l = m + 1;
248 | }
249 | }
250 | //match nothing just stop it
251 | if (sptr == 0) return null;
252 | //2. search the index blocks to define the data
253 | int blockLen = eptr - sptr, blen = IndexBlock.LENGTH;
254 | byte[] iBuffer = new byte[blockLen + blen]; //include the right border block
255 | _raf.Seek(sptr, SeekOrigin.Begin);
256 | _raf.Read(iBuffer, 0, iBuffer.Length);
257 | l = 0; h = blockLen / blen;
258 | long sip = 0;
259 | int p = 0;
260 | while (l <= h)
261 | {
262 | m = (l + h) >> 1;
263 | p = m * blen;
264 | sip = Utils.GetIntLong(iBuffer, p);
265 | if (ip < sip)
266 | {
267 | h = m - 1;
268 | }
269 | else
270 | {
271 | sip = Utils.GetIntLong(iBuffer, p + 4);
272 | if (ip > sip)
273 | {
274 | l = m + 1;
275 | }
276 | else
277 | {
278 | sip = Utils.GetIntLong(iBuffer, p + 8);
279 | break;
280 | }
281 | }
282 | }
283 | //not matched
284 | if (sip == 0) return null;
285 | //3. get the data
286 | int dataLen = (int)((sip >> 24) & 0xFF);
287 | int dataPtr = (int)((sip & 0x00FFFFFF));
288 | _raf.Seek(dataPtr, SeekOrigin.Begin);
289 | byte[] data = new byte[dataLen];
290 | _raf.Read(data, 0, data.Length);
291 | int city_id = (int)Utils.GetIntLong(data, 0);
292 | String region = Encoding.UTF8.GetString(data, 4, data.Length - 4);// new String(data, 4, data.Length - 4, "UTF-8");
293 | return new DataBlock(city_id, region, dataPtr);
294 | }
295 |
296 | ///
297 | /// Get the region throught the ip address with b-tree search algorithm.
298 | ///
299 | public DataBlock BtreeSearch(string ip)
300 | {
301 | return BtreeSearch(Utils.Ip2long(ip));
302 | }
303 |
304 | ///
305 | /// Get the region with a int ip address with binary search algorithm.
306 | ///
307 | private DataBlock BinarySearch(long ip)
308 | {
309 | int blen = IndexBlock.LENGTH;
310 | if (_totalIndexBlocks == 0)
311 | {
312 | _raf.Seek(0L, SeekOrigin.Begin);
313 | byte[] superBytes = new byte[8];
314 | _raf.Read(superBytes, 0, superBytes.Length);
315 | //initialize the global vars
316 | _firstIndexPtr = Utils.GetIntLong(superBytes, 0);
317 | _lastIndexPtr = Utils.GetIntLong(superBytes, 4);
318 | _totalIndexBlocks = (int)((_lastIndexPtr - _firstIndexPtr) / blen) + 1;
319 | }
320 |
321 | //search the index blocks to define the data
322 | int l = 0, h = _totalIndexBlocks;
323 | byte[] buffer = new byte[blen];
324 | long sip = 0;
325 | while (l <= h)
326 | {
327 | int m = (l + h) >> 1;
328 | _raf.Seek(_firstIndexPtr + m * blen, SeekOrigin.Begin); //set the file pointer
329 | _raf.Read(buffer, 0, buffer.Length);
330 | sip = Utils.GetIntLong(buffer, 0);
331 | if (ip < sip)
332 | {
333 | h = m - 1;
334 | }
335 | else
336 | {
337 | sip = Utils.GetIntLong(buffer, 4);
338 | if (ip > sip)
339 | {
340 | l = m + 1;
341 | }
342 | else
343 | {
344 | sip = Utils.GetIntLong(buffer, 8);
345 | break;
346 | }
347 | }
348 | }
349 | //not matched
350 | if (sip == 0) return null;
351 | //get the data
352 | int dataLen = (int)((sip >> 24) & 0xFF);
353 | int dataPtr = (int)((sip & 0x00FFFFFF));
354 | _raf.Seek(dataPtr, SeekOrigin.Begin);
355 | byte[] data = new byte[dataLen];
356 | _raf.Read(data, 0, data.Length);
357 | int city_id = (int)Utils.GetIntLong(data, 0);
358 | String region = Encoding.UTF8.GetString(data, 4, data.Length - 4);//new String(data, 4, data.Length - 4, "UTF-8");
359 | return new DataBlock(city_id, region, dataPtr);
360 | }
361 |
362 | ///
363 | /// Get the region throught the ip address with binary search algorithm.
364 | ///
365 | public DataBlock BinarySearch(String ip)
366 | {
367 | return BinarySearch(Utils.Ip2long(ip));
368 | }
369 | #endregion
370 |
371 | #region Async Methods
372 | ///
373 | /// Get the region throught the ip address with memory binary search algorithm.
374 | ///
375 | public Task MemorySearchAsync(string ip)
376 | {
377 | return Task.FromResult(MemorySearch(ip));
378 | }
379 | ///
380 | /// Get the region throught the ip address with b-tree search algorithm.
381 | ///
382 | public Task BtreeSearchAsync(string ip)
383 | {
384 | return Task.FromResult(BtreeSearch(ip));
385 | }
386 | ///
387 | /// Get the region throught the ip address with binary search algorithm.
388 | ///
389 | public Task BinarySearchAsync(string ip)
390 | {
391 | return Task.FromResult(BinarySearch(ip));
392 | }
393 | #endregion
394 |
395 | ///
396 | /// Close the db.
397 | ///
398 | public void Close()
399 | {
400 | _headerSip = null;
401 | _headerPtr = null;
402 | _dbBinStr = null;
403 | _raf.Close();
404 | }
405 |
406 | public void Dispose()
407 | {
408 | Close();
409 | }
410 | }
411 |
412 | }
413 |
--------------------------------------------------------------------------------
/src/IP2Region.Ex/IP2Region.Ex.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0;net45;net451;net452;net461
5 | https://github.com/stulzq/IPTools/tree/master/src/IP2Region.Ex
6 | Add extensions base on https://www.nuget.org/packages/IP2Region/
7 | Rocher.Kong
8 | 1.2.0
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/IP2Region.Ex/IP2Region.LICENSE.md:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 | ==========================================================================
204 | The following license applies to the ip2region library
205 | --------------------------------------------------------------------------
206 | Copyright (c) 2015 Lionsoul
207 |
208 | Permission is hereby granted, free of charge, to any person obtaining
209 | a copy of this software and associated documentation files (the
210 | "Software"), to deal in the Software without restriction, including
211 | without limitation the rights to use, copy, modify, merge, publish,
212 | distribute, sublicense, and/or sell copies of the Software, and to
213 | permit persons to whom the Software is furnished to do so, subject to
214 | the following conditions:
215 |
216 | The above copyright notice and this permission notice shall be
217 | included in all copies or substantial portions of the Software.
218 |
219 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
220 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
221 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
222 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
223 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
224 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
225 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
226 |
--------------------------------------------------------------------------------
/src/IP2Region.Ex/Models/DataBlock.cs:
--------------------------------------------------------------------------------
1 | //*******************************
2 | // Created By Rocher Kong
3 | // Github https://github.com/RocherKong
4 | // Date 2018.02.09
5 | //*******************************
6 | namespace IP2Region.Ex.Models
7 | {
8 | public class DataBlock
9 | {
10 | #region Private Properties
11 | public int CityID
12 | {
13 | get;
14 | private set;
15 | }
16 |
17 | public string Region
18 | {
19 | get;
20 | private set;
21 | }
22 |
23 | public int DataPtr
24 | {
25 | get;
26 | private set;
27 | }
28 | #endregion
29 |
30 | #region Constructor
31 | public DataBlock(int city_id, string region, int dataPtr = 0)
32 | {
33 | CityID = city_id;
34 | Region = region;
35 | DataPtr = dataPtr;
36 | }
37 |
38 | public DataBlock(int city_id, string region):this(city_id,region,0)
39 | {
40 | }
41 | #endregion
42 |
43 | public override string ToString()
44 | {
45 | return $"{CityID}|{Region}|{DataPtr}";
46 | }
47 |
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/IP2Region.Ex/Models/DbConfig.cs:
--------------------------------------------------------------------------------
1 | //*******************************
2 | // Created By Rocher Kong
3 | // Github https://github.com/RocherKong
4 | // Date 2018.02.09
5 | //*******************************
6 |
7 | using System;
8 |
9 | namespace IP2Region.Ex.Models
10 | {
11 | public class DbMakerConfigException : Exception
12 | {
13 | public string ErrMsg { get; private set; }
14 | public DbMakerConfigException(string errMsg)
15 | {
16 | ErrMsg = errMsg;
17 | }
18 | }
19 |
20 | public class DbConfig
21 | {
22 | public int TotalHeaderSize
23 | {
24 | get;
25 | private set;
26 | }
27 |
28 | public int indexBlockSize
29 | {
30 | get;
31 | private set;
32 | }
33 |
34 | public DbConfig(int totalHeaderSize)
35 | {
36 | if ((totalHeaderSize % 8) != 0)
37 | {
38 | throw new DbMakerConfigException("totalHeaderSize must be times of 8");
39 | }
40 | TotalHeaderSize = totalHeaderSize;
41 | //4 * 2048
42 | indexBlockSize = 8192;
43 | }
44 |
45 | public DbConfig():this(8 * 2048)
46 | {
47 | }
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/src/IP2Region.Ex/Models/HeaderBlock.cs:
--------------------------------------------------------------------------------
1 | //*******************************
2 | // Created By Rocher Kong
3 | // Github https://github.com/RocherKong
4 | // Date 2018.02.09
5 | //*******************************
6 |
7 | namespace IP2Region.Ex.Models
8 | {
9 | internal class HeaderBlock
10 | {
11 | public long IndexStartIp
12 | {
13 | get;
14 | private set;
15 | }
16 |
17 | public int IndexPtr
18 | {
19 | get;
20 | private set;
21 | }
22 |
23 | public HeaderBlock(long indexStartIp, int indexPtr)
24 | {
25 | IndexStartIp = indexStartIp;
26 | IndexPtr = indexPtr;
27 | }
28 |
29 | ///
30 | /// Get the bytes for total storage
31 | ///
32 | ///
33 | /// Bytes gotten.
34 | ///
35 | public byte[] GetBytes()
36 | {
37 | /*
38 | * +------------+-----------+
39 | * | 4bytes | 4bytes |
40 | * +------------+-----------+
41 | * start ip index ptr
42 | */
43 | byte[] b = new byte[8];
44 | Utils.WriteIntLong(b, 0, IndexStartIp);
45 | Utils.WriteIntLong(b, 4, IndexPtr);
46 | return b;
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/src/IP2Region.Ex/Models/IndexBlock.cs:
--------------------------------------------------------------------------------
1 | //*******************************
2 | // Created By Rocher Kong
3 | // Github https://github.com/RocherKong
4 | // Date 2018.02.09
5 | //*******************************
6 |
7 | namespace IP2Region.Ex.Models
8 | {
9 | internal class IndexBlock
10 | {
11 | public const int LENGTH = 12;
12 |
13 | public long StartIP
14 | {
15 | get;
16 | private set;
17 | }
18 |
19 | public long EndIp
20 | {
21 | get;
22 | private set;
23 | }
24 |
25 | public uint DataPtr
26 | {
27 | get;
28 | private set;
29 | }
30 |
31 | public int DataLen
32 | {
33 | get;
34 | private set;
35 | }
36 |
37 | public IndexBlock(long startIp, long endIp, uint dataPtr, int dataLen)
38 | {
39 | StartIP = startIp;
40 | EndIp = endIp;
41 | DataPtr = dataPtr;
42 | DataLen = dataLen;
43 | }
44 |
45 | public byte[] GetBytes()
46 | {
47 | /*
48 | * +------------+-----------+-----------+
49 | * | 4bytes | 4bytes | 4bytes |
50 | * +------------+-----------+-----------+
51 | * start ip end ip data ptr + len
52 | */
53 | byte[] b = new byte[12];
54 |
55 | Utils.WriteIntLong(b, 0, StartIP); //start ip
56 | Utils.WriteIntLong(b, 4, EndIp); //end ip
57 |
58 | //write the data ptr and the length
59 | long mix = DataPtr | ((DataLen << 24) & 0xFF000000L);
60 | Utils.WriteIntLong(b, 8, mix);
61 |
62 | return b;
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/src/IP2Region.Ex/README.md:
--------------------------------------------------------------------------------
1 | # IP2Region.Ex
2 |
3 | IP2Region.Ex is a cloned IP2Region project, named IP2Region.Ex in order not to conflict with the original project name. I modified some files and added some code to make it easy to use. At the same time I will also add the code like the original author submitted pull request. This project will be closed when the original author accepts the pull request I submitted.
4 |
5 | IP2Region https://github.com/lionsoul2014/ip2region
6 |
7 | ## Modified file list
8 |
9 | DBSearcher.cs
--------------------------------------------------------------------------------
/src/IP2Region.Ex/Utils.cs:
--------------------------------------------------------------------------------
1 | //*******************************
2 | // Created By Rocher Kong
3 | // Github https://github.com/RocherKong
4 | // Date 2018.02.09
5 | //*******************************
6 |
7 | using System;
8 |
9 | namespace IP2Region.Ex
10 | {
11 | public class IPInValidException : Exception
12 | {
13 | const string ERROR_MSG = "IP Illigel. Please input a valid IP.";
14 | public IPInValidException() : base(ERROR_MSG) { }
15 | }
16 | internal static class Utils
17 | {
18 | ///
19 | /// Write specfield bytes to a byte array start from offset.
20 | ///
21 | public static void Write(byte[] b, int offset, ulong v, int bytes)
22 | {
23 | for (int i = 0; i < bytes; i++)
24 | {
25 | b[offset++] = (byte)((v >> (8 * i)) & 0xFF);
26 | }
27 | }
28 |
29 | ///
30 | /// Write a int to a byte array.
31 | ///
32 | public static void WriteIntLong(byte[] b, int offset, long v)
33 | {
34 | b[offset++] = (byte)((v >> 0) & 0xFF);
35 | b[offset++] = (byte)((v >> 8) & 0xFF);
36 | b[offset++] = (byte)((v >> 16) & 0xFF);
37 | b[offset] = (byte)((v >> 24) & 0xFF);
38 | }
39 |
40 | ///
41 | /// Get a int from a byte array start from the specifiled offset.
42 | ///
43 | public static long GetIntLong(byte[] b, int offset)
44 | {
45 | return (
46 | ((b[offset++] & 0x000000FFL)) |
47 | ((b[offset++] << 8) & 0x0000FF00L) |
48 | ((b[offset++] << 16) & 0x00FF0000L) |
49 | ((b[offset] << 24) & 0xFF000000L)
50 | );
51 | }
52 |
53 | ///
54 | /// Get a int from a byte array start from the specifield offset.
55 | ///
56 | public static int GetInt3(byte[] b, int offset)
57 | {
58 | return (
59 | (b[offset++] & 0x000000FF) |
60 | (b[offset++] & 0x0000FF00) |
61 | (b[offset] & 0x00FF0000)
62 | );
63 | }
64 |
65 | public static int GetInt2(byte[] b, int offset)
66 | {
67 | return (
68 | (b[offset++] & 0x000000FF) |
69 | (b[offset] & 0x0000FF00)
70 | );
71 | }
72 |
73 | public static int GetInt1(byte[] b, int offset)
74 | {
75 | return (
76 | (b[offset] & 0x000000FF)
77 | );
78 | }
79 | ///
80 | /// String ip to long ip.
81 | ///
82 | public static long Ip2long(string ip)
83 | {
84 | string[] p = ip.Split('.');
85 | if (p.Length != 4) throw new IPInValidException();
86 |
87 | foreach (string pp in p)
88 | {
89 | if (pp.Length > 3) throw new IPInValidException();
90 | if (!int.TryParse(pp, out int value) || value > 255)
91 | {
92 | throw new IPInValidException();
93 | }
94 | }
95 | var bip1 = long.TryParse(p[0], out long ip1);
96 | var bip2 = long.TryParse(p[1], out long ip2);
97 | var bip3 = long.TryParse(p[2], out long ip3);
98 | var bip4 = long.TryParse(p[3], out long ip4);
99 |
100 | if (!bip1 || !bip2 || !bip3 || !bip4
101 | || ip4 > 255 || ip1 > 255 || ip2 > 255 || ip3 > 255
102 | || ip4 < 0 || ip1 < 0 || ip2 < 0 || ip3 < 0)
103 | {
104 | throw new IPInValidException();
105 | }
106 | long p1 = ((ip1 << 24) & 0xFF000000);
107 | long p2 = ((ip2 << 16) & 0x00FF0000);
108 | long p3 = ((ip3 << 8) & 0x0000FF00);
109 | long p4 = ((ip4 << 0) & 0x000000FF);
110 | return ((p1 | p2 | p3 | p4) & 0xFFFFFFFFL);
111 | }
112 |
113 | ///
114 | /// Int to ip string.
115 | ///
116 | public static string Long2ip(long ip)
117 | {
118 | return $"{(ip >> 24) & 0xFF}.{(ip >> 16) & 0xFF}.{(ip >> 8) & 0xFF}.{ip & 0xFF}";
119 | }
120 | }
121 |
122 | }
--------------------------------------------------------------------------------
/src/IPTools.China/IPTools.China.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1;net45;net451;net452;net461
5 | Quickly query China IP information, national, provincial, city and network operators. Non China IP can only query national information.Docs: https://github.com/stulzq/IPTools.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | PreserveNewest
29 | True
30 | %(FileName).db
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/IPTools.China/IpSimpleSearcher.cs:
--------------------------------------------------------------------------------
1 | // #region File Annotation
2 | //
3 | // Author:Zhiqiang Li
4 | //
5 | // FileName:IpLightweightSearcher.cs
6 | //
7 | // Project:IPTools.China
8 | //
9 | // CreateDate:2018/08/19
10 | //
11 | // Note: The reference to this document code must not delete this note, and indicate the source!
12 | //
13 | // #endregion
14 |
15 | using System;
16 | using System.IO;
17 | using System.Reflection;
18 | using IP2Region.Ex;
19 | using IPTools.Core;
20 | using IPTools.Core.Exception;
21 |
22 | namespace IPTools.China
23 | {
24 | public class IpSimpleSearcher:IIpSearcher
25 | {
26 | private readonly DbSearcher _search;
27 |
28 | public IpSimpleSearcher()
29 | {
30 | /*Assembly assembly = Assembly.GetExecutingAssembly();
31 | var dbResourceStream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.ip2region.db");
32 | _search = new DbSearcher(dbResourceStream);*/
33 | #if NETSTANDARD2_0
34 | var dbPath = Path.Combine(AppContext.BaseDirectory, "ip2region.db");
35 | #else
36 | var dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ip2region.db");
37 | #endif
38 | if (!string.IsNullOrEmpty(IpToolSettings.ChinaDbPath))
39 | {
40 | dbPath = IpToolSettings.ChinaDbPath;
41 | }
42 | if (!File.Exists(dbPath))
43 | {
44 | throw new IpToolException($"IPTools.China initialize failed. Can not find database file from {dbPath}. Please download the file to your application root directory, then set it can be copied to the output directory. Url: https://github.com/stulzq/IPTools/raw/master/db/ip2region.db");
45 | }
46 |
47 | _search = new DbSearcher(dbPath);
48 | }
49 |
50 | public IpInfo Search(string ip)
51 | {
52 | if (string.IsNullOrEmpty(ip))
53 | {
54 | throw new ArgumentException(nameof(ip));
55 | }
56 |
57 | var region = _search.MemorySearch(ip).Region;
58 | var ipinfo = RegionStrToIpInfo(region);
59 | ipinfo.IpAddress = ip;
60 | return ipinfo;
61 | }
62 |
63 | public IpInfo SearchWithI18N(string ip, string langCode)
64 | {
65 | throw new NotImplementedException();
66 | }
67 |
68 | private IpInfo RegionStrToIpInfo(string region)
69 | {
70 | try
71 | {
72 | var array = region.Split('|');
73 | var info = new IpInfo()
74 | {
75 | Country = array[0],
76 | Province = array[2],
77 | City = array[3],
78 | NetworkOperator = array[4]
79 | };
80 | return info;
81 | }
82 | catch(Exception e)
83 | {
84 | throw new IpToolException("Error converting ip address information to ipinfo object",e);
85 | }
86 | }
87 |
88 | public void Dispose()
89 | {
90 | _search?.Dispose();
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/src/IPTools.Core/Exception/IpToolException.cs:
--------------------------------------------------------------------------------
1 | // #region File Annotation
2 | //
3 | // Author:Zhiqiang Li
4 | //
5 | // FileName:IpToolException.cs
6 | //
7 | // Project:IPTools.Core
8 | //
9 | // CreateDate:2018/08/19
10 | //
11 | // Note: The reference to this document code must not delete this note, and indicate the source!
12 | //
13 | // #endregion
14 |
15 | namespace IPTools.Core.Exception
16 | {
17 | public class IpToolException:System.Exception
18 | {
19 | public IpToolException(string message) : base(message)
20 | {
21 | }
22 |
23 | public IpToolException(string message,System.Exception innerException) : base(message, innerException)
24 | {
25 | }
26 |
27 | }
28 | }
--------------------------------------------------------------------------------
/src/IPTools.Core/Extensions/IpToolExtension.cs:
--------------------------------------------------------------------------------
1 | // #region File Annotation
2 | //
3 | // Author:Zhiqiang Li
4 | //
5 | // FileName:IpToolExtension.cs
6 | //
7 | // Project:IPTools.Core
8 | //
9 | // CreateDate:2018/08/19
10 | //
11 | // Note: The reference to this document code must not delete this note, and indicate the source!
12 | //
13 | // #endregion
14 |
15 |
16 | #if NETCOREAPP3_1
17 | using Microsoft.AspNetCore.Http;
18 | #else
19 | using System.Web;
20 | #endif
21 |
22 | namespace IPTools.Core.Extensions
23 | {
24 | public static class IpToolExtension
25 | {
26 | public static IpInfo GetRemoteIpInfo(this HttpContext context)
27 | {
28 | #if NETCOREAPP3_1
29 |
30 | return IpTool.Search(context.Connection.RemoteIpAddress.ToString());
31 | #else
32 | return IpTool.Search(context.Request.UserHostAddress);
33 | #endif
34 | }
35 |
36 | ///
37 | /// Get ip info from request header.
38 | ///
39 | ///
40 | /// request header key.
41 | ///
42 | public static IpInfo GetRemoteIpInfo(this HttpContext context,string headerKey)
43 | {
44 | return IpTool.Search(context.Request.Headers[headerKey]);
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/src/IPTools.Core/IIpSearcher.cs:
--------------------------------------------------------------------------------
1 | // #region File Annotation
2 | //
3 | // Author:Zhiqiang Li
4 | //
5 | // FileName:IIpSearcher.cs
6 | //
7 | // Project:IPTools.Core
8 | //
9 | // CreateDate:2018/08/19
10 | //
11 | // Note: The reference to this document code must not delete this note, and indicate the source!
12 | //
13 | // #endregion
14 |
15 | namespace IPTools.Core
16 | {
17 | public interface IIpSearcher
18 | {
19 | IpInfo Search(string ip);
20 |
21 | IpInfo SearchWithI18N(string ip,string langCode="");
22 | }
23 | }
--------------------------------------------------------------------------------
/src/IPTools.Core/IPTools.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1;net45;net451;net452;net461
5 | The IPtools abstraction layer can not be used alone.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/IPTools.Core/IpInfo.cs:
--------------------------------------------------------------------------------
1 | // #region File Annotation
2 | //
3 | // Author:Zhiqiang Li
4 | //
5 | // FileName:IpInfo.cs
6 | //
7 | // Project:IPTools.Core
8 | //
9 | // CreateDate:2018/08/19
10 | //
11 | // Note: The reference to this document code must not delete this note, and indicate the source!
12 | //
13 | // #endregion
14 |
15 | namespace IPTools.Core
16 | {
17 | public class IpInfo
18 | {
19 | public string IpAddress { get; set; }
20 |
21 | public string Country { get; set; }
22 |
23 | public string CountryCode { get; set; }
24 |
25 | public string Province { get; set; }
26 | public string ProvinceCode { get; set; }
27 |
28 | public string City { get; set; }
29 |
30 | public string PostCode { get; set; }
31 |
32 | public string NetworkOperator { get; set; }
33 |
34 | public double? Latitude { get; set; } = 0d;
35 |
36 | public double? Longitude { get; set; } = 0d;
37 | public int? AccuracyRadius { get; set; }
38 | }
39 | }
--------------------------------------------------------------------------------
/src/IPTools.Core/IpSearcherType.cs:
--------------------------------------------------------------------------------
1 | // #region File Annotation
2 | //
3 | // Author:Zhiqiang Li
4 | //
5 | // FileName:IpSearcherType.cs
6 | //
7 | // Project:IPTools.Core
8 | //
9 | // CreateDate:2018/08/20
10 | //
11 | // Note: The reference to this document code must not delete this note, and indicate the source!
12 | //
13 | // #endregion
14 |
15 | namespace IPTools.Core
16 | {
17 | public enum IpSearcherType
18 | {
19 | China,
20 | International
21 | }
22 | }
--------------------------------------------------------------------------------
/src/IPTools.Core/IpTool.cs:
--------------------------------------------------------------------------------
1 | // #region File Annotation
2 | //
3 | // Author:Zhiqiang Li
4 | //
5 | // FileName:IpTool.cs
6 | //
7 | // Project:IPTools.Core
8 | //
9 | // CreateDate:2018/08/19
10 | //
11 | // Note: The reference to this document code must not delete this note, and indicate the source!
12 | //
13 | // #endregion
14 |
15 | using System;
16 | using System.IO;
17 | using System.Reflection;
18 | #if !NETSTANDARD2_0
19 | using System.Web;
20 | #endif
21 | using IPTools.Core.Exception;
22 |
23 | namespace IPTools.Core
24 | {
25 | public static class IpTool
26 | {
27 | //IPTools.International asm name
28 | private const string IpAllAsmName = "IPTools.International";
29 | //IPTools.China asm name
30 | private const string IpCnAsmName = "IPTools.China";
31 |
32 | ///
33 | /// If you add IPTools.International and IPTools.China to your project.The IPTools.China is Default IpSearcher.
34 | ///
35 | public static readonly IIpSearcher DefaultSearcher;
36 |
37 | ///
38 | /// IPTools.China
39 | ///
40 | public static readonly IIpSearcher IpChinaSearcher;
41 |
42 | ///
43 | /// IPTools.International
44 | ///
45 | public static readonly IIpSearcher IpAllSearcher;
46 |
47 | static IpTool()
48 | {
49 | try
50 | {
51 | #if NETSTANDARD2_0
52 | var depJsonName = Path.Combine(AppContext.BaseDirectory,
53 | $"{Assembly.GetEntryAssembly().GetName().Name}.deps.json");
54 | var depJsonStr = File.ReadAllText(depJsonName);
55 | if (File.Exists(Path.Combine(AppContext.BaseDirectory, IpCnAsmName + ".dll"))|| depJsonStr.Contains(IpCnAsmName))
56 | {
57 | var ipCnAsm = Assembly.Load(IpCnAsmName);
58 | IpChinaSearcher = (IIpSearcher)ipCnAsm.CreateInstance("IPTools.China.IpSimpleSearcher");
59 | }
60 |
61 | if (File.Exists(Path.Combine(AppContext.BaseDirectory, IpAllAsmName + ".dll"))|| depJsonStr.Contains(IpAllAsmName))
62 | {
63 | var ipAllAsm = Assembly.Load(IpAllAsmName);
64 | IpAllSearcher = (IIpSearcher)ipAllAsm.CreateInstance("IPTools.International.IpComplexSearcher");
65 | }
66 | #else
67 |
68 | #region China
69 |
70 | if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, IpCnAsmName + ".dll"))) //netfx console
71 | {
72 | var ipCnAsm = Assembly.Load(IpCnAsmName);
73 | IpChinaSearcher = (IIpSearcher)ipCnAsm.CreateInstance("IPTools.China.IpSimpleSearcher");
74 | }
75 | else if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin", IpCnAsmName + ".dll"))) // netfx asp.net
76 | {
77 | var ipCnAsm = Assembly.Load(IpCnAsmName);
78 | IpChinaSearcher = (IIpSearcher)ipCnAsm.CreateInstance("IPTools.China.IpSimpleSearcher");
79 | }
80 |
81 | #endregion
82 |
83 | #region All
84 |
85 | if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, IpAllAsmName + ".dll"))) //netfx console
86 | {
87 | var ipAllAsm = Assembly.Load(IpAllAsmName);
88 | IpAllSearcher = (IIpSearcher)ipAllAsm.CreateInstance("IPTools.International.IpComplexSearcher");
89 | }
90 | else if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin", IpAllAsmName + ".dll"))) // netfx asp.net
91 | {
92 | var ipAllAsm = Assembly.Load(IpAllAsmName);
93 | IpAllSearcher = (IIpSearcher)ipAllAsm.CreateInstance("IPTools.International.IpComplexSearcher");
94 | }
95 |
96 | #endregion
97 | #endif
98 |
99 |
100 | if (IpChinaSearcher == null && IpAllSearcher == null)
101 | {
102 | throw new IpToolException("Can not load any IpSearcher.");
103 | }
104 | else if (IpChinaSearcher != null && IpAllSearcher != null)
105 | {
106 | DefaultSearcher = IpToolSettings.DefalutSearcherType == IpSearcherType.International ? IpAllSearcher : IpChinaSearcher;
107 | }
108 | else if (IpChinaSearcher != null)
109 | {
110 | DefaultSearcher = IpChinaSearcher;
111 | }
112 | else
113 | {
114 | DefaultSearcher = IpAllSearcher;
115 | }
116 | }
117 | catch (System.Exception e)
118 | {
119 | throw new IpToolException("IPTools initialize failed.", e);
120 | }
121 |
122 | }
123 |
124 |
125 | ///
126 | /// Use DefaultSearcher get ip addredd information.
127 | ///
128 | ///
129 | ///
130 | public static IpInfo Search(string ip)
131 | {
132 | return DefaultSearcher.Search(ip);
133 | }
134 |
135 | ///
136 | /// Use DefaultSearcher get ip addredd information with i8n.
137 | ///
138 | /// Now support IPTools.China.
139 | ///
140 | ///
141 | /// language code.eg. zh-CN, en.
142 | ///
143 | public static IpInfo SearchWithI18N(string ip, string langCode = "")
144 | {
145 | return DefaultSearcher.SearchWithI18N(ip, langCode);
146 | }
147 | }
148 | }
--------------------------------------------------------------------------------
/src/IPTools.Core/IpToolSettings.cs:
--------------------------------------------------------------------------------
1 | // #region File Annotation
2 | //
3 | // Author:Zhiqiang Li
4 | //
5 | // FileName:IpToolSettings.cs
6 | //
7 | // Project:IPTools.Core
8 | //
9 | // CreateDate:2018/08/19
10 | //
11 | // Note: The reference to this document code must not delete this note, and indicate the source!
12 | //
13 | // #endregion
14 |
15 | namespace IPTools.Core
16 | {
17 | public class IpToolSettings
18 | {
19 | ///
20 | /// Default language code, eg. zh-CN, en
21 | ///
22 | public static string DefaultLanguage = "zh-CN";
23 |
24 | ///
25 | /// Only when IPTools.International and IPTools.China are applied at the same time will they take effect.
26 | ///
27 | public static IpSearcherType DefalutSearcherType = IpSearcherType.China;
28 |
29 | ///
30 | /// It can double the query speed. Only using IPTools.International will take effect.
31 | ///
32 | public static bool LoadInternationalDbToMemory = false;
33 |
34 | public static string ChinaDbPath = string.Empty;
35 |
36 | public static string InternationalDbPath = string.Empty;
37 | }
38 | }
--------------------------------------------------------------------------------
/src/IPTools.International/IPTools.International.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1;net45;net451;net452;net461
5 | Quickly query global IP information, support multi lingual, national, provincial, city, longitude and latitude.Docs: https://github.com/stulzq/IPTools.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | PreserveNewest
32 | True
33 | %(FileName).mmdb
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/IPTools.International/IpComplexSearcher.cs:
--------------------------------------------------------------------------------
1 | // #region File Annotation
2 | //
3 | // Author:Zhiqiang Li
4 | //
5 | // FileName:IpHeavyweightSearcher.cs
6 | //
7 | // Project:IPTools.International
8 | //
9 | // CreateDate:2018/08/19
10 | //
11 | // Note: The reference to this document code must not delete this note, and indicate the source!
12 | //
13 | // #endregion
14 |
15 | using System;
16 | using System.IO;
17 | using System.IO.MemoryMappedFiles;
18 | using System.Reflection;
19 | using IPTools.Core;
20 | using IPTools.Core.Exception;
21 | using MaxMind.GeoIP2;
22 |
23 | namespace IPTools.International
24 | {
25 | public class IpComplexSearcher:IIpSearcher
26 | {
27 | private readonly DatabaseReader _search;
28 |
29 | public IpComplexSearcher()
30 | {
31 | // Assembly assembly = Assembly.GetExecutingAssembly();
32 | // var dbResourceStream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.GeoLite2-City.mmdb");
33 | // _search = new DatabaseReader(dbResourceStream);
34 |
35 | #if NETSTANDARD2_0
36 | var dbPath = Path.Combine(AppContext.BaseDirectory, "GeoLite2-City.mmdb");
37 | #else
38 | var dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "GeoLite2-City.mmdb");
39 | #endif
40 | if (!string.IsNullOrEmpty(IpToolSettings.InternationalDbPath))
41 | {
42 | dbPath = IpToolSettings.InternationalDbPath;
43 | }
44 | if (!File.Exists(dbPath))
45 | {
46 | throw new IpToolException($"IPTools.International initialize failed. Can not find database file from {dbPath}. Please download the file to your application root directory, then set it can be copied to the output directory. Url: https://github.com/stulzq/IPTools/raw/master/db/GeoLite2-City.mmdb");
47 | }
48 |
49 | if (IpToolSettings.LoadInternationalDbToMemory)
50 | {
51 | MemoryMappedFile file = MemoryMappedFile.CreateFromFile(dbPath);
52 | _search = new DatabaseReader(file.CreateViewStream());
53 | }
54 | else
55 | {
56 | _search = new DatabaseReader(dbPath);
57 | }
58 |
59 | }
60 |
61 | public IpInfo Search(string ip)
62 | {
63 | if (string.IsNullOrEmpty(ip))
64 | {
65 | throw new ArgumentException(nameof(ip));
66 | }
67 |
68 | if (_search.TryCity(ip, out var city))
69 | {
70 | var ipinfo = new IpInfo
71 | {
72 | IpAddress = ip,
73 | CountryCode = city.Country.IsoCode,
74 | Country = city.Country.Name,
75 | Province = city.MostSpecificSubdivision.Name,
76 | ProvinceCode = city.MostSpecificSubdivision.IsoCode,
77 | City =city.City.Name,
78 | PostCode = city.Postal.Code,
79 | Latitude = city.Location.Latitude,
80 | Longitude = city.Location.Longitude,
81 | AccuracyRadius = city.Location.AccuracyRadius
82 | };
83 | return ipinfo;
84 | }
85 | else
86 | {
87 | return new IpInfo();
88 | }
89 |
90 | }
91 |
92 | public IpInfo SearchWithI18N(string ip, string langCode="")
93 | {
94 | if (string.IsNullOrEmpty(ip))
95 | {
96 | throw new ArgumentException(nameof(ip));
97 | }
98 |
99 | if (string.IsNullOrEmpty(langCode))
100 | {
101 | langCode = IpToolSettings.DefaultLanguage;
102 | }
103 |
104 | if (_search.TryCity(ip, out var city))
105 | {
106 | var ipinfo = new IpInfo
107 | {
108 | IpAddress = ip,
109 | CountryCode = city.Country.IsoCode,
110 | Country = city.Country.Names.ContainsKey(langCode) ? city.Country.Names[langCode] : city.Country.Name,
111 | Province = city.MostSpecificSubdivision.Names.ContainsKey(langCode) ? city.MostSpecificSubdivision.Names[langCode] : city.MostSpecificSubdivision.Name,
112 | ProvinceCode = city.MostSpecificSubdivision.IsoCode,
113 | City = city.City.Names.ContainsKey(langCode) ? city.City.Names[langCode] : city.City.Name,
114 | PostCode = city.Postal.Code,
115 | Latitude = city.Location.Latitude,
116 | Longitude = city.Location.Longitude,
117 | AccuracyRadius = city.Location.AccuracyRadius
118 | };
119 | return ipinfo;
120 | }
121 | else
122 | {
123 | return new IpInfo();
124 | }
125 | }
126 | }
127 | }
--------------------------------------------------------------------------------