erichutchins/polars_iptools
GitHub: erichutchins/polars_iptools
基于 Rust 的高性能 Polars 扩展,提供 IP 地址解析、GeoIP 地理位置富化及代理/VPN 检测能力。
Stars: 28 | Forks: 1
# Polars IPTools
Polars IPTools 是一个基于 Rust 的扩展,旨在加速 Polars dataframe 中的 IP 地址操作和富化。该库包含了各种用于处理 IPv4 和 IPv6 地址的实用函数,以及使用 MaxMind 数据库进行的 GeoIP 和匿名化/代理富化功能。
[](https://erichutchins.github.io/polars_iptools/)
[](https://pypi.org/project/polars-iptools/)
[](https://github.com/astral-sh/uv)
[](https://github.com/astral-sh/ruff)
[](https://github.com/astral-sh/ty)
[](LICENSE)
[](https://claude.ai)
[](https://antigravity.google)
## 安装
```
pip install polars-iptools
```
## 示例
### 简单富化
IPTools 的 Rust 实现能为您提供关于基本 IP 问题的快速解答,例如“这是一个私有 IP 吗?”
```
>>> import polars as pl
>>> import polars_iptools as ip
>>> df = pl.DataFrame({'ip': ['8.8.8.8', '2606:4700::1111', '192.168.100.100', '172.21.1.1', '172.34.5.5', 'a.b.c.d']})
>>> df.with_columns(ip.is_private(pl.col('ip')).alias('is_private'))
shape: (6, 2)
┌─────────────────┬────────────┐
│ ip ┆ is_private │
│ --- ┆ --- │
│ str ┆ bool │
╞═════════════════╪════════════╡
│ 8.8.8.8 ┆ false │
│ 2606:4700::1111 ┆ false │
│ 192.168.100.100 ┆ true │
│ 172.21.1.1 ┆ true │
│ 172.34.5.5 ┆ false │
│ a.b.c.d ┆ false │
└─────────────────┴────────────┘
```
### IP 扩展类型
IPTools 提供了两种 Arrow 扩展类型用于高效存储 IP 地址。
`IPv4` 使用 4 字节的 `UInt32` 存储;`IPAddress` 使用 16 字节二进制格式,并同时处理 IPv4 和 IPv6。这两种类型在 Parquet 和 IPC 往返过程中都能保留 dtype。
```
>>> import polars as pl
>>> import polars_iptools as ip
>>> df = pl.DataFrame({"ip": ["8.8.8.8", "2606:4700::1111", "192.168.1.1", "invalid"]})
>>> df.with_columns(ip.to_address("ip"))
shape: (4, 2)
┌─────────────────┬─────────────────┐
│ ip ┆ ip │
│ --- ┆ --- │
│ str ┆ ip_addr │
╞═════════════════╪═════════════════╡
│ 8.8.8.8 ┆ 8.8.8.8 │
│ 2606:4700::1111 ┆ 2606:4700::1111 │
│ 192.168.1.1 ┆ 192.168.1.1 │
│ invalid ┆ null │
└─────────────────┴─────────────────┘
>>> # Write typed column to Parquet — dtype is preserved on read
>>> typed = df.with_columns(ip.to_address("ip"))
>>> typed.write_parquet("/tmp/ips.parquet")
>>> pl.read_parquet("/tmp/ips.parquet").dtypes
[String, IPAddress]
```
### 网络范围的 `is_in`
Pandas 和 Polars 拥有 `is_in` 函数来执行成员查找。IPTools 扩展了此功能,支持 IP 地址在 IP _网络_ 中的成员资格判断。该函数无缝支持 IPv4 和 IPv6 地址,并将指定的网络转换为 [层级压缩前缀树](https://github.com/Orange-OpenSource/iptrie) 以实现快速、高效的查找。
```
>>> import polars as pl
>>> import polars_iptools as ip
>>> df = pl.DataFrame({'ip': ['8.8.8.8', '1.1.1.1', '2606:4700::1111']})
>>> networks = ['8.8.8.0/24', '2606:4700::/32']
>>> df.with_columns(ip.is_in(pl.col('ip'), networks).alias('is_in'))
shape: (3, 2)
┌─────────────────┬───────┐
│ ip ┆ is_in │
│ --- ┆ --- │
│ str ┆ bool │
╞═════════════════╪═══════╡
│ 8.8.8.8 ┆ true │
│ 1.1.1.1 ┆ false │
│ 2606:4700::1111 ┆ true │
└─────────────────┴───────┘
```
### GeoIP 富化
使用 [MaxMind](https://www.maxmind.com/en/geoip-databases) 的 _GeoLite2-ASN.mmdb_ 和 _GeoLite2-City.mmdb_ 数据库,IPTools 提供了网络归属和地理位置的离线富化功能。
`ip.geoip.full` 返回一个包含所有可用元数据参数的 Polars struct。如果您只需要 ASN 和 AS 组织信息,可以使用 `ip.geoip.asn`。
```
>>> import polars as pl
>>> import polars_iptools as ip
>>> df = pl.DataFrame({"ip":["8.8.8.8", "192.168.1.1", "2606:4700::1111", "999.abc.def.123"]})
>>> df.with_columns([ip.geoip.full(pl.col("ip")).alias("geoip")])
shape: (4, 2)
┌─────────────────┬─────────────────────────────────┐
│ ip ┆ geoip │
│ --- ┆ --- │
│ str ┆ struct[11] │
╞═════════════════╪═════════════════════════════════╡
│ 8.8.8.8 ┆ {15169,"GOOGLE","","NA","","",… │
│ 192.168.1.1 ┆ {0,"","","","","","","",0.0,0.… │
│ 2606:4700::1111 ┆ {13335,"CLOUDFLARENET","","","… │
│ 999.abc.def.123 ┆ {null,null,null,null,null,null… │
└─────────────────┴─────────────────────────────────┘
>>> df.with_columns([ip.geoip.asn(pl.col("ip")).alias("asn")])
shape: (4, 2)
┌─────────────────┬───────────────────────┐
│ ip ┆ asn │
│ --- ┆ --- │
│ str ┆ str │
╞═════════════════╪═══════════════════════╡
│ 8.8.8.8 ┆ AS15169 GOOGLE │
│ 192.168.1.1 ┆ │
│ 2606:4700::1111 ┆ AS13335 CLOUDFLARENET │
│ 999.abc.def.123 ┆ │
└─────────────────┴───────────────────────┘
```
### Spur 富化
[Spur](https://spur.us/) 是一项商业服务,提供“用于检测 VPN、住宅代理和机器人的数据”。其产品之一是 [Maxmind mmdb 格式](https://docs.spur.us/feeds?id=feed-export-utility) 的数据库,包含最多 2,000,000 个“最繁忙”的匿名或匿名+住宅 IP。
`ip.spur.full` 返回一个包含所有可用元数据参数的 Polars struct。
```
>>> import polars as pl
>>> import polars_iptools as ip
>>> df = pl.DataFrame({"ip":["8.8.8.8", "192.168.1.1", "999.abc.def.123"]})
>>> df.with_columns([ip.spur.full(pl.col("ip")).alias("spur")])
shape: (3, 2)
┌─────────────────┬─────────────────────────────────┐
│ ip ┆ spur │
│ --- ┆ --- │
│ str ┆ struct[7] │
╞═════════════════╪═════════════════════════════════╡
│ 8.8.8.8 ┆ {0.0,"","","","","",null} │
│ 192.168.1.1 ┆ {0.0,"","","","","",null} │
│ 999.abc.def.123 ┆ {null,null,null,null,null,null… │
└─────────────────┴─────────────────────────────────┘
```
## 环境配置
IPTools 使用两个 MaxMind 数据库:_GeoLite2-ASN.mmdb_ 和 _GeoLite2-City.mmdb_。只有在调用 geoip 函数时才需要这些文件。
设置 `MAXMIND_MMDB_DIR` 环境变量以告知扩展这些文件的位置。
```
export MAXMIND_MMDB_DIR=/path/to/your/mmdb/files
# 或 Windows 用户
set MAXMIND_MMDB_DIR=c:\path\to\your\mmdb\files
```
如果未设置环境变量,polars_iptools 将检查另外两个常见位置(在 Mac/Linux 上):
```
/usr/local/share/GeoIP
/opt/homebrew/var/GeoIP
```
### Spur 环境
如果您是 Spur 的客户,请将数据源导出为 `spur.mmdb`,并使用 `SPUR_MMDB_DIR` 环境变量指定其位置。
```
export SPUR_MMDB_DIR=/path/to/spur/mmdb
# 或 Windows 用户
set SPUR_MMDB_DIR=c:\path\to\spur\mmdb
```
## 致谢
遵循 Marco Gorelli 的 [教程](https://marcogorelli.github.io/polars-plugins-tutorial/) 和 [cookiecutter 模板](https://github.com/MarcoGorelli/cookiecutter-polars-plugins),开发此扩展变得非常简单。
标签:Cybersecurity, EDR, GitHub, IPv4, IPv6, IP 地址批量处理, IP地址解析, MaxMind, Polars扩展, PowerShell, Prompt Injection, Python, Rust, Siem工具, Threat Intelligence, 代理检测, 代码示例, 匿名化, 可视化界面, 地理定位, 威胁情报, 开发者工具, 开源, 数据 enrichment, 数据分析, 数据处理库, 无后门, 网络安全, 网络流量审计, 脆弱性评估, 逆向工具, 隐私保护