Mac-Adresse

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Shardik
Beiträge: 746
Registriert: 25.01.2005 12:19

Re: Mac-Adresse

Beitrag von Shardik »

Das verlinkte Windows-Beispiel von RSBasic ermittlet die Hardware GUID, aber nicht die gewünschte MAC-Adresse der lokalen Ethernet-Netzwerkschnittstelle!

Ein ganz einfaches Windows-Beispiel (getestet unter Windows XP SP3 und Windows 7 x86 SP1) verwendet den GetMAC-Befehl:

Code: Alles auswählen

EnableExplicit

Define i.I
Define MACEntry.S
Define MACInfo.S
Define Output.S
Define ProgramID.I

ProgramID = RunProgram("GetMAC", "/FO CSV", "", #PB_Program_Open | #PB_Program_Read | #PB_Program_Hide)

If ProgramID
  While ProgramRunning(ProgramID)
    If AvailableProgramOutput(ProgramID)
      Output + ReadProgramString(ProgramID) + #CR$
    EndIf
  Wend
 
  CloseProgram(ProgramID)

  For i = 1 To CountString(Output, #CR$)
    MACEntry = ReplaceString(StringField(StringField(Output, i, #CR$), 1, ","), #DQUOTE$, "")

    If MACEntry <> "" And Left(MACEntry, 1) <> "P"
      MACInfo + MACEntry + #CRLF$
    EndIf
  Next i

  MessageRequester("MAC-Adressen", MACInfo)
EndIf
Das von Vera verlinkte Beispiel mit Einsatz des arp-Befehls funktioniert nicht zur Ermittlung lokaler MAC-Adressen!

Daher zeige ich hier ein Beispiel für MacOS (erfolgreich getestet auf MacOS X 10.6.8 SnowLeopard mit PB 5.31 x86 und x64 im ASCII- und Unicode-Modus), das die MAC-Adressen aller lokalen Ethernet-Schnittstellen anzeigt. Es werden sowohl aktive als auch inaktive Ethernet-Schnittstellen angezeigt (z.B. die aktive WLAN-Schnittstelle und die inaktive kabelgebundene Schnittstelle). Es ist auch möglich, dieses Beispiel so zu erweitern, dass nur aktive Ethernet-Schnittstellen angezeigt werden. Da diese Erweiterung allerdings recht kompliziert ist, habe ich sie aus Gründen der Übersichtlichkeit weggelassen. Bei Interesse kann ich das erweiterte Beispiel gerne ebenfalls zeigen.

Code: Alles auswählen

EnableExplicit

#AF_LINK       = 18 ; Address family on BSD and MacOS X
#IFT_ETHER     =  6 ; Ethernet CSMACD
#SOCK_DGRAM    =  2

ImportC ""
  freeifaddrs(*InterfaceList)
  getifaddrs(*InterfaceList)
EndImport

Structure ifaddrs
  *ifa_next        ; Next item in list
  *ifa_name        ; Name of interface
  ifa_flags.I      ; Flags from SIOCGIFFLAGS
  *ifa_addr        ; Address of interface
  *ifa_netmask     ; Netmask of interface
  StructureUnion
    *ifu_broadaddr ; Broadcast address of interface
    *ifu_dstaddr   ; Point-to-point destination address
  EndStructureUnion
  *ifa_data        ; Address-specific data
EndStructure

Structure sockaddr_dl
  sdl_len.A       ; Total length
  sdl_family.A    ; Address family = AF_LINK
  sdl_index.U     ; Index of interface
  sdl_type.A      ; Interface type
  sdl_nlen.A      ; Interface name length
  sdl_alen.A      ; Link level address length
  sdl_slen.A      ; Link layer selector length
  sdl_data.A[12]  ; Interface name and link level address
  sdl_rcf.U       ; Source routing protocol
  sdl_route.U[16] ; Source routing information
EndStructure

Procedure.S GetMACAddress(*SocketAddress.sockaddr_dl)
  Protected i.I
  Protected MACAddress.S

  If *SocketAddress\sdl_alen > 0
    For i = 0 To *SocketAddress\sdl_alen - 1
      MACAddress + RSet(Hex(*SocketAddress\sdl_data[i +
        *SocketAddress\sdl_nlen], #PB_Byte), 2, "0")

      If i < *SocketAddress\sdl_alen - 1
        MACAddress + ":"
      EndIf
    Next i
  EndIf

  ProcedureReturn MACAddress  
EndProcedure

Procedure.S GetMACAddressesOfEthernetInterfaces()
  Protected *InterfaceList
  Protected *ListPointer.ifaddrs
  Protected MACList.S
  Protected *SocketAddress.sockaddr_dl
  
  If getifaddrs(@*InterfaceList) = 0
    *ListPointer = *InterfaceList
    
    Repeat
      *SocketAddress = *ListPointer\ifa_addr

      If *SocketAddress
        If *SocketAddress\sdl_family = #AF_LINK And
          *SocketAddress\sdl_type = #IFT_ETHER
          MACList + "Schnittstellenname: " +
            PeekS(@*SocketAddress\sdl_data[0], *SocketAddress\sdl_nlen,
            #PB_Ascii) + ", MAC = " +
            GetMACAddress(*SocketAddress) + #CR$
        EndIf
      EndIf
      
      *ListPointer = *ListPointer\ifa_next
    Until *ListPointer = 0
    
    freeifaddrs(*InterfaceList)
  EndIf
  
  ProcedureReturn MACList
EndProcedure

Define MACList.S

InitNetwork()
MACList = GetMACAddressesOfEthernetInterfaces()

If MACList <> ""
  MessageRequester("MAC-Adressen aller Ethernet-Schnittstellen", MACList)
EndIf
Und hier habe ich das obige Mac-Beispiel an Linux angepaßt (erfolgreich getestet unter Ubuntu 14.04 x64 mit KDE, Fedora 20 x86 mit Gnome 3 und Ubuntu 14.04 x86 mit Unity jeweils im ASCII- und Unicode-Modus):

Code: Alles auswählen

EnableExplicit

#AF_PACKET    = 17
#ARPHRD_ETHER =  1 ; Ethernet 10/100Mbps
#SOCK_DGRAM   =  2

ImportC ""
  freeifaddrs(*InterfaceList)
  getifaddrs(*InterfaceList)
EndImport

Structure ifaddrs
  *ifa_next        ; Next item in list
  *ifa_name        ; Name of interface
  ifa_flags.I      ; Flags from SIOCGIFFLAGS
  *ifa_addr        ; Address of interface
  *ifa_netmask     ; Netmask of interface
  StructureUnion
    *ifu_broadaddr ; Broadcast address of interface
    *ifu_dstaddr   ; Point-to-point destination address
  EndStructureUnion
  *ifa_data        ; Address-specific data
EndStructure

Structure sockaddr_ll
  sll_family.U     ; Address family = AF_PACKET
  sll_protocol.U   ; Physical layer protocol
  sll_ifindex.L    ; Interface number
  sll_hatype.U     ; ARP hardware type
  sll_pkttype.A    ; Packet type
  sll_halen.A      ; Length of address
  sll_addr.A[8]    ; Physical layer address
EndStructure

Procedure.S GetMACAddress(*SocketAddress.sockaddr_ll)
  Protected i.I
  Protected MACAddress.S

  If *SocketAddress\sll_halen > 0
    For i = 0 To *SocketAddress\sll_halen - 1
      MACAddress + RSet(Hex(*SocketAddress\sll_addr[i], #PB_Byte), 2, "0")

      If i < *SocketAddress\sll_halen - 1
        MACAddress + ":"
      EndIf
    Next i
  EndIf

  ProcedureReturn MACAddress  
EndProcedure

Procedure.S GetMACAddressesOfEthernetInterfaces()
  Protected InterfaceName.S
  Protected *InterfaceList
  Protected *ListPointer.ifaddrs
  Protected MACList.S
  Protected *SocketAddress.sockaddr_ll
  
  If getifaddrs(@*InterfaceList) = 0
    *ListPointer = *InterfaceList
    
    Repeat
      InterfaceName = PeekS(*ListPointer\ifa_name, -1, #PB_Ascii)
      *SocketAddress = *ListPointer\ifa_addr

      If *SocketAddress
        If *SocketAddress\sll_family = #AF_PACKET And
          *SocketAddress\sll_hatype = #ARPHRD_ETHER
          MACList + "Schnittstelle: " + InterfaceName + ", MAC = " +
            GetMACAddress(*SocketAddress) + #CR$
        EndIf
      EndIf
      
      *ListPointer = *ListPointer\ifa_next
    Until *ListPointer = 0
    
    freeifaddrs(*InterfaceList)
  EndIf
  
  ProcedureReturn MACList
EndProcedure

Define MACList.S

InitNetwork()
MACList = GetMACAddressesOfEthernetInterfaces()

If MACList <> ""
  MessageRequester("MAC-Adressen aller Ethernet-Schnittstellen", MACList)
EndIf
Zuletzt geändert von Shardik am 01.12.2014 12:35, insgesamt 1-mal geändert.
stevie1401
Beiträge: 700
Registriert: 19.10.2014 15:51
Kontaktdaten:

Re: Mac-Adresse

Beitrag von stevie1401 »

Vielen herzlichen Dank! :allright:
Ich programmiere nur noch mit Linux.
Linux Mint 21.x
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Mac-Adresse

Beitrag von RSBasic »

Shardik hat geschrieben:Das verlinkte Windows-Beispiel von RSBasic ermittlet die Hardware GUID, aber nicht die gewünschte MAC-Adresse [...]
Ja, das war beabsichtigt. Eine Lösung zum Ermitteln der MAC-Adresse habe ich bereits anfangs gepostet:
RSBasic hat geschrieben:Für Windows: http://www.rsbasic.de/aktualisierung/wi ... mitteln.pb
Der von mir später verlinkte Code war ein alternativer Code. Ich habe ja vorher "Alternativ" geschrieben, weil stevie1401 gerne unterschiedliche Rechner feststellen möchte. Das heißt, man könnte auch mit Hilfe der Hardware-GUID feststellen, ob es derselbe PC ist:
RSBasic hat geschrieben:Alternativ: http://www.rsbasic.de/aktualisierung/wi ... mitteln.pb
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
Vera
Beiträge: 928
Registriert: 18.03.2009 14:47
Computerausstattung: Win XP SP2, Suse 11.1
Wohnort: Essen

Re: Mac-Adresse

Beitrag von Vera »

stevie1401 hat geschrieben:Ich benötige die Mac-Adresse zur Erkennung von Spielerrechnern.
Ah - darf ich noch fragen, was einen Spielerechner von einem 'normalen' Rechner unterscheidet?

ps: 'Einstellung' bezog sich auf 'arp' und die AdminProblematik.


Dank Dir auch Shardik :-)
... besonders für die verständnisbildenden Hinweise.
Auf meiner Suse 11.1 mit KDE werden via PB 4.50 zwei Schnittstellen ermittelt (was vermutlich alle sind)
°
<°)))o><
~~~~~~~~~
echo "Don't worry"
echo "Keep quiet"
@echo off
format forum:\
Benutzeravatar
Shardik
Beiträge: 746
Registriert: 25.01.2005 12:19

Re: Mac-Adresse

Beitrag von Shardik »

RSBasic hat geschrieben:
Shardik hat geschrieben:Das verlinkte Windows-Beispiel von RSBasic ermittlet die Hardware GUID, aber nicht die gewünschte MAC-Adresse [...]
Ja, das war beabsichtigt. Eine Lösung zum Ermitteln der MAC-Adresse habe ich bereits anfangs gepostet:
RSBasic hat geschrieben:Für Windows: http://www.rsbasic.de/aktualisierung/wi ... mitteln.pb
Entschuldigung, ich war nur dem Link in Bisontes Beitrag gefolgt und hatte versäumt, den Link in Deinem 1.Beitrag direkt auf die Frage von stevie1401 zu öffnen!

Allerdings hat das von Dir verlinkte Beispiel von Flype einen großen Nachteil: es untersucht nur den ersten Eintrag einer Netzwerkkarte. So wird auf meinem aktuellen Rechner nur die MAC-Adresse einer virtuellen Netzwerkkarte angezeigt, die mich aber normalerweise nicht interessiert... Daher ist es sicherlich sinnvoller, alle Einträge von Netzwerkkarten auszuwerten. Ich habe dazu ein weiteres Windows-Beispiel erstellt (wieder getestet unter Windows XP SP3 und Windows 7 SP1 x86):

Code: Alles auswählen

EnableExplicit

Define AdapterNumber.I
Define i.I
Define IP.I
Define MacAddress.S
Define MACBufferSize.I = 6
Define MACInfo.S
Define Result.I

Dim MACArray.A(5)

If InitNetwork()
  ExamineIPAddresses()

  Repeat
    IP = NextIPAddress()

    If IP
      AdapterNumber = AdapterNumber + 1
      MacAddress = ""
      MACInfo + "Netzwerkkarte " + Str(AdapterNumber) + ": " + "IP-Adresse = " + IPString(IP)
      Result = SendARP_(IP, 0, @MACArray(0), @MACBufferSize)
      
      If Result = #NO_ERROR
        For i = 0 To 4
          MacAddress = MacAddress + RSet(Hex(MACArray(i)), 2, "0") + ":"
        Next
        
        MACAddress = MACAddress + RSet(Hex(MACArray(i)), 2, "0")
        MACInfo + ", MAC-Adresse = " + MACAddress + #CR$
      Else
        MessageRequester("Fehler", "Die Ermittlung der MAC-Adresse für IP " +
          IPString(IP) + " ist fehlgschlagen!", #MB_ICONEXCLAMATION)
      EndIf
    EndIf
  Until IP = 0
EndIf

MessageRequester("MAC-Adressen", MACInfo, #MB_ICONINFORMATION)
Ich habe auch noch eine Anregung für Deine von mir sehr geschätzte Sammlung von Windows API Beispielen: ich habe schon öfter den Link zu dem Forenbeitrag Deines Beispiels vermisst (wenn das Beispiel aus einem Forenbeitrag kopiert wurde oder darauf aufbaut). In Deinem verlinkten Beispiel also

http://www.purebasic.fr/english/viewtop ... 6&start=13

Denn dieser Link zum Forenbeitrag bringt oft noch einen Mehrwert, weil man über den Link auch andere alternative Beispiele findet (z.B. in diesem Fall ein weiteres Beispiel von ABBKlaus) oder in der Zwischenzeit sogar noch Verbesserungen oder Fehlerbehebungen erschienen sind.
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Mac-Adresse

Beitrag von RSBasic »

Shardik hat geschrieben:ich habe schon öfter den Link zu dem Forenbeitrag Deines Beispiels vermisst (wenn das Beispiel aus einem Forenbeitrag kopiert wurde oder darauf aufbaut).
Jupp, du hast recht. Leider habe ich das von Anfang an nicht gemacht, sondern habe nur den jeweiligen Autor genannt. Ebenfalls in meiner Backupliste habe ich keine Forenthreadlinks miteingefügt, die natürlich ebenfalls hilfreich gewesen wären, aber daran habe ich damals nicht gedacht und nach einer hohen Anzahl habe ich leider auch keine Lust, die einzelnen Forenlinks nachträglich hinzuzufügen. Aber ja, die Links hätte ich mitangeben müssen, dann hätte man auch gleich die Forenbeiträge, die man lesen kann. :)
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Mac-Adresse

Beitrag von NicTheQuick »

@Shardik:
Bist du einfach durch ein wenig googlen auf die korrekte API gestoßen oder hast du zufällig einen Link zu einer größeren Sammlung von Linux-Libraries und ihrer Funktionen parat?
Benutzeravatar
Shardik
Beiträge: 746
Registriert: 25.01.2005 12:19

Re: Mac-Adresse

Beitrag von Shardik »

NicTheQuick hat geschrieben:@Shardik:
Bist du einfach durch ein wenig googlen auf die korrekte API gestoßen oder hast du zufällig einen Link zu einer größeren Sammlung von Linux-Libraries und ihrer Funktionen parat?
Es war harte Arbeit: ich habe das ganze Wochenende damit zugebracht, mich in die BSD-Socketprogrammierung einzuarbeiten. Dazu habe ich sowohl Google genutzt, um die C-Header-Dateien, in denen die nötigen Strukturen definiert sind, zu finden als auch die Header-Dateien von MacOS und Linux durchgeackert. Für einige Sonderfunktionen mußte ich teilweise kompliziert verschachtelte Makros aus den Header-Dateien nachprogrammieren. Die gezeigten Beispiele stellen nur die Spitze des Eisberges dar... :lol:
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Mac-Adresse

Beitrag von RSBasic »

Dann von mir herzlichen Dank für deine Arbeit. :allright:
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Antworten