Windows DHCP Server - dapatkan pemberitahuan ketika perangkat yang tidak bergabung dengan AD mendapatkan alamat IP

15

SKENARIO

Untuk menyederhanakan ini ke contoh termudah:

Saya memiliki DC standar Windows 2008 R2 dengan peran server DHCP. Ini membagikan IP melalui berbagai cakupan IPv4, tidak ada masalah di sana.

APA YANG SAYA INGIN

Saya ingin cara untuk membuat entri notifikasi / eventlog / serupa setiap kali perangkat mendapat sewa alamat DHCP dan perangkat itu BUKAN domain yang bergabung dengan komputer di Active Directory. Tidak masalah bagi saya apakah itu custom Powershell, dll.

Intinya = Saya ingin mengetahui kapan perangkat non-domain berada di jaringan tanpa menggunakan 802.1X saat ini. Saya tahu ini tidak akan menjelaskan perangkat IP statis. Saya memang memiliki perangkat lunak pemantauan yang akan memindai jaringan dan menemukan perangkat, tetapi ini tidak cukup rinci.

SELESAI PENELITIAN / OPSI YANG DIPERTIMBANGKAN

Saya tidak melihat kemungkinan seperti itu dengan logging bawaan.

Ya, saya mengetahui 802.1X dan memiliki kemampuan untuk mengimplementasikannya dalam jangka panjang di lokasi ini, tetapi kami berada agak jauh dari proyek seperti itu, dan sementara itu akan menyelesaikan masalah otentikasi jaringan, ini masih membantu saya di luar dari 802.1X tujuan.

Saya telah mencari-cari beberapa bit skrip, dll. Yang mungkin terbukti berguna tetapi hal-hal yang saya temukan membuat saya percaya bahwa google-fu saya gagal saat ini.

