当前位置: 首页 > news >正文

WindowsAPI|每天了解几个winAPI接口之网络配置相关文档Iphlpapi.h详细分析七

上一篇:WindowsAPI|每天了解几个winAPI接口之网络配置相关文档Iphlpapi.h详细分析六
如果有错误欢迎指正批评,在此只作为科普和参考。

C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\um\iphlpapi.h

文章目录

  • CreateIpNetEntry:把某个 IPv4 地址强行绑定到指定 MAC(或更新现有绑定)
      • 函数原型(简化)
      • 关键参数
      • 典型使用场景
      • 注意事项
      • 简单代码示例
  • ARP 缓存条目是什么
      • 为什么需要这张纸条?
      • 一条 ARP 缓存长什么样?
      • 存在哪里?
      • 生命周期
  • SetIpNetEntry:**用来“修改”一条已经存在的 ARP 缓存条目**
      • 功能一句话
      • 与 CreateIpNetEntry 的区别
      • 调用要点
      • 最小示例
      • 常见错误码
  • DeleteIpNetEntry:**把本机 ARP 缓存中的一条**(且仅一条)**已有条目删除**
      • 函数原型
      • 关键约束
      • 使用流程(典型)
      • 最小示例
      • 与 FlushIpNetTable 的区别
  • FlushIpNetTable:
      • 函数原型
      • 行为要点
      • 典型场景
      • 最小示例
      • 与 DeleteIpNetEntry 的关系
  • CreateProxyArpEntry:**让本机在指定接口上“假装”自己拥有某个 IP(段),从而替别人回答 ARP 请求——这就是 Proxy ARP(代理 ARP)。**
      • 1. 什么是 Proxy ARP?
      • 2. 函数原型
      • 3. 结果表现
      • 4. 典型场景
      • 5. 注意事项
      • 6. 最小示例
  • DeleteProxyArpEntry:撤销之前通过 `CreateProxyArpEntry` 建立的 Proxy ARP 代理范围
      • 函数原型
      • 成功后的效果
      • 常见返回值
      • 最小示例

CreateIpNetEntry:把某个 IPv4 地址强行绑定到指定 MAC(或更新现有绑定)


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Used to create, modify or delete an ARP entry.  In all cases the dwIndex //
// dwAddr field MUST BE SPECIFIED.                                          //
// For a set, the complete MIB_IPNETROW structure must be specified         //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
CreateIpNetEntry(_In_ PMIB_IPNETROW    pArpEntry);

CreateIpNetEntry 是 Windows IP 帮助库(iphlpapi.dll)导出的一个 API 函数,用于 创建或修改本机的 ARP 缓存条目。它的核心功能是:往 IPv4 邻居缓存(ARP 表)里“写”一个条目,实现 IP 地址到 MAC 地址的静态映射。


函数原型(简化)

DWORD CreateIpNetEntry(_In_ const MIB_IPNETROW *pArpEntry
);
  • 返回值DWORD
    • NO_ERROR(0)表示成功;
    • 其他 Win32 错误码表示失败,常见如 ERROR_INVALID_PARAMETERERROR_NOT_SUPPORTED 等。

关键参数

typedef struct _MIB_IPNETROW {DWORD dwIndex;     // 对应本地接口的索引(LUID),**必须正确**DWORD dwPhysAddrLen;BYTE  bPhysAddr[MAXLEN_PHYSADDR]; // 目标 MAC 地址DWORD dwAddr;      // 目标 IPv4 地址(网络字节序),**必须指定**DWORD dwType;      // 条目类型:static(4)、dynamic(3) 等
} MIB_IPNETROW, *PMIB_IPNETROW;
  • dwIndex:通过 GetAdaptersInfoGetIfTable 等 API 获取,指明要把 ARP 条目绑到哪块网卡。
  • dwAddr:要映射的 IPv4 地址(如 192.168.1.100)。
  • bPhysAddr:对应的 MAC 地址(如 00-11-22-33-44-55)。
  • dwType
    • MIB_IPNET_TYPE_STATIC(4)→ 静态条目,重启后仍保留,除非手动删除。
    • MIB_IPNET_TYPE_DYNAMIC(3)→ 动态条目,随 ARP 老化机制自动过期。
      通常创建“永久”映射时设为 STATIC

