그간 SOCK_PACKET은 sniffer (tcpdump...)에서 패킷 빼올때나 쓰는것줄 알았는데 패킷을 보낼 때도 쓰더라..
packet socket도 raw socket과 비슷하게 application 단에서 패킷을 비교적 자유롭게 보내기 위해 사용되는데... - 내가 봤던 코드는 GARP를 전송하는 코드였뜸 -
문득 raw 와 packet socket의 차이점에 대해 궁금해 졌다.

차이점은 아래와 같다.
http://www.developerweb.net/forum/showthread.php?t=4981
Raw socket
1. Layer3까지 조작이 가능하다.
2. 일반적인 network stack을 이용한다.
3. 커널이 처리하기 전에 먼저 빼올 수 있다.
4. sockaddr_in을 사용한다.

=>raw socket도 hooking이 가능해야 한다는 말이다!

Packet socket
1. Layer2까지 조작이 가능하다.
2. network stack을 skip하고 device driver로 전송된다.
3. 커널이 처리하기 전에 먼저 빼올 수 있다.
4. sockaddr_ll을 사용한다.

=>hooking이 안된단 말이다!

큰 차이점을 요약하면
어느 layer까지 조작이 가능한가와 일반적인 network stack을 통과하느냐 그렇지 않느냐의 차이겠다. 

나에게 있어 header 조작이야 그냥 그렇고(지겨움 ^^;) network stack skip에 대한 부분은 매우 흥미로웠다.
만약 packet socket이 정말로 device driver (e1000..) 단으로 빠져 버린다면 net-filter에서 어떤 처리 (NAT, FW..)도 할 수 없다는 결론이 나온다.
어찌 관심을 안가질 수 있으리오..?

포스팅은 포스팅일 뿐이므로, - 이건 100% 신뢰 할 수 없다는 얘기다! - 
정말 그런지는 kernel source를 확인하는게 언제나 진리다 ^^;

이에 앞서 raw와 socket에 얽힌 이야기를 먼저 해보자.
- 위 원문에 RobSeace 씨가 한 얘기다 이분 왠지 포스 있다 -

Raw socket은 거의 BSD 표준을 따랐으며 유닉스 계열의 시스템에서 사용된다.
그 목적은 IP위에 올라갈 수 있는 사용자 단의 protocol을 쉽게 설계하도록 하는 거였지만,
몇몇 사람만 이렇게 쓰는것 같다.
<<< 넉두리 시작
 - 사실 누가 열라 시간을 들여가며 IP 바로 윗단의 (이말은 TCP, UDP, ICMP 등등을 사용하지 않는 다는거죠~) Layer를 만들 겠수? 만든다고 해도 kernel단의 network stack에 통합하지 복잡하게 user space에 만들지는 안을거유 (이말은 와닿지 않는다) -
>>> 넉두리 끝
요세는 ICMP 메시지를 주고 받는데 주로 사용되는것 같다. (맞는 말이죠??)

Packet socket은 Linux 독자적인 특성으로 다른 시스템에는 없다. 
하지만 각 시스템들은 표준에 동의하지 않았기 때문에 비슷한 역할을 수행하는 some을 가지고 있다. - 이게 여러분이 libpcap과 같은 higher-level library를 사용하는 이유다 -
어쨋든, 주된 차이점은 packet socket이 network-layer 보다는 link-layer에서 수행되는게 맞다.
때문에 여러분은 IP 트래픽 외에도 모든 종류의 트래픽을 sniffing 할수 있다.

- 이상 조사 끝, 코드 분석 시작 (아 근데 RobSeace 너무 스마트해 보여서 부럽다. 투덜대는거 빼고) -

자 그럼 packet이 정말 network stack을 skip하는 지에 대해 알아보자. 우훗우훗

가정:
packet socket의 경우 network stack을 skip 하므로 
sendto api 호출 시 초기 단계에서 dev_queue_xmit 혹은 hard_start_xmit을 call 할 것이다.

상콤하게 sock_sendmsg부터 가자

1. sock_sendmsg
필요한 것만 보자.
__sock_sendmsg에서 sock->ops->sendmsg를 call 한다.
역시나 virtual function~ 아 귀차나~~
af_packet.c를 뒤져보자!!
후훗 차자뜸

2. packet_sendmsg
등록은 packet_create 가 한다. 
sock->ops = &packet_ops; 

오!!!!! 굳굳 일단 가설은 적중 lol 
함수 마지막 부분을 보면 

     /*
     *    Now send it
     */

    err = dev_queue_xmit(skb);
    if (err > 0 && (err = net_xmit_errno(err)) != 0)
        goto out_unlock;

    dev_put(dev);

    return(len);

명확하다!! 난 이런게 좋다 ^_^
dev_queue_xmit -> hard_start_xmit -> e1000_xmit_frame (intel)

엄밀히 말하면 device driver로 곧바로는 아니지만 (dev_queue_xmit에서 queuing 처리를 하므로)
이정도는 애교로 봐줄 만 하다.
이는 또한 sock_packet이 hooking이 되지 않는 이유도 명확히 설명된다.

참고로 이 function을 보면 routing 역시 skip 하는걸 볼 수 있다.
dev = dev_get_by_index(ifindex); // output device를 얻어오고
...
skb->dev = dev; // 그대로 집어 넣는다.

이말은 application에서 반드시 해당 정보들을 설정해 주어야 한다는 것이다.

[출처] SOCK_RAW verse SOCK_PACKET|작성자 데비



출 처 : http://blog.naver.com/realbright1?Redirect=Log&logNo=94508080

+ Recent posts