Saya percaya logika di bawah ini masuk akal ( dengan asumsi tidak ada solusi yang ada ):

  1. Perangkat menerima alamat DHCP
  2. Entri log peristiwa dicatat (ID peristiwa 10 dalam log audit DHCP harus berfungsi (karena sewa baru adalah yang paling saya minati, bukan pembaruan): http://technet.microsoft.com/en-us/library /dd759178.aspx )
  3. Pada titik ini suatu naskah mungkin harus mengambil alih untuk "LANGKAH" yang tersisa di bawah ini.
  4. Entah bagaimana menanyakan log DHCP ini untuk acara ID 10 ini (Saya ingin push, tapi saya kira tarikan adalah satu-satunya jalan di sini)
  5. Parsing kueri untuk nama perangkat yang ditugaskan sewa baru
  6. Permintaan AD untuk nama perangkat
  7. JIKA tidak ditemukan dalam AD, kirim email notifikasi

Jika ada yang punya ide tentang bagaimana melakukan ini dengan benar, saya akan sangat menghargainya. Saya tidak mencari "beri kode" tetapi ingin tahu apakah ada alternatif untuk daftar di atas atau jika saya tidak berpikir jernih dan ada metode lain untuk mengumpulkan informasi ini. Jika Anda memiliki cuplikan kode / perintah PS yang ingin Anda bagikan untuk membantu menyelesaikan ini, semuanya lebih baik.

Pembersih
sumber
Apakah Anda ingin memblokirnya, atau hanya diberi tahu jika mereka mendapatkan IP?
HostBits
@Cheekaleak - baru saja diberitahu.
TheCleaner
Bagaimana dengan printer jaringan yang menggunakan DHCP?
jftuga
@ jftuga - kami menggunakan IP statis untuk printer jaringan.
TheCleaner

Jawaban:

6

Dengan banyak terima kasih kepada ErikE dan yang lainnya di sini, saya telah menempuh jalan ... Saya tidak akan mengatakan itu jalan yang benar, tetapi skrip Powershell yang saya buat berhasil.

Kode di bawah ini jika ada yang menginginkannya. Jalankan saja menunjuk secara manual pada setiap server DHCP atau jadwalkan (sekali lagi menunjuk ke setiap server DHCP dalam skrip).

Apa yang dilakukan skrip:

  1. Mendapat informasi sewa dari server DHCP (sewa ipv4)
  2. Output sewa untuk file csv
  3. Membaca kembali dalam file CSV untuk kueri AD
  4. Kueri AD untuk komputer
  5. Jika tidak ditemukan output ke file txt baru
  6. Membuat file txt akhir daftar unik dari yang dibuat di # 5 di atas (karena mungkin ada dupe jika klien mendaftar lebih dari sekali atau dengan lebih dari satu adaptor)
  7. mengirim email isi file hasil akhir ke admin

Apa yang Anda butuhkan:

Script menggunakan modul AD ( import-module activedirectory) jadi sebaiknya dijalankan pada AD DC yang menjalankan DHCP. Jika ini bukan masalahnya, Anda dapat menginstal modul AD powershell: http://blogs.msdn.com/b/rkramesh/archive/2012/01/17/how-to-add-active-directory- module-in-powershell-in-windows-7.aspx

Anda juga akan memerlukan cmdlet AD Powershell milik Quest yang ditemukan di sini: http://www.quest.com/powershell/activeroles-server.aspx . Instal INI SEBELUM menjalankan skrip atau itu akan gagal.

Script itu sendiri (dibersihkan, Anda harus mengatur beberapa variabel agar sesuai dengan kebutuhan Anda seperti nama file input, domain untuk terhubung, server dhcp untuk terhubung, pengaturan email di dekat akhir, dll.):

# Get-nonADclientsOnDHCP.ps1

# Author : TheCleaner http://serverfault.com/users/7861/thecleaner with a big thanks for a lot of the lease grab code to Assaf Miron on code.google.com

# Description : This Script grabs the current leases on a Windows DHCP server, outputs it to a csv
# then takes that csv file as input and determines if the lease is from a non-AD joined computer.  It then emails
# an administrator notification.  Set it up on a schedule of your choosing in Task Scheduler.
# This helps non-802.1X shops keep track of rogue DHCP clients that aren't part of the domain.

#

# Input : leaselog.csv

# Output: Lease log = leaselog.csv
# Output: Rogue Clients with dupes = RogueClients.txt
# Output: Rogue Clients - unique = RogueClientsFinal.txt

$DHCP_SERVER = "PUT YOUR SERVER NAME OR IP HERE" # The DHCP Server Name

$LOG_FOLDER = "C:\DHCP" # A Folder to save all the Logs

# Create Log File Paths

$LeaseLog = $LOG_FOLDER+"\LeaseLog.csv"

#region Create Scope Object

# Create a New Object

$Scope = New-Object psobject

# Add new members to the Object

$Scope | Add-Member noteproperty "Address" ""

$Scope | Add-Member noteproperty "Mask" ""

$Scope | Add-Member noteproperty "State" ""

$Scope | Add-Member noteproperty "Name" ""

$Scope | Add-Member noteproperty "LeaseDuration" ""

# Create Each Member in the Object as an Array

$Scope.Address = @()

$Scope.Mask = @()

$Scope.State = @()

$Scope.Name = @()

$Scope.LeaseDuration = @()

#endregion


#region Create Lease Object

# Create a New Object

$LeaseClients = New-Object psObject

# Add new members to the Object

$LeaseClients | Add-Member noteproperty "IP" ""

$LeaseClients | Add-Member noteproperty "Name" ""

$LeaseClients | Add-Member noteproperty "Mask" ""

$LeaseClients | Add-Member noteproperty "MAC" ""

$LeaseClients | Add-Member noteproperty "Expires" ""

$LeaseClients | Add-Member noteproperty "Type" ""

# Create Each Member in the Object as an Array

$LeaseClients.IP = @()

$LeaseClients.Name = @()

$LeaseClients.MAC = @()

$LeaseClients.Mask = @()

$LeaseClients.Expires = @()

$LeaseClients.Type = @()

#endregion


#region Create Reserved Object

# Create a New Object

$LeaseReserved = New-Object psObject

# Add new members to the Object

$LeaseReserved | Add-Member noteproperty "IP" ""

$LeaseReserved | Add-Member noteproperty "MAC" ""

# Create Each Member in the Object as an Array

$LeaseReserved.IP = @()

$LeaseReserved.MAC = @()

#endregion


#region Define Commands

#Commad to Connect to DHCP Server

$NetCommand = "netsh dhcp server \\$DHCP_SERVER"

#Command to get all Scope details on the Server

$ShowScopes = "$NetCommand show scope"

#endregion


function Get-LeaseType( $LeaseType )

{

# Input : The Lease type in one Char

# Output : The Lease type description

# Description : This function translates a Lease type Char to it's relevant Description


Switch($LeaseType){

"N" { return "None" }

"D" { return "DHCP" }

"B" { return "BOOTP" }

"U" { return "UNSPECIFIED" }

"R" { return "RESERVATION IP" }

}

}


function Check-Empty( $Object ){

# Input : An Object with values.

# Output : A Trimmed String of the Object or '-' if it's Null.

# Description : Check the object if its null or not and return it's value.

If($Object -eq $null)

{

return "-"

}

else

{

return $Object.ToString().Trim()

}

}


function out-CSV ( $LogFile, $Append = $false) {

# Input : An Object with values, Boolean value if to append the file or not, a File path to a Log File

# Output : Export of the object values to a CSV File

# Description : This Function Exports all the Values and Headers of an object to a CSV File.

#  The Object is recieved with the Input Const (Used with Pipelineing) or the $inputObject

Foreach ($item in $input){

# Get all the Object Properties

$Properties = $item.PsObject.get_properties()

# Create Empty Strings - Start Fresh

$Headers = ""

$Values = ""

# Go over each Property and get it's Name and value

$Properties | %{ 

$Headers += $_.Name + ","

$Values += $_.Value

}

# Output the Object Values and Headers to the Log file

If($Append -and (Test-Path $LogFile)) {

$Values | Out-File -Append -FilePath $LogFile -Encoding Unicode

}

else {

# Used to mark it as an Powershell Custum object - you can Import it later and use it

# "#TYPE System.Management.Automation.PSCustomObject" | Out-File -FilePath $LogFile

$Headers | Out-File -FilePath $LogFile -Encoding Unicode

$Values | Out-File -Append -FilePath $LogFile -Encoding Unicode

}

}

}


#region Get all Scopes in the Server 

# Run the Command in the Show Scopes var

$AllScopes = Invoke-Expression $ShowScopes

# Go over all the Results, start from index 5 and finish in last index -3

for($i=5;$i -lt $AllScopes.Length-3;$i++)

{

# Split the line and get the strings

$line = $AllScopes[$i].Split("-")

$Scope.Address += Check-Empty $line[0]

$Scope.Mask += Check-Empty $line[1]

$Scope.State += Check-Empty $line[2]

# Line 3 and 4 represent the Name and Comment of the Scope

# If the name is empty, try taking the comment

If (Check-Empty $line[3] -eq "-") {

$Scope.Name += Check-Empty $line[4]

}

else { $Scope.Name += Check-Empty $line[3] }

}

# Get all the Active Scopes IP Address

$ScopesIP = $Scope | Where { $_.State -eq "Active" } | Select Address

# Go over all the Adresses to collect Scope Client Lease Details

Foreach($ScopeAddress in $ScopesIP.Address){

# Define some Commands to run later - these commands need to be here because we use the ScopeAddress var that changes every loop

#Command to get all Lease Details from a specific Scope - when 1 is amitted the output includes the computer name

$ShowLeases = "$NetCommand scope "+$ScopeAddress+" show clients 1"

#Command to get all Reserved IP Details from a specific Scope

$ShowReserved = "$NetCommand scope "+$ScopeAddress+" show reservedip"

#Command to get all the Scopes Options (Including the Scope Lease Duration)

$ShowScopeDuration = "$NetCommand scope "+$ScopeAddress+" show option"

# Run the Commands and save the output in the accourding var

$AllLeases = Invoke-Expression $ShowLeases 

$AllReserved = Invoke-Expression $ShowReserved 

$AllOptions = Invoke-Expression $ShowScopeDuration

# Get the Lease Duration from Each Scope

for($i=0; $i -lt $AllOptions.count;$i++) 

{ 

# Find a Scope Option ID number 51 - this Option ID Represents  the Scope Lease Duration

if($AllOptions[$i] -match "OptionId : 51")

{ 

# Get the Lease Duration from the Specified line

$tmpLease = $AllOptions[$i+4].Split("=")[1].Trim()

# The Lease Duration is recieved in Ticks / 10000000

$tmpLease = [int]$tmpLease * 10000000; # Need to Convert to Int and Multiply by 10000000 to get Ticks

# Create a TimeSpan Object

$TimeSpan = New-Object -TypeName TimeSpan -ArgumentList $tmpLease

# Calculate the $tmpLease Ticks to Days and put it in the Scope Lease Duration

$Scope.LeaseDuration += $TimeSpan.TotalDays

# After you found one Exit the For

break;

} 

}

# Get all Client Leases from Each Scope

for($i=8;$i -lt $AllLeases.Length-4;$i++)

{

# Split the line and get the strings

$line = [regex]::split($AllLeases[$i],"\s{2,}")

# Check if you recieve all the lines that you need

$LeaseClients.IP += Check-Empty $line[0]

$LeaseClients.Mask += Check-Empty $line[1].ToString().replace("-","").Trim()

$LeaseClients.MAC += $line[2].ToString().substring($line[2].ToString().indexOf("-")+1,$line[2].toString().Length-1).Trim()

$LeaseClients.Expires += $(Check-Empty $line[3]).replace("-","").Trim()

$LeaseClients.Type += Get-LeaseType $(Check-Empty $line[4]).replace("-","").Trim()

$LeaseClients.Name += Check-Empty $line[5]

}

# Get all Client Lease Reservations from Each Scope

for($i=7;$i -lt $AllReserved.Length-5;$i++)

{

# Split the line and get the strings

$line = [regex]::split($AllReserved[$i],"\s{2,}")

$LeaseReserved.IP += Check-Empty $line[0]

$LeaseReserved.MAC += Check-Empty $line[2]

}

}

#endregion 


#region Create a Temp Scope Object

# Create a New Object

$tmpScope = New-Object psobject

# Add new members to the Object

$tmpScope | Add-Member noteproperty "Address" ""

$tmpScope | Add-Member noteproperty "Mask" ""

$tmpScope | Add-Member noteproperty "State" ""

$tmpScope | Add-Member noteproperty "Name" ""

$tmpScope | Add-Member noteproperty "LeaseDuration" ""

#endregion

#region Create a Temp Lease Object

# Create a New Object

$tmpLeaseClients = New-Object psObject

# Add new members to the Object

$tmpLeaseClients | Add-Member noteproperty "IP" ""

$tmpLeaseClients | Add-Member noteproperty "Name" ""

$tmpLeaseClients | Add-Member noteproperty "Mask" ""

$tmpLeaseClients | Add-Member noteproperty "MAC" ""

$tmpLeaseClients | Add-Member noteproperty "Expires" ""

$tmpLeaseClients | Add-Member noteproperty "Type" ""

#endregion

#region Create a Temp Reserved Object

# Create a New Object

$tmpLeaseReserved = New-Object psObject

# Add new members to the Object

$tmpLeaseReserved | Add-Member noteproperty "IP" ""

$tmpLeaseReserved | Add-Member noteproperty "MAC" ""

#endregion

# Go over all the Client Lease addresses and export each detail to a temporary var and out to the log file

For($l=0; $l -lt $LeaseClients.IP.Length;$l++)

{

# Get all Scope details to a temp var

$tmpLeaseClients.IP = $LeaseClients.IP[$l] + ","

$tmpLeaseClients.Name = $LeaseClients.Name[$l] + ","

$tmpLeaseClients.Mask =  $LeaseClients.Mask[$l] + ","

$tmpLeaseClients.MAC = $LeaseClients.MAC[$l] + ","

$tmpLeaseClients.Expires = $LeaseClients.Expires[$l] + ","

$tmpLeaseClients.Type = $LeaseClients.Type[$l]

# Export with the Out-CSV Function to the Log File

$tmpLeaseClients | out-csv $LeaseLog -append $true

}



#Continue on figuring out if the DHCP lease clients are in AD or not

#Import the Active Directory module
import-module activedirectory

#import Quest AD module
Add-PSSnapin Quest.ActiveRoles.ADManagement

#connect to AD
Connect-QADService PUTTHEFQDNOFYOURDOMAINHERE_LIKE_DOMAIN.LOCAL | Out-Null

# get input CSV
$leaselogpath = "c:\DHCP\LeaseLog.csv"
Import-csv -path $leaselogpath | 
#query AD for computer name based on csv log
foreach-object `
{ 
   $NameResult = Get-QADComputer -DnsName $_.Name
   If ($NameResult -eq $null) {$RogueSystem = $_.Name}
   $RogueSystem | Out-File C:\DHCP\RogueClients.txt -Append
   $RogueSystem = $null

}
Get-Content C:\DHCP\RogueClients.txt | Select-Object -Unique | Out-File C:\DHCP\RogueClientsFinal.txt
Remove-Item C:\DHCP\RogueClients.txt

#send email to netadmin
$smtpserver = "SMTP SERVER IP"
$from="[email protected]"
$to="[email protected]"
$subject="Non-AD joined DHCP clients"
$body= (Get-Content C:\DHCP\RogueClientsFinal.txt) -join '<BR>&nbsp;<BR>'
$mailer = new-object Net.Mail.SMTPclient($smtpserver)
$msg = new-object Net.Mail.MailMessage($from,$to,$subject,$body)
$msg.IsBodyHTML = $true
$mailer.send($msg)

Semoga itu bisa membantu orang lain!

Pembersih
sumber
3

OK, saya tidak yakin saya mengikuti etiket di sini tetapi saya memposting jawaban kedua alih-alih mengedit jawaban saya sebelumnya, karena memang berisi beberapa info yang mungkin berguna untuk seseorang bahkan jika terbukti tidak relevan dengan kasus ini. Jika itu membuat saya idiot di forum ini, silakan memberi tahu saya tentang cara saya yang salah.

Masalahnya dibagi menjadi beberapa bagian, berikut adalah saran untuk yang menurut saya paling menarik. Tanpa contoh dari log ini adalah yang terbaik yang bisa saya lakukan, jadi itu hanya saran bukan solusi.

Untuk mengurai log digunakan get-contentdengan -waitparameter. Untuk kasus penggunaan saya, itu cukup untuk menemukan kesalahan dalam log kesalahan.

Inilah yang berfungsi untuk kasus penggunaan saya sendiri, maafkan pemformatan:

get-content E:\temp13\log.txt -tail(1) -wait | where {$_ -match "ERROR"} |
    foreach {
        send-mailmessage `
        -port 25 `
        -smtpserver my.mail.server `
        -from [email protected] `
        -to [email protected] `
        -subject "test logmonitor" `
        -body "ERROR found: $_" `
        }

