@@ -598,7 +598,8 @@ def _parse_netsh_dns_ipv4_list(text: str) -> List[str]:
598598
599599def _netsh_ipv4_enrich_from_ifindex (if_idx : int ) -> Dict [str , Any ]:
600600 """
601- 用「接口索引」调用 netsh,不依赖中文连接名;补缺子网掩码与 DNS(Win7/编码异常时尤其有效)。
601+ 用「接口索引」调用 netsh,不依赖中文连接名;
602+ 补缺子网掩码与 DNS(Win7/编码异常时尤其有效),并从 show addresses 解析 DHCP 是否启用。
602603 """
603604 out : Dict [str , Any ] = {}
604605 if sys .platform != "win32" or if_idx < 0 :
@@ -614,6 +615,10 @@ def _netsh_ipv4_enrich_from_ifindex(if_idx: int) -> Dict[str, Any]:
614615 return out
615616 text = p .stdout or ""
616617
618+ ndhcp = _netsh_parse_dhcp_enabled_from_addresses (text )
619+ if ndhcp is not None :
620+ out ["dhcp" ] = ndhcp
621+
617622 mmask = re .search (
618623 r"\(\s*mask\s+(\d{1,3}(?:\.\d{1,3}){3})\s*\)" ,
619624 text ,
@@ -924,32 +929,36 @@ def _wmic_interface_index_for_netconnection_id(target: str) -> Optional[int]:
924929
925930
926931def _wmic_nic_configuration_by_interface_index (if_idx : int ) -> Optional [Dict [str , str ]]:
927- """Win7 上部分环境需用 Index= 而非 InterfaceIndex=,两种都试。"""
928- for where in ("InterfaceIndex=%d" % if_idx , "Index=%d" % if_idx ):
929- try :
930- p = _run_text_cmd (
931- [
932- "wmic" ,
933- "path" ,
934- "Win32_NetworkAdapterConfiguration" ,
935- "where" ,
936- where ,
937- "get" ,
938- "IPAddress,IPSubnet,DefaultIPGateway,DNSServerSearchOrder,DHCPEnabled,IPEnabled" ,
939- "/format:list" ,
940- ],
941- timeout = 30 ,
942- )
943- except (OSError , subprocess .TimeoutExpired , ValueError ):
944- continue
945- if p .returncode != 0 :
946- continue
947- rows = _parse_wmic_list (p .stdout or "" )
948- for row in rows :
949- if row .get ("ipenabled" , "" ).strip ().lower () in ("true" , "1" ):
950- return row
951- if rows :
952- return rows [0 ]
932+ """
933+ 按 Win32_NetworkAdapterConfiguration.InterfaceIndex 查询。
934+ Win32_IP4RouteTable.InterfaceIndex、netsh/route print「接口」索引与此字段一致。
935+ 勿再以 Index=N 回退:Win7 上常见 Index≠InterfaceIndex(如 Index=7、InterfaceIndex=11);
936+ 用路由表得到的 11 去查 Index=11 会得到另一块网卡,DHCPEnabled 误判为假。
937+ """
938+ try :
939+ p = _run_text_cmd (
940+ [
941+ "wmic" ,
942+ "path" ,
943+ "Win32_NetworkAdapterConfiguration" ,
944+ "where" ,
945+ "InterfaceIndex=%d" % if_idx ,
946+ "get" ,
947+ "IPAddress,IPSubnet,DefaultIPGateway,DNSServerSearchOrder,DHCPEnabled,IPEnabled" ,
948+ "/format:list" ,
949+ ],
950+ timeout = 30 ,
951+ )
952+ except (OSError , subprocess .TimeoutExpired , ValueError ):
953+ return None
954+ if p .returncode != 0 :
955+ return None
956+ rows = _parse_wmic_list (p .stdout or "" )
957+ for row in rows :
958+ if row .get ("ipenabled" , "" ).strip ().lower () in ("true" , "1" ):
959+ return row
960+ if rows :
961+ return rows [0 ]
953962 return None
954963
955964
@@ -1018,6 +1027,59 @@ def _wmic_default_route_interface_index() -> Optional[int]:
10181027 return candidates [0 ][1 ]
10191028
10201029
1030+ def _dhcp_enabled_from_wmic_raw (raw : str ) -> Optional [bool ]:
1031+ """
1032+ Win32_NetworkAdapterConfiguration.DHCPEnabled。
1033+ WMIC list 常为 TRUE/FALSE;缺省或非布尔时不应当成「静态」(否则 Win7 DHCP 易被误判)。
1034+ """
1035+ s = _clean_wmic_value ((raw or "" ).strip ()).strip ().lower ()
1036+ if not s or s in ("(null)" , "null" , "none" ):
1037+ return None
1038+ if s in ("true" , "1" , "yes" , "y" , "-1" ):
1039+ return True
1040+ if s in ("false" , "0" , "no" , "n" ):
1041+ return False
1042+ return None
1043+
1044+
1045+ def _netsh_value_after_label_colon (line : str ) -> str :
1046+ """中英文 netsh 可能用半角 ':' 或全角 ':' 分隔标签与取值。"""
1047+ for sep in (":" , "\uff1a " ):
1048+ if sep in line :
1049+ return line .split (sep , 1 )[- 1 ].strip ()
1050+ return ""
1051+
1052+
1053+ def _netsh_parse_dhcp_enabled_from_addresses (text : str ) -> Optional [bool ]:
1054+ """解析 netsh interface ipv4 show addresses 输出里的 DHCP 启用行(中英界面)。"""
1055+ for raw in (text or "" ).replace ("\r \n " , "\n " ).split ("\n " ):
1056+ line = raw .strip ()
1057+ if not line :
1058+ continue
1059+ low = line .lower ()
1060+ if "dhcp" not in low :
1061+ continue
1062+ if ("enabled" not in low ) and ("启用" not in line ):
1063+ continue
1064+ tail = _netsh_value_after_label_colon (line )
1065+ tl = tail .lower ()
1066+ if re .match (r"(?i)^(yes|true|y|1)\b" , tl ):
1067+ return True
1068+ if re .match (r"(?i)^(no|false|n|0)\b" , tl ):
1069+ return False
1070+ if tail in ("否" , "否。" , "NO" , "no" ):
1071+ return False
1072+ # 中文版常见:冒号后为「是」(半角冒号或非 ASCII 分隔已在上面的 tail 中取到)
1073+ if tail in ("是" , "是。" ) or tail .startswith ("是" ):
1074+ return True
1075+ # 容错:极少数主题下取值与标签粘在同一侧
1076+ if "否" in tail and len (tail ) <= 8 :
1077+ return False
1078+ if "是" in tail and ("否" not in tail ):
1079+ return True
1080+ return None
1081+
1082+
10211083def _detail_row_to_dict (
10221084 row : Dict [str , str ], preferred_ip : str
10231085) -> Dict [str , Any ]:
@@ -1039,16 +1101,17 @@ def _detail_row_to_dict(
10391101 t = t .strip ()
10401102 if _is_dotted_ipv4 (t ):
10411103 dns_v4 .append (t )
1042- dhcp_raw = row .get ("dhcpenabled" , "" ).strip ().lower ()
1043- dhcp = dhcp_raw in ("true" , "1" )
1044- return {
1104+ dhcp_hint = _dhcp_enabled_from_wmic_raw (row .get ("dhcpenabled" , "" ))
1105+ out_d : Dict [str , Any ] = {
10451106 "ip" : chosen_ip ,
10461107 "mask" : chosen_mask ,
10471108 "gateway" : gw ,
10481109 "dns_primary" : dns_v4 [0 ] if dns_v4 else "" ,
10491110 "dns_secondary" : dns_v4 [1 ] if len (dns_v4 ) > 1 else "" ,
1050- "dhcp" : dhcp ,
10511111 }
1112+ if dhcp_hint is not None :
1113+ out_d ["dhcp" ] = bool (dhcp_hint )
1114+ return out_d
10521115
10531116
10541117def _powershell_ipv4_detail_by_default_route () -> Optional [Dict [str , Any ]]:
@@ -1082,7 +1145,10 @@ def _powershell_ipv4_detail_by_default_route() -> Optional[Dict[str, Any]]:
10821145 "$d1 = ''; $d2 = ''; "
10831146 "if ($dns.Count -ge 1) { $d1 = [string]$dns[0] }; "
10841147 "if ($dns.Count -ge 2) { $d2 = [string]$dns[1] }; "
1085- "$dhcp = ($pick.PrefixOrigin -eq 'Dhcp'); "
1148+ "$ifi = Get-NetIPInterface -InterfaceIndex $idx -AddressFamily IPv4 "
1149+ "-ErrorAction SilentlyContinue | Select-Object -First 1; "
1150+ "$dhcpIfc = ($ifi -ne $null -and $ifi.Dhcp -eq 'Enabled'); "
1151+ "$dhcp = ($dhcpIfc -or ($pick.PrefixOrigin -eq 'Dhcp')); "
10861152 "$pfx = [int]$pick.PrefixLength; "
10871153 "$o = @{ ok=$true; ip=$pick.IPAddress; prefix=$pfx; gateway=$gw; "
10881154 "dns_primary=$d1; dns_secondary=$d2; dhcp=$dhcp }; "
@@ -1240,6 +1306,7 @@ def get_default_ipv4_detail_snapshot(
12401306 if idx_netsh is not None and (
12411307 not str (out .get ("mask" ) or "" ).strip ()
12421308 or not str (out .get ("dns_primary" ) or "" ).strip ()
1309+ or not bool (out .get ("dhcp" ))
12431310 ):
12441311 _merge_ipv4_detail_fields (out , _netsh_ipv4_enrich_from_ifindex (idx_netsh ))
12451312
0 commit comments