* 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 이 안되는 경우가 있다.


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

 

 

 

 (깔끔하게 구성된 화면)

자바 5.0 이후로 추가된 문법이다.

자바에서 제공하는 많은 라이브러리를 활용하려면
제네릭에 대해 이해하고 있어야한다.

많은 라이브러리가 제네릭으로 이루어져있기 때문이다.

제네릭이란

매개변수가 어떤 값이 들어와도 성립하도록 그 때 그 때 바뀌게 만든
쉽게 말하면
모든 값에 대해 이루어 질 수 있게 하는 것이다.

예를 들면
AAA class로 참조 받아야하는 클래스가 있다.
이 클래스는 제네릭이 아닌 그냥 설계한다면
AAA class만 받을 수 있다.

그렇기에 BBB class에 관한 그 클래스를 만들고 싶으면
또 만들어야한다.

하지만 이 것을 제네릭으로 만들면 하나만 만들어도 된다.

그 하나가 AAA 일때는 AAA에 맞춰 생성되고
BBB일 때는 BBB에 맞춰 생성되기 때문이다.

표현 방법은


class FruitBox<T>
{ T item;
...
}


위는 과일 상자를 제네릭으로 표현한 것이다. < > 안에 T는 기호이다.
저 클래스에 AAA를 참조하려하면 제네릭 클래스 안에 표시한 T기호가 AAA로 바뀌어서 나타내어진다.

문제 21-1
FruitBox<T>클래스에 생성자를 추가해서 코드를 만들어보자.

(생성자 코드 추가)



위 코드는 생성자를 추가한 코드이다.
제네릭 표현으로 클래스 앞에 < > 기호를 쓴것과 아래 표현하고 싶은 클래스를 기호 T로 쓴것을 제외하면
일반적인 표현 방법과 다르지 않다.

제네릭의 문법은 생각보다 복잡하다.
제네릭을 직접 만들 일은 적겠지만,

대신 우리는 제네릭으로 이루어진 라이브러리를 잘 활용해야할 필요가 있다.

제네릭 표현에 제네릭 메소드도 있다.
이 메소드에 참조되는 값은 제네릭클래스와 마찬가지로 전부 올 수 있는데
이렇게 되면 Object 클래스의 메소드만 호출할 수 있게된다.

왜냐하면 모든 경우에 대비해야되기 때문에..

이런 문제점 때문에

참조변수를 제한하는 방법이 있다.

많이 사용되는 배열을 제한하는 방법으로는

ex)


public static <T> void showArrayData(T[] arr)

{ ....

}

[] 의 표현으로 들어오는 타입을 제한할 수 있고
또 추가적으로 arr의 .length라든가 배열의 메서드를 이용할 수 있게된다.

* 와일드 카드

자료형에 상관없이 FruitBox<T>의 인스턴스를 참조하려면


FruitBox<?> box;

라고 표현하면 된다. 여기서 '?' 기호는 어떤값이 들어와도 된다는 뜻이다.

(* 참조 - 난 JAVA를 공부한 적이 없다구요, 윤성우)


지금까지 배운 내용들로

다양한 클래스들을 이해해보겠다.

자바에는 다양한 클래스들을 지원해주는데
오늘 알아볼 클래스는
 Wrapper, BIgInteger, BigDecimal, 난수 생성 함수, 문자열 토큰 이다.

1. Wrapper 클래스

Wrapper 클래스는 기본 자료형의 데이터를 인스턴스화 시키는 클래스이다.
Wrapper란 말 그대로 감싸고 있다는 것이다.

데이터 클래스를 의미한다.

이런걸 Boxing 이라고 하고 반대는 Unboxing이라고한다.
자바5.0부터는

Auto Boxing, Auto Unboxing이 지원 되서
클래스 생성선언 없이도 바로 생성되어 지원된다.

ex)


Integer iValue = 10; // auto boxing
Double dValue = 3.14;
int num1 = iValue; // auto unboxing
double num2 = dValue;


문제 20-1
static 메소드를 이용하여  Boxing 해보아라.

(valueOf(); 메소드 사용)





(실행 화면)



이러한 Wrapper 클래스안에 valueOf 의 메소드가 있다. 이 값을 이용하면 Wrapper 클래스의 인스턴스를 생성할 수 있다.

