Skip to content

Commit f233da7

Browse files
authored
feat: add ip calculator
[no ci]
2 parents 3bce2b1 + 7463deb commit f233da7

File tree

13 files changed

+467
-11
lines changed

13 files changed

+467
-11
lines changed

.github/ipcalc-sc.png

39.2 KB
Loading

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"cSpell.words": [
33
"duckdb",
4+
"ipcalc",
45
"Netquack",
56
"publicsuffix",
67
"varchar",

README.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,47 @@ D SELECT get_tranco_rank_category('microsoft.com') as category;
267267
└──────────┘
268268
```
269269

270+
### IP Address Functions
271+
272+
This extension provides various functions to manipulate and analyze IP addresses, including calculating networks, hosts, and subnet masks.
273+
274+
#### IP Calculator
275+
276+
The `ipcalc` function takes an IP address and netmask and calculates the resulting broadcast, network, wildcard mask, and host range.
277+
278+
![ipcalc-sc](./.github/ipcalc-sc.png)
279+
280+
It's a table function that provides various details about IP addresses including:
281+
282+
- Address
283+
- Netmask
284+
- Wildcard
285+
- Network / Hostroute
286+
- HostMin
287+
- HostMax
288+
- Broadcast
289+
- Hosts count
290+
291+
You can use this table function with your data easily:
292+
293+
```sql
294+
D CREATE OR REPLACE TABLE ips AS SELECT '127.0.0.1' AS ip UNION ALL SELECT '192.168.1.0/22';
295+
296+
D SELECT i.IP,
297+
(
298+
SELECT hostsPerNet
299+
FROM ipcalc(i.IP)
300+
) AS hosts
301+
FROM ips AS i;
302+
┌────────────────┬───────┐
303+
│ ip │ hosts │
304+
varchar │ int64 │
305+
├────────────────┼───────┤
306+
127.0.0.1254
307+
192.168.1.0/221022
308+
└────────────────┴───────┘
309+
```
310+
270311
### Get Extension Version
271312

272313
You can use the `netquack_version` function to get the version of the extension.
@@ -286,7 +327,6 @@ D select * from netquack_version();
286327
- [ ] Create a `TableFunction` for `extract_query_parameters` that return each key-value pair as a row.
287328
- [ ] Save Tranco data as Parquet
288329
- [ ] Implement GeoIP functionality
289-
- [ ] Add new functions to work with IPs
290330
- [ ] Return default value for `get_tranco_rank`
291331
- [ ] Support internationalized domain names (IDNs)
292332

src/functions/extract_domain.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ namespace duckdb
6363
std::string public_suffix;
6464
int public_suffix_index = -1;
6565

66-
for (int j = 0; j < parts.size (); j++)
66+
for (size_t j = 0; j < parts.size (); j++)
6767
{
6868
// Build the candidate suffix
6969
std::string candidate;
70-
for (int k = j; k < parts.size (); k++)
70+
for (size_t k = j; k < parts.size (); k++)
7171
{
7272
candidate += (k == j ? "" : ".") + parts[k];
7373
}

src/functions/extract_subdomain.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ namespace duckdb
6363
std::string public_suffix;
6464
int public_suffix_index = -1;
6565

66-
for (int j = 0; j < parts.size (); j++)
66+
for (size_t j = 0; j < parts.size (); j++)
6767
{
6868
// Build the candidate suffix
6969
std::string candidate;
70-
for (int k = j; k < parts.size (); k++)
70+
for (size_t k = j; k < parts.size (); k++)
7171
{
7272
candidate += (k == j ? "" : ".") + parts[k];
7373
}

src/functions/extract_tld.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,12 @@ namespace duckdb
6161

6262
// Find the longest matching public suffix
6363
std::string public_suffix;
64-
int public_suffix_index = -1;
6564

66-
for (int j = 0; j < parts.size (); j++)
65+
for (size_t j = 0; j < parts.size (); j++)
6766
{
6867
// Build the candidate suffix
6968
std::string candidate;
70-
for (int k = j; k < parts.size (); k++)
69+
for (size_t k = j; k < parts.size (); k++)
7170
{
7271
candidate += (k == j ? "" : ".") + parts[k];
7372
}
@@ -78,8 +77,7 @@ namespace duckdb
7877

7978
if (query_result->RowCount () > 0)
8079
{
81-
public_suffix = candidate;
82-
public_suffix_index = j;
80+
public_suffix = candidate;
8381
break;
8482
}
8583
}

src/functions/get_version.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,5 @@ namespace duckdb
4848
auto &local_state = (VersionLocalState &)*data_p.local_state;
4949
local_state.done = true;
5050
}
51-
5251
} // namespace netquack
5352
} // namespace duckdb

src/functions/ipcalc.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#include "ipcalc.hpp"
2+
3+
#include "../utils/ip_utils.hpp"
4+
5+
namespace duckdb
6+
{
7+
namespace netquack
8+
{
9+
struct IPCalcData : public TableFunctionData
10+
{
11+
string ip;
12+
};
13+
14+
struct IPCalcLocalState : public LocalTableFunctionState
15+
{
16+
std::atomic_bool done{ false };
17+
};
18+
19+
unique_ptr<FunctionData> IPCalcFunc::Bind (ClientContext &context, TableFunctionBindInput &input, vector<LogicalType> &return_types, vector<string> &names)
20+
{
21+
// 0. address
22+
return_types.emplace_back (LogicalType::VARCHAR);
23+
names.emplace_back ("address");
24+
25+
// 1. netmask
26+
return_types.emplace_back (LogicalType::VARCHAR);
27+
names.emplace_back ("netmask");
28+
29+
// 2. wildcard
30+
return_types.emplace_back (LogicalType::VARCHAR);
31+
names.emplace_back ("wildcard");
32+
33+
// 3. network
34+
return_types.emplace_back (LogicalType::VARCHAR);
35+
names.emplace_back ("network");
36+
37+
// 4. hostMin
38+
return_types.emplace_back (LogicalType::VARCHAR);
39+
names.emplace_back ("hostMin");
40+
41+
// 5. hostMax
42+
return_types.emplace_back (LogicalType::VARCHAR);
43+
names.emplace_back ("hostMax");
44+
45+
// 6. broadcast
46+
return_types.emplace_back (LogicalType::VARCHAR);
47+
names.emplace_back ("broadcast");
48+
49+
// 7. hostsPerNet
50+
return_types.emplace_back (LogicalType::BIGINT);
51+
names.emplace_back ("hostsPerNet");
52+
53+
// 8. ipClass
54+
return_types.emplace_back (LogicalType::VARCHAR);
55+
names.emplace_back ("ipClass");
56+
57+
return make_uniq<IPCalcData> ();
58+
}
59+
60+
unique_ptr<LocalTableFunctionState> IPCalcFunc::InitLocal (ExecutionContext &context, TableFunctionInitInput &input, GlobalTableFunctionState *global_state_p)
61+
{
62+
return make_uniq<IPCalcLocalState> ();
63+
}
64+
65+
OperatorResultType IPCalcFunc::Function (ExecutionContext &context, TableFunctionInput &data_p, DataChunk &input, DataChunk &output)
66+
{
67+
// Check done
68+
if (((IPCalcLocalState &)*data_p.local_state).done)
69+
{
70+
return OperatorResultType::NEED_MORE_INPUT;
71+
}
72+
73+
auto &data = data_p.bind_data->Cast<IPCalcData> ();
74+
auto &local_state = (IPCalcLocalState &)*data_p.local_state;
75+
76+
auto ip = input.data[0].GetValue (0).GetValue<string> ();
77+
78+
IPInfo info = IPCalculator::calculate (ip);
79+
80+
output.data[0].SetValue (0, info.address);
81+
output.data[1].SetValue (0, info.netmask);
82+
output.data[2].SetValue (0, info.wildcard);
83+
output.data[3].SetValue (0, info.network);
84+
output.data[4].SetValue (0, info.hostMin);
85+
output.data[5].SetValue (0, info.hostMax);
86+
output.data[6].SetValue (0, info.broadcast);
87+
output.data[7].SetValue (0, info.hostsPerNet);
88+
output.data[8].SetValue (0, info.ipClass);
89+
output.SetCardinality (1);
90+
91+
// Set done
92+
local_state.done = true;
93+
94+
return OperatorResultType::NEED_MORE_INPUT;
95+
}
96+
} // namespace netquack
97+
} // namespace duckdb

src/functions/ipcalc.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#pragma once
2+
3+
#include <regex>
4+
#include <stdexcept>
5+
#include <string>
6+
#include <vector>
7+
8+
#include "duckdb.hpp"
9+
10+
namespace duckdb
11+
{
12+
namespace netquack
13+
{
14+
struct IPCalcFunc
15+
{
16+
static unique_ptr<FunctionData> Bind (ClientContext &context, TableFunctionBindInput &input, vector<LogicalType> &return_types, vector<string> &names);
17+
static unique_ptr<LocalTableFunctionState> InitLocal (ExecutionContext &context, TableFunctionInitInput &input, GlobalTableFunctionState *global_state_p);
18+
static OperatorResultType Function (ExecutionContext &context, TableFunctionInput &data_p, DataChunk &input, DataChunk &output);
19+
};
20+
} // namespace netquack
21+
} // namespace duckdb

src/netquack_extension.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "functions/extract_tld.hpp"
1818
#include "functions/get_tranco.hpp"
1919
#include "functions/get_version.hpp"
20+
#include "functions/ipcalc.hpp"
2021
#include "utils/utils.hpp"
2122

2223
namespace duckdb
@@ -106,6 +107,16 @@ namespace duckdb
106107
netquack::GetTrancoRankCategoryFunction);
107108
ExtensionUtil::RegisterFunction (instance, get_tranco_rank_category_function);
108109

110+
auto ipcalc_function = TableFunction (
111+
"ipcalc",
112+
{ LogicalType::VARCHAR },
113+
nullptr,
114+
netquack::IPCalcFunc::Bind,
115+
nullptr,
116+
netquack::IPCalcFunc::InitLocal);
117+
ipcalc_function.in_out_function = netquack::IPCalcFunc::Function;
118+
ExtensionUtil::RegisterFunction (instance, ipcalc_function);
119+
109120
auto version_function = TableFunction (
110121
"netquack_version",
111122
{},

0 commit comments

Comments
 (0)