raw socket 프로그래밍에서 특정 packet 을 drop 하는 방법
글쓴이: thisnome / 작성시간: 수, 2012/06/13 - 1:08오후
tcpdump 처럼 서버에 들어오는 모든 패킷을 살펴보는 프로그램을 만들어보고 있습니다.
raw socket 을 열고 recv 를 호출하면, 해당 기능이 동작하게 되는데요..
이렇게 제가 간단히 만든 프로그램에서 raw socket 으로 recv 를 한 이후에도 해당 패킷들은 서버내의 다른 프로그램들에게 잘 전달됩니다. tcpdump 를 작동시켰다고 tcpdump 가 패킷을 중간에 drop 하지 않는것 처럼 말이죠..
궁금한 점은 아래입니다. (사실 위에서 특정 프로세스가 읽고나서도 다른 프로세스가 또 읽는다는게 TCP , UDP, SCTP 등을 사용하는 프로그래밍만 해본 저로서는 좀 이상하기도 합니다. L4 에서는 특정 포트에 대해 binding 을 한 프로세스만 할 수 있어서 그런건지..)
이때, 특정 패킷에 대해서는 iptables 에서 패킷을 drop 하는것 처럼 다른 프로세스들이 읽지 못하게 하려면 어떻게 해야 하는가 입니다.
처음에 프로그램을 만들 때는, raw socket 으로 recv 한 것을 모두다 sendto 로 다시 돌려 주어야 다른 L4 (TCP/UDP... ) 주소를 바인딩한 프로그램들이 해당 패킷을 받을 것이라고 생각했었네요.
답변 부탁드립니다.
Forums:
한 번도 이런 생각을 못하고 있었는데
한 번도 이런 생각을 못하고 있었는데 흥미롭군요...
저는 10년이상 게임외는 컴퓨팅을 하지 않았으니 단순히 멋대로 추측하는 점 고려바랍니다.
커널의 수신 데이타그램 처리순서가
넷트웍루틴--전송루틴 : 사용자 버퍼로 덤프
생소켓은 fd 를 넷트웍 루틴에 위치시키는데 그러면 넷트웍루틴이 끝난 후 사용자버퍼로 덤프하고 커널버퍼를 비운다면 말씀하신것처럼 원래의 각 프로세서는 데이타를 받을 수 없습니다.
예를들어 넷트웍루틴이 끝난 후 tcpdump 의 버퍼로 덤프후 커널버퍼가 비워진다면 텔넷도 웹도 모든게 데이타를 받지 못하겠지만 이는 거짓이므로...
커널은 넷필터같은 추가 모듈을 구현하지 않은 커널은 전송루틴이 끝날 때까지 커널버퍼를 플러시하지 않는다.
즉 링버퍼-sk버퍼포인터-sock버퍼포인터 가 전송루틴 끝을 리턴할 때까지 유지된다.
하는게 제 추측입니다.
이어서 말씀드리면
큰그림을 이해하시면 세부 범위는 검색을 통해 좁혀질수 있을 겁니다.
수신시
실제 데이타 위치 = 커널 풀링버퍼(백로그버퍼 ) = 랜카드 드라이버가설정한 DMA 버퍼 일정부분 = 도착한 패킷 MTU 별로 ( 300개까지) 쌓임 = 위에서 말한 커널버퍼
이 커널버퍼가 커널 최하단의 버퍼고 이 리스트 하나하나는 백로그 또는 풀링리스트 수치로 관리됨
하나의 블럭마다 무조건 skb 를 만들고
전송계층이 필요없는 icmp 또는 SAN 스토리지 프로토콜같은경우 전송계층 자료구조인 sock 은 생성되지 않고 skb 에서 끝나고 레퍼런스 카운터가 0 이면 실제 커널버퍼도 비워지고 백로그 카운터 -1
갤러기로 쓰는데 뭐가 짤렸네요... 생소켓은 커널
갤러기로 쓰는데 뭐가 짤렸네요...
생소켓은 커널 넷트웍루틴에.fd 를 둔다고 했는데 이는 정규 커널의 전송루틴을 대체한다는 말이며 커널은 이런 skb 에 대해 생소켓 리스트를 따로 갖고 있음 따라서 생소켓으로 호출된 fd 라고해서 모든 데이타그램을 볼 수 있는게 아님.
tcpdump 같은 경우 생소켓과 별개로 모든 데이타그램을 볼 수 있는 구현이 있는데 이는
시스템내의 모든 skb 를 읽든가 아니면 직접적으로 커널 풀링버퍼,백로그버퍼를 읽는 구현이 있을 것으로 추정
정상적인 데이타 흐름은
커널버퍼에 1패킷 도착=skb 생성 넷트워루틴 거침=sock 생성 전송루틴 거침=사용자 버퍼에 덤프 =sock 해제 skb 해제= 실제 커널버퍼의 패킷 삭제
질문하신것처럼 생소켓에서 특정 프로토콜 드랍은
생소켓구현 + 커널버퍼,skb,sock 직접제어
의 구현이 합해져야 하는 것이겠죠.
그럴바에야 넷필터 모듈을 통과시키는게 낫겠고....
흠
모바일로 답글 쓰려니 타이핑도 그렇고 모든게 난해합니다.짧은 말투 이해를...
SCTP를 하시는 분을 만나뵙게 되니 반갑네요. 석사
SCTP를 하시는 분을 만나뵙게 되니 반갑네요. 석사 과정때 한창 연구했던 프로토콜 이었죠. :-)
raw socket에서는 패킷을 수정하거나 드랍 할 수 없습니다.
패킷을 드랍하거나 수정하는 것은 커널 레이어의 netfilter에서 해야 합니다. 단순 드랍하시는 것이면 iptables를 쓰시면 되구요.
원하시는 것을 하시려면 netfilter를 활용하시면 되겠네요.
Just do it!
음
RAW 소켓이든 일반 소켓이든
소켓 descriptor 를 통해서 데이터를 읽은것은
커널의 네트워크 체인의 어느 지점에서의 데이터의 복사본을 얻을 뿐이니
당연히 패킷을 drop 할 수 없습니다
네트워크 트래픽을 제어하려면 netfilter 같은 프레임워크로
네트워크 체인의 특정 지점에 후킹을 걸던지
직접 네트워크 디바이스 드라이버를 수정하거나 작성하거나 해야겠죠
iptables 는 netfilter 인터페이스를 사용하는 프로그램입니다
소켓별로 정확하게 어느 시점에서 어떤식으로 데이터의 복사가 이루어지는지는 궁금하네요
자기실력이 좋다고 느껴지는건 공부를 안하고 있다는 신호.
짧은 지식
네트워크 디바이스 드라이버를 직접 수정하는 것은 너무 오버 입니다;;
말씀하신 것처럼, iptables 는 netfilter로 구현한 프로그램입니다. iptables로 할 수 있으면
netfilter로 새로 구현하기 보다는 그냥 iptables를 사용하는게 편합니다.
네트워크 드라이버와 리눅스 커널 네트워크 코드를 본지 몇년이 지나서, 저도 잘 모르지만
우선 PF_INET의 경우 inet_init 함수에서 프로토콜과 소켓 패밀리를 등록합니다.
http://lxr.linux.no/linux+v3.4.2/net/ipv4/af_inet.c#L1635
proto_register() 함수로 각 프로토콜을 등록하고, sock_register() 함수로 PF_INET 소켓
패밀리를 등록합니다. 여기서 등록한다는 것의 의미는 각 프로토콜에 따라 동작 함수를
설정한다는 의미입니다. 예를 들면, UDP 프로토콜은 다음과 같은 동작 함수들로 설정
되어 있습니다.
* http://lxr.linux.no/linux+v3.4.2/net/ipv4/udp.c#L1919
'소켓별로 정확하게 어느 시점에서 어떤식으로 데이터의 복사가 이루어지는지'는
각 프로토콜에 따라 skb(소켓 버퍼)에 있는 패킷을 처리 한 뒤에,
skb_copy_and_csum_datagram_iovec() 함수로 커널 영역에 있는 패킷의 내용을
user 영역에 있는 어플리케이션 버퍼로 복사합니다.
* TCP> http://lxr.linux.no/linux+v3.4.2/net/ipv4/tcp.c#L1696
* UDP> http://lxr.linux.no/linux+v3.4.2/net/ipv4/udp.c#L1213
* RAW> http://lxr.linux.no/linux+v3.4.2/net/ipv4/raw.c#L707
(이때 발생하는 커널 -> 유저 영역으로 메모리 복사 오버헤드가 발생하게 되는데,
이것을 없애보고자 하는 것을 Zero Copy라고 합니다.)
오래된 기억에 의존한 것이라 제가 잘못 알고 있을지도 모릅니다. 잘못된 정보
수정이나 좀 더 자세한 내용을 덧 붙여주시는건 언제든지 환영입니다.
ps. 공부해야겠습니다.
Just do it!
댓글 달기