그런데 결과 화면을 보면 동일한 인스턴스라고 나온다.

저장되는 데이터는 문자열과 같이 수정이 불가능하다. 그렇기 때문에 메모리 효율 상 같은 인스턴스를 여러개 만들 필요가 없는것이다.
값을 변경하려면 새로운 인스턴스를 만들어 참조값을 변경해주면 된다.

현재 iValue1 과 iValue2는 같은 인스턴스를 참조하고 있다.


2. BigInteger, BigDecimal 클래스
매우 큰 수( BigInteger)
가장 표현범위가 넓은 long형으로도 표현이 불가능한 수를 표현할때 사용한다.
ex)

BigInteger bigValue1 = new BigInteger("10000000000000000000000000000");


왜 입력을 문자열로 넣을까?
그 이유는 정수로 넣게되면 그 정수를 옯겨줄 매개변수가 필요한데
가장큰 long형으로도 커버가 안되기 때문에
문자열로 입력해야하는 것이다.

BigDecimal
-> 정확한 소수점 표현

처음 자료형을 배울때 float나 double의 소수점 표현에
오차가 있다고 말했다.
하지만 오차가 없게 표현하려면
BigDecimal 함수를 사용하면 된다.
BigInteger와 같이 문자열로 입력된다.

문제 20-2
두 개의 실수를 입력받아 두 실수의 차를 절대값으로 계산하시오.




(BigDeciaml 이용 코드)




(실행화면)



결과를 보면 오차없이 계산된 것을 확인 할 수 있다.

3. 난수 생성

JAVA에는 java.util 패키지로 Random 클래스를 제공한다.
- boolean nextBoolean()   : boolean형 난수 반환
- int nextInt() : int형 난수 반환
- long nextLong() : long형 난수 반환
- int nextInt(int n) : 0이상 n미만의 범위 내에있는 int형 난수 반환
- float nextFloat() : 0.0 이상 1.0 미만의 float형 난수 반환
- double nextDouble() : 0.0 이상 1.0 미만의 double형 난수 반환

괄호() 안에는 seed 값이 들어간다.
default 값은 System.currentTimeMillis() 이다.
시간에 관련한 seed 값이 들어간다.

4. 문자열 토큰

- 문자열에서 구분자를 이용해 문자열을 구분하는 방법이다.
ex)
14:99 
위 글자에서 ' : ' 를 구분자로 하여 14와 99를 구분할 수 있다.


StringTokenizer st = new StringTokenizer("14:99", ":");

public String nextToken() // 다음 토큰 반환 메서드




(*참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)





Layer 1 - 물리적인 전송을 담당한다.
            - 전기 신호
 ex) 허브에 스타토폴로지로 host들이 연결되있다.
 한 host에서 전기신호를 보내고 그 전기신호를 수신하여서 데이터를 주고받는다.

Layer 2 - 데이터 링크 계층
 
 - 터널링관련 프로토콜 : PPP, L2TP, ...
 - 라우팅이 필요하지 않는 계층
 - 라우팅없이도 통신이 가능하다.
- 이더넷, 토큰링방식
 토큰링 방식 (토큰을 가진사람만 보낼 수 있고, 그 토큰은 네트워크를 돌아다닌다., 충돌을 예방하는 방법이다.)
  - 단점 : 토큰이 돌아서 내 차례가 될때까지가 오래걸린다.
 이더넷 : Collison Domain (충돌을 이용한다.)
 이더넷 헤더 (고정 : 14바이트)
 -우리는 보통 이더넷을 사용한다.

* 각 계층별 주소
L4 - Port Number
L3 - IP Address
L2 - MAC 주소. (Media Access Control) : 하드웨어 주소
 - 16진수 6자리  (유일한 주소)

 L2까지 합하면 패킷의 구성은
 
   - 이더넷 + IP + TCP/UDP + 데이터

지금까지 IP, TCP/UDP, 데이터까지 보았다.
 
기존에 만들었던건 윈도우즈 소켓을 이용해 패킷을 덤프했던 것이다.
이 윈도우즈소켓으로는 L3까지밖에 확인이 안된다.
그래서
L2까지 보기위해 다른 방법을 사용해보겠다.

