* HTTP ( Hyper Text Transfer Protocol )
 - 웹(Web) 통신에서 사용되는 프로토콜

* HTTP 메세지 구조
(\ -> 역슬래쉬)

-기본
start line\r\n   (모든 메세지는 스타트라인 한줄을 가지고 있다.)
header-field\r\n (헤더필드는 여러개가 올 수 있다.)
header-field2\r\n
ex)
header-name: header-value\r\n
...
\r\n     (캐리지리턴이 나오면 헤더필더가 다 나왔다는 것이다.
message-body (있을 수도 있고 없을 수도 있다.)

1) HTTP request Message
 request line\r\n
 request-header\r\n
 ...
 \r\n
 message-body







(요청 request-line)



1.1) request-line  ( sp :스페이스(공백), 구분자 )
 
 method sp URI(URL) sp HTTP version\r\n
method 필드




(메소드)



(메소드)



URI Vs URL
- URI : Uniformed Resource Identifier (자원에 대한 식별자)
- URL : Uniformed Resource Location (자원에대한 위치)
         : 어떠한 경로에 있는지 정확하게 나와있다.

2) HTTP response Message
 status line\r\n
 response-header\r\n
 ...
 \r\n
 message-body

2.1) status-line ( sp :스페이스(공백), 구분자 )
 HTTP version (sp) status code (sp) reason phrase\r\n

- HTTP의 request-line과 status-line의 구조를 살펴보았다.



DNS의 동작 까지 확인해보았고
오늘은
DNS 동작을 이루는 패킷이 어떻게 이루어져 있는지 분석해보겠다.

호스트의 DNS IP주소를 확인해보겠다.




(DNS 서버 주소)



164.124.101.2 로 되어있다. 아래 IP주소도 맞다.
DNS 캐시 서버이다.

이제 패킷을 덤프해서 확인해보겠다.
와이어샤크 실행
간단하게 캡쳐 필터링 룰을 설정하였다.




(캡쳐 필터링 룰 설정)



멀티캐스트를 제거하였다.
멀티캐스트와 브로드캐스트를 제거해야하는데 지금보니
위에 오타가 있었다. :)

간단한 룰을 설정해주고 naver.com에 접속하였다.
(도메인 네임을 가지고)




(naver.com 입력)



그리고 디스플레이 필터 룰을 dns 로 설정하여
dns 패킷만 확인하였다.
아래 화면에
같은 Trx Id 를 가진 패킷들을 빨간색 표시해두었다.




(DNS 패킷)



디스플레이 필터링 룰을 dns.id == 0x0e68 로 설정하여
해당 아이디의 패킷만 필터링 하였다. (보기 좋게)



(필터링 룰 적용)



이제 query (Qeustion) 패킷부터 살펴보겠다.




(Trx ID)



DNS query 패킷의 첫번째 요소는
Transaction ID 이다.
UDP 통신이기 때문에 패킷을 구별할 수 없다. 그렇기 때문에 이 ID가 존재하고
이 ID로 해당 질문에 대한 답변을 구분 한다.




(Flag)



두번 째는 Flag이다.
질문, 응답 등의 패킷 타입을 결정한다.




(Question)



Question 필드에는 물어보는 도메인 네임의 수이다.
보통 한개가 생기면 바로 물어보기 때문에
한개 이상의 패킷을 보기는 힘들다.




(나머지 필드)



나머지로 Answer , Authority, Addional 이 있다.
Answer는 질문에 대한 답이고
Authority는 그 답에대한 근거(?) 출처(?) 정도이다.
Additional은 추가적인 내용이 붙는다.

정리하자면
DNS Header
 1. transaction id (2바이트)
 2. Flag (2바이트)
 3. qeustion(2바이트)
  - 질의 갯수
 4. answer(2바이트)
 5. authority(2바이트)
 6. additional(2바이트)

이렇게 구성되어있다.
도메인 네임의 전송을 살펴보겠다.



(www.naver.com 이 담겨져 있는 모습)



살펴보면
먼저 문자의 수가 나온다. 03, 그 뒤로 www (77 77 77) 이 나온다.
그리고 다시 문자의 수 05, 그리고 naver 5글자가 나오고
마지막으로 03 , com 3글자가 나온다.




(응답 패킷)



응답 패킷을 보면
DNS 헤더의 똑같은 양식에
응답부분이 채워져서 전송되었음을 확인 할 수 있다.

그러면 위에서 작성했던 도메인 네임을 여러번 쓸까?

그렇지 않다.
패킷을 잘 보면 c0 이 보이는데
c0은 포인터라는 뜻이다.
c0 뒤에 2b는 43이라는 숫자로 DNS 헤더의 43번째에 있는 주소를 나타내는 뜻이다.



(포인터 표시)



지금까지 DNS 패킷을 분석해보았다.

이제 DNS 패킷을 조작하여 할 수 있는 공격기법을 살펴보겠다.

* DNS Spoofing
- DNS를 속이는 공격 기법
 - trx id와 포트번호를 맞춰야한다.
 - Birthday Attack(추측성 공격, trx id를 추측하는 공격기법)
 - 그래서 보통 ARP Spoofing과 함께 공격을한다. (클라이언트가 대상일때)
 - 스푸핑 환경을 만든 후에 공격을 한다.
 - 공격자와 피해자가 같은 환경에 있어야한다.