典型使用场景

  1. 手动添加静态 ARP 条目
    避免局域网内目标主机被 ARP 欺骗,或为了在脚本里预先绑定关键服务器。
  2. 网络诊断/管理工具
    如自己写个“arp -s”替代品,或集成到网管软件里。
  3. 驱动或安全软件
    在驱动层之上快速写入静态邻居条目,防止某些攻击。

注意事项

  • 权限:调用进程需具备 管理员权限SeLoadDriverPrivilegeSeManageVolumePrivilege 在某些系统上也可能要求)。
  • IPv4 Only:该 API 只操作 IPv4 ARP 缓存。IPv6 邻居缓存请用 CreateUnicastIpAddressEntrySetIpNetEntry2
  • 已有条目:如果 (dwIndex, dwAddr) 已存在,函数会更新该条目(相当于 Set 操作)。
  • 删除条目:用 DeleteIpNetEntryFlushIpNetTable

简单代码示例

MIB_IPNETROW arp = {0};
arp.dwIndex       = IfIndex;          // 网卡索引
arp.dwAddr        = inet_addr("192.168.1.100");
arp.dwPhysAddrLen = 6;
memcpy(arp.bPhysAddr, "\x00\x11\x22\x33\x44\x55", 6);
arp.dwType        = MIB_IPNET_TYPE_STATIC; // 静态DWORD ret = CreateIpNetEntry(&arp);
if (ret == NO_ERROR) {printf("ARP entry added.\n");
} else {printf("Error: %lu\n", ret);
}

一句话总结:
CreateIpNetEntry 就是“以编程方式执行 arp -s”的 Win32 API,用来把某个 IPv4 地址强行绑定到指定 MAC(或更新现有绑定)。

ARP 缓存条目是什么

ARP 缓存条目(ARP Cache Entry)就是操作系统在内存里“记的一张小纸条”:
把某个 IP 地址暂时或永久地对应到某个 MAC 地址


为什么需要这张纸条?

局域网通信时,数据链路层(以太网/Wi-Fi)只看 MAC 地址(形如 00:11:22:33:44:55)。
但应用程序只知道 IP 地址(如 192.168.1.10)。
于是操作系统必须在发送数据包前,先回答:

“192.168.1.10 对应的 MAC 是多少?”

这个“查表 + 找不到就广播询问”的过程就是 ARP(Address Resolution Protocol)

为了避免每次都广播,操作系统把“问到的答案”缓存起来——这就是 ARP 缓存条目


一条 ARP 缓存长什么样?

在 Windows 上用 arp -a 可以看到:

Internet Address      Physical Address      Type
192.168.1.1          00-11-22-33-44-55     dynamic
192.168.1.100        66-77-88-99-aa-bb     static
  • Internet Address:目标 IPv4 地址
  • Physical Address:对方的 MAC 地址
  • Type
    • dynamic:动态条目,默认存活 2 分钟~10 分钟(可配置),超时自动删除。
    • static:静态条目,除非手动删除或重启,否则长期保留。

存在哪里?

  • Windows:内核的一块内存数据结构(可通过 GetIpNetTable API 读取)。
  • Linux/proc/net/arpip neigh 命令查看。

生命周期

  1. 首次通信 → 发 ARP 请求广播 → 收到 ARP 应答 → 写入动态条目。
  2. 继续通信 → 每用一次就刷新“老化计时器”。
  3. 超时未用 → 动态条目被删除。
  4. 管理员手动 → 用 arp -sCreateIpNetEntry 创建静态条目,永不过期。

一句话总结:
ARP 缓存条目就是“IP 与 MAC 的映射关系表里的某一行”,让操作系统在局域网里发数据包时,不必每次都重新问“谁有 IP x.x.x.x?”

SetIpNetEntry:用来“修改”一条已经存在的 ARP 缓存条目

IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
SetIpNetEntry(_In_ PMIB_IPNETROW    pArpEntry);

SetIpNetEntry 与刚才介绍的 CreateIpNetEntry 同属 iphlpapi.dll,用来“修改”一条已经存在的 ARP 缓存条目,而不是新建一条。


功能一句话

把本地 ARP 表里已有的 (接口, IPv4) 对应关系更新成新的 MAC 或新的类型(dynamic / static)。


与 CreateIpNetEntry 的区别

API条目不存在时的行为条目已存在时的行为典型用途
CreateIpNetEntry新建更新相当于 arp -s
SetIpNetEntry返回错误 (ERROR_NOT_FOUND)更新只改已有条目