새로 만든 모듈을 이용했다.



(모듈로 설정한 get_device)





(실행화면)



어떤 장치로 들어오고 나가는 내용을 화면에 출력할지를 정해야한다.
화면에서 Microsoft 라고 나온것이 무선어댑터 지금 사용하는 것이다.

 실행하면 인터페이스를 선택하라고 나온다.
이 때 여기서 나오는 인터페이스란

제어판에서 네트워크 정보에갔을 때 나오는 목록이다.
이 목록은 컴퓨터의 네트워크 장치이다.
이제 이 장치로부터 패킷을 가져와 열어보겠다는 것이다.





(두개의 어댑터)



이 화면은 집마다 다르다.

여기서 전에 소켓통신했던것과 유사하게
핸들러(장치를 다룰) 를 선언했다. 소켓과 비슷한 역할이다.

그 후 전에 덤프 프로그램과 비슷하게 작성해준다.



(패킷을 덤프받아 출력하는 코드)



이렇게 하면 전에 사용했던 프로그램과 비슷한 모양의 코드가 된다.



(실행 화면)



출력을 해보면 데이터가 출력된다.
캡쳐된 내용을 보면 앞에 14바이트 빼고는 지금까지 봤던 정보들이다.

앞에 14바이트는 이더넷프레임이다.


['0xff', '0xff', '0xff', '0xff', '0xff', '0xff', '0x90', '0x9f', '0x33', '0xeb', '0x34', '0xa1', '0x8', '0x0']

분석해보면
1. 도착지 맥주소(6바이트) :  0xff', '0xff', '0xff', '0xff', '0xff', '0xff
2. 출발지 맥주소(6바이트) : '0x90', '0x9f', '0x33', '0xeb', '0x34', '0xa1'
3. 프로토콜 타입(2바이트) : '0x8', '0x0'
                                          - 0x0800 -> IPv4  , IP 프로토콜
                                            0x8600 -> IPv6
                                            0x0806 -> ARP 프로토콜

통신을 하려면 MAC주소를 알아야한다. 하지만 우리는 IP주소만 알고있다.
그렇기 때문에
ARP 가 필요하다.
ARP : Address Resolution Protocol

이제 전에 작성했던 프로그램에서 L2까지 나오는프로그램으로 확장시켜본다.



(확장 코드)




(출력 화면)


출력 화면을 보면 이제 L2의 프레임 단위로 패킷을 확인할 수 있는것을 볼 수 있다.

이제 내일부터
이 내용을 가지고 네트워크를 살펴보겠다.





그렇다면 스택영역과 힙역역을 왜 구지 나누었을까?
-> 그 이유는 인스턴스 소멸시기와 지역변수 소멸시기가 다르기 때문이다.

* Object 클래스

- finalize 메소드
모든 Object 클래스에는 finalize 메소드가 있다. 이 finalize메소드는 함수가 소멸되기 전에 반드시 실행되어야하는 코드다.
인스턴스를 지칭하는 참조변수가 사라진다고해서
바로 사라지는 것은 아니다. 너무 빈번하게 일어나면 프로그램 성능에 문제가 될 수 있기 때문이다.

그래서 finalize를 인스턴스가 사라질때 반드시 실행시키고 싶다면,
System.gc();
System.runFinalization(); 
이 코드를 적어주면 된다.

- equals 메소드
== 연산자는 참조변수의 참조 값을 비교한다.
문제 19-1
equals 메소드를 삽입해 참조 내용을 비교해보자.



(equal 오버라이딩)





(equal 오버라이딩)




(비교 코드)




(실행 화면)



* 인스턴스 복사 clone

인스턴스를 복사하기 위한 메소드가 정해져있다.
protected Object clone() throws CloneNotSupportedException

이란 메소드로 정해져있다.

이 메소드를 쓰기위해서는 Cloneable 인터페이스를 구현해야한다.

왜냐하면 프로그래밍을 하다보면 복사에 민감한, 인스턴스들도 있다. 그런것과 복사해도 되는 것을 구별하기 위해서 표현하기 위해서
Cloneable 인터페이스를 구현하는지를 확인한다.