Alih-alih, $_ -match "ERROR"Anda harus memisahkan bidang ID log dan nama komputer. Saya tidak yakin bagaimana cara melakukannya dengan cara terbaik saat ini, tetapi karena where-object -matchmemberikan dukungan regex saya kira itu bisa menjadi pilihan. Anda juga bisa mulai dengan menyimpan variabel $ _ di variabel baru lainnya, untuk dapat mengambilnya sesuka Anda nanti dalam saluran pipa, di dalam loop foreach bersarang terlebih dahulu dll.

Dengan asumsi Anda bisa mendapatkan di computername, saya kira get-adcomputercmdlet akan menjadi cara paling sederhana untuk menanyakan AD Anda ( import-module activedirectory), dan saya kira pada kesalahan mengirim email?

Menggunakan import-csvtentu saja akan jauh lebih elegan dalam kasus Anda, tapi saya tidak mengetahui cara untuk mengikutinya (jika ada yang membaca ini dan mengetahui trik menaiki lorong itu tolong, silakan berbagi).

ErikE
sumber
Terima kasih ErikE, saya akan menjalankan ini dan memberi tahu Anda. Saya perlu mencari cara untuk mengambil info, kueri AD, lalu setelah "lansiran" abaikan cek di masa depan dari jalur input yang sama. Misalnya, jika ia menanyakan file setiap lima menit, saya tidak ingin mem-reparse informasi yang sama dan mengirim peringatan dupe setiap 5 menit.
TheCleaner
Dua hal yang menurut saya sedikit rapi: Jika Anda membiarkan skrip berjalan, parameter tunggu akan terus menunggu baris baru muncul. Anda tidak perlu menjalankan ulang skrip. Dia akan memberikan efek dorong daripada menarik. Juga, ekor (1) akan hanya mengurai 1 baris terakhir saat mulai. Dengan demikian, jika pengelola tugas menemukan itu harus memulai ulang skrip, dan Anda menemukan cara untuk menyuntikkan baris placeholder menggantikan baris terakhir untuk memicu peringatan, Anda akan melucuti gangguan dari realerts.
ErikE
1
Erik, saya telah menemukan cara untuk mengekspor sewa dari DHCP (jelek bahwa 2012 memiliki cmdlet PS untuk itu tetapi 2008 tidak) ke file csv. Dengan cara ini saya tidak mengacaukan log audit yang sebenarnya dan tidak perlu khawatir melanggar apa pun dengan input. Saya akan mulai mengacaukan dengan menyelesaikan seluruh kode dan segera memperbarui.
TheCleaner
1

