Windows DHCP 서버-AD에 가입하지 않은 장치가 IP 주소를 받으면 알림 받기


15

대본

이것을 가장 쉬운 예로 단순화하려면 :

DHCP 서버 역할을 가진 Windows 2008 R2 표준 DC가 있습니다. 다양한 IPv4 범위를 통해 IP를 전달하며 아무런 문제가 없습니다.

내가 좋아하는 것

내가 알림 / 이벤트 로그 항목을 만들 수있는 방법을 싶습니다 / 장치가 DHCP 주소 임대를 얻고 해당 장치가 때마다 비슷한 을지지 않습니다 Active Directory의 도메인 가입 컴퓨터. 사용자 정의 Powershell인지 여부는 중요하지 않습니다.

결론 : 현재 802.1X를 사용하지 않고 비 도메인 장치가 네트워크에 있는지 알 수있는 방법을 원합니다. 이것이 고정 IP 장치를 설명하지는 않는다는 것을 알고 있습니다. 네트워크를 스캔하고 장치를 찾을 수있는 모니터링 소프트웨어가 있지만 세부적인 것은 아닙니다.

연구 완료 / 옵션 고려

내장 로깅으로 그러한 가능성을 보지 못했습니다.

예, 802.1X에 대해 알고 있으며이 위치에서 장기적으로 구현할 수 있지만 프로젝트와는 거리가 멀고 네트워크 인증 문제를 해결하는 데 도움이되지만 외부에서도 도움이됩니다. 802.1X 목표.

유용 할 수있는 스크립트 비트 등을 살펴 보았지만 내가 찾은 것들로 인해 현재 Google fu가 실패하고 있다고 생각하게되었습니다.

나는 기존의 해결책이 없다고 가정 할 때 아래의 논리가 건전하다고 생각합니다 .

  1. 장치가 DHCP 주소를받습니다
  2. 이벤트 로그 항목이 기록됩니다 (DHCP 감사 로그의 이벤트 ID 10이 작동해야합니다 (새 임대는 내가 가장 관심이 있고 갱신하지 않기 때문에) : http://technet.microsoft.com/en-us/library /dd759178.aspx )
  3. 이 시점에서 어떤 종류의 스크립트가 아래의 나머지 "STEPS"를 대신해야 할 것입니다.
  4. 어떻게 든이 이벤트 ID 10에 대해이 DHCP 로그를 쿼리합니다 (푸시를 원하지만 풀이 유일한 해결책이라고 생각합니다)
  5. 새 임대가 할당 된 장치 이름에 대한 쿼리를 구문 분석합니다
  6. 장치 이름에 대한 AD 쿼리
  7. IF 하지 AD에서 발견, 알림 이메일을 보내

누구든지 올바르게 수행하는 방법에 대한 아이디어가 있다면 정말 감사하겠습니다. 나는 "코 임즈"를 찾고 있지 않지만 위의 목록에 대한 대안이 있는지 또는 명확하게 생각하지 않고이 정보를 수집하는 다른 방법이 있는지 알고 싶습니다. 코드 스 니펫 / PS 명령이 있다면이를 달성하기 위해 공유하고 싶을 때 더 좋습니다.


당신이 그들을 차단하려고하거나 IP를 얻었을 때 그냥 알림을 받고 있습니까?
HostBits

@Cheekaleak-알림 받기.
TheCleaner

DHCP를 사용하는 네트워크 프린터는 어떻습니까?
jftuga

@jftuga-네트워크 프린터에 고정 IP를 사용합니다.
TheCleaner

답변:


6

ErikE와 다른 사람들 덕분에 나는 길을 갔다 ... 나는 그것이 옳은 길이라고 말하지는 않지만 내가 생각해 낸 Powershell 스크립트는 그 트릭을 수행한다.

원하는 경우 코드가 아래에 있습니다. 각 DHCP 서버에서 수동으로 가리 키거나 스크립트에서 각 DHCP 서버를 가리 키도록 예약하십시오.

스크립트가하는 일 :

  1. DHCP 서버에서 임대 정보를 가져옵니다 (ipv4 임대)
  2. 임대를 csv 파일로 출력
  3. AD 쿼리를 위해 해당 CSV 파일을 다시 읽습니다.
  4. 컴퓨터에 대한 AD 쿼리
  5. 새 txt 파일로 출력을 찾을 수없는 경우
  6. 위의 # 5에서 생성 된 파일에서 고유 목록 최종 txt 파일을 작성합니다 (클라이언트가 두 번 이상 또는 둘 이상의 어댑터로 등록 할 경우 중복이있을 수 있으므로)
  7. 최종 출력 파일의 내용을 관리자에게 이메일로 보냅니다.

필요한 것 :

이 스크립트는 AD 모듈 ( import-module activedirectory)을 사용하므로 DHCP를 실행하는 AD DC에서 가장 잘 실행됩니다. 그렇지 않은 경우 AD powershell 모듈을 설치할 수 있습니다. http://blogs.msdn.com/b/rkramesh/archive/2012/01/17/how-to-add-active-directory- power-in-windows-7.aspx의 모듈

http://www.quest.com/powershell/activeroles-server.aspx에있는 Quest의 AD Powershell cmdlet도 필요합니다 . 스크립트를 실행하기 전에 설치하십시오 . 그렇지 않으면 실패합니다.

스크립트 자체 (위생, 입력 파일 이름, 연결할 도메인, 연결할 DHCP 서버, 끝 근처의 이메일 설정 등과 같은 요구 사항에 맞게 일부 변수를 설정해야 함) :

# 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="DHCPSERVER@domain.com"
$to="TheCleaner@domain.com"
$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)