여기서 중요한건 clone으로 복사되는데
그 안의 변수들도 복사가 된다.
하지만 그 인스턴스 내부의 인스턴스는 복사되지 않으니 같은 참조값으로써 복삭가 된다.

결론적으로 말하면
인스턴스를 완전히 복사하기 위해서는
내부 인스턴스들 또한 같이 복사해줘야한다.

문제 19-2를 보면 이해가 될것이다.


(Business 클래스 복사)




(PersonalInfo를 복사하고 그 내부의 Business 클래스 복사)




이렇게 내부도 복사해주어야

중간에 값을 변경해도 다른 복사본에 영향을 주지 않는다.



(복사 후 내부 문자열을 바꾸는 내용)



(실행화면)



내부 문자열을 변경했어도 복사본에 영향이 없음을 확인 할 수 있다.

(*참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)



예외처리는

예상가능한 예외 지역에 대비해 처리해두는 것이다.

보통 지금까지 우리는
if문을 이용해 예외처리를 해왔다.

나누기연산에서 분모에 0이 들어가면 에러가 나니까
if문으로 0이들어오면 다시 입력해달라고 할 때
if문을 보통 사용했다.
하지만 JAVA든 모든 프로그래밍 언어에서 if문은 유용하게 사용되는 구문 중 하나이다.

그렇기에 예외처리가 아니더라도 많이 사용될 수 있고
그렇게 되면 예외처리부분을 찾기가 어려운 상황이 생길수 있다.

또, 예외처리를 따로 한다면
코드를 읽는데 더 쉽게 해줄수 있을 것이다.

JAVA에서는 이러한 예외처리를 위해
try-catch 구문이 있다.

try
   {
내용
   }
catch
{}

이런 형식으로 작성할 수 있다.

우리가 예외상황이 일어날 수 있을 것 같은 구문을 try로 감싼다. 그리고 바로 catch구문을 적어
예외상황이 일어나면 이렇게 처리하라는 내용을 적는다.
여기서 catch사이에 다른 구문이 들어갈 수 없다.

try로 감싼 부분이 끝나자마자 catch가 나와야한다.

이렇게 되면 catch영역이 실행되고나면 무조건 예외적인 상황이 적절하게 처리됬다고 판단하고 다음 실행으로 넘어가게 된다.

* 이때 중요한건 오류가 해결됬다는 건 아니다. 오류에대한 보고를 출력하고 그 부분을 넘어가겠다는 말이지 오류에 대한 해결책은 될 수 없다는 것이다.

예외처리는 예외 클래스를 이용해 가능하다.

알고있어야할 메소드
e.getMessage()

여기서 e는 예외처리의 클래스 변수다.
이 메소드는 오류에 대한 내용을 출력한다.

* finally

try catch 구문 바로 뒤에 finally를 쓰고 {}로 내용을 채우면

finally
{ }

이렇게 바로 나오면 try구문에 들어가자마자 무조건 그 finally코드는 실행되는 코드이다.

try영역으로 일단 들어가면 무조건 실행되는 영역
이 바로 finally 구문 안의 영역이다.
중간에 return이 되더라도 finally영역은 실행되고 나서 메소드를 빠져나가게 된다.


이러한 예외 상황을 프로그래머가 직접 정의할 수도 있다.
0으로 나누기를 한다던가 등등
자바가 직접 설정한 예외상황뿐 아니라 프로그래머가 직접 정의할 수도 있다.

예를들면,
나이를 입력하는데 0보다 작은 값을 입력하면
문법적으로 틀리진 않지만 논리적인 오류가 발생한다.

그렇기 때문에 이런예외상황은 자바머신은 인지하지 못하지만 사람들은
알 수 있고, 이걸 따로 처리해주고 싶다면
예외 클래스를 만들어야한다.


(예외 클래스 선언)



예외 클래스 선언이다. extends로 Exception 클래스를 상속받고 있다.
우리가 정의할 예외 클래스들은 모두 Exception클래스를 상속받아야한다.

또 위 코드를 보면 생성자에 문자열을 입력하고 있다.
이 구문은 예외상황이 발생하였을때 호출되어 출력되는 문자열이다.



(throw)



위 코드를 보면 나이를 입력하는 메소드에서 예외처리를 한 상황이 일어날 법하다.