调用要点

  1. 必须保证 MIB_IPNETROW
    • dwIndex(接口索引)
    • dwAddr(IPv4 地址)
      与现有条目 完全一致,否则函数会失败。
  2. 可以修改:
    • 目标 MAC (bPhysAddr)
    • 条目类型 (dwType):dynamic → static 或反之
  3. 权限:同样需要管理员权限。

最小示例

MIB_IPNETROW row = {0};
// 1. 先取出现有条目(这里仅演示,实际用 GetIpNetTable 找到)
row.dwIndex = 7;                       // 本机接口索引
row.dwAddr  = inet_addr("192.168.1.1");// 要改的 IP
memcpy(row.bPhysAddr, "\xAA\xBB\xCC\xDD\xEE\xFF", 6);
row.dwPhysAddrLen = 6;
row.dwType = MIB_IPNET_TYPE_STATIC;    // 把 dynamic 改成 staticDWORD ret = SetIpNetEntry(&row);
if (ret == NO_ERROR) {printf("ARP entry updated.\n");
} else {printf("Error: %lu\n", ret);
}

常见错误码

  • ERROR_NOT_FOUND(1168)
    → 指定的 (接口, IP) 组合在 ARP 表里不存在。
  • ERROR_INVALID_PARAMETER(87)
    → 参数不合法(MAC 长度、接口索引、地址格式等)。

一句话总结:
SetIpNetEntry 就是“只能改、不能建”的 ARP 表编辑 API;当你想 更新 某条已有邻居条目的 MAC 或类型时就用它。

DeleteIpNetEntry:把本机 ARP 缓存中的一条(且仅一条)已有条目删除

IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
DeleteIpNetEntry(_In_ PMIB_IPNETROW    pArpEntry);

DeleteIpNetEntry 是 iphlpapi.dll 提供的 API,用于把本机 ARP 缓存中的一条(且仅一条)已有条目删除
换句话说,它是“以编程方式执行 arp -d <IP>”的函数版本。


函数原型

DWORD WINAPI DeleteIpNetEntry(_In_ PMIB_IPNETROW pArpEntry
);
  • 返回值
    • NO_ERROR (0) 删除成功
    • ERROR_NOT_FOUND (1168) 指定条目不存在
    • ERROR_INVALID_PARAMETER 参数非法
    • 其他 Win32 错误码

关键约束

  1. 必须提供
    • dwIndex(本地接口索引)
    • dwAddr(IPv4 地址,网络字节序)
      这两个字段合在一起充当“主键”,精确匹配要删的那一行。
  2. 其余字段可忽略
    函数只看 (dwIndex, dwAddr),MAC 地址、类型等字段不会被比对。
  3. 权限
    需要管理员权限;非特权进程调用会失败(ERROR_ACCESS_DENIED)。

使用流程(典型)

  1. 先用 GetIpNetTable 枚举当前 ARP 表,找到要删的条目,把其 dwIndexdwAddr 拷出来。
  2. 填充一个 MIB_IPNETROW,仅填这两个关键字段即可。
  3. 调用 DeleteIpNetEntry

最小示例

MIB_IPNETROW entry = {0};
entry.dwIndex = 7;                       // 网卡接口索引
entry.dwAddr  = inet_addr("192.168.1.100"); // 要删除的 IPDWORD err = DeleteIpNetEntry(&entry);
if (err == NO_ERROR) {printf("ARP entry deleted.\n");
} else {printf("Delete failed: %lu\n", err);
}

与 FlushIpNetTable 的区别

  • DeleteIpNetEntry
    删除单条指定 (接口, IP) 的条目。
  • FlushIpNetTable
    整张接口的 ARP 表全部清空(暴力版 arp -d *)。

一句话总结:
DeleteIpNetEntry 就是“精确制导”地删掉某个接口下某个 IPv4 地址对应的 ARP 缓存行;条目必须已存在,否则返回 ERROR_NOT_FOUND

FlushIpNetTable:

IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
FlushIpNetTable(_In_ DWORD   dwIfIndex);

FlushIpNetTable 是 iphlpapi.dll 提供的“一键清空”接口——
把指定网卡接口(由 dwIfIndex 标识)的整张 IPv4 ARP 缓存表全部刷掉,相当于在该接口上执行 arp -d *(Windows 无此命令行,但效果类似)。


函数原型

DWORD WINAPI FlushIpNetTable(_In_ DWORD dwIfIndex   // 要清空的接口索引
);
  • 返回值
    • NO_ERROR (0) 成功
    • ERROR_INVALID_PARAMETER:接口索引无效
    • 其他 Win32 错误码(如权限不足)