DNS Spoofing을 해볼 것이다.

우리가 작성해야할 프로그램
1. ARP spoofing (pcap library를 이용)
 1) arp cache poisoning
 * ARP request 메세지를 작성하여 스푸핑
 * 브로드 캐스팅은 사용하지 않는다
 * 유니 캐스팅을 할 수 있도록 작성
target : 192.168.3.99
 - mac : 90-9f-33-ec-cc-37
attacker : 192.168.3.100
 - mac : 90-9F-33-EC-CB-0B
게이트웨이
 00-10-f3-4e-58-40

2. DNS spoofing (pcap library를 이용)
 
0) packet forwarding
  - 자기 패킷이 아니라면 원래 목적지로 포워딩
 1) DNS Query 패킷을 모니터링
 2) 타겟 도메인(www.daum.net) 모니터링
 3) 속이려고 하는 도메인에 대한 DNS 쿼리
     패킷이 검출되면 가짜 응답을 만들어서 전송해준다.
  - 출발지 포트번호와 TRX id 정보를 알아야 한다.

먼저 ARP Spoofing도구를 만들것이다.
(이건 우리가 전에 작성했던 코드로 바로 여기서 사용하겠다.)




(ARP Spoofing 코드)



이 프로그램으로 ARP 스푸핑이 된 결과를 확인 할 수 있었다.

두번째로
DNS Spoofing을 해주는 프로그램을 만들 것이다.
우리가 ARP 스푸핑을 해서 스니핑을 할 때 포워딩 기능이 없었다.
그래서 DNS Spoofing 코드에 포워딩 기능을 추가할 것이다.

먼저 포워딩 기능 부터 구현해보겠다.

arp_cache_table 변수는
subprocess를 이용해 arp table을 받아 가지고 있는 arp table이다.
IPv4 패킷만 걸러내보겠다.




(IPv4 필터링)




(결과 화면)



끝에 2048이 16진수로 0x800이다. IPv4만 걸러낼 수 있다.

여기서 IP 주소를 보고 구별 할 것이다.

나에게 오는 것이 아닌것 그리고 브로드캐스팅 되는 것 멀티캐스팅되는것을 제외하고는
포워딩을 해줘야할 필요가 있다.
그 패킷들만 필터링 해보겠다.



(포워딩할 패킷 필터링)



자 여기까지 포워딩이 되야할 필터링을 마쳤다.
이제 ARP 스푸핑과 지금까지 작성됬던 프로그램을 동작시켜서
포워딩 해야할 패킷들이 잘 필터링 되는지 확인해 보겠다.
두개 같이 동작 시킨후
피해자가 8.8.8.8 외부 IP로 핑 메세지를 보냈다.



(결과화면)




결과 화면을 보면
99(피해자)가 보낸 핑 메세지들이 필터링 되서 내 화면에 출력되고 잇는 것을 확인할 수 있다.

이제 여기서 포워딩을 추가해주고
DNS Spoofing 프로그램을 만들어 보겠다.


* NAT  환경
NAT 안쪽 : Interner
NAT 밖쪽 : Externer

게이트웨이 : 외부망과 내부망을 연결해주는 라우터이다.

게이트웨이에서 내부망으로 연결되는 사설 ip는
 보통 끝자리가 1 or 254이다.
(주로 그렇다는것이다. 꼭그런건 아니다.)

같은 네트워크에 있지 않으면 맥주소를 알 수 없다.
(같은 네트워크에 있다면  ARP를 통해 맥주소를 알 수 있다.)
이유는

ARP 패킷은 IP 패킷안에 패키징 되지 않기 때문에
라우터를 넘어가지 못한다.
그렇기 때문에 ARP는 같은 네트워크 안에서만 동작한다.

내부망에서는 MAC주소로 통신을 하고
외부망과의 통신은 IP주소만 가지고 통신을 한다.


내부망에서 어떻게 상대방의 맥주소를 알 수 있을까?
-ARP ( Address Resolution Protocol)
내부망에서 상대방의 맥주소를 알아야하는 이유는 게이트웨이까지 통신이 되야하기 때문이다.

1. ARP Request
        - Broadcast

2. ARP Reply



일단,
ARP 패킷을 한번 직접 받아서 분석해보겠다.

먼저 패킷을 덤프받는 코드를 조금 수정하였다.
어제까지 L2의 이더넷 헤더를 덤프받을 수 있었으므로
이더넷 헤더에서 ARP 패킷을 구분할 수 있다.

(마지막 부분에 ARP 표시한 코드)

 

 

 

(덤프받은 ARP 패킷 내용)

 

 

ARP 패킷 받은것
['0x0', '0x1',  '0x8', '0x0',  '0x6', '0x4',  '0x0', '0x1',
'0x90', '0x9f', '0x33', '0xeb','0x3b', '0x42',
'0xc0', '0xa8', '0x3', '0x60',
'0x0', '0x0', '0x0', '0x0', '0x0', '0x0',
'0xc0', '0xa8', '0x3', '0x67',
 '0x0', '0x0', '0x0',
 '0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0', '0x0',
'0x0', '0x0', '0x0', '0x0', '0x0', '0x0']