하지만 이 코드에 try-catch구문이 없다.
이 예외상황을 누군가는 처리해야한다. 하지만 try-catch가 없고 대신
메소드 위에 throws 라고 적혀있다.

이 말은 자기는 안할꺼고 이 메소드를 호출한 부분으로 예외처리를 던지겠다는 말이다.
즉, 해야할 일을 넘기는 거다.



(try-catch)



나이를 입력받는 메소드에서 던져진 예외 처리가 바로 이 메소드가 호출된 지점으로 던져진다.
다행히도(?) 던져진 지점이 try구문으로 덮여있다.

그렇게 되면 try구문 안에서 예외처리가 일어났으므로 catch로 잘 넘어가
예외처리가 된다.

만약 try-catch구문이 전혀없고 심지어
main 함수 또한 throws를 한다면?

-> 그렇게 되면 자바머신이 예외처리를 한다.

* printStackTrace
-> 이 메소드는 마치 자바머신이 예외처리를 하는 상황과 비슷해진다.
-> 예외처리가 된 이유를 추적해서 어디서부터 잘못됬는지 화면에 보여준다.

정리하자면
예외처리상황은
try-catch문을 이용해서 예외를 처리하든
throws를 이용해서 던지든
해야한다.



* 전화번호 관리 프로그램 06단계

오늘 공부한 예외처리를 전화번호관리 프로그램에 적용시켜보았다.

1번부터 4번까지의 선택지중 다른걸 선택하였을 때
사용자에게 예외상황임을 알리는 것이다.




(예외 클래스)




먼저 예외 클래스를 정의 하였다. 메뉴선택예외이다. 이때 출력되는 구문은
"잘못된 선택이 이뤄졌습니다." 이다. 또 예외 처리시 선택된 choice를 매개변수로 받아와
어떤 선택은 없다고 다시 말해주는 메소드도 추가해보았다.



(초기 선택)




(예외상황 throws)


(try-catch 구문)



(정상적인 실행)



이로써 오늘 배운
예외처리를 이용하여
전화번호관리 프로그램도 6단계로 업그레이드 하였다.


(*참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)


어제 IP 주소의 A class 까지 알아보았다.

B class부터 살펴보면

B Class
 - 네트워크 id : 첫번째와 두번재 수를 사용
 - host id : 나머지 두자리를 사용
 - 공통비트 : 10
 
 ex)  1000 0000.0000 0000.hhhh hhhh.hhhh hhhh(2)
      1011 1111.1111.1111.hhhh hhhh.hhhh hhhh(2)
 -10진수로 바꾸면 앞자리가 128이다. (A 클래스가 127까지였고, B클래스는 128부터이다.)
 -128.0.h.h ~ 191.255.h.h (B 클래스 IP주소의 범위)

 ex) 한 네트워크에서 사용 가능한 호스트의 주소
  
  160.120 (네트워크)라면
  
  160.120.0.0 ~ 160.120.255.255
  
- 이 경우 사용 불가능한 주소
  160.120.0.0    -> 160.120 네트워크의 대표주소
  160.120.255.255  -> 160.120. 네트워크 안으로 브로드캐스트 하는 주소
  172 번으로 시작하는 것은 사설IP로 네트워크 ID로 사용할 수 없다.

C Class
 - 네트워크 id : 첫번째, 두번째. 세번째 수를 사용
 - host id : 나머지 한자리를 사용
 - 공통비트 : 110
 1100 0000.0000 0000.0000 0000.hhhh.hhhh(2)
 1101 1111.1111 1111.1111 1111.hhhh.hhhh(2)
 192.0.0.h ~ 223.255.255.h(10) (C 클래스 IP주소의 범위)

 - 사용불가능한 주소는 위의 규칙과 같다.
 - 192 번은 사설 IP로 사용할 수 없다.

D Class
 - 장비나 인터페이스에 설정이 불가능하다.
 - 즉, 사용할 수 없는 IP주소이다.
 
 - 멀티캐스팅 용도로 사용한다.

 - 공통비트 : 1110
 1110 0000.0000 0000.0000 0000.0000 0000
 1110 1111.1111 1111.1111 1111.1111 1111
 224.0.0.0 ~ 239.255.255.255(10) 

