Delphi:获取路由器的MAC

chy5wohz  于 2022-09-21  发布在  Mac
关注(0)|答案(2)|浏览(252)

我使用的是Delphi,我想确定网络中网络设备的物理MAC地址,在本例中是路由器本身。

我的代码是:

var
  idsnmp: tidsnmp;
  val:string;
begin
  idsnmp := tidsnmp.create;
  try
    idsnmp.QuickSend('.1.3.6.1.2.1.4.22.1.2', 'public', '10.0.0.1', val);
    showmessage(val);
  finally
    idsnmp.free;
  end;
end;

其中10.0.0.1是我的路由器。

可惜,QuickSend总是发送“Connection Reset by Peer#10054”。我尝试修改MIB-OID,还尝试了连接永远不会失败的IP 127.0.0.1。我在Google上找不到任何关于TIdSNMP的有用教程。-(

向Daniel Marschall致敬

5hcedyr0

5hcedyr01#

您可以使用SendARP函数来获取Mac地址。

检查此样本

uses
 Windows,
 WinSock,
 SysUtils;

function SendArp(DestIP,SrcIP:ULONG;pMacAddr:pointer;PhyAddrLen:pointer) : DWord; StdCall; external 'iphlpapi.dll' name 'SendARP';

function GetMacAddr(const IPAddress: string; var ErrCode : DWORD): string;
var
MacAddr    : Array[0..5] of Byte;
DestIP     : ULONG;
PhyAddrLen : ULONG;
WSAData    : TWSAData;
begin
  Result    :='';
  WSAStartup(B1a0a1b101, WSAData);
  try
    ZeroMemory(@MacAddr,SizeOf(MacAddr));
    DestIP    :=inet_addr(PAnsiChar(AnsiString(IPAddress)));
    PhyAddrLen:=SizeOf(MacAddr);
    ErrCode   :=SendArp(DestIP,0,@MacAddr,@PhyAddrLen);
    if ErrCode = S_OK then
     Result:=Format('%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x',[MacAddr[0], MacAddr[1],MacAddr[2], MacAddr[3], MacAddr[4], MacAddr[5]])
  finally
    WSACleanup;
  end;
end;
nue99wik

nue99wik2#

不想抢了RRUZ的风头,我提供了以下变体,摘自我的代码库,并进行了一些观察。我这样做是作为一个回答,而不是一个注解,以便包括代码。

type
  TMacAddress = array [0..5] of Byte;

function inet_addr(const IPAddress: string): ULONG;
begin
  Result := ULONG(WinSock.inet_addr(PAnsiChar(AnsiString(IPAddress))));
end;

function SendARP(DestIP, SrcIP: ULONG; pMacAddr: Pointer; var PhyAddrLen: ULONG): DWORD; stdcall; external 'Iphlpapi.dll';

function GetMacAddress(const IPAddress: string): TMacAddress;
var
  MaxMacAddrLen: ULONG;
begin
  MaxMacAddrLen := SizeOf(Result);
  if SendARP(inet_addr(IPAddress), 0, @Result, MaxMacAddrLen)<>NO_ERROR then begin
    raise EMacAddressError.CreateFmt('Unable to do SendARP on address: ''%s''', [IPAddress]);
  end;
end;

这里有几点需要说明。

不需要调用WSAStartup/WSACleanup。

EDIT正如RRUZ在一条评论中指出的那样,winsock文档并没有明确地将inet_addr从WSAStartup/WSACleanup中排除,所以我撤回了这一点。在Vista上,只需调用RtlIpv4StringToAddress就更简单了。话虽如此,inetaddr是如此容易实现,可能只是更容易使用您自己的。

其次,WinSock.pas中的inet_addr声明不正确。它将返回值声明为u_long类型,该类型在WinSock.pas中定义为Longint。这是一个带符号的4字节整数,但它应该是一个无符号的4字节整数,ulong。如果没有显式强制转换,则可能会出现范围错误。

相关问题