https://www.codeproject.com/Articles/5344688/Network-Sniffer-and-Analyzer-Program-Part-1
C# .NET 6.0 Windows Form(Sharppcap, PacketDotNet)으로 만들어 보는 네트워크 스니퍼 및 분석기 프로그램
이 프로그램으로 DNS 패킷을 캡처하고 분석할 수 있습니다. 또한 네트워크에서 다른 사용자 패킷을 스니핑할 수 있도록 ARP를 스푸핑할 수 있습니다. 이 프로그램은 먼저 네트워크를 스캔하여 네트워크에 연결된 장치를 찾은 다음, 검색 된 장치 중 하나를 선택하여 해당 장치에 대한 수신 및 발신 패킷을 스니핑할 수 있습니다.
소개
이 기사에서는 내 프로그램(네트워크 스니퍼 및 분석기)을 소개하고 코드에 대한 단계별 설명을 제공하여 프로그램의 메커니즘을 보여 드릴 것입니다.
참고: 이 기사를 이해하려면 네트워킹에 대한 일반적인 지식과 고급 C# 지식이 있어야만 합니다.
참고: 프로그램을 완전히 설명하기 위해 기사를 여러 부분으로 나눌 것입니다.
각 부분에는 프로그램에서 사용되는 함수들에 대한 전체 설명이 포함됩니다. 기사의 각 부분과 함께 프로그램의 일부를 따로 업로드하겠습니다. 기사의 마지막 부분에서는 프로그램의 배경과 사용 방법을 설명한 후 물론 프로그램의 최종 버전을 업로드하겠습니다.
기사는 다음 순서를 따를 것입니다:
- 서브넷마스크 기반 IP 주소 분석.
- 네트워크를 스캔하여 사용 가능한 모든 장치를 찾기.
- Arp 스푸핑
- 특정 장치를 통해 탐색하는 웹사이트 모니터링
그럼 시작해 볼까요~!
1부: 서브넷 마스크 기반 IP 주소 분석
먼저 컴퓨터에서 사용 가능한 모든 IP를 가져온 다음 IP 클래스에 따라 이 IP에 적합한 서브넷 마스크를 결정 할 것입니다. 또 해당 IP에 대한 인터넷 ID, 사용 가능한 호스트 수, 사용 가능한 Net ID 수, 이 네트워크의 첫 번째 IP와 마지막 IP를 추출 할 것입니다. 먼저 우리는 주어진 IP에 대한 IP 클래스를 정의 할 것입니다.
일반적으로 IP 클래스를 결정하려면 IP의 첫 번째 숫자를 가져와 해당 IP 주소가 속한 범위를 분석해야 합니다. 클래스에 따른 IP의 순서는 다음 표와 같습니다:
Class
|
Range
|
Subnetmask
|
A
|
1-126
|
\8
|
B
|
128-191
|
\16
|
C
|
192-223
|
\24
|
D
|
224-239
|
_
|
E
|
240-255
|
_
|
그리고 다음 코드와 같이 수행 해 볼 수 있습니다:
public enum IPClass { A, B, C, D, E, notDetected }
IPClass getIPClass(string IP)
{
if (!string.IsNullOrEmpty(IP) && IP.Split('.').Length == 4 &&
!string.IsNullOrEmpty(IP.Split('.').Last()))
{
string ipclassstr = IP.Split('.').First();
int ipclasssnum = int.Parse(ipclassstr);
if (0 <= ipclasssnum && ipclasssnum <= 126)
{
return IPClass.A;
}
if (128 <= ipclasssnum && ipclasssnum <= 191)
{
return IPClass.B;
}
if (192 <= ipclasssnum && ipclasssnum <= 223)
{
return IPClass.C;
}
if (224 <= ipclasssnum && ipclasssnum <= 239)
{
return IPClass.D;
}
if (240 <= ipclasssnum && ipclasssnum <= 255)
{
return IPClass.E;
}
}
else return IPClass.notDetected;
return IPClass.notDetected;
}
그리고 서브넷 마스크:
int getSubnetMaskBitsCount(string ip)
{
IPClass iPClass = getIPClass(ip);
if (iPClass == IPClass.A)
return 8;
if (iPClass == IPClass.B)
return 16;
if (iPClass == IPClass.C)
return 24;
if (iPClass == IPClass.D)
return 31;
if (iPClass == IPClass.E)
return 32;
return -1;
}
다음 단계에서는 주어진 IP에 대한 넷 ID, 사용 가능한 호스트 수, 사용 가능한 넷 ID 수, 이 네트워크의 첫 번째 IP와 마지막 IP를 추출 할 것입니다. 이 방식은 현재 서브넷 마스크와 해당 비트 수를 기반으로 하는 동적이며 유연한 방식입니다.
주어진 IP 주소의 Net ID 형식 추출
기본 마스크 값을 찾았다면, 우리는 주어진 IP 주소로 AND 연산을 수행하여 네트워크 IP 주소를 얻을 것입니다.
다음 IP를 예로 사용 해 볼 것입니다: ,,192.168.178.112".
IP의 첫 번째 숫자에서 알 수 있듯이 클래스 C에 속하며 이 IP의 서브넷 마스크가 \24 255.255 .255 .0임을 의미합니다.
우리는 이제 IP와 해당 서브넷 마스크를 비트로 변환하고 AND 연산을 통해 네트워크 ID를 계산 할 것입니다:
11000000.10101000.10110010.01110000 (192.168.178.112)
&
11111111.11111111.11111111.00000000 (255.255 .255 .0)
----------------------------------------------
11000000.10101000.10110010.00000000 (192.168.178.0)
다음과 같이 코드로 수행할 수 있습니다:
public string getNetID(string ipadresse, string subnetmask)
{
StringBuilder sb = new StringBuilder();
string[] subMaskValues = subnetmask.Split('.');
string[] subIpValues = ipadresse.Split('.');
for (int i = 0; i < subMaskValues.Length; i++)
{
if (i == subMaskValues.Length - 1)
sb.Append((int.Parse(subMaskValues[i]) &
int.Parse(subIpValues[i])).ToString());
else
{
int maskvalue = int.Parse(subMaskValues[i]);
int ipvalue = int.Parse(subIpValues[i]);
string str = ((maskvalue & ipvalue).ToString());
str += ".";
sb.Append(str);
}
}
return sb.ToString();
}
사용 가능한 호스트 수 찾기
총 주소 수
다음 공식을 사용하여 서브넷의 총 주소 수를 계산할 수 있습니다:
TNOA( Total number of addresses) = (2^(32 - Current Subnetmask Bits Count))
최대 호스트 수
네트워크 및 브로드캐스트 주소는 네트워크의 호스트에 할당할 수 없습니다. 따라서 호스트에 할당할 수 있는 사용 가능한 주소 수는 총 주소 수에서 2를 뺀 값 = (2^(32 - 현재 서브넷 마스크 비트 수))-2입니다.
코드는 다음과 같이 작성하여 수행할 수 있습니다:
int getHostcount(int Current_Subnetmask_Bits_Count)
{
double resultbits = Math.Max(Math.Pow(2,
(32 - (Current_Subnetmask_Bits_Count))) - 2, 0);
return (int)resultbits;
}
사용 가능한 Net ID 수 찾기
다음 공식을 사용하여 서브넷의 Net ID 수를 계산할 수 있습니다.
(2^(IP CLass Standart Subnetmask Bits Count - Current Subnetmask Bits Count))
다음과 같은 코드로 진행할 수 있습니다:
int getNetcount(int IP_CLass_Standart_Subnetmask_Bits_Count,
int Current_Subnetmask_Bits_Count)
{
double resultbits = Math.Max(
Math.Pow(
2, Current_Subnetmask_Bits_Count -
IP_CLass_Standart_Subnetmask_Bits_Count),
0);
return (int)resultbits;
}
서브넷에서 첫 번째 IP 추출
먼저 다음 4개의 변수를 정의해야 합니다:
- A. 주어진 IP 클래스 표준 서브넷 마스크 비트 수.
- B. 주어진 또는 현재 서브넷 마스크 비트 수
- C. 호스트 부분 길이 = 32 - B
- D. 서브넷 부분 = B - A
1단계: 주어진 서브넷 마스크에서 호스트 부분을 가져옵니다.
2단계: 호스트 부분의 마지막 비트를 1로 변경합니다.
3단계: D>0이면 서브넷 마스크에서 서브넷 부분을 가져온 다음 추출된 서브넷 부분과 IP 주소의 해당 비트에 And 연산을 적용합니다.
4단계: 호스트 및 서브넷 부분을 이진수에서 정수로 변환합니다.
5단계: 주어진 IP 주소에서 호스트 부분을 교체합니다.
예: 주소 192.168.178.112 라면 예를 들어 우리는 서브넷 마스크 255.255.255.128 를 취합니다.
IP 주소는 192.168.178.112 => IP 클래스는 C => 표준 서브넷 마스크는 \24 255.255.255.0 입니다.
1단계: 주어진 서브넷 마스크를 비트로 변환하여 해당 비트에서 호스트 부분을 취합니다:
255 . 255 . 255 . 128
11111111.11111111.11111111.10000000
서브 넷 부분(첫 번째 놈) <_ ---------->호스트 부분(0 인 부분)
2단계: 호스트 부분의 마지막 비트를 1로 변경 => 0000001
Step 3: If D>0, get the Subnet Part from the Subnet Mask and then apply the And operation on the extracted Subnet Part and the equivalent Bits in the IP Adresse => the subnet part is on the index: 25 = 1
3단계: D>0인 경우 서브넷 마스크에서 서브넷 부분을 가져온 다음 추출된 서브넷 부분과 IP 주소의 동등한 비트에 And 연산을 적용합니다. => 서브넷 부분은 인덱스에 있습니다. 25 = 1
192 . 168 . 178 . 112
11000000.10101000.10110010.01110000
->the equivalent Bit(첫 번째 놈(0))
따라서 1 & 0 = 0 => 이제 우리는 호스트 부분에 추가 한다 0000001 =>00000001
4단계: 호스트 및 서브넷 부분 형식 바이너리를 정수로 변환 =>00000001 = 1
5단계: 주어진 IP 주소에서 호스트 부분 교체 => 192.168.178.1
이 부분의 코드는 아래와 같습니다:
public string getFirstIpAdresse(string ipadresse,
int standard_subnet_mask_bits_count, int current_subnet_mask_bits_count,
string current_subnet_mask_bits)
{
int hostlength = 32 - current_subnet_mask_bits_count;
int subnet_length = current_subnet_mask_bits_count -
standard_subnet_mask_bits_count;
string hostpart = current_subnet_mask_bits.Substring
(current_subnet_mask_bits_count, hostlength);
string ip_bits = ip_to_bit_string(ipadresse);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < hostpart.Length; i++)
{
if (i == hostpart.Length - 1) stringBuilder.Append("1");
else stringBuilder.Append("0");
}
string net_id_plus_host = stringBuilder.ToString();
if (subnet_length > 0)
{
string subnet_part = current_subnet_mask_bits.Substring
(standard_subnet_mask_bits_count, subnet_length);
string to_operat_ip_bits = ip_bits.Substring
(standard_subnet_mask_bits_count, subnet_length);
// var And_operation_result = Convert.ToByte(to_operat_ip_bits, 2) &
// Convert.ToByte(subnet_part, 2);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < subnet_part.Length; i++)
sb.Append(Convert.ToUInt64(to_operat_ip_bits[i].ToString(), 2)
& Convert.ToUInt64(subnet_part[i].ToString(), 2));
for (int i = 0; i < hostpart.Length; i++)
if (i == hostpart.Length - 1) sb.Append("1");
else sb.Append("0");
net_id_plus_host = sb.ToString();
}
//*****************
int IPPartsLength = net_id_plus_host.Length / 8;
string[] ipnewparts = new string[IPPartsLength];
int j = 0;
for (int i = 0; i < ipnewparts.Length; i++)
{
ipnewparts[i] = net_id_plus_host.Substring(j, 8);
j = j + 8;
}
string[] ipparts = ipadresse.Split('.');
j = ipparts.Length - 1;
for (int i = ipnewparts.Length - 1; i >= 0; i--)
{
ipparts[j] = Convert.ToInt64(ipnewparts[i], 2).ToString();
j--;
}
StringBuilder stringBuilder1 = new StringBuilder();
for (int i = 0; i < ipparts.Length; i++)
if (i == ipparts.Length - 1) stringBuilder1.Append(ipparts[i]);
else stringBuilder1.Append(ipparts[i] + ".");
return stringBuilder1.ToString();
//*****************
}
서브넷에서 마지막 IP 추출
마지막 IP를 추출하기 위해 "첫 번째 IP"와 동일한 단계를 따르지만 두 번째 단계를 변경하여 0으로 남겨둔 마지막 비트와 코드를 제외한 모든 호스트 비트를 1로 변경합니다:
public string getLastIpAdresse(string ipadresse,
int standard_subnet_mask_bits_count, int current_subnet_mask_bits_count,
string current_subnet_mask_bits)
{
int hostlength = 32 - current_subnet_mask_bits_count;
int subnet_length = current_subnet_mask_bits_count -
standard_subnet_mask_bits_count;
string hostpart = current_subnet_mask_bits.Substring
(current_subnet_mask_bits_count, hostlength);
string ip_bits = ip_to_bit_string(ipadresse);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < hostpart.Length; i++)
{
if (i == hostpart.Length - 1) stringBuilder.Append("0");
else stringBuilder.Append("1");
}
string net_id_plus_host = stringBuilder.ToString();
if (subnet_length > 0)
{
// string net_id_part = current_subnet_mask_bits.Substring
// (standard_subnet_mask_bits_count, net_id_length).PadRight
// (net_id_length + hostlength, '0');
string subnet_part = current_subnet_mask_bits.Substring
(standard_subnet_mask_bits_count, subnet_length);
string to_operat_ip_bits = ip_bits.Substring
(standard_subnet_mask_bits_count, subnet_length);
// var And_operation_result = Convert.ToByte(to_operat_ip_bits, 2)
// & Convert.ToByte(subnet_part, 2);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < subnet_part.Length; i++)
sb.Append(Convert.ToUInt64(to_operat_ip_bits[i].ToString(), 2)
& Convert.ToUInt64(subnet_part[i].ToString(), 2));
for (int i = 0; i < hostpart.Length; i++)
if (i == hostpart.Length - 1) sb.Append("0");
else sb.Append("1");
net_id_plus_host = sb.ToString();
}
//*****************
int IPPartsLength = net_id_plus_host.Length / 8;
string[] ipnewparts = new string[IPPartsLength];
int j = 0;
for (int i = 0; i < ipnewparts.Length; i++)
{
ipnewparts[i] = net_id_plus_host.Substring(j, 8);
j = j + 8;
}
string[] ipparts = ipadresse.Split('.');
j = ipparts.Length - 1;
for (int i = ipnewparts.Length - 1; i >= 0; i--)
{
ipparts[j] = Convert.ToInt64(ipnewparts[i], 2).ToString();
j--;
}
StringBuilder stringBuilder1 = new StringBuilder();
for (int i = 0; i < ipparts.Length; i++)
if (i == ipparts.Length - 1) stringBuilder1.Append(ipparts[i]);
else stringBuilder1.Append(ipparts[i] + ".");
return stringBuilder1.ToString();
//*****************
}
History
- 20th October, 2022: Initial version
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
이상.
'프로그래밍' 카테고리의 다른 글
[C] 포인터와 구조체 (0) | 2022.12.18 |
---|---|
[C#] 네트워크 스니퍼 및 분석기 프로그램 - 2부 (0) | 2022.12.16 |
빠른 2:1 이미지 축소(축소) (0) | 2022.12.14 |
C++ 심층 네트워크 프로그래밍 (0) | 2022.12.13 |
당신 손안에 사이언스 소프트웨어 (0) | 2022.12.12 |