行为要点

  1. 作用范围
    仅影响 dwIfIndex 对应的接口;其他接口的 ARP 表保持不变。
  2. 清空内容
    该接口下 所有动态条目 立即被删除;静态条目 不受影响(静态条目需用 DeleteIpNetEntry 或重启才能移除)。
  3. 触发后续 ARP 广播
    清空后,如果进程再次访问这些 IP,系统会重新发起 ARP 请求广播。
  4. 权限
    需要管理员权限;普通进程返回 ERROR_ACCESS_DENIED

典型场景

  • 网络故障排查:怀疑 ARP 缓存被污染,先整体清掉再观察。
  • DHCP/网络切换:接口刚拿到新的网段地址,清掉旧网段残留的条目。
  • 安全/测试工具:模拟“ARP 表刷新”。

最小示例

DWORD dwIfIndex = 7;   // 例:有线网卡接口索引
DWORD err = FlushIpNetTable(dwIfIndex);
if (err == NO_ERROR) {printf("Interface %lu ARP table flushed.\n", dwIfIndex);
} else {printf("Flush failed: %lu\n", err);
}

与 DeleteIpNetEntry 的关系

API粒度影响静态条目?
DeleteIpNetEntry单条(IP + 接口)可以删除
FlushIpNetTable整接口所有动态条目不删除静态

一句话总结:
FlushIpNetTable 就是“把某块网卡的 IPv4 ARP 缓存瞬间格式化”,只留下静态条目,动态邻居全部强制失效并重新解析。

CreateProxyArpEntry:让本机在指定接口上“假装”自己拥有某个 IP(段),从而替别人回答 ARP 请求——这就是 Proxy ARP(代理 ARP)。


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Used to create or delete a Proxy ARP entry. The dwIndex is the index of  //
// the interface on which to PARP for the dwAddress.  If the interface is   //
// of a type that doesnt support ARP, e.g. PPP, then the call will fail     //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
CreateProxyArpEntry(_In_  DWORD   dwAddress,_In_  DWORD   dwMask,_In_  DWORD   dwIfIndex);

CreateProxyArpEntry 作用一句话:让本机在指定接口上“假装”自己拥有某个 IP(段),从而替别人回答 ARP 请求——这就是 Proxy ARP(代理 ARP)。


1. 什么是 Proxy ARP?

  • 当主机 A 想访问 IP X,但 X 并不在本子网,按常理 A 应该先把包发给网关。
  • 如果网关上启用了 Proxy ARP,它会回应 A 的 ARP 请求:
    “IP X 的 MAC 就是我的 MAC”。
    于是 A 把数据直接发到网关 MAC,再由网关转发到真正的 X整个过程对 A 完全透明

2. 函数原型

DWORD WINAPI CreateProxyArpEntry(_In_ DWORD dwAddress,  // 起始 IPv4 地址(网络字节序)_In_ DWORD dwMask,     // 子网掩码(决定范围)_In_ DWORD dwIfIndex   // 在哪个接口上代答
);
  • dwAddress + dwMask 共同描述 要代理的 IP 范围
    例如 192.168.1.0 + 255.255.255.0 → 代理整个 /24
  • dwIfIndex 必须是支持 ARP 的接口(以太网、Wi-Fi 等);PPP/隧道接口会返回 ERROR_NOT_SUPPORTED

3. 结果表现

调用成功后,内核在该接口上:

  • 接收 任何落在这个 IP 范围内的 ARP 请求
  • 立即回发 ARP Reply,源 MAC 填本机接口 MAC;
  • 后续数据包由本机按路由表转发给真正的目标。

4. 典型场景

  • 无感知网关
    老设备不懂子网,只能广播 ARP。网关用 Proxy ARP 让它以为所有地址都在本地 LAN。
  • 地址迁移/透明迁移
    临时把某段地址代理到新网关,无需修改终端配置。
  • VPN/拨号服务器
    让远程客户端仿佛直接位于公司局域网。

5. 注意事项

  • 仅 IPv4;IPv6 用 NDP Proxy。
  • 需要 管理员权限
  • 删除用 DeleteProxyArpEntry(参数完全一致)。
  • 不会自动加路由,必须确保本机能把流量正确转发到真正目的地,否则虽有 ARP 回复,数据仍会黑洞。

6. 最小示例

