@@ -485,10 +485,13 @@ def _interface_from_route_print(interface_ip: str) -> Tuple[Optional[str], str]:
485485 return None , "no WMI row for interface IP %s" % interface_ip
486486
487487
488- def _parse_route_print_default_interface_ip (route_text : str ) -> Optional [str ]:
489- """解析 route print -4 中 0.0.0.0/0.0.0.0 默认路由行,取「接口」列 IPv4(中英界面均多为数字列)。"""
488+ def _parse_route_print_default_route_row (route_text : str ) -> Optional [Tuple [int , str , str ]]:
489+ """
490+ 解析 route print -4 中默认 IPv4 路由行(0.0.0.0 0.0.0.0 …)。
491+ 返回 (metric, gateway_ipv4, interface_ipv4);无则 None。
492+ """
490493 lines = route_text .replace ("\r \n " , "\n " ).split ("\n " )
491- best : Optional [Tuple [int , str ]] = None # (metric, interface_ip )
494+ best : Optional [Tuple [int , str , str ]] = None # (metric, gw, iface_ip )
492495 for line in lines :
493496 line_stripped = line .strip ()
494497 if not line_stripped .startswith ("0.0.0.0" ):
@@ -499,16 +502,91 @@ def _parse_route_print_default_interface_ip(route_text: str) -> Optional[str]:
499502 continue
500503 if parts [1 ] != "0.0.0.0" :
501504 continue
505+ gw_ip = parts [2 ]
502506 iface_ip = parts [3 ]
503507 if not re .match (r"^\d{1,3}(\.\d{1,3}){3}$" , iface_ip ):
504508 continue
509+ if not re .match (r"^\d{1,3}(\.\d{1,3}){3}$" , gw_ip ):
510+ continue
505511 try :
506512 metric = int (parts [4 ])
507513 except ValueError :
508514 continue
509515 if best is None or metric < best [0 ]:
510- best = (metric , iface_ip )
511- return best [1 ] if best else None
516+ best = (metric , gw_ip , iface_ip )
517+ return best
518+
519+
520+ def _parse_route_print_default_interface_ip (route_text : str ) -> Optional [str ]:
521+ """解析 route print -4 中 0.0.0.0/0.0.0.0 默认路由行,取「接口」列 IPv4(中英界面均多为数字列)。"""
522+ row = _parse_route_print_default_route_row (route_text )
523+ return row [2 ] if row else None
524+
525+
526+ def _parse_route_print_default_gateway (route_text : str ) -> Optional [str ]:
527+ """默认路由行中的 IPv4 网关。"""
528+ row = _parse_route_print_default_route_row (route_text )
529+ return row [1 ] if row else None
530+
531+
532+ def _route_print_ipv4_default_gateway () -> str :
533+ try :
534+ p = subprocess .run (
535+ ["route" , "print" , "-4" ],
536+ capture_output = True ,
537+ text = True ,
538+ creationflags = _subprocess_flags (),
539+ timeout = 30 ,
540+ )
541+ except (OSError , subprocess .TimeoutExpired ):
542+ return ""
543+ if p .returncode != 0 :
544+ return ""
545+ g = _parse_route_print_default_gateway (p .stdout or "" )
546+ return g if g else ""
547+
548+
549+ def _wmic_nic_configuration_row_for_ipv4 (target_ipv4 : str ) -> Optional [Dict [str , str ]]:
550+ """
551+ Win7 等环境下路由表 InterfaceIndex 与 NICConfiguration.InterfaceIndex 可能不一致;
552+ 按本机 IPv4 在 WMI 全部已启用配置中反查对应行。
553+ """
554+ target = (target_ipv4 or "" ).strip ().lower ()
555+ if not target or not _is_dotted_ipv4 (target ):
556+ return None
557+ try :
558+ p = subprocess .run (
559+ [
560+ "wmic" ,
561+ "path" ,
562+ "Win32_NetworkAdapterConfiguration" ,
563+ "where" ,
564+ "IPEnabled=true" ,
565+ "get" ,
566+ "InterfaceIndex,IPAddress,IPSubnet,DefaultIPGateway,DNSServerSearchOrder,DHCPEnabled,IPEnabled" ,
567+ "/format:list" ,
568+ ],
569+ capture_output = True ,
570+ text = True ,
571+ creationflags = _subprocess_flags (),
572+ timeout = 45 ,
573+ )
574+ except (OSError , subprocess .TimeoutExpired ):
575+ return None
576+ if p .returncode != 0 :
577+ return None
578+ for row in _parse_wmic_list (p .stdout or "" ):
579+ if row .get ("ipenabled" , "" ).strip ().lower () not in ("true" , "1" ):
580+ continue
581+ raw_ip = row .get ("ipaddress" , "" )
582+ tokens = [t .strip ().lower () for t in _wmic_multivalue_tokens (raw_ip )]
583+ if not tokens :
584+ t0 = _clean_wmic_value (raw_ip ).strip ().lower ()
585+ if t0 :
586+ tokens = [t0 ]
587+ if target in tokens :
588+ return row
589+ return None
512590
513591
514592def _interface_from_route_print_only () -> Tuple [Optional [str ], str ]:
@@ -744,32 +822,36 @@ def _wmic_interface_index_for_netconnection_id(target: str) -> Optional[int]:
744822
745823
746824def _wmic_nic_configuration_by_interface_index (if_idx : int ) -> Optional [Dict [str , str ]]:
747- try :
748- p = subprocess .run (
749- [
750- "wmic" ,
751- "path" ,
752- "Win32_NetworkAdapterConfiguration" ,
753- "where" ,
754- "InterfaceIndex=%d" % if_idx ,
755- "get" ,
756- "IPAddress,IPSubnet,DefaultIPGateway,DNSServerSearchOrder,DHCPEnabled,IPEnabled" ,
757- "/format:list" ,
758- ],
759- capture_output = True ,
760- text = True ,
761- creationflags = _subprocess_flags (),
762- timeout = 30 ,
763- )
764- except (OSError , subprocess .TimeoutExpired ):
765- return None
766- if p .returncode != 0 :
767- return None
768- rows = _parse_wmic_list (p .stdout or "" )
769- for row in rows :
770- if row .get ("ipenabled" , "" ).strip ().lower () in ("true" , "1" ):
771- return row
772- return rows [0 ] if rows else None
825+ """Win7 上部分环境需用 Index= 而非 InterfaceIndex=,两种都试。"""
826+ for where in ("InterfaceIndex=%d" % if_idx , "Index=%d" % if_idx ):
827+ try :
828+ p = subprocess .run (
829+ [
830+ "wmic" ,
831+ "path" ,
832+ "Win32_NetworkAdapterConfiguration" ,
833+ "where" ,
834+ where ,
835+ "get" ,
836+ "IPAddress,IPSubnet,DefaultIPGateway,DNSServerSearchOrder,DHCPEnabled,IPEnabled" ,
837+ "/format:list" ,
838+ ],
839+ capture_output = True ,
840+ text = True ,
841+ creationflags = _subprocess_flags (),
842+ timeout = 30 ,
843+ )
844+ except (OSError , subprocess .TimeoutExpired ):
845+ continue
846+ if p .returncode != 0 :
847+ continue
848+ rows = _parse_wmic_list (p .stdout or "" )
849+ for row in rows :
850+ if row .get ("ipenabled" , "" ).strip ().lower () in ("true" , "1" ):
851+ return row
852+ if rows :
853+ return rows [0 ]
854+ return None
773855
774856
775857def _ipv4_subnet_pairs_from_wmi_row (row : Dict [str , str ]) -> List [Tuple [str , str ]]:
@@ -1017,6 +1099,22 @@ def get_default_ipv4_detail_snapshot(ttl_sec: float = 20.0) -> Dict[str, Any]:
10171099 if not str (out .get ("ip" ) or "" ).strip () and pref :
10181100 out ["ip" ] = pref
10191101
1102+ hip = str (out .get ("ip" ) or pref ).strip ()
1103+ if hip :
1104+ need_more = (
1105+ not str (out .get ("mask" ) or "" ).strip ()
1106+ or not str (out .get ("gateway" ) or "" ).strip ()
1107+ or not str (out .get ("dns_primary" ) or "" ).strip ()
1108+ )
1109+ if need_more :
1110+ row_fix = _wmic_nic_configuration_row_for_ipv4 (hip )
1111+ if row_fix :
1112+ _merge_ipv4_detail_fields (out , _detail_row_to_dict (row_fix , hip ))
1113+ if not str (out .get ("gateway" ) or "" ).strip ():
1114+ gw_rp = _route_print_ipv4_default_gateway ()
1115+ if gw_rp :
1116+ out ["gateway" ] = gw_rp
1117+
10201118 _detail_mono = now
10211119 _detail_payload = dict (out )
10221120 return dict (out )
0 commit comments