1. Hardware type (2바이트) : '0x0', '0x1 = 이더넷인터페이스
2. Protocol type (2바이트) : '0x8', '0x0' = 0x0800 = IPv4
3. Hardware length (1바이트) : '0x6'
4. Protocol length (1바이트) : '0x4'
5. Operation (2바이트) : '0x0', '0x1 = 1 : Request
                                                              2 : Reply
6. sender Mac Address (6바이트) : '0x90', '0x9f', '0x33', '0xeb','0x3b', '0x42'
7. sender IP Address (4바이트) : '0xc0', '0xa8', '0x3', '0x60', = 192.168.3.96
8. Target Mac Address (6바이트) : '0x0', '0x0', '0x0', '0x0', '0x0', '0x0',
     -> 모르니까 0으로 비워서 보내는 것이다.
9. Target IP Address (4바이트) : '0xc0', '0xa8', '0x3', '0x67'

그 뒤 0들은 프레임맞추기위해 집어넣은것이다.
-> 윈도우즈는 정기적으로 주기적으로 주변 host들에게 맥주소를 물어보는 작업을 한다. (3분? 정도마다)
  그리고 ARP 캐쉬테이블에 넣어둔다.
   커맨드 창에서 arp -a   로 확인할 수 있다.

 

 

 

(윈도우즈 ARP 캐쉬 테이블을 확인할수있다.)

 

 

다음주부터는 패킷을 직접 만들어볼것이다.

* 팁
 집에 갑자기 인터넷이 안될때 검사
1계층 - 잘 꼽혀있는지
2계층 - 나랑 게이트웨이가 통신이 잘되는지 확인
 - 게이트주소에 ping
게트웨이까지는 잘가는데 인터넷이 안되면
게이트웨이의 포워딩이 문제거나
통신사업자에서의 문제거나
3계층...
핑까지 서버에 잘 되는데 웹툰이 안보일때.
-> 이 때는 DNS 문제일 가능성도 있다.  nsloopup 이 안되는 경우가 있다.


또 오늘은 패킷을 보기 쉽게 한번
디자인해보았다.
코드를..

 

 

 

 (깔끔하게 구성된 화면)

오늘은 어제 작성했던 패킷을 덤프하는 프로그램작성을 완성시켰다.

TCP의 데이터까지 출력할 수 있게 만들었다.



(패킷 덤프 프로그램 코드)




(실행결과.(왼쪽-패킷내용, 오른쪽-TCP 통신프로그램))



이 때 Data를 보내는데 TCP에서 많은 패킷이 왔다갔다 한 것을 볼 수 있었다.

TCP헤더의 flag 필드를 보면 패킷의 용도를 확인 할 수 있다.

* TCP는 통신하기 앞서 동기화과정이 먼저 들어간다.


(SYN 패킷)


위 캡쳐한 패킷을 보면 Flag가 SYN으로 나와있다.
캡쳐한 패킷내용을 보면 IP주소 165가 client고  239가 server여서 server로 동기화 요청하였다.



(SYN-ACK 패킷)



그 다음으로 서버측에서 SYN-ACK 패킷을 보내오는 것을 확인할 수 있다.
ACK 패킷은 응답을 주는 것이다. 또 서버측도 내게 동기화를 맞춰야해서 SYN패킷을 보낸다.



(ACK 패킷)



마지막으로 클라이언트쪽에서 서버로 응답 ACK 패킷을 보내는 것을 확인할 수 있다.
여기서 데이터도 같이 보냈는데,
지금 상황에서는 데이터보내는 겸 같이 ACK 패킷을 전송한 것이다.
바로 이런식으로 보내는 것을 Piggyback이라고 한다.

바로 위에서 본 것이 3 Hand Shaking 과정을 본것이다.
3 Hand shaking은 데이터를 주고 받기 전에세션을 맺는 과정이다.

전에 확인했던 걸 생각해보면
TCP에는 상태라는 게 있었다. (Listen, Established...)
그래서 Listen 상태일 때 SYN패킷이 오면 응답을 해주고 쓰리핸드쉐이킹과정을 할 수 있다.
Listen 상태가 아니면 응답을 못해주게 된다. (이점이용하면 SYN Flooding 공격을 할 수 있다.)

3 Hand shaking이 진행됨에 따라 서버측의 상태변화
Listen -> Syn receive -> sysn sent -> established

* 세션을 끝낼때는 4 Hand 쉐이킹 과정이 있다.
  이건 나중에 확인해 보겠다.

* Syn 패킷에 들어있는 시퀀스 넘버를 ISN (Initial Sequence Number) 초기 시퀀스번호라고 한다.
-> 서버에게 나를 식별할 수 있는 번호를 보내준다. 서버와 클라이언트는 이 시퀀스 번호를 서로를 알아본다.
-> SYN 패킷의 목적은 이 ISN을 서버에 전달하는 목적이다.