Di bawah asumsi bahwa Anda yakin dengan ID Peristiwa, dan bahwa tidak ada peristiwa lain yang masuk ke ID ini di log DHCP tetapi yang Anda minati, push memang pilihan.

1) Buka Server Manager, buka log DHCP di Event Viewer.

2) Temukan entri representatif yang ingin Anda lampirkan tindakan Anda. Pilih dan klik kanan.

3) Pilih "Lampirkan Tugas Ke Acara Ini".

4) Wisaya Pembuatan Tugas terbuka, bawa pergi dari sana ...

Sebenarnya ada opsi email eksplisit, tetapi jika Anda membutuhkan lebih banyak logika dari itu Anda tentu saja bebas menggunakan opsi start-a-program untuk menjalankan powershell.exe dan melampirkan skrip untuk itu. Ada banyak howtos googleable yang sangat baik tentang cara membiarkan Task Manager menjalankan skrip PowerShell jika Anda memerlukan panduan.

Alternatif langsung yang saya lihat adalah menggunakan tarikan dengan mem-parsing Event Log menggunakan PowerShell pada interval yang dijadwalkan. "The Microsoft Scripting Guy", alias Ed Wilson telah menulis beberapa posting blog yang luar biasa tentang cara mem-parsing Event Log menggunakan cmdlet yang tersedia dalam versi PowerShell yang berbeda, jadi menjadikan blognya sebagai titik awal akan menjadi saran saya.