E Class
 - 장비나 인터페이스에 설정이 불가능하다.
 - 즉, 사용할 수 없는 IP주소이다.

 - 공통비트 : 1111
 240.0.0.0 ~ 255.255.255.255(10)
 -> 우리는 못쓴다. 예약된 주소로써 사용되지 않는다.

- 통신 방법
유니캐스팅 -> 1:1로 전달하는것이다.
멀티캐스팅 -> 특정 그룹에만 전체 전달하는 것이다.
브로드캐스팅 -> 연결되있는 모든 host에 전달하는 것이다.

위 주소들의 특징을 살펴보면 어떤 통신 방법으로 통신하는지
주소만 보고 알 수 있다.




(목적지 주소가 224.0.0.252)


주소를 보면 D Class에 해당하는 것을 알 수 있다. 이 주소는 멀티캐스팅을 위한 주소이다.
멀티캐스트하는 패킷이라는 것을 알 수 있다.




(192.169.3.255 주소)



이번엔 목적지 주소 끝이 255 이다. 이 주소는 현재 192.168.3.0 이라는 네트워크 id를 가진 네트워크 안에서 브로드캐스트하는 주소이다.

* 넷마스크
 - ip에서 네트워크 아이디를 확인하기 위한 목적이다.
 - 네트워크를 분리한다.(서브네팅)
- 혹은 네트워크를 통합한다.(슈퍼네팅)
 
ex)  192.168.3.100/24      ( /24 ) 가 넷마스크를 의미한다. 넷마스크의 비트수
    -> 24비트를 넷마스크로 쓰겠다는 말이다.

 - 192.168.3.100 / 255.255.255.0  
 -> 2진수로 바꾸면
 1100 0000.1010 1000.0000 0011.0110 0100  
   / 1111 1111.1111 1111.1111 1111.0000 0000 

 Bit Masking 은 and 연산을 통해 이루어진다.

 1100 0000.1010 1000.0000 0011.0110 0100
 1111 1111.1111 1111.1111 1111.0000 0000
 ------------------------------------------------------------
 1100 0000.1010 1000.0000 0011.0000 0000 
-> 10진수로 바꾸면 192.168.3.0 이 나온다.
-> 네트워크 id를 얻을 수 있게된다.
 -> 서브넷마스크의 역할이다.
 - 그래서 이 서브넷마스크를 조절하면 네트워크망의 크기를 조절할 수 있다.(서브넷팅, 슈퍼넷팅)

 -> 만약 의도적으로 서브넷 마스크를 비트 하나 더 늘려주면
 1111 1111.1111 1111.1111 1111.1000 0000  -> 서브넷마스크 25
 192.168.3.100/255.255.255.128
 1100 0000.1010 1000.0000 0011.0110 0100 
        /  1111 1111.1111 1111.1111 1111.1000 0000
 
 ->그렇게되면 두개의 네트워크로 분할 할 수 있고, host의 수는 절반만큼 줄어든다.
 1100 0000.1010 1000.0000 0011.0110 0100
 1111 1111.1111 1111.1111 1111.1000 0000
 ----------------------------------------
 1100 0000.1010 1000.0000 0011.0000 0000   -> 192.168.3.0

만약 
 192.168.3.200/255.255.255.128
 1100 0000.1010 1000.0000 0011.1100 1000
 1111 1111.1111 1111.1111 1111.1000 0000
 ---------------------------------------
 1100 0000.1010 1000.0000 0011.1000 0000  -> 192.168.3.128 이라는 네트워크 id가 된다.
-> 같은 192.168.3 C class에서 네트워크 id가 2개로 분할이 됬다.
(하지만 요즘은 넷마스크로 서브네팅을 하지 않는다.)
(요즘은 VLAN등 좋은 장비들이 나와서 그 장비를 이용한다.)

* 공인망, 사설망
- 공인망(Public Network)
   : 공인 IP를 사용하는 네트워크