3 Hand shaking 동작 내용.
1. 클라이언트는 SYN 패킷에 ISN을 넣어서 보낸다.
2. 서버도 SYN-ACK 패킷으로 응답을 한다. 이 때 서버의 ISN을 생성해서 클라이언트에 보내면서 응답을 한다.
(서버의 ACK 필드에는 클라이언트의 시퀀스넘버에 1을 더한 값이 들어간다.)
그래서 이 시퀀스 넘버가 틀어지지 않는 이상 이 연결은 유효하다.
3. 클라이언트는 ACK 패킷을 전송한다.


* 세션 하이재킹 -> 남이 로그인한 세션이 인증된 패킷 시퀀스 넘버를 예측해서 그 값을 데이터로 만들어서 보내면 서버에 로그인할수있다.

-> 시퀀스 넘버는 서로 주고받는 크기만큼 늘어난다.
* ACK -> 잘 받았다는 응답이다.
만약 이 패킷을 못받으면 잘 안간줄 간주하고 다시 보낸다.
이게 TCP가 가지고있는 에러정정(Error Control)이다.

이걸 응용하여 다음 ACK응답으로 올 번호를 예상하여 출력해보았다.



(추가한 코드)


(예상 다음 ACK 번호와 일치)



확인해보면 다음 받을 ACK 번호랑 예측한 값과 같음을 확인할 수 있다.

* IP에 관해 이야기를 시작하겠다.

Layer 3
 - IP - 경로 설정
       - 네트워크 상에서 호스트를 식별하는 식별자(IP주소)로도 사용한다.
       - 라우팅 프로토콜이 들어간다.
 -> ( 라우팅 프로토콜을 이용하여 취약점을 공략해 공격할 수 있다.)

 PDU : Packet (IP 패킷)
 - 라우팅 장비가 IP주소를 보고 어디로 보낼지 결정한다.

IP address
 -> IANA에서 IP주소 관리, 할당, 표준 제정등을 한다.
     - IPv4, IPv6

- 주소의 분류 (체계적으로 관리하기 위해서)
: IPv4의 주소 체계이다.
 - 4자리 자연수를 '.' 으로 구분해서 표기한다.
 - 1자리 수는 0~255까지 표현이 가능하다.
    전체 사용가능한 ip주소 범위 -> 0.0.0.0 ~ 255.255.255.255
   -> 실제 사용 불가능한 주소가 있다.
   ex)  0.0.0.0    ( 모든 ip를 의미한다. ) 
        255.255.255.255  (브로트캐스팅 주소)
: A class, B class, C class, D class, E class

IP 주소 클래스

A Class
 -> 앞에 한자리가 구역을 나타낸다. 이것을 network id라고 표현한다.
 -> 나머지 세자리는 host id이다.
 -> 네트워크 id : 첫번째 자리
 -> host id : 나머지 세 자리. (host를 구별하기위해 사용)
 -> 맨 앞 1비트가 0으로 공통이다.
ex) 1.xxx.xxx.xxx
    10.xxx.xxx.xxx
-> 2진수로 표현하면 0000 0000.hhhh hhhh.hhhh hhhh.hhhh hhhh
-> 맨 앞비트가 0이어야한다. 즉, 0000 0000 ~ 0111 1111 까지 표현 가능하다.
 -> 10진수로 따지면 1.h.h.h(10) ~ 126.h.h.h 까지 가능한 A클래스 주소 범위다. (0도 안된다.) (127도 가상ip주소이므로 사용못한다.)
 -> 또 10.h.h.h 도 사용하지 못한다. -> 사설 IP주소이다.
 -> 127로 시작하는건 loop back 주소로 자기자신을 표현하는 IP주소이다.
 ex) 1.0.0.0 ~ 1.255.255.255 ( 1.h.h.h 주소를 가지고 있다면, 이만큼 쓸수 있는 것이다.)
  -> 1.0.0.0 (x)
  -> 1.255.255.255  (x)  
  -> 이 두개는 사용하지 못한다. 이유는 1.0.0.0 은 1.h.h.h를 대표하는 IP주소이고
      1.255.255.255는 1.h.h.h 네트워크에 있는 전체에 보내는 브로드캐스트주소이다.
      실제 사용 가능한 주소는 1.0.0.1 ~ 1.255.255.254 이다.






저번주까지 UDP 패킷분석, 그리고 IP 패킷을 분석하였다.

오늘은 TCP 패킷을 분석해보았다.

TCP는 UDP와 달리 조금 까다로운 부분이 많았다.

포함관계를 다시 정리하자면

IP 패킷안에 TCP 혹은 UDP가 들어가는 것이다.

저번주 까지 했던 패킷을 덤프받는 프로그램에서
이제 IP헤더를 분석할 수 있었고
그에 따라
소스 IP주소와 목적지 IP주소를 파악할 수 있었으므로

조금 더 정교한 필터링을 할 수 있게 되었다.



(조건 문에 IP주소로 필터링 하는 코드)


또, IP 헤더에서 Protocol 타입을 알아낼 수 있으므로
TCP, UDP, ICMP를 구분하기로 했다.



(Protocol 필드로 구분하는 모습)


위 코드를 보면 이제 TCP 헤더를 분석해볼 것이므로
처음에 list를 이용해 16진수로 표현해보았다.