Adapun cmdlet aktual, saya tidak punya waktu sekarang untuk menarik simpanan potongan berguna saya, tetapi akan melihat lagi dalam satu atau dua hari dan dapat berkontribusi jika tidak ada orang lain yang memilih dengan beberapa yang dipilih dengan baik, atau Anda berlindung ´t diselesaikan sendiri :-)

ErikE
sumber
2
Erik, terima kasih. Masalahnya di sini adalah bahwa DHCPsrvlog- "hari" di C: \ windows \ system32 \ DHCP (dengan audit DHCP diaktifkan di server DHCP GUI), tidak menulis ke log Peraga Peristiwa termasuk log peraga peristiwa DHCP-Server di bawah Applications and Services Logs(sejauh ini berdasarkan penelitian / pengujian saya)
TheCleaner
Saya lupa tentang log-log itu. Tapi saya percaya ini adalah tempat yang memungkinkan: Parse log teks menggunakan get-content dengan arahan-wait dan -tail. Ini mirip dengan tail in * nix. Untuk memastikan sebuah instance selalu mengurai log, Task Manager dapat menjadwalkan skrip pada startup sistem, kemudian memulai setiap (interval sesingkat mungkin) tetapi hanya mengizinkan satu instance berjalan. Jika acara Anda muncul, jalankan logika.
ErikE
Ternyata saya memiliki masalah penguraian log yang serupa untuk dipecahkan pada Windows, saya akan memposting temuan saya pada bagian tertentu ketika saya yakin itu berhasil, dan kemungkinan beberapa blok bangunan lain yang saya miliki tergeletak di sekitar yang seharusnya bermanfaat bagi Anda. Bisakah Anda menempelkan beberapa baris representatif tetapi tidak jelas dari log dhcp Anda? Saya sangat tertarik dengan format nama perangkat.
ErikE
1

Meskipun ini tidak membahas solusi yang Anda inginkan, opsi yang dapat mencapai tujuan Anda adalah menggunakan arpwatch( tautan ) untuk memberi tahu Anda ketika host baru (sebelumnya tidak terlihat) terlihat di jaringan.

Alternatif Windows arpwatchuntuk menjadi decaffeinatid tapi saya tidak pernah menggunakannya jadi tidak bisa berbicara baik atau buruk.

fukawi2
sumber
Terima kasih. Idenya ada suara. Saya mungkin turun jalan itu jika perlu.
TheCleaner
Manfaat tambahan adalah bahwa ini juga akan menangkap mesin-mesin baru yang menggunakan IP statis, yang tidak berada dalam ruang lingkup Anda tetapi mungkin seharusnya.
mfinni