├── include ├── version.h.in └── ipapi.h ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── CMakeLists.txt ├── test └── ipapi_test.cpp ├── Readme.md └── src └── ipapi.cpp /include/version.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ 4 | #define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@ 5 | #define PROJECT_VERSION_PATCH @PROJECT_VERSION_PATCH@ 6 | #define PROJECT_VERSION "@PROJECT_VERSION@" 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: C++ CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | build-and-test: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v3 18 | 19 | - name: Install dependencies 20 | run: | 21 | sudo apt-get update 22 | sudo apt-get install -y cmake g++ libcurl4-openssl-dev 23 | 24 | - name: Configure CMake 25 | run: | 26 | cmake -S . -B build 27 | 28 | - name: Build project 29 | run: | 30 | cmake --build build 31 | 32 | - name: Run tests 33 | run: | 34 | cd build && ctest --output-on-failure 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # CMake 2 | CMakeCache.txt 3 | CMakeFiles/ 4 | CMakeDumps/ 5 | Makefile 6 | Makefile2 7 | cmake_install.cmake 8 | CTestTestfile.cmake 9 | Testing/ 10 | 11 | # Build Directories 12 | /build/ 13 | 14 | # Compiled Object Files 15 | *.o 16 | *.a 17 | *.so 18 | *.dll 19 | *.dylib 20 | *.obj 21 | 22 | # Executable Files 23 | *.exe 24 | *.out 25 | *.app 26 | 27 | # IDE and Editor Directories 28 | .idea/ 29 | .vscode/ 30 | *.swp 31 | *.swo 32 | *.sublime-project 33 | *.sublime-workspace 34 | 35 | # Temporary files 36 | *~ 37 | *.bak 38 | *.tmp 39 | *.swp 40 | 41 | # Google Test (googletest) 42 | googletest/ 43 | googlemock/ 44 | 45 | # Dependency Directories (if using external dependencies) 46 | _deps/ 47 | 48 | # Generated Files 49 | *.log 50 | *.d 51 | *.cxx 52 | *.gch 53 | *.gcda 54 | *.gcno 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Rezwan Ahmed Sami 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 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(ipapi-cpp) 3 | 4 | # Use C++20 5 | set(CMAKE_CXX_STANDARD 20) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | # Fetch the latest Git tag as the project version 9 | find_package(Git REQUIRED) 10 | execute_process( 11 | COMMAND git describe --tags --abbrev=0 12 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 13 | OUTPUT_VARIABLE GIT_TAG 14 | OUTPUT_STRIP_TRAILING_WHITESPACE 15 | ) 16 | 17 | if(GIT_TAG) 18 | string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" VERSION_MATCH ${GIT_TAG}) 19 | if(VERSION_MATCH) 20 | set(PROJECT_VERSION ${GIT_TAG}) 21 | else() 22 | set(PROJECT_VERSION "0.0.0") # Default version if no valid tag is found 23 | endif() 24 | else() 25 | set(PROJECT_VERSION "0.0.0") # Default version if Git is unavailable 26 | endif() 27 | 28 | # Display the version 29 | message(STATUS "Project version: ${PROJECT_VERSION}") 30 | 31 | # Configure the version header 32 | configure_file( 33 | ${CMAKE_SOURCE_DIR}/include/version.h.in 34 | ${CMAKE_BINARY_DIR}/version.h 35 | ) 36 | include_directories(${CMAKE_BINARY_DIR}) 37 | 38 | # Include GoogleTest via FetchContent 39 | include(FetchContent) 40 | FetchContent_Declare( 41 | googletest 42 | URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip 43 | ) 44 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 45 | FetchContent_MakeAvailable(googletest) 46 | 47 | # Find and link libcurl 48 | find_package(CURL REQUIRED) 49 | 50 | # Add your ipapi-cpp library (example) 51 | add_library(ipapi-cpp STATIC 52 | src/ipapi.cpp # Update with your source files 53 | ) 54 | 55 | # Add include and source files 56 | target_sources(ipapi-cpp 57 | PRIVATE 58 | src/ipapi.cpp 59 | PUBLIC 60 | $ 61 | $ 62 | ) 63 | 64 | # Specify the include directory 65 | target_include_directories(ipapi-cpp 66 | PUBLIC 67 | $ 68 | $ 69 | ) 70 | 71 | # Link curl to ipapi-cpp 72 | target_link_libraries(ipapi-cpp 73 | PRIVATE 74 | CURL::libcurl # Link the curl library 75 | ) 76 | 77 | # Enable testing 78 | enable_testing() 79 | 80 | # Add your test executable 81 | add_executable(ipapi-test 82 | test/ipapi_test.cpp # Update with your test files 83 | ) 84 | 85 | # Link the test executable with GoogleTest, ipapi-cpp library, and curl 86 | target_link_libraries(ipapi-test 87 | gtest gtest_main 88 | ipapi-cpp 89 | CURL::libcurl # Link curl to your test executable 90 | ) 91 | 92 | # Automatically discover tests 93 | include(GoogleTest) 94 | gtest_discover_tests(ipapi-test) 95 | -------------------------------------------------------------------------------- /test/ipapi_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ipapi.h" // Include your project’s header 3 | 4 | // Test the `query_ip` function 5 | TEST(IPAPITest, QueryIP) { 6 | ipapi::IPInfo ip_info = ipapi::query_ip("8.8.8.8"); 7 | std::cout << "Library version: " << PROJECT_VERSION << std::endl; 8 | 9 | // String comparisons for the fields 10 | EXPECT_EQ(ip_info.ip, "8.8.8.8"); 11 | EXPECT_EQ(ip_info.isp.asn, "AS15169"); 12 | EXPECT_EQ(ip_info.isp.organization, "Google LLC"); 13 | EXPECT_EQ(ip_info.isp.name, "Google LLC"); // Adjusted to match the actual response 14 | 15 | // Location comparisons 16 | EXPECT_EQ(ip_info.location.country, "United States"); 17 | EXPECT_EQ(ip_info.location.country_code, "US"); 18 | EXPECT_EQ(ip_info.location.city, "Mountain View"); 19 | EXPECT_EQ(ip_info.location.state, "California"); 20 | EXPECT_EQ(ip_info.location.zipcode, "94043"); 21 | 22 | // Latitude and longitude comparisons using EXPECT_NEAR for floating-point precision 23 | EXPECT_NEAR(ip_info.location.latitude, 37.436551599813335, 0.0001); // Adjusted expected value 24 | EXPECT_NEAR(ip_info.location.longitude, -122.09383799087185, 0.0001); // Adjusted expected value 25 | 26 | // Timezone and localtime 27 | EXPECT_EQ(ip_info.location.timezone, "America/Los_Angeles"); 28 | // EXPECT_EQ(ip_info.location.localtime, "2024-12-10T18:51:40"); // Adjusted the date based on your raw JSON 29 | 30 | // Risk section 31 | EXPECT_FALSE(ip_info.risk.is_mobile); 32 | EXPECT_FALSE(ip_info.risk.is_vpn); 33 | EXPECT_FALSE(ip_info.risk.is_tor); 34 | EXPECT_FALSE(ip_info.risk.is_proxy); 35 | } 36 | 37 | // Test the `query_bulk` function 38 | TEST(IPAPITest, QueryBulk) { 39 | std::vector ips = { 40 | "8.8.8.8", 41 | "1.1.1.1" 42 | }; 43 | std::vector ip_infos = ipapi::query_bulk(ips); 44 | 45 | // Validate the size of the returned vector 46 | EXPECT_EQ(ip_infos.size(), ips.size()); 47 | 48 | // Validate the information for each IP address 49 | for (size_t i = 0; i < ips.size(); i++) { 50 | ipapi::IPInfo ip_info = ip_infos[i]; 51 | std::cout << "IP: " << ip_info.ip << std::endl; 52 | EXPECT_EQ(ip_info.ip, ips[i]); 53 | } 54 | 55 | // Validate the information for the first IP address 56 | ipapi::IPInfo ip_info = ip_infos[0]; 57 | EXPECT_EQ(ip_info.isp.asn, "AS15169"); 58 | EXPECT_EQ(ip_info.isp.organization, "Google LLC"); 59 | EXPECT_EQ(ip_info.isp.name, "Google LLC"); // Adjusted to match the actual response 60 | 61 | // Location comparisons for the first IP address 62 | EXPECT_EQ(ip_info.location.country, "United States"); 63 | EXPECT_EQ(ip_info.location.country_code, "US"); 64 | EXPECT_EQ(ip_info.location.city, "Mountain View"); 65 | EXPECT_EQ(ip_info.location.state, "California"); 66 | EXPECT_EQ(ip_info.location.zipcode, "94043"); 67 | 68 | // Latitude and longitude comparisons for the first IP address 69 | EXPECT_NEAR(ip_info.location.latitude, 37.436551599813335, 0.0001); // Adjusted expected value 70 | EXPECT_NEAR(ip_info.location.longitude, -122.09383799087185, 0.0001); // Adjusted expected value 71 | 72 | // Timezone and localtime for the first IP address 73 | EXPECT_EQ(ip_info.location.timezone, "America/Los_Angeles"); 74 | // EXPECT_EQ(ip_info.location.localtime, "2024-12-10T18:51:40"); // Adjusted the date based on your raw JSON 75 | 76 | // Risk section for the first IP address 77 | EXPECT_FALSE(ip_info.risk.is_mobile); 78 | EXPECT_FALSE(ip_info.risk.is_vpn); 79 | EXPECT_FALSE(ip_info.risk.is_tor); 80 | EXPECT_FALSE(ip_info.risk.is_proxy); 81 | } 82 | 83 | // Test the `query_own_ip` function 84 | TEST(IPAPITest, QueryOwnIP) { 85 | std::string own_ip = ipapi::query_own_ip(); 86 | std::string expected_ip = ipapi::query_own_ip(); 87 | 88 | // Validate the IP address 89 | EXPECT_EQ(own_ip, expected_ip); 90 | 91 | } 92 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # ipapi 2 | 3 | A C++ library to query IP addresses using the [ipquery.io](https://ipquery.io) API. 4 | 5 | ## Features 6 | 7 | - Query details for a specific IP address 8 | - Bulk query multiple IP addresses 9 | - Fetch your own public IP address 10 | 11 | ## Installation 12 | 13 | To use this library, include the `ipapi.h` and link the necessary dependencies for HTTP requests (e.g., libcurl). 14 | 15 | ### Prerequisites 16 | 17 | - A C++17 or later compiler 18 | - `libcurl` for making HTTP requests 19 | 20 | Install `libcurl`: 21 | ```bash 22 | # Ubuntu 23 | sudo apt-get install libcurl4-openssl-dev 24 | 25 | # macOS (using Homebrew) 26 | brew install curl 27 | ``` 28 | 29 | Include the following files in your project: 30 | - `ipapi.h` 31 | - `ipapi.cpp` 32 | 33 | ## Usage 34 | 35 | ### Query a Specific IP Address 36 | 37 | The `query_ip` function retrieves information about a specific IP address, including its ISP, location, and risk data. 38 | 39 | ```cpp 40 | #include 41 | #include "ipapi.h" 42 | 43 | int main() { 44 | auto ip_info = ipapi::query_ip("8.8.8.8"); 45 | if (ip_info) { 46 | std::cout << *ip_info << std::endl; 47 | } else { 48 | std::cerr << "Failed to fetch IP information." << std::endl; 49 | } 50 | return 0; 51 | } 52 | ``` 53 | 54 | #### Output Example 55 | ```plaintext 56 | IPInfo { 57 | ip: "8.8.8.8", 58 | isp: { asn: "AS15169", org: "Google LLC", isp: "Google LLC" }, 59 | location: { 60 | country: "United States", 61 | country_code: "US", 62 | city: "Mountain View", 63 | state: "California", 64 | zipcode: "94035", 65 | latitude: 37.386, 66 | longitude: -122.0838, 67 | timezone: "America/Los_Angeles", 68 | localtime: "2024-11-09T12:45:32" 69 | }, 70 | risk: { 71 | is_mobile: false, 72 | is_vpn: false, 73 | is_tor: false, 74 | is_proxy: false, 75 | is_datacenter: true, 76 | risk_score: 0 77 | } 78 | } 79 | ``` 80 | 81 | ### Bulk Query Multiple IP Addresses 82 | 83 | The `query_bulk` function allows you to query information for multiple IP addresses at once. 84 | 85 | ```cpp 86 | #include 87 | #include "ipapi.h" 88 | 89 | int main() { 90 | std::vector ips = {"8.8.8.8", "1.1.1.1"}; 91 | auto ip_infos = ipapi::query_bulk(ips); 92 | for (const auto& info : ip_infos) { 93 | std::cout << info << std::endl; 94 | } 95 | return 0; 96 | } 97 | ``` 98 | 99 | #### Output Example 100 | ```plaintext 101 | IPInfo { 102 | ip: "8.8.8.8", 103 | ... 104 | } 105 | IPInfo { 106 | ip: "1.1.1.1", 107 | ... 108 | } 109 | ``` 110 | 111 | ### Fetch Your Own Public IP Address 112 | 113 | The `query_own_ip` function retrieves the public IP address of the current machine. 114 | 115 | ```cpp 116 | #include 117 | #include "ipapi.h" 118 | 119 | int main() { 120 | auto ip = ipapi::query_own_ip(); 121 | if (ip) { 122 | std::cout << "Your IP Address: " << *ip << std::endl; 123 | } else { 124 | std::cerr << "Failed to fetch public IP address." << std::endl; 125 | } 126 | return 0; 127 | } 128 | ``` 129 | 130 | #### Output Example 131 | ```plaintext 132 | Your IP Address: 203.0.113.45 133 | ``` 134 | 135 | ## API Documentation 136 | 137 | ### 1. `query_ip` 138 | 139 | #### Signature 140 | ```cpp 141 | std::optional query_ip(const std::string& ip); 142 | ``` 143 | 144 | #### Description 145 | Fetches detailed information about a specific IP address, including its ISP, location, and risk information. 146 | 147 | #### Parameters 148 | - `ip`: A `std::string` representing the IP address to query. 149 | 150 | #### Returns 151 | - `std::optional` containing details about the IP address on success. 152 | - `std::nullopt` if the network request fails. 153 | 154 | --- 155 | 156 | ### 2. `query_bulk` 157 | 158 | #### Signature 159 | ```cpp 160 | std::vector query_bulk(const std::vector& ips); 161 | ``` 162 | 163 | #### Description 164 | Fetches information for multiple IP addresses at once. Useful for batch processing. 165 | 166 | #### Parameters 167 | - `ips`: A `std::vector` containing the list of IP addresses to query. 168 | 169 | #### Returns 170 | - A `std::vector` containing details for each IP address. 171 | 172 | --- 173 | 174 | ### 3. `query_own_ip` 175 | 176 | #### Signature 177 | ```cpp 178 | std::optional query_own_ip(); 179 | ``` 180 | 181 | #### Description 182 | Fetches the public IP address of the current machine. 183 | 184 | #### Returns 185 | - `std::optional` containing the public IP address on success. 186 | - `std::nullopt` if the network request fails. 187 | 188 | --- 189 | 190 | ## Running Tests 191 | 192 | To run tests for this library, include and execute the `tests.cpp` file: 193 | ```bash 194 | # initialize the cmake build first 195 | cmake -S . -B build 196 | 197 | # Build and test 198 | cmake --build build 199 | cd build && ctest 200 | ``` 201 | 202 | ## Contributing 203 | 204 | Contributions are welcome! Feel free to open issues or submit pull requests on the [GitHub repository](https://github.com/rezwanahmedsami/ipapi-cpp). 205 | 206 | ## License 207 | 208 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. 209 | -------------------------------------------------------------------------------- /include/ipapi.h: -------------------------------------------------------------------------------- 1 | #ifndef IPAPI_H 2 | #define IPAPI_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace ipapi { 10 | 11 | /// The base URL for the ipquery.io API. 12 | const std::string BASE_URL = "https://api.ipquery.io/"; 13 | 14 | /// Represents information about an ISP (Internet Service Provider). 15 | struct IspInfo { 16 | /// The Autonomous System Number (ASN) of the ISP. 17 | std::string asn; 18 | /// The organization associated with the ISP. 19 | std::string organization; 20 | /// The name of the ISP. 21 | std::string name; 22 | }; 23 | 24 | /// Represents information about the geographical location of an IP address. 25 | struct LocationInfo { 26 | /// The country name. 27 | std::string country; 28 | 29 | /// The ISO country code. 30 | std::string country_code; 31 | 32 | /// The city name. 33 | std::string city; 34 | 35 | /// The state or region. 36 | std::string state; 37 | 38 | /// The postal or ZIP code. 39 | std::string zipcode; 40 | 41 | /// The latitude of the location. 42 | double latitude; 43 | 44 | /// The longitude of the location. 45 | double longitude; 46 | 47 | /// The timezone of the location. 48 | std::string timezone; 49 | 50 | /// The local time in the specified timezone. 51 | std::string localtime; 52 | }; 53 | 54 | /// Represents information about potential risks associated with an IP address. 55 | struct RiskInfo { 56 | /// Indicates if the IP is associated with a mobile network. 57 | bool is_mobile; 58 | /// Indicates if the IP is using a VPN. 59 | bool is_vpn; 60 | /// Indicates if the IP is part of the Tor network. 61 | bool is_tor; 62 | /// Indicates if the IP is using a proxy. 63 | bool is_proxy; 64 | /// Indicates if the IP is associated with a data center. 65 | bool is_datacenter; 66 | /// A score indicating the risk level (0-100). 67 | unsigned char risk_score; 68 | }; 69 | 70 | /// Represents the full set of information returned by the API for an IP address. 71 | struct IPInfo { 72 | /// The queried IP address. 73 | std::string ip; 74 | /// Information about the ISP. 75 | IspInfo isp; 76 | /// Information about the location. 77 | LocationInfo location; 78 | /// Information about the risk level. 79 | RiskInfo risk; 80 | }; 81 | 82 | /// Callback function for writing the response data from the API request. 83 | /// 84 | /// # Arguments 85 | /// 86 | /// * `contents` - A pointer to the response data. 87 | /// * `size` - The size of each element in the data. 88 | /// * `nmemb` - The number of elements in the data. 89 | /// * `userp` - A pointer to the user data. 90 | /// 91 | /// # Returns 92 | /// 93 | /// Returns the total size of the data written. 94 | size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp); 95 | 96 | // callback function for bulk requests, where will receive a vector of IPInfo 97 | size_t write_callback_bulk(void* contents, size_t size, size_t nmemb, void* userp); 98 | 99 | /// Fetches the IP information for a given IP address. 100 | /// 101 | /// # Arguments 102 | /// 103 | /// * `ip` - A string representing the IP address to query. 104 | /// 105 | /// # Returns 106 | /// 107 | /// Returns an `IPInfo` struct containing the information about the IP address. 108 | /// 109 | /// # Example 110 | /// 111 | /// ```cpp 112 | /// #include 113 | /// #include "ipapi.h" 114 | /// 115 | /// int main() { 116 | /// auto ip_info = ipapi::query_ip("8.8.8.8"); 117 | /// std::cout << "IP: " << ip_info.ip << std::endl; 118 | /// std::cout << "ISP: " << ip_info.isp.name << std::endl; 119 | /// std::cout << "Country: " << ip_info.location.country << std::endl; 120 | /// return 0; 121 | /// } 122 | /// ``` 123 | /// 124 | /// # Errors 125 | /// 126 | /// Returns an error if the network request fails or the response cannot be deserialized. 127 | IPInfo query_ip(const std::string& ip); 128 | 129 | /* 130 | /// Fetches information for multiple IP addresses. 131 | /// 132 | /// # Arguments 133 | /// 134 | /// * `ips` - A slice of string slices representing the list of IP addresses to query. 135 | /// 136 | /// # Example 137 | /// 138 | /// ```rust 139 | /// use ipapi::query_bulk; 140 | /// use tokio; 141 | /// 142 | /// #[tokio::main] 143 | /// async fn main() { 144 | /// let ip_infos = query_bulk(&["8.8.8.8", "1.1.1.1"]).await.unwrap(); 145 | /// println!("{:?}", ip_infos); 146 | /// } 147 | /// ``` 148 | /// 149 | /// # Errors 150 | /// 151 | /// Returns an error if the network request fails or the response cannot be deserialized. 152 | pub async fn query_bulk(ips: &[&str]) -> Result, Error> { 153 | let ip_list = ips.join(","); 154 | let url = format!("{}{}", BASE_URL, ip_list); 155 | let response = reqwest::get(&url).await?.json::>().await?; 156 | Ok(response) 157 | } 158 | */ 159 | 160 | /// Fetches information for multiple IP addresses. 161 | /// 162 | /// # Arguments 163 | /// 164 | /// * `ips` - A vector of strings representing the list of IP addresses to query. 165 | /// 166 | /// # Returns 167 | /// 168 | /// Returns a vector of `IPInfo` structs containing the information about the IP addresses. 169 | /// 170 | /// # Example 171 | /// 172 | /// ```cpp 173 | /// #include 174 | /// #include "ipapi.h" 175 | /// 176 | /// int main() { 177 | /// std::vector ips = {" 178 | /// "8.8.8.8", 179 | /// "1.1.1.1" 180 | /// }; 181 | /// auto ip_infos = ipapi::query_bulk(ips); 182 | /// for (const auto& ip_info : ip_infos) { 183 | /// std::cout << "IP: " << ip_info.ip << std::endl; 184 | /// std::cout << "ISP: " << ip_info.isp.name << std::endl; 185 | /// std::cout << "Country: " << ip_info.location.country << std::endl; 186 | /// } 187 | /// return 0; 188 | /// } 189 | /// ``` 190 | /// 191 | /// # Errors 192 | /// 193 | /// Returns an error if the network request fails or the response cannot be deserialized. 194 | std::vector query_bulk(const std::vector& ips); 195 | 196 | /* 197 | /// Fetches the IP address of the current machine. 198 | /// 199 | /// # Example 200 | /// 201 | /// ```rust 202 | /// use ipapi::query_own_ip; 203 | /// use tokio; 204 | /// 205 | /// #[tokio::main] 206 | /// async fn main() { 207 | /// let ip = query_own_ip().await.unwrap(); 208 | /// println!("Your IP Address: {}", ip); 209 | /// } 210 | /// ``` 211 | /// 212 | /// # Errors 213 | /// 214 | /// Returns an error if the network request fails. 215 | pub async fn query_own_ip() -> Result { 216 | let response = reqwest::get(BASE_URL).await?.text().await?; 217 | Ok(response) 218 | } 219 | */ 220 | 221 | /// Fetches the IP address of the current machine. 222 | /// 223 | /// # Returns 224 | /// 225 | /// Returns a string representing the IP address of the current machine. 226 | /// 227 | /// # Example 228 | /// 229 | /// ```cpp 230 | /// #include 231 | /// #include "ipapi.h" 232 | /// 233 | /// int main() { 234 | /// auto ip = ipapi::query_own_ip(); 235 | /// std::cout << "Your IP Address: " << ip << std::endl; 236 | /// return 0; 237 | /// } 238 | /// ``` 239 | /// 240 | /// # Errors 241 | /// 242 | /// Returns an error if the network request fails. 243 | std::string query_own_ip(); 244 | 245 | 246 | 247 | 248 | } 249 | 250 | #endif // IPAPI_H 251 | -------------------------------------------------------------------------------- /src/ipapi.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ipapi.h" 3 | 4 | namespace ipapi { 5 | 6 | size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) { 7 | size_t realsize = size * nmemb; 8 | IPInfo* ip_info = static_cast(userp); 9 | try { 10 | nlohmann::json json = nlohmann::json::parse(std::string(static_cast(contents), realsize)); 11 | 12 | // Use .value() with a default to handle missing or null keys 13 | ip_info->ip = json.value("ip", "Unknown"); 14 | 15 | // Handle 'isp' section 16 | ip_info->isp.asn = json.value("isp", nlohmann::json::object()).value("asn", "Unknown"); 17 | ip_info->isp.organization = json.value("isp", nlohmann::json::object()).value("org", "Unknown"); // Corrected 'org' key 18 | ip_info->isp.name = json.value("isp", nlohmann::json::object()).value("isp", "Unknown"); // Corrected 'isp' key 19 | 20 | // Handle 'location' section 21 | ip_info->location.country = json.value("location", nlohmann::json::object()).value("country", "Unknown"); 22 | ip_info->location.country_code = json.value("location", nlohmann::json::object()).value("country_code", "Unknown"); 23 | ip_info->location.city = json.value("location", nlohmann::json::object()).value("city", "Unknown"); 24 | ip_info->location.state = json.value("location", nlohmann::json::object()).value("state", "Unknown"); 25 | ip_info->location.zipcode = json.value("location", nlohmann::json::object()).value("zipcode", "Unknown"); 26 | ip_info->location.latitude = json.value("location", nlohmann::json::object()).value("latitude", 0.0); 27 | ip_info->location.longitude = json.value("location", nlohmann::json::object()).value("longitude", 0.0); 28 | ip_info->location.timezone = json.value("location", nlohmann::json::object()).value("timezone", "Unknown"); 29 | ip_info->location.localtime = json.value("location", nlohmann::json::object()).value("localtime", "Unknown"); 30 | 31 | // Handle 'risk' section 32 | ip_info->risk.is_mobile = json.value("risk", nlohmann::json::object()).value("is_mobile", false); 33 | ip_info->risk.is_vpn = json.value("risk", nlohmann::json::object()).value("is_vpn", false); 34 | ip_info->risk.is_tor = json.value("risk", nlohmann::json::object()).value("is_tor", false); 35 | ip_info->risk.is_proxy = json.value("risk", nlohmann::json::object()).value("is_proxy", false); 36 | 37 | } catch (const nlohmann::json::exception& e) { 38 | std::cerr << "JSON parsing error: " << e.what() << std::endl; 39 | } 40 | 41 | return realsize; 42 | } 43 | 44 | size_t write_callback_bulk(void* contents, size_t size, size_t nmemb, void* userp) { 45 | size_t realsize = size * nmemb; 46 | std::vector* ip_infos = static_cast*>(userp); 47 | try { 48 | nlohmann::json json = nlohmann::json::parse(std::string(static_cast(contents), realsize)); 49 | for (const auto& item : json) { 50 | IPInfo ip_info; 51 | ip_info.ip = item.value("ip", "Unknown"); 52 | 53 | // Handle 'isp' section 54 | ip_info.isp.asn = item.value("isp", nlohmann::json::object()).value("asn", "Unknown"); 55 | ip_info.isp.organization = item.value("isp", nlohmann::json::object()).value("org", "Unknown"); // Corrected 'org' key 56 | ip_info.isp.name = item.value("isp", nlohmann::json::object()).value("isp", "Unknown"); // Corrected 'isp' key 57 | 58 | // Handle 'location' section 59 | ip_info.location.country = item.value("location", nlohmann::json::object()).value("country", "Unknown"); 60 | ip_info.location.country_code = item.value("location", nlohmann::json::object()).value("country_code", "Unknown"); 61 | ip_info.location.city = item.value("location", nlohmann::json::object()).value("city", "Unknown"); 62 | ip_info.location.state = item.value("location", nlohmann::json::object()).value("state", "Unknown"); 63 | ip_info.location.zipcode = item.value("location", nlohmann::json::object()).value("zipcode", "Unknown"); 64 | ip_info.location.latitude = item.value("location", nlohmann::json::object()).value("latitude", 0.0); 65 | ip_info.location.longitude = item.value("location", nlohmann::json::object()).value("longitude", 0.0); 66 | ip_info.location.timezone = item.value("location", nlohmann::json::object()).value("timezone", "Unknown"); 67 | ip_info.location.localtime = item.value("location", nlohmann::json::object()).value("localtime", "Unknown"); 68 | 69 | // Handle 'risk' section 70 | ip_info.risk.is_mobile = item.value("risk", nlohmann::json::object()).value("is_mobile", false); 71 | ip_info.risk.is_vpn = item.value("risk", nlohmann::json::object()).value("is_vpn", false); 72 | ip_info.risk.is_tor = item.value("risk", nlohmann::json::object()).value("is_tor", false); 73 | ip_info.risk.is_proxy = item.value("risk", nlohmann::json::object()).value("is_proxy", false); 74 | 75 | ip_infos->push_back(ip_info); 76 | } 77 | } catch (const nlohmann::json::exception& e) { 78 | std::cerr << "JSON parsing error: " << e.what() << std::endl; 79 | } 80 | 81 | return realsize; 82 | } 83 | 84 | IPInfo query_ip(const std::string& ip) { 85 | IPInfo ip_info; 86 | CURL* curl = curl_easy_init(); 87 | if (curl) { 88 | std::string url = BASE_URL + ip; 89 | curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 90 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); 91 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); 92 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ip_info); 93 | CURLcode res = curl_easy_perform(curl); 94 | if (res != CURLE_OK) { 95 | std::cerr << "Failed to fetch IP information: " << curl_easy_strerror(res) << std::endl; 96 | } 97 | curl_easy_cleanup(curl); 98 | } else { 99 | std::cerr << "Failed to initialize cURL." << std::endl; 100 | } 101 | return ip_info; 102 | } 103 | 104 | std::vector query_bulk(const std::vector& ips) { 105 | std::vector ip_infos; 106 | CURL* curl = curl_easy_init(); 107 | if (curl) { 108 | std::string ip_list = std::accumulate(std::next(ips.begin()), ips.end(), ips[0], [](std::string a, std::string b) { 109 | return a + "," + b; 110 | }); 111 | std::string url = BASE_URL + ip_list; 112 | curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 113 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); 114 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback_bulk); 115 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ip_infos); 116 | CURLcode res = curl_easy_perform(curl); 117 | if (res != CURLE_OK) { 118 | std::cerr << "Failed to fetch IP information: " << curl_easy_strerror(res) << std::endl; 119 | } 120 | curl_easy_cleanup(curl); 121 | } else { 122 | std::cerr << "Failed to initialize cURL." << std::endl; 123 | } 124 | return ip_infos; 125 | } 126 | 127 | std::string query_own_ip() { 128 | std::string ip; 129 | CURL* curl = curl_easy_init(); 130 | if (curl) { 131 | curl_easy_setopt(curl, CURLOPT_URL, BASE_URL.c_str()); 132 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); 133 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); 134 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ip); 135 | CURLcode res = curl_easy_perform(curl); 136 | if (res != CURLE_OK) { 137 | std::cerr << "Failed to fetch IP information: " << curl_easy_strerror(res) << std::endl; 138 | } 139 | curl_easy_cleanup(curl); 140 | } else { 141 | std::cerr << "Failed to initialize cURL." << std::endl; 142 | } 143 | return ip; 144 | } 145 | 146 | } 147 | --------------------------------------------------------------------------------