(오른쪽화면은 저번주에 만들었던 TCP 메세지전송 프로그램.)


위 화면을 보면 TCP 데이터가 나오는 것을 확인 할 수 있다.

UDP와 다른점은 UDP는 메세지 하나 보내면 끝이었는데
TCP는 그 전에 많은 패킷들이 왔다 갔다 한다.
자세한 특징은 다음에 더 알아보겠다.
우선,
TCP 패킷의 헤더를 분석하는 것이 먼저다.

우리가 덤프받은 TCP 패킷의 헤더
['0xc3', '0x29', '0xea', '0x60', '0x2a', '0x4', '0x15',
'0x1a', '0x0', '0x0', '0x0', '0x0', '0x80', '0x2', '0x20', '0x0',
 '0xd9', '0x88', '0x0', '0x0', '0x2', '0x4', '0x5', '0xb4', '0x1', '0x3',
'0x3', '0x2', '0x1', '0x1', '0x4', '0x2']

내용은 이렇다.
1. 출발지 포트번호(2바이트) : '0xc3', '0x29' = 0xc329 = 49961
2. 도착지 포트번호(2바이트) : '0xea', '0x60' = 0xea60 = 60000
3.  Sequence Number(4바이트) : '0x2a', '0x4', '0x15', '0x1a'
- 운영체제에 의하여 랜덤하게 시작된다. Session을 표현하는 고유값이다.
4. Acknowledge Number(4바이트) : '0x0', '0x0', '0x0', '0x0'
*'0x80' -> 8과 0으로 본다.
5. TCP 헤더의 길이 (4비트) -> 8 (x4) = 32바이트
6.  예약된 영역 : 0 (사용하지 않는 필드이다.)
7. Flag : '0x2' = 2 (여기서는 SYN패킷, 동기화요청)
Flag 종류
1 : FIN
2: SYN
4: RST(reset)
8: PSH(push)
16: ACK(응답)
32: URG(urgent) 
(만약 동시에 설정된다면, 예를들어 SYN과 ACK가 같이 설정되면 두개의 합이된다.)
(ex. SYN-ACK 은 18번이 된다.)

8. window size (2바이트) : '0x20', '0x0'
9. TCP의 Checksum(2바이트) : '0xd9', '0x88'
10. Urgent Pointer(2바이트) : '0x0', '0x0'
---- 여기까지 딱 20바이트다.-----------------

그 이후로 옵션이 더 붙어서 패킷이 보내질 수도 있다.

자. 그러면 이제 이 내용을 바탕으로 헤더내용을
분석하여 출력해보겠다.


(TCP 패킷 분석코드)


(TCP 헤더 분석 내용)



여기서
Header 길이를 표현하려면 아까 한 바이트를 4비트로 나누어야한다.
이제 그 작업을 시작하겠다.

0x45를 4와 5로 분리하는 것이다.
먼저 0x45를 2진수로 변환한다. (bin()함수 사용)

그 후 슬라이스로 4개씩 자르고 int로 형변환 해준다.
아래와 같다.


(분리된 모습)



이걸 이용해
IP 헤더의 버젼과 헤더길이를 나누고
TCP의 길이를 구하겠다.

또 IP헤더에서 헤더길이를 정확하게 구할 수 있고 그러면
UDP,TCP 패킷이 어디서부터 시작하는지 또한 정확하게 표현할 수 있다.

(지금까지는 그냥 IP헤더가 20바이트라고 가정하고 했었다.)




(헤더 길이를 분리하는 코드)



(UDP의 시작 슬라이스와 TCP 헤더 길이, 또 flag를 표현해 수정해주었다.)



flag를 dictionary로 정의하여 키값을 대입하면 그에 대응하는 값이 출력된다.



(결과 화면)



지금 까지 TCP패킷을 분석해보았고

IP헤더도 더 정밀하게 분석하였다.

내일은 현재 진행중인 패킷 분석 프로그램을 조금 더 수정하고
본격적으로 패킷을 확인하고 변조해 보겠다.









어제
UDP를 이용해 데이터를 주고받는 프로그램을 만들었고

그 데이터를 덤프시킬 프로그램도 만들었었다.

이제 그 데이터를 분석해보겠다.


(어제 했던 Hello 데이터를 전달하는 UDP 패킷내용)


Hello 앞에 나오는 헤더부분을 살펴보자.
b'E\x00\x00!\x11\xf6\x00\x00\x80\x11\x9f\xf1\xc0\xa8\x03\xa5\xc0\xa8\x03\xef\xce\x89\xea`\x00\r\x9a2
(이건 오늘 실행시켜서 복사한 패킷헤더이다.)

\ (역슬래쉬)
\x 로 표시는 16진수 표시이다.

왜 어떤건 문자로 나오고 16진수로 나올까?
-> 문자로 나올수 있는 것은 문자로 나온다.
16진수 중에 문자로 표시할수 있는건 문자로 표시한다. (이것도 16진수)
(아스키 코드에 따라)

앞에 b라고 붙어있다. -> 실제 네트워크 스트림에 사용하는 데이터가 파이썬에서 맞지 않는다.
       -> 그래서 C에서 API를 가져온다.
       -> C언어가 쓰는 바이트타입을 가져온것이다.
       -> 그래서 다시 파이썬에 맞게 바꾸는 함수가 있는데,
           그건 - pack()
                  - unpack()
             함수이다.