- 사설망(Private Network)
   : 사설 IP를 사용하는 네트워크

 사설 IP ??
 -> 공인망과 분리된 네트워크, 공인망과 격리되었다.
 -> A class (10번)
    B class (172번)
    C class (192번)
 -> NAT  (Network Address Translation) 네트워크 주소 변환
 : 사설망도 외부와 통신이 되게하기 위해서  사설망과 외부망이 연결되는 지점에 공인IP하나를 준다.
 사설망 내에서 밖으로 나갈때 공인 IP로 바꾸어서 내보낸다.


 IP fragment Vs TCP segment  (UDP는 segment가 없다.)

* IP fragment ( IP 단편화/조각,파편... )
 - IP 패킷을 조각내는 것이다.
 - IP 패킷으로 패키징할 대 너무 크니까 적정크기로 잘라서 패키징한다.
 -> 이것이 IP fragment라고 한다.
 - 적정 크기는 MTU로 정한다.
 - MTU (Maximum Transfer Unit) (최대 전송 단위) : 보통 1500바이트




(2005바이트를 보내는 화면)



(2005바이트 수신)



위 결과를 보면 IP패킷이 분할되서 전송된것을 볼 수 있다.

ex)
우리가 2000바이트를 udp로 보내는 경우
 보낼려는 데이터 2000바이트
 
 거기에서 udp헤더가 붙는다.
 -> 2008바이트
 - 앞에 1500만큼 잘라낸다.
 
 그리고 IP패킷으로 패키징,
 -> IP패킷이 2개 나온다.
 - 도착지에서는 이걸 다시 하나로 합쳐야된다.
 - Identification을 보고 같으면 합친다. 
 분할된건지 어떻게 알까? -> Flag를 보면 안다.  
0으로 되있으면 분할되지 않았다. DF면 분할하지 마라. MF는 뒤에 더 있다라는 내용이다.

정리. (Flag비트)
 0010 0000 ->(More Fragment) MF 맨앞이 1이면 32 -> 이거면 뒤에 분할된게 더 있다는 뜻이다.
 0000 0000 -> 아무것도 분할되지 않았다는 뜻이다.
 0100 0000 -> (Dont Fragement) : 분할하지 마라

 offset은 원래 분할되기 전의 위치를 뜻한다.

- UDP는 segment가 없다. 분할된건지 확인할 헤더 필드가 없다.
- TCP단에서 segment가 된다.
TCP segmentation ( TCP 조각, 파편...)
 - TCP segment를 조각내는 것이다.
 - MSU( Maximum Segment Unit ) : 1500 (윈도우에서)
 ->그래서 일반적인 PC에서는 이미 TCP단에서 1500바이트에서 이미 조각 났기때문에
 IP fragment를 보기는 힘들다. -> IP에서는 분할되지 않아도된다. 일반적인 PC에서
 -> TCP 패킷을 의도적으로 작게 조각내서 보내면 방화벽을 통과시킬 수 있다.
 -> TCP에는 시퀀스 넘버가 있어서 재조립도 가능하다.

 * 요새는 offset을 보지않는다. 취약점때문에 사용하지 않는다.
 왜냐하면 이걸 이용해 방화벽우회도 할 수 있기 때문이다. 혹은 offset 설정으로 Tear Drop 공격기법이 있다.

상황
서버가 있다고 가정해보자.

 서버가 있다. 서버에 방화벽을 둔다. 
 방화벽 두개가 같이 있어야한다. ( host기반의 방화벽(윈도우즈방화벽), 네트워크 기반의 방화벽 )
 IP패킷의 최소 8바이트까지 쪼갤수있다. 작게 쪼개진 패킷들을 보낸다.
 방화벽은 첫번째 프레그먼트만 확인 후 이상이 없으면 나머지는 그냥 통과시킨다.
 성능면때문에 첫번째 fragment만 확인한다.
 
 그래서 offset을 조작해서 통과한 패킷들을 서버에 도착해서 조립을 하면 중첩되면서 새로운 데이터가 된다. (요즘은 IP는 안되지만 TCP에서는 된다.)
 
 그리고 뚫고 들어오면 이제 호스트기반의 방화벽이 있다.