다른 사람을 돕는 희망!


3

좋아, 나는 여기에 에티켓을 따르지 않을지 모르겠지만 이전의 내용을 편집하는 대신 두 번째 답변을 게시하고 있습니다. 그것이이 포럼에서 바보가된다면 저의 잘못된 길을 알려주세요.

문제는 여러 부분으로 나뉘어져 있으며 가장 흥미로운 것으로 생각되는 부분에 대한 제안입니다. 로그의 예가 없으면 이것이 최선의 방법이므로 솔루션이 아닌 제안 일뿐입니다.

로그를 구문 분석하려면 매개 변수를 사용 get-content하십시오 -wait. 내 유스 케이스의 경우 오류 로그에서 오류를 찾는 것으로 충분합니다.

이것은 내 자신의 유스 케이스에서 작동 한 형식입니다.

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

대신 $_ -match "ERROR"로그 ID 필드와 컴퓨터 이름을 분리해야합니다. 지금 최선의 방법으로 그 방법을 모릅니다. 그러나 where-object -match정규식 지원을 제공 한 이후로 이것이 옵션 일 수 있다고 생각합니다. 또한 $ _ 변수를 다른 새 변수에 저장하여 파이프 라인에서 나중에 중첩 된 foreach 루프 등에서 편리하게 선택할 수 있습니다.

컴퓨터 이름을 얻을 수 있다고 가정하면 get-adcomputercmdlet을 사용하여 AD ( import-module activedirectory) 를 쿼리하는 가장 간단한 방법이 될 것입니다. 메일 전송 오류가 있다고 생각하십니까?

import-csv물론 당신의 경우에는 사용하는 것이 훨씬 더 우아하지만, 나는 그것을 꼬리를 두는 방법을 모른다.


감사합니다 ErikE, 나는 이것을 가지고 당신에게 알려줄 것입니다. 정보를 가져 와서 AD를 쿼리하는 방법을 찾아야합니다. 그런 다음 "경고"후에 동일한 입력 행에 대한 향후 검사를 무시하십시오. 예를 들어 5 분마다 파일을 쿼리하면 동일한 정보를 다시 분석하고 5 분마다 속박 경고를 보내지 않기를 바랍니다.
TheCleaner

내가 약간 깔끔하게 찾은 두 가지 : 스크립트를 그냥 실행 시키면 wait 매개 변수는 계속해서 새 줄이 나타날 때까지 대기하게됩니다. 스크립트를 다시 실행할 필요가 없습니다. Hhis는 당기기보다는 밀어 넣기 효과를 줄 것입니다. 또한 tail (1)은 시작시 마지막 1 줄을 구문 분석합니다. 따라서 작업 관리자가 스크립트를 다시 시작해야한다는 것을 발견하고 마지막 줄을 대체하여 자리 표시 자 줄을 삽입하여 경고를 트리거하는 방법을 찾으면 부동산업자의 성가심을 무력화시킬 수 있습니다.
ErikE