이 함수들은 struct 모듈 안에 들어있다.


(unpack의 사용 모습 (파이썬공식홈페이지 출처))


hhl 표시  -> 각각 2바이트 2바이트 4바이트로 묶어서 출력하라는 뜻이다.

우리는 앞에부터 20바이트는 뺄것이다. 이 패킷은 IP헤더이기 때문에
20바이트 뒤부터 분석을 해볼 것이다.


(slice로 앞 20바이트는 잘라내는 모습)



(IP헤더는 떨어지고 UDP 패킷내용만 남은 모습)



여기서 unpack을 사용하지않고
list를 사용해 전부 hex 표시로 바꾸겠다.

* map() 함수 - 두번째 인자를 첫번째인자(함수)에모두 입력한다.
hex 또한 함수이기 때문에 지금 쓰는것은 두번째 인자를 모두 16진수의 수로 바꿔주는 것이다.

(hex 표시로 바꿔주는 코드)



(16진수로 표시되는 모습)



전부 16진수로 나오는 모습이다.

뒤에 다섯자리 '0x48', '0x65', '0x6c', '0x6c', '0x6f' 를 아스키코드에 대입하면
Hello 라고 우리가 보내는 데이터임을 알 수 있다.

그리고 데이터 앞자리 우리가 구한 UDP헤더의 내용이다.
['0xcc', '0xe8', '0xea', '0x60', '0x0', '0xd', '0x9b', '0xd3']

헤더에는 총 4개의 내용이 들어있다. (첫번째 부터)

1. Sorce Port Number (출발지의 포트번호) 
     ->2바이트 (출발지 포트)

2. Destination Port Number (출발지의 포트번호) 
     -> 2바이트 (도착지 포트)  '0xea', '0x60'  = ea60  = 60000
3. Length (길이) 
     -> 2바이트  = '0x0', '0xd  = 0d   =13  = 13바이트 
(헤더 8바이트, UDP데이터 5바이트) 13바이트가 맞다.

4. Checksum
     ->2바이트   검사용

-> 이런게 Protocol 프로토콜이다.
처음에는 데이터 Hello가 보내지는걸  봤는데 이제 Hello가 패키징 되면서 붙는 내용들을 확인한다.
그 과정중 하나가 UDP를 본것이다.

UDP 헤더의 내용은 4개 밖에 없다. -> 에러정정, Flow Control 등 기능은 없다.

* 바이트
1 바이트로 숫자 하나를 표현할 수 있다. 16진수 2자리를 표현할수 있는 것이 1 바이트 (0x00 ~ 0xFF)

이제 unpack을 이용해 좀더 정확하게 데이터를 출력해보겠다.

H -> 2바이트를 묶어서 하나로 만들어준다.
! -> network stream 데이터를 읽어들일때는 !를 붙여준다.
 붙이는 이유 네트워크에서 돌아다니는 데이터랑 컴퓨터에서 다루는 데이터랑 다르다.
 그래서 ! 느낌표를 붙여서 네트워크 데이터라라는것을 알려줘야한다.

이제는 조금 구분 할 수 있게 됬다.


(UDP 헤더 패킷 분석 코드)


-> 목적지 주소가 60000 포트인 경우에만 출력한다. (내가 60000번 포트로 패킷을 전송할거기 때문에
       내가 보내는 패킷의 정보가 궁금한 것.)


(UDP 헤더 분석)



지금까지 Hello라는 데이터를 UDP로 보낼때의 패킷 내용들을 분석해 보았다.

윈도우 소켓으로 볼수있는 것은 L3 까지 볼 수 있다.

- Layer 4 ( Transport Layer ) 의 프로토콜(UDP, TCP)
- L4에서는 데이터가 어디서 어떻게 전달되는지 해당 계층에서는 상관이 없다.
- 에러 정정(UDP에는 없다.), 흐름제어(UDP에는 없다.), 이런 내용만 포함하고 있다.

- L4에서는 관련된 정보만을 포함한다.
-> UDP의 checksum에서는 오류가 났는지 안났는지만 판별 오류났으면 버린다. 그 외의 행동은 하지 않는다. 그래서 에러정정의 기능이 없다고 말한다.


* UDP인지, TCP인지 어떻게 판별할까?
: 더 하위계층에서 그 내용을 가지고 있다. -> IP 패킷

우리가 잘라냈던 IP헤더를 보면 UDP인지 TCP인지 확인할 수 있다.
socket 생성시 PROTOCOL 부분을  IPPROTO_UDP 를 IPPROTO_IP로 바꾸었다.



(socket 타입 변경)


UDP = User Datagram Protocol

IP 헤더 ( Internet Protocol Header )
-> L3 ( Network Layer (네트워크 계층) )
-> IP는 해당 계층의 대표적인 프로토콜이다.
-> 데이터를 송신지에서 수신지로 향하게 하는 데이터의 전달과 밀접한 관련이 있다.
-> 주요목적은 전송경로 설정 등이 있다.
-> 경로에대한 담당은 라우터가 하는것이다. 즉 IP헤더에는 IP주소만 적혀있고 라우터가 IP주소를 보고 경로를 설정한다.
-> 사이즈는 기본 20바이트이다. (추가로 옵션이 있긴하다.)
현재 우리가 보는 것은 IPv4의 IP헤더 이다. IPv6는 또 조금 다르다.