DWORD dwAddr = inet_addr("192.168.10.0");   // 起始地址
DWORD dwMask = inet_addr("255.255.255.0");  // /24
DWORD dwIdx  = 7;                           // 以太网接口索引DWORD err = CreateProxyArpEntry(dwAddr, dwMask, dwIdx);
if (err == NO_ERROR)printf("Proxy ARP enabled on 192.168.10.0/24\n");
elseprintf("Error: %lu\n", err);

一句话再总结:
CreateProxyArpEntry 让指定网卡“撒谎”说自己拥有某一段 IP,从而充当透明的 ARP 代理,把 ARP 请求全部揽到自己身上,再负责把数据包真正送出去。

DeleteProxyArpEntry:撤销之前通过 CreateProxyArpEntry 建立的 Proxy ARP 代理范围

IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
DeleteProxyArpEntry(_In_  DWORD   dwAddress,_In_  DWORD   dwMask,_In_  DWORD   dwIfIndex);

DeleteProxyArpEntryCreateProxyArpEntry逆向操作

  • 功能:在指定接口上,撤销之前通过 CreateProxyArpEntry 建立的 Proxy ARP 代理范围
  • 参数必须与创建时完全一致dwAddressdwMaskdwIfIndex),否则系统找不到对应条目而返回 ERROR_NOT_FOUND

函数原型

DWORD WINAPI DeleteProxyArpEntry(_In_ DWORD dwAddress,  // 起始 IPv4 地址(网络字节序)_In_ DWORD dwMask,     // 子网掩码_In_ DWORD dwIfIndex   // 接口索引
);

成功后的效果

  • 该接口停止为指定 IP 段代答 ARP 请求。
  • 终端下次 ARP 该段地址时,将收不到代理回复,只能得到真实主机或网关的响应(若存在)。
  • 对已建立的流量连接无影响,仅对新 ARP 请求生效。

常见返回值

含义
NO_ERROR (0)删除成功
ERROR_NOT_FOUND (1168)指定 (地址/掩码/接口) 的组合不存在
ERROR_INVALID_PARAMETER参数非法
ERROR_ACCESS_DENIED权限不足(需管理员)

最小示例

// 撤销先前对 192.168.10.0/24 的 Proxy ARP
DWORD addr = inet_addr("192.168.10.0");
DWORD mask = inet_addr("255.255.255.0");
DWORD idx  = 7;   // 对应接口DWORD err = DeleteProxyArpEntry(addr, mask, idx);
if (err == NO_ERROR)printf("Proxy ARP entry removed.\n");
elseprintf("Failed: %lu\n", err);

一句话总结:
DeleteProxyArpEntry 用来“注销” Proxy ARP 代理范围,让接口不再冒充指定网段的 IP 地址去回应 ARP 请求。

http://www.dtcms.com/a/342529.html

相关文章:

  • 如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
  • CTFshow系列——命令执行web41-44
  • YOLOv8 原理与跨领域应用全景分析
  • CVPR | 2025 | MAP:通过掩码自回归预训练释放混合 Mamba - Transformer 视觉骨干网络的潜力
  • 【C++】仿函数和回调函数
  • Python数值取整完全指南:从基础到金融工程实践
  • uniapp实现分页,效果如图
  • 自然语言处理——04 注意力机制
  • npm全局安装后,cmd命令行可以访问,vscode访问报错
  • HTTP 403 错误:后端权限校验机制深度解析
  • 长尾关键词优化SEO核心策略
  • JeeSite 快速开发平台:全能企业级快速开发解决方案
  • 自己动手,在Mac开发机上利用ollama部署一款轻量级的大模型Phi-3:mini
  • ElasticSearch——常用命令
  • VSCode Import Cost:5 分钟学会依赖瘦身
  • java16学习笔记
  • uniapp 全局弹窗
  • 力扣1005:k次取反后最大化的数组和
  • pycharm编译器如何快速掌握一个新模块的使用方法
  • K-means 聚类算法学习
  • matplotlib 6 - Gallery Images
  • 在 Linux 中全局搜索 Word 文档内容的完整指南
  • 从零搭建Kubernetes集群:常见踩坑与解决方案
  • Django中的MVC和MVT模式
  • Unity接入DeepSeek实现AI对话功能
  • 解析火语言 RPA 核心功能:让流程自动化更高效​
  • leetcode 76 最小覆盖子串
  • 有关spring-ai的defaultSystem与systemMessage优先级
  • AI 发展的伦理困局:在创新与规范间寻找平衡
  • MYSQL库及表的操作