1
Erik, 임대를 DHCP에서 임대하는 방법을 찾았습니다 (2012 년에는 PS cmdlet이 있지만 2008 년에는없는 CRppy). 이렇게하면 실제 감사 로그를 엉망으로 만들지 않고 입력 내용을 손상시키는 것에 대해 걱정할 필요가 없습니다. 나머지 코드를 완성하고 곧 업데이트 할 것입니다.
TheCleaner

1

이벤트 ID가 확실하고 DHCP 로그에이 ID에 다른 이벤트가 기록되지 않고 관심있는 이벤트가 있다는 가정하에 푸시는 실제로 옵션입니다.

1) 서버 관리자를 열고 이벤트 뷰어에서 DHCP 로그로 이동하십시오.

2) 조치를 첨부 할 대표 항목을 찾으십시오. 그것을 선택하고 마우스 오른쪽 버튼을 클릭하십시오.

3) "이 이벤트에 작업 첨부"를 선택하십시오.

4) Task Creation Wizard (작업 생성 마법사)가 열립니다.

실제로 명시적인 전자 메일 옵션이 있지만 그보다 많은 논리가 필요한 경우 물론 프로그램 시작 옵션을 사용하여 powershell.exe를 실행하고 스크립트를 첨부 할 수 있습니다. 지침이 필요한 경우 작업 관리자가 powershell 스크립트를 실행하도록하는 방법에 대한 훌륭한 Google 방법이 많이 있습니다.

내가 보는 직접적인 대안은 예약 된 간격으로 powershell을 사용하여 이벤트 로그를 구문 분석하여 pull을 사용하는 것입니다. "Microsoft Scripting Guy"(일명 Ed Wilson)는 여러 버전의 powershell에서 제공되는 cmdlet을 사용하여 이벤트 로그를 구문 분석하는 방법에 대한 멋진 블로그 게시물을 작성 했으므로 블로그를 시작점으로 삼는 것이 좋습니다.

실제 cmdlet과 관련하여 지금은 편리한 스 니펫을 숨길 시간이 없지만 하루나 이틀 후에 다시 살펴볼 것입니다. 혼자서 해결하지 못했습니다 :-)


2
에릭, 고마워 여기서 문제는 C : \ windows \ system32 \ DHCP의 DHCPsrvlog- "일"(DHCP 서버 GUI에서 DHCP 감사가 활성화 된 상태)에서 DHCP 서버 이벤트 뷰어 로그를 포함한 이벤트 뷰어 로그에 기록하지 않는다는 것입니다. Applications and Services Logs(지금까지 내 연구 / 테스트를 기반으로 함)
TheCleaner

나는 그 로그에 대해 잊었다. 그러나 나는 이것이 가능한 장소라고 생각합니다. -wait 및 -tail 지시문과 함께 get-content를 사용하여 텍스트 로그를 구문 분석하십시오. 이것은 * nix의 tail과 유사합니다. 인스턴스가 항상 로그를 구문 분석하는지 확인하기 위해 작업 관리자는 시스템 시작시 스크립트를 예약 한 다음 매번 (가장 짧은 간격으로) 시작하지만 실행중인 인스턴스는 하나만 허용 할 수 있습니다. 이벤트가 나타나면 로직을 실행하십시오.
ErikE

Windows에서 해결할 수있는 비슷한 로그 구문 분석 문제가 있음이 밝혀졌습니다. 확실히 확실하다고 판단 될 때 특정 부분에 내 결과를 게시하고 아마도 내가 가지고있는 다른 빌딩 블록을 사용하면 유용 할 것입니다. dhcp 로그에서 몇 가지 대표적이지만 난독 화 된 행을 붙여 넣을 수 있습니까? 특히 장치 이름 형식에 관심이 있습니다.
ErikE

1

이 방법으로 원하는 솔루션을 해결할 수는 없지만 목표를 달성 할 수있는 옵션 은 네트워크에 새 (이전에 보이지 않는) 호스트가 표시 될 때 알리기 위해 arpwatch( link ) 활용 하는 것입니다.

Windows 대안은 카페인이 아닌 arpwatch것처럼 보이지만 결코 사용하지 않았으므로 좋거나 나쁘다고 말할 수 없습니다.


감사. 소리가 있다는 생각. 필요한 경우 그 길을 따라 갈 수 있습니다.
TheCleaner

추가 이점은 정적 IP를 사용하는 새 컴퓨터를 잡을 수 있다는 것입니다.이 컴퓨터는 명시된 범위에 속하지 않았지만 아마도 그럴 것입니다.
mfinni
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.