Layer2, Layer1의 내용들은 현재 윈도우즈 환경에서는 지원하지 않는다.
윈도우즈 소켓은 Layer3 까지 밖에 지원이 안된다.

이제 IP헤더를 분석해 본다.

(list를 이용해 출력하는 코드)



(IP 헤더 출력 모습)



출력한 IP 헤더
['0x45', '0x0', '0x0', '0x21', '0x35', '0xd3', '0x0', '0x0',
'0x80', '0x11', '0x7c', '0x14', '0xc0', '0xa8', '0x3', '0xa5',
'0xc0', '0xa8', '0x3', '0xef']

ip 헤더 분석
총 20바이트로 되어있다. 

첫번째 바이트 숫자 하나가 2개의 값을 의미한다.
   0x45  -> 4랑 5로 읽을 수 있다.
1. Version -> 맨 앞 4 = IPv4
2. Header length -> 그 뒤 숫자 5 = 헤더의 길이 : 4를 곱해준다. 5x4 = 20 바이트  헤더의 길이다.
3. Service  -> 현대 IPv4에서는 사용하지 않는다. 거의 항상 0으로 초기화된 값이 들어간다.  : 0x0'
4. Total length (전체길이) : 그다음 숫자 2바이트 '0x0', '0x21' = 0x021  = 33바이트
    ( Ip헤더 20바이트, udp패킷 13바이트 )
5. Identification (식별자) : 그다음 숫자 2바이트 '0x35', '0xd3'
6. Flag ->  '0x0'
7. Fragment OFFSET ->  '0x0'
* IP패킷은 여러개로 분할 될 수도있다. 그래서 5,6,7 정보가 필요하다.
    자세한 내용은 다음에 확인하겠다.
8. TTL (Time to live) -> '0x80'  = 128.  ( 윈도우즈에서 만들어진 패킷은 기본적으로 128로 나간다.)
 TTL은 네트워크를 방황하는 패킷들을 예방하기 위해서 있다.
 TTL은 라우터를 한 Hop이라고 지날수 있는 Hop의 수이다.
9. Protocol 타입 -> '0x11' = 17 :  (udp :17번) (tcp:6번) (ICMP: 1번)
10. Header checksum -> '0x7c', '0x14'  checksum은 각 헤더마다 들어있다.
11. 출발지 IP (4글자) : '0xc0', '0xa8', '0x3', '0xa5'  -> 192  168  3  165  
12. 도착지 IP (4글자) : '0xc0', '0xa8', '0x3', '0xef


-> 전송에 관련된 내용들을 가지고 있다.
1,1,2,2,1,1,1,1,2,4,4 개씩 unpack하면 된다. 위 데이터를 끊는 개수이다.



(IP 헤더 내용을 쪼개어 출력하는 코드)



(IP 헤더 분석)


IP 헤더에 무슨 내용들이 있는지
어떤 역할을 하는지
확인하였다.

또, UDP 패킷도 함께 분석하였다.

-> 나중에 이걸 이용해 패킷 스니퍼를 만들것이다.
(비슷한 원리로 만들것이므로 기억해둬야한다.)













어제 하던 통신프로그램을 보완해서

그럴싸한 통신을 하는 프로그램으로 업그레이드 했다.



(while 문을 이용해 메세지를 종료할 때 까지 통신하는 코드)


(메세지를 주고받는 모습)


(맨 아래줄에 보면 외부 IP주소와 포트번호가 나와있다.)



위 화면에서 외부주소 맨 아래를 보면 상대 IP주소와 포트번호가 나와있다.

코드에 적힌 대로 IP주소와 포트번호로 연결된것을 확인할 수 있다.

현재, 이 프로그램은 동기식 통신이다. 즉 한번 보내고 한번 받고 해야하는 방식이다.

여기서,

상대와 보통 채팅처럼 비동기식으로도 만들 수 있다.
내가 보내지않아도 상대가 마음껏 보낼 수 있는 상태로.

그러려면
Thread를 이용해야한다.

하나는 send만 하고 하나는 recv만 하도록 쓰레드를 열어서 실행해야한다.

하지만 현재 우리는 네트워크를 이해하는 차원에서
여기 까지 하겠다.

우리가 패킷을 분석하기 위해 만드는 프로그램이기 때문이다.

우리가 위에서 보낸 메세지나
네트워크에서 주고받는 데이터는
전달하기위해 여러가지가 붙어서 패킷을 만들어 전달된다.

이런 규칙들이 프로토콜인데
4계층의 TCP, UDP를 알아보겠다.

먼저 파이썬 코드로 어떻게 동작되는지 두 프로토콜의 차이점을 봐야한다.

동작 과정

* TCP server
 1. socket()
 2. bind()
 3. listen()
 4. accept()
 5., send(), recv()

* TCP Client
 1. socket()
 2. connect()    -> server의 accept와 연결된다.
 3. send(), recv()