호스트기반의 방화벽에서는 천천히 잘 조립해서 확인한다. 그래서 서버에서 막힐 수 있다.
 그래서 호스트 기반의 방화벽에서는 우회할 수 없다.

 이 방법으로 네트워크 방화벽을 우회할 수 있다.
 그러면 네트워크 기반의 방화벽은 필요없는거 아닐까?
 -> 그렇지 않다.  DDos 공격이 있다.

 * DDos 공격
 -> 대량의 패킷을 서버에 보내 서버의 부하를 많게 하여 다운되게 하는 것이 목적이다.
 -> 호스트 기반의 방화벽에서는 막지 못한다. 이미 호스트 기반의 방화벽까지 들어왔다는거 자체가 공격 성공이다.
 --> 그래서 방화벽 두개를 운영하는게 맞다.

 : 현재는 offset을 조절하는 공격은 쉽지 않다.



오늘은 여러가지 클래스에 관해 공부했다.
먼저, abstrcat 클래스부터 살펴보면

abstract 클래스는 인스턴스화 될 수 없는 클래스이다.
??
그러면 왜 abstract 클래스를 쓰는 것일까?

상속을 목적으로 상위클래스로 선언하고 싶은 경우 abstract를 사용한다.
abstract 선언은 클래스와 메소드에서 사용할 수 있다.

abstract 클래스는 인스턴스 생성이 불가능하다.
그렇기 때문에 다른 클래스에서 상속을 받은 후 abstract 메소드를 오버라이딩 해서 사용한다.

- Interface
: 완벽한 abstract 클래스이다.
완벽한 abstract 클래스란 내부 메소드들이 전부 abstract메소드인 클래스를 말한다.
전부 abstract 인 메소드들을 가지고 있는 클래스 앞에 interface라고 선언을 하면
자동으로 내부 메소드들은 public abstract으로 설정되고 내부에 존재하는 변수는 자동으로 public static final로 선언된다.



(interface 선언)



위 선언을 보면 메소드들의 { } 의 내용이 없는 것을 확인 할 수 있다.

즉 이 메소드들은 오버라이딩 해서 사용해야한다.
이러한 interface는 extends로 받지 않고 implements 라고 받는다.
상속이라는 표현보다 구현이라는 표현을 사용한다. 텅 빈 메소드들을 채워 넣는 개념이다.

- interface 기반의 상수표현
interface를 이용해 상수를 표현하는 방법도 있다.



(interface를 이용해 상수를 표현하는 방법)



* 인터페이스를 이용해 다중상속을 구현할 수 있다.

원칙적으로 자바에서는 다중상속을 못하게 되어있다.

하지만, interface를 이용하면 다중상속과 같은 표현을 할 수 있다.

예를 들어 IPTV는 TV이기도 하고 Computer이기도 하다. 이 것을 표현하고자 한다면
interface를 이용해서



(interface와 TV, Computer 클래스 선언)





(IPTV는 TV와 Computer 다중상속)



정확히 표현하자면 다중상속은 아니지만
다중상속과 같은 표현이다.

* Inner 클래스
클래스 안에 클래스를 선언 할 수 있다.

- Outer 클래스의 인스턴스 생성 후에야 Inner 클래스의 인스턴스 생성이 가능하다.
- Inner 클래스 내에서는 Outer 클래스의 멤버에 직접 접근이 가능하다.
- Inner 클래스의 인스턴스는 자신이 속할 Outer 클래스의 인스턴스를 기반으로 생성된다.

-> Inner 클래스를 사용하면
1. 클래스들을 논리적으로 묶는 수단이된다.
2. 클래스들을 논리적으로 묶다 보니, 캡슐화가 증가하는 효과가 있다.
3. 결과적을 ㅗ코드의 가독성이 향상되고, 유지보수성이 좋아진다.


* 전화번호 관리 프로그램 5단계
출력 내용은 같지만
코드 면에서 가독성을 높이고
효율적으로 만들기 위해 5단계로 업그레이드하였다.

바꾼 내용은 먼저



(case 상수)



case에서 쓰던 상수를 읽기 편하게 interface를 이용해 상수를 선언했다.


(안정성을 높인 코드)


위 코드는 PhoneBookManager가 하나만 생성될 수 있도록
static메소드로 밖에서 호출 할 수 있고 이 메소드를 이용해 PhoneBookManager를 생성 할 수 있도록 하였다.

(* 참조 - 난 정말 JAVA를 공부한 적이 없다구요, 윤성우)




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

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헤더도 더 정밀하게 분석하였다.

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









+ Recent posts