Anmeldungen im LAN via UDP Broadcast mitbekommen

  • Hallo,

    ich möchte mir gerne ein kleines Systray-Tool schreiben, welches mit anzeigt, wenn sich etwas in meinem Netzwerk anmeldet.
    Das müsste ja eigentlich über UDP Broadcast gehen. Ich weiß jetzt aber nicht, über welche Ports das geht.
    Hat das evtl. schon jemand mal gemacht?
    Diesen Thread hab ich mir auch schon angesehen
    [ gelöst ] Hilfe mit UDP Broadcast
    Aber da fängt es dann wieder beim Port, wo ich nicht weiß, welche ich da nehmen muss.
    Bei Google hab ich auch nix hilfreiches gefunden.
    Als Router hab ich die Fritzbox Cable 6360.

  • Du musst ja beide Seiten programmieren, also die Seite die den Broadcast abschickt und die Seite die ihn empfängt. Also kannst du dir auch den Port selber auswählen. Am besten einen nicht verwendeten aus dieser Liste. Oder glaubst du, dass dieser Broadcast bereits automatisch passiert? Habe nichts dazu gefunden.
    BTW: Wenn das Tool fertig ist, dann hätte ich auch gerne eine Kopie davon :D

  • Das Client-Server Prinzip hab ich auch schon überall gelesen. Nur der Router macht es ja auch zu den Geräten und die Antworten ja dann auch. Das ganze geschieht ja über das ARP-Protokoll und das unterstützen schon die meisten Geräte. Ich will ja nur das die Geräte mir auch antworten mit ihrer IP.

  • Das wirst denke ich nicht so ohne weites hinbekommen. Da die Geräte sich ja nicht zu dir verbinden sondern zum Accesspoint. Was du mach kannst ist schauen ob dein Accesspoint ein API-Schnittstelle bzw. Webinterface hat und darüber periodisch prüfen ob ein neues Gerät hinzugekommen ist.

    Andy hat mir ein Schnitzel gebacken aber da war ein Raupi drauf und bevor Oscar das Bugfixen konnte kam Alina und gab mir ein AspirinJunkie.

  • Ich vermute mal du redest davon DHCP Anfragen in deinem Subnet zu erkennen um daraus letzlich auf ein neues Netzwerkgerät schließen zu können. Du müsstest also prinzipiell auf solche DHCP(-DHCPDISCOVER) Anfragen warten du wirst dabei aber keine IP Adresse des neuen Gerätes erfahren, denn dieses hat noch garkeine und möchte erstmal eine bekommen. Mehr als die MAC Adresse bekommst du dadurch also nicht. Der echte DHCP Server deines Netzwerkes (deine Fritzbox) wird solche Anfragen dann mit einem IP Vorschlag (DHCPOFFER) beantworten. Das neue Gerät wird im Anschluß alle IP Angebote der antwortenden DHCP Server auswerten und sich für eine der IP Adressen entscheiden, seine Wahl gibt es wiederum per DHCPREQUEST bekannt (=alle DHCP Server wissen nun ob ihr Angebot gewählt wurde). Alle 3 Pakete werden per Broadcast versendet und können demzufolge mitgeschnitten werden. Der DHCP Server muss dies dann noch mit einem DHCPACK (enthält die netz config, also gateway, client ip, dns server usw.) bestätigen oder mit einem DHCPNAK ablehnen (ich bin mir nicht sicher ob das auch noch per Broadcast oder eher per unicast passiert). Zu guter letzt findet noch eine ARP Anfrage des neuen Gerätes statt um sicherzustellen, dass kein anderes Gerät diese IP verwendet.

    Da DHCP eine lease time vorsieht wird die IP Zuweisung in regelmässigen Intervallen neu angefragt / bestätigt, was per unicast passiert, da das Gerät ja nun alle nötigen Informationen für eine direkte Kommunikation mit dem Server besitzt.

    Noch detailierter kannst du das hier nachlesen: http://de.wikipedia.org/wiki/Dynamic_H…P-Kommunikation

    Dort stehen auch die Ports und der genaue Aufbau der einzelnen Pakete.

    Ich sehe aber ein kleines Problem in deiner Vorgehensweise, denn niemand zwingt eine neues Gerät dazu DHCP zu nutzen, man könnte das Netzwerkinterface auch statisch konfigurieren. Das würde vermutlich in einer unicast Kommunikation zwischen Router und neuem Gerät resultieren, welche du nicht mitschneiden kannst. Das einzige was du eventuell mitschneiden könntest sind die ARP Request, welche sicherstellen sollen, dass die IP einmalig im Netzwerk verwendet wird.

    Am zuverlässigsten und einfachsten dürfte es wie vereits erwähnt wurde sein die bereitgestellten Schnittstellen der Fritzbox zu nutzen, denn diese zeigt alle verbundenen Geräte im Webinterface an.

  • Hier mal ein kleines Testscript, welches mitbekommt wenn sich mein Smartphone mit dem WLAN verbindet, allerdings erhalte ich immer nur 1 UDP Paket, was möglicherweise damit zusammenhängt, dass entweder mein Smartphone die Daten gecached hat oder an der statischen MAC->IP Zuweisung in der Fritzbox:

    [autoit]


    Opt("TrayMenuMode",1)
    $tExit=TrayCreateItem("beenden")
    ;SERVER!! Start Me First !!!!!!!!!!!!!!!
    $myIP = "192.168.1.110"

    [/autoit][autoit][/autoit][autoit]

    ; Start The UDP Services
    ;==============================================
    UDPStartUp()

    [/autoit][autoit][/autoit][autoit]

    ; Create a Listening "SOCKET"
    ;==============================================
    $socket = UDPBind($myIP, 67)
    If @error <> 0 Then Exit

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    $j = 1
    While TrayGetMsg()<>$tExit
    $aResult = UDPRecv($socket,576,3)
    If IsArray($aResult) Then
    ConsoleWrite("new DHCP packet received: " & $j & @CRLF & "-------------------------" & @CRLF)
    For $i = 0 To UBound($aResult)-1
    ConsoleWrite($i & ": " & $aResult[$i] & @CRLF)
    Next
    ConsoleWrite("-------------------------" & @CRLF)
    $j+=1
    EndIf
    WEnd

    [/autoit][autoit][/autoit][autoit]

    UDPCloseSocket($socket)
    UDPShutdown()

    [/autoit]

    2 Mal editiert, zuletzt von misterspeed (3. Juli 2013 um 20:51)

  • Funktioniert Prima. Bekomme die MAC und welche IP zugeteilt wird über DHCP Request.
    Danke.

  • Bekommst du mehr als 1 Paket in der console angezeigt? Hab ein wenig hier rumgespielt und bekomme mit obigem Script immer nur 1 Paket:

    Code
    new DHCP packet received: 1
    -------------------------
    0: 0x0101060058D539990000000000000000000000000000000000000000Xmac-adresseX00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Xoption feldXFF
    1: 0.0.0.0
    2: 68

    EDIT:
    Ist scheinbar nur bei meinem Nexus4 via wlan so, wenn ich am selben Rechner einen wlan Stick zusätzlich zur fixen LAN Verkabelung anschließe bekomme ich deutlich mehr Pakete von der DHCP aushandlung des Sticks mit. Seltsame Sache...

    2 Mal editiert, zuletzt von misterspeed (3. Juli 2013 um 20:50)

  • So..mein Script sieht inzwischen so aus:

    Spoiler anzeigen
    [autoit]

    #NoTrayIcon

    [/autoit] [autoit][/autoit] [autoit]

    Opt("TrayMenuMode", 1)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Global $cExit
    Global $sIP = "192.168.178.101"
    Global $iSocket, $aRecv, $sReqMAC, $sReqIP, $sReqHostName

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $cExit = TrayCreateItem("Beenden")
    TraySetState()

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    UDPStartUp()

    [/autoit] [autoit][/autoit] [autoit]

    $iSocket = UDPBind($sIP, 67)
    If @error <> 0 Then Exit

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While 1
    $aRecv = UDPRecv($iSocket, 576, 2)
    If IsArray($aRecv) Then
    $aRecv[0] = Binary($aRecv[0])
    $sReqMAC = StringTrimLeft(String(BinaryMid($aRecv[0], 29, 6)), 2)
    For $i = 0 To 4
    $sReqMAC = StringLeft($sReqMAC, (($i + 1) * 2) + $i) & ":" & StringRight($sReqMAC, (5 - $i) * 2)
    Next
    $sReqIP = _BinToIP(BinaryMid($aRecv[0], _FindBinary($aRecv[0], Binary("0x32")) + 2, 4))
    $sReqHostName = BinaryToString(BinaryMid($aRecv[0], _FindBinary($aRecv[0], Binary("0x0C")) + 2, Dec(StringTrimLeft(String(BinaryMid($aRecv[0], _FindBinary($aRecv[0], Binary("0x0C")) + 1, 1)), 2))))
    TrayTip("Ein neues Gerät hat sich angemeldet.", "Name: " & @TAB & $sReqHostName & @CRLF & "MAC: " & @TAB & $sReqMAC & @CRLF & "IP: " & @TAB & $sReqIP, 5)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Switch TrayGetMsg()
    Case $cExit
    UDPCloseSocket($iSocket)
    UDPShutdown()
    Exit
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _FindBinary($_bBinary, $_bToFind)
    Local $_iPos = 1
    While 1
    If BinaryMid($_bBinary, $_iPos, 1) = $_bToFind Then Return $_iPos
    $_iPos += 1
    WEnd
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _BinToIP($_bBinary)
    Local $_sIP = StringTrimLeft(String($_bBinary), 2)
    Return Dec(StringMid($_sIP, 1, 2)) & "." & Dec(StringMid($_sIP, 3, 2)) & "." & Dec(StringMid($_sIP, 5, 2)) & "." & Dec(StringMid($_sIP, 7, 2))
    EndFunc

    [/autoit]
  • Hab auch noch ein wenig damit rumgespielt:

    Spoiler anzeigen
    [autoit]


    #include <array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt("TrayMenuMode",1)
    $tExit=TrayCreateItem("beenden")

    [/autoit] [autoit][/autoit] [autoit]

    ;SERVER!! Start Me First !!!!!!!!!!!!!!!
    $myIP = "192.168.1.110"

    [/autoit] [autoit][/autoit] [autoit]

    ; Start The UDP Services
    ;==============================================
    UDPStartUp()

    [/autoit] [autoit][/autoit] [autoit]

    ; Create a Listening "SOCKET"
    ;==============================================
    $socket = UDPBind($myIP, 67)
    If @error <> 0 Then Exit

    [/autoit] [autoit][/autoit] [autoit]

    $j = 1
    While TrayGetMsg()<>$tExit
    $aResult = UDPRecv($socket,4000,3)
    If IsArray($aResult) Then
    ConsoleWrite("new DHCP Server paket received: " & $j & @CRLF & "-------------------------" & @CRLF)
    For $i = 0 To UBound($aResult)-1
    ConsoleWrite($i & ": " & $aResult[$i] & @CRLF)
    If $i = 0 And StringInStr($aResult[0],"FF") Then
    $sTemp = $aResult[0]
    While StringRight($sTemp,2) <> "FF"
    $sTemp = StringTrimRight($sTemp,1)
    WEnd
    getFormatedHex($sTemp)
    EndIf
    Next
    ConsoleWrite("-------------------------" & @CRLF)
    $j+=1
    EndIf
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    UDPCloseSocket($socket)
    UDPShutdown()

    [/autoit] [autoit][/autoit] [autoit]

    Func getFormatedHex($sData)
    Local $magicCookie = "63825363"
    Local $aSplit = StringSplit($sData,$magicCookie,1)
    If IsArray($aSplit) Then
    $sData = $aSplit[$aSplit[0]]
    Local $aData[stringlen($sData)/2]
    For $i = 0 To UBound($aData)-1
    $aData[$i] = StringMid($sData,($i*2)+1,2)
    Next
    ;_ArrayDisplay($aData)
    $sData = ""
    $type = "tagByte"
    $len = 0
    For $i = 0 To UBound($aData)-1
    If $i = UBound($aData)-1 Then
    If $aData[$i] <> "FF" Then Return -1
    $sData = StringReplace($sData,@CRLF,"",-1)
    ConsoleWrite($sData & @CRLF)
    $sData = getFormatedText($sData)
    ConsoleWrite($sData & @CRLF)
    Return 1
    EndIf
    If $type = "tagByte" Then
    $sData &= $aData[$i] & " "
    $type = "len"
    ContinueLoop
    EndIf
    If $type = "len" Then
    ;$sData &= $aData[$i] & " "
    $len = Dec($aData[$i])
    For $j = $i To $i+$len
    $sData &= $aData[$j] & " "
    Next
    $sData = StringReplace($sData," ",@CRLF,-1)
    $i += $len
    $type = "tagByte"
    ContinueLoop
    EndIf
    Next
    EndIf
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func getFormatedText($sData)

    [/autoit] [autoit][/autoit] [autoit]

    ; http://www.networksorcery.com/enp/protocol/bootp/options.htm

    [/autoit] [autoit][/autoit] [autoit]

    Local $aTagTypes[256] = [ "Pad","Subnet Mask","Time Offset (deprecated)","Router","Time Server","Name Server","Domain Name Server","Log Server","Quote Server","LPR Server","Impress Server","Resource Location Server", _
    "Host Name","Boot File Size","Merit Dump File","Domain Name","Swap Server","Root Path","Extensions Path","IP Forwarding enable/disable","Non-local Source Routing enable/disable","Policy Filter", _
    "Maximum Datagram Reassembly Size","Default IP Time-to-live","Path MTU Aging Timeout","Path MTU Plateau Table","Interface MTU","All Subnets are Local","Broadcast Address","Perform Mask Discovery", _
    "Mask supplier","Perform router discovery","Router solicitation address","Static routing table","Trailer encapsulation","ARP cache timeout","Ethernet encapsulation","Default TCP TTL", _
    "TCP keepalive interval","TCP keepalive garbage","Network Information Service Domain","Network Information Servers","NTP servers","Vendor specific information","NetBIOS over TCP/IP name server", _
    "NetBIOS over TCP/IP Datagram Distribution Server","NetBIOS over TCP/IP Node Type","NetBIOS over TCP/IP Scope","X Window System Font Server","X Window System Display Manager","Requested IP Address", _
    "IP address lease time","Option overload","DHCP message type","Server identifier","Parameter request list","Message","Maximum DHCP message size","Renew time value","Rebinding time value", _
    "Class-identifier","Client-identifier","NetWare/IP Domain Name","NetWare/IP information","Network Information Service+ Domain","Network Information Service+ Servers","TFTP server name","Bootfile name", _
    "Mobile IP Home Agent","Simple Mail Transport Protocol Server","Post Office Protocol Server","Network News Transport Protocol Server","Default World Wide Web Server","Default Finger Server", _
    "Default Internet Relay Chat Server","StreetTalk Server","StreetTalk Directory Assistance Server","User Class Information","SLP Directory Agent","SLP Service Scope","Rapid Commit", _
    "FQDN, Fully Qualified Domain Name","Relay Agent Information","Internet Storage Name Service","???? RFC 3679","NDS servers","NDS tree name","NDS context","BCMCS Controller Domain Name list", _
    "BCMCS Controller IPv4 address list","Authentication","client-last-transaction-time","associated-ip","Client System Architecture Type","Client Network Interface Identifier", _
    "LDAP, Lightweight Directory Access Protocol","???? RFC 3679","Client Machine Identifier","Open Group's User Authentication","GEOCONF_CIVIC","IEEE 1003.1 TZ String","Reference to the TZ Database", _
    "???? RFC 3679","???? RFC 3679","???? RFC 3679","???? RFC 3679","???? RFC 3679","???? RFC 3679","???? RFC 3679","???? RFC 3679","???? RFC 3679","???? RFC 3679","NetInfo Parent Server Address", _
    "NetInfo Parent Server Tag","URL","???? RFC 3679","Auto-Configure","Name Service Search","Subnet Selection","DNS domain search list","SIP Servers DHCP Option","Classless Static Route Option", _
    "CCC, CableLabs Client Configuration","GeoConf","Vendor-Identifying Vendor Class","Vendor-Identifying Vendor-Specific","???? RFC 3679","???? RFC 3679","TFTP Server IP address", _
    "Call Server IP address","Discrimination string","Remote statistics server IP address","802.1P VLAN ID","802.1Q L2 Priority","Diffserv Code Point","HTTP Proxy for phone-specific applications", _
    "PANA Authentication Agent","LoST Server","CAPWAP Access Controller addresses","OPTION-IPv4_Address-MoS","OPTION-IPv4_FQDN-MoS","SIP UA Configuration Service Domains","OPTION-IPv4_Address-ANDSF", _
    "OPTION-IPv6_Address-ANDSF","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","TFTP server address","status-code","base-time","start-time-of-state", _
    "query-start-time","query-end-time","dhcp-state","data-source","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942", _
    "???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","Etherboot","IP Telephone", _
    "Etherboot / PacketCable and CableHome","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942", _
    "???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942", _
    "???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","???? RFC 3942","pxelinux.magic (string) = F1:00:74:7E (241.0.116.126)", _
    "pxelinux.configfile (text)","pxelinux.pathprefix (text)","pxelinux.reboottime (unsigned integer 32 bits)","OPTION_6RD","OPTION_V4_ACCESS_DOMAIN","---","---","---","---","---","---","Subnet Allocation", _
    "Virtual Subnet Selection","???? RFC 3942","???? RFC 3942","Private use","Private use","Private use","Private use","Private use","Private use","Private use","Private use","Private use","Private use", _
    "Private use","Private use","Private use","Private use","Private use","Private use","Private use","Private use","Private use","Private use","Private use","Private use","Private use","Private use", _
    "Private use","Private use","Private use","Private use","Private use","Private use","Private use","End" _
    ]
    Local $aRequestTypes[9]=["---","DHCPDISCOVER","DHCPOFFER","DHCPREQUEST","DHCPDECLINE","DHCPACK","DHCPNAK","DHCPRELEASE","DHCPINFORM"]
    Local $aSplit = StringSplit(StringReplace($sData," ",""),@CRLF,1)
    If IsArray($aSplit) Then
    For $i=1 To $aSplit[0]
    $tagByte = StringLeft($aSplit[$i],2)
    $temp = StringTrimLeft($aSplit[$i],4)
    Switch $tagByte
    Case "35"
    $aSplit[$i]= "RequestType:" & @TAB & @TAB & @TAB & $aRequestTypes[dec($temp)]
    Case "3D"
    $aSplit[$i]= "Client Identifier (MAC):" & @TAB
    For $j = 3 to StringLen($temp)-1 Step 2
    $aSplit[$i] &= StringMid($temp,$j,2) & ":"
    Next
    $aSplit[$i] = StringReplace($aSplit[$i],":","",-1)
    Case "32"
    $aSplit[$i]= "Requested IP:" & @TAB & @TAB & @TAB
    $aSplit[$i] &= Dec(StringLeft($temp,2)) & "." & Dec(StringMid($temp,3,2)) & "." & Dec(StringMid($temp,5,2)) & "." & Dec(StringRight($temp,2))
    Case "39"
    $aSplit[$i] = "Maximum DHCP message size:" & @TAB & Dec($temp)
    Case "3C"
    $aSplit[$i] = "Class identifier:" & @TAB & @TAB & BinaryToString(Binary("0x" & $temp))
    Case "0C"
    $aSplit[$i] = "Hostname:" & @TAB & @TAB & @TAB & BinaryToString(Binary("0x" & $temp))
    Case "36"
    $aSplit[$i] = "Sever Identifier (IP):" & @TAB & @TAB
    $aSplit[$i] &= Dec(StringLeft($temp,2)) & "." & Dec(StringMid($temp,3,2)) & "." & Dec(StringMid($temp,5,2)) & "." & Dec(StringRight($temp,2))
    Case "37"
    $aSplit[$i] = "Parameter request list:" & @TAB & @TAB
    For $j = 1 to StringLen($temp)-1 Step 2
    ;ConsoleWrite(Dec(StringMid($temp,$j,2)) & @CRLF)
    $aSplit[$i] &= $aTagTypes[Dec(StringMid($temp,$j,2))] & "|"
    Next
    $aSplit[$i] = StringReplace($aSplit[$i],"|","",-1)
    Case "51"
    $aSplit[$i] = "FQDN:" & @TAB & @TAB & @TAB & @TAB & BinaryToString(Binary("0x" & StringTrimLeft($temp,6)))
    Case Else
    $aSplit[$i] = "Unsupported RAW Data:" & @TAB & @TAB & $tagByte & " " & StringMid($aSplit[$i],3,2) & " " & $temp
    EndSwitch
    Next
    Local $sReturn = ""
    For $i = 1 to $aSplit[0]
    $sReturn &= $aSplit[$i] & @CRLF
    Next
    Return StringReplace($sReturn,@CRLF,"",-1)
    EndIf
    EndFunc

    [/autoit]

    EDIT:

    Anmerkung zu deiner Variante um an MAC / IP / Hostname zu kommen... du solltest zum einen nicht vergessen, dass diverse Felder variable Längen haben und zum anderen, dass die TagTypes nicht zwingend einmalig im String vorkommen, da manche Felder wie z.B. der Hostname beliebige Zahlen und Strings enthalten kann, dadurch könnte dein binarymid() in _findbinary() ggf. eine falsche Stelle im Binär-String zurückgeben. Deswegen zerlege ich bei mir den String zunächst Byte für Byte mithilfe der Längenangaben in Sätze und kann diese dann im Anschluß anhand des jeweils ersten Byte eines jeden Satzes auswerten.

    2 Mal editiert, zuletzt von misterspeed (4. Juli 2013 um 02:56)