* UDP server
 1. socket()
 2. bind()
 3. sendto() ,recvfrom()

* UDP server
 1. socket()
 2. sendto(), recvfrom()
-> send()를 못쓰는 이유는 send는 연결되어있는 곳으로 보내는건데
UDP는 연결된게 없으므로 sendto()로 그때그때 어디로 보내는지 적어줘야한다.

UDP의 특징
-> 연결과정 없이 바로 보내고 받는다.
-> 데이터가 갈수도있고 안갈 수도 있다. 그래서 TCP는 신회성이 있는 통신이다. 왜냐하면 안갔는지 갔는지 체크하기 때문이다. TCP는 체크하지만 UDP는 체크하지 않는다.
-> UDP는 신뢰할 수 없는 통신이다. ( 이말은 상대가 받았는지 체크할 수 없다는 뜻)
-> 인증 절차도 없다. 그냥 보내고 그냥 받는다.
보통 UDP를 사용하는 프로그램은 보통 인증과정이 없다.
UDP자체로는 인증을 할 수 없다.

그렇다면 왜 쓸까?
  위 말만 들으면 왜쓰는 걸까 싶지만 UDP의 큰 장점은 복잡하지않고 빨리빨리 보낼 수 있다는 것이다. 보내는 데이터가 크지 않다면 UDP가 적절하다. UDP는 에러체크등이 없고 그냥 보내기만 하는 것이다. 그래서 사실 예전에는 많이 쓰이지 않았다. 하지만 요즘 많이 쓰이고 있는것이 실시간 통신이 필요할 때 특히 UDP를 많이 쓴다. 빨리보낼 수 있고 에러 났다고 다시 보낼 필요가 없는 실시간 통신에 적합하다. 혹은 짧은 데이터 같은 경우가 적합하다.

- netstat -anp UDP
입력하면 UDP 포트 정보를 볼 수 있다. 여기에 상태 정보가 없다. 연결과정이 없기 때문이다.


(상태 부분이 없다.)


파이썬에서 UDP에 사용되는
recvfrom() 함수.
-> 받아온 내용보면 클라이언트 정보도 같이 출력된다.


(맨 아래 데이터와 데이터가 날라온 IP주소와 포트정보)


-> 튜블정보이므로 ip주소와 포트번호를 따로 입력받아서 출력해 봤다.


(튜플정보를 따로 받아와 출력한 모습)


TCP, UDP  -> Layer 4 (4계층)에 속한다.
-> 전송계층 (Transport Layer)

* PDU : Protocol Data Unit


-> packet : 패킷, 3계층에서 사용되는 단위
    근데 그냥 보내는 데이터 덩어리를 패킷이라고도 한다.


L4에서는 pdu가 segment 다.

-> 주소 체계 : Port번호

-> 각 계층별 사용하는 단위와 주소가 다르다.


패키징
-> Hello 데이터를 패키지화한다. 포장하듯이.
-> UDP 헤더를 붙인다. 데이터 앞에

헤더에 어떤 정보들이 들어가있는지 정해논다 -> 규약 Protocol

프로토콜에 맞게 데이터를 패키징해서 다음 계층으로 보낸다.



UDP 헤더에는 어떤 정보가 들어있을가?


UDP Header

 - dst Port 번호, src Port 번호
 - data length, checksum



-> 직접 확인해본다.

(먼저 패킷 데이터를 덤프받을 프로그램을 만들었다.)


socket.gethostname() 을 이용하면 컴퓨터의 이름을 얻어올 수 있다.

gethostbyname() 을 이용하면 이름을 가지고 호스트 정보를 가져올 수 있다. (IP정보)


-> 여기서 포트번호에 0을 쓴이유는 특정포트를 보기위해 하는게 아니라 특정 IP에 모든 포트들을 확인하는 것이다.


(여러번 실행한 경우)


뭔지 모를 데이터들이 오고가는 모습이다.


그러면 우리가 오늘 바로 작성한 UDP로 패킷을 보내고 이 패킷의 내용을 확인해보자.


(코드)


위 코드를 보면 info[0]에는 IP정보가 들어가므로 IP주소가 내꺼인 주소만 보겠다는 것이다.

이걸 안하면 이것저것 위에서 본거 처럼 구별하기가 힘들어서 그렇다.


이제 내가 UDP로 패킷을 보내고 이 프로그램으로 확인 해 볼 것이다.

보낼 데이터 : Hello


(출력 화면)


그림은 클릭하면 크게 보인다.


출력화면을 보면 끝에 Hello라고 적혀있는것이 보인다.

그리고 그 앞부분은 헤더의 내용이다.

UDP는 헤더에 많은 내용이 들어간다고 안햇는데 왜이렇게 길지???..


그건 UDP헤더만 붙는게 아니기 때문이다.


아래 계층으로 내려가면서 패키징되는데 점점 헤더가 붙어서 늘어나기 때문이다.


이제 앞으로 이 헤더 정보, 데이터 정보를 구별하여 읽는 법을 공부할 것이다.


다른 패킷을 분석하여 어떤 정보가 오고가는지 확인할 수 있게 될 것이다.







+ Recent posts