kernel에서 Port별 packet captuer와 packet ordering에 대한 질

김경태의 이미지

linux kernel단에서 kernel의 TCP/IP stack을 직접이용하는 device driver를 구성하여 다음과 같은 작업을 하고자 합니다.

1. local port번호를 ioctl로 App prog에서 입력받아 이 번호에 해당하는 포트를 통과하는 모든 packet을 capturing하고 싶습니다.

* kernel단 프로그램이므로 divert socket, raw socket 등은
app prog에서 사용하는 function을 사용할 수 없다.
* sys_socket, sys_bind 등을 사용하여 app prog에서 사용
하는 유사한 방법으로 packet capturing을 하는 것은 over
load가 커서 사용할 수 없다.
* 직접 struct socket이나 socket recv buffer를 직접 access
하여 특정 port에 packet이 들어올 때마다 packet을
capture하고 싶다.
* port 번호를 가지고 커널단에서 사용하는 recv buffer 자료구
조를 찾아가는 방법이 없을까요?

2. port 별 packet을 이용하여 TCP/IP에서 사용하는 stream의 내용을 analyse하기 위해 TCP/IP stack에서 사용하는 function을 이용하여 check sum든 다른 작업은 제외하고 sequence number별로 ordering하고 싶다..

* kernel단 프로그램이므로 divert socket, raw socket 등은
app prog에서 사용하는 function이므로 사용할 수 없다.
* sys_socket, sys_bind 등을 사용하여 app prog에서 사용
하는 유사한 방법으로 packet ordering을 하는 것은 over
load가 커서 사용할 수 없다.
* 1에서 capturing한 packet들을 다른 작업없이 reordering
만 하려고 할경우 어떤 function을 사용하면 될까요?

혹시 이에 대한 정보나 아이디어가 있는 고수분은 저에게 알려주시면 정말 감사하겠습니다.

익명 사용자의 이미지

음.

익명 사용자의 이미지

간단히 커널모듈하나 짜올리거나 모디파이 해버림되겠네요. ip_table에 넣어주는게 만만할듯

hie의 이미지

Quote:
1. local port번호를 ioctl로 App prog에서 입력받아 이 번호에 해당하는 포트를 통과하는 모든 packet을 capturing하고 싶습니다.

--> NETFILTER 사용

Quote:
* port 번호를 가지고 커널단에서 사용하는 recv buffer 자료구 조를 찾아가는 방법이 없을까요?

--> 어떤 의미로 쓴 글인지 이해할 수가 없군요.. ㅡ.ㅡ;;

Quote:
2. port 별 packet을 이용하여 TCP/IP에서 사용하는 stream의 내용을 analyse하기 위해 TCP/IP stack에서 사용하는 function을 이용하여 check sum든 다른 작업은 제외하고 sequence number별로 ordering하고 싶다.
.
--> 큐잉과 관련이 있나요?? 버츄얼 큐를 만들어 사용하는 것이 좋으나...

즐프~~

익명 사용자의 이미지

인용:
1. local port번호를 ioctl로 App prog에서 입력받아 이 번호에 해당하는 포트를 통과하는 모든 packet을 capturing하고 싶습니다.

--> NETFILTER 사용

---------------------------------------------------------------------

제가 원하는 것은 device driver를 짜서 거기서 ioctl를 통하여 입력된 user application 에서 filtering을 원하는 port 번호를 입력 받고 그 port 번호에 해당하는 모든 packet을 capturing하고 싶습니다.

다만 그렇게 하기 위해서 다른 함수를 사용하는 것이 아니라 port 번호를 이용하여 그 포트를 이용하는 struct socket 구조체를 직접 찾고 그 구조체의 recv 구조체를 감시하여 매 packet을 입력 받을 때마다 등록된 함수를 이용하여 packet을 받도록 하고 싶은 겁니다.

그러기 위해서 필요한 것은 user space에서 받아들인 port 번호를 이용하여 어떻게 하면 port에 해당하는 struct socket을 찾을 수 있을 것인가에 대한 방법론이 필요합니다.

해당하는 struct socket을 찾으면 struct socket에 해당하는 recv 구조체를 찾는 것은 어렵지 않다고 생각합니다.

인용:
* port 번호를 가지고 커널단에서 사용하는 recv buffer 자료구 조를 찾아가는 방법이 없을까요?

--> 어떤 의미로 쓴 글인지 이해할 수가 없군요.. ㅡ.ㅡ;;

-----------------------------------------------------------------

user space의 application 프로그램에서 ioctl을 통하여 디바이스 드라이버 프로그램에게 port번호를 전달합니다.

device driver 프로그램에서는 전달된 port 번호를 이용하여 이 port번호를 사용하고 있는 struct socket 구조체를 찾습니다.
(이게 실질적으로 필요한 정보입니다.)

struct socket을 찾으면 여기에 해당하는 recv 자료구조를 감시하여 새로운 패킷 정보가 들어오게 되면 패킷 capturing을 하는 device driver function을 불러줍니다.

여기서 과연 어떤 구조체를 어떤 방식으로 접근하여야만 port번호에 해당하는 socket 구조체를 찾을 수 있느냐 하는 게 중요해 지는 겁니다.

인용:
2. port 별 packet을 이용하여 TCP/IP에서 사용하는 stream의 내용을 analyse하기 위해 TCP/IP stack에서 사용하는 function을 이용하여 check sum든 다른 작업은 제외하고 sequence number별로 ordering하고 싶다.
.
--> 큐잉과 관련이 있나요?? 버츄얼 큐를 만들어 사용하는 것이 좋으나...

---------------------------------------------------------------------

큐잉과도 관련이 있을 수는 있습니다.

일단 port 별 packet을 잡았지만 제가 최종적으로 원하는 것은 각 packet의 내용 정보를 sequence 순서대로 재배열하는 것입니다.

왜냐하면 사실 제가 검사하고자 하는 단위는 packet 단위가 아닌 stream 단위인데 stream 형태의 분석을 위해서는 packet이 순서대로 배열되어야 합니다.

이러한 요구사항에 맞게 tcp recv function에서는 packet ordering을 수행하게 됩니다.

하지만 tcp recv function을 사용하는 경우, 단지 packet ordering만을 하는 것이 아니라 check sum 등 원하지 않는 다른 동작들을 수행하게 됩니다.

한데 제가 하고 싶은 것은 단지 packet에 대한 ordering 뿐입니다.

결국 제가 궁금하게 생각하는 것은 tcp단의 recv 관련 모듈 중에서 과연 어디에서 packet ordering을 수행하는지 그게 참 궁금합니다.

그 부분을 알게 되면 저는 이 packet ordering 부분을 적절하게 변형시켜 제가 원하는 대로 저의 device driver 모듈에 삽입하면 되는 것입니다.

혹시 이에 대한 귀한 가르침을 주실 고수님이 계신다면 한수만 가르쳐 주시면 감사하겠습니다.

gestate의 이미지

김경태 wrote:
1. local port번호를 ioctl로 App prog에서 입력받아 이 번호에 해당하는 포트를 통과하는 모든 packet을 capturing하고 싶습니다.

커널안에서 캡춰링한 패킷을 어떻게 하실껀지? 그냥 프린트? 아니면 메시지 큐로 날린다? 아니면 특정 메모리에 저장?
어쨋든.. net/core/dev.c 파일을 보면 device driver 에서 receive 할때 불려지는 함수(netif_receive_skb)와 device driver 로 send 하기 전의 함수(dev_queue_xmit) 함수에서 device port number 혹은 name으로 해당 패킷(skb->data)의 raw data(ethernet header를 포함한 패킷)를 얻을수 있음. 이것을 원하는 방법으로 가공하면 됨(memcpy를 하던 message queue로 날리던 등등)

김경태 wrote:
2. port 별 packet을 이용하여 TCP/IP에서 사용하는 stream의 내용을 analyse하기 위해 TCP/IP stack에서 사용하는 function을 이용하여 check sum든 다른 작업은 제외하고 sequence number별로 ordering하고 싶다..

raw data(ehternet header + ip header + tcp/udp.. header)이므로 원하는 분석은 맘대로 할수 있음

아직도 세상은 살만한 가치가 있나(?)

김경태의 이미지

커널안에서 캡춰링한 패킷을 어떻게 하실껀지? 그냥 프린트? 아니면 메시지 큐로 날린다? 아니면 특정 메모리에 저장?
어쨋든.. net/core/dev.c 파일을 보면 device driver 에서 receive 할때 불려지는 함수(netif_receive_skb)와 device driver 로 send 하기 전의 함수(dev_queue_xmit) 함수에서 device port number 혹은 name으로 해당 패킷(skb->data)의 raw data(ethernet header를 포함한 패킷)를 얻을수 있음. 이것을 원하는 방법으로 가공하면 됨(memcpy를 하던 message queue로 날리던 등등)

----------------------------------------------------------

지금 말씀하시는 동작은 network device driver 단에서 동작하는 방식으로 가령 모든 port 번호에 대한 모든 packet을 다 잡아낼 수 있는 방법입니다.

이 방법은 물론 쉽게 포트별 데이타를 찾을 수 있겠지만 그렇게 하게 되면 가령 8000 번 port를 감시하는 경우 전혀 관련없는 70, 77, 800등등의 packet까지 다 받게 되겠지요.

이건 엄청난 낭비입니다.

그래서 제가 원하는 것은 ip 단에서 올라온 packet을 받되 다만 내가 원하는 port에 대해서만 packet 자료를 받고 싶은 겁니다.

그렇게 하기 위해서는 해당 port를 이용하여 socket 자료구조를 찾을 수 있어야 하고 socket 자료구조를 찾은 경우에는 해당하는 recv 자료구조의 변화만 감시하면 되는 것입니다.

모든 packet을 다 받는 것은 간단한 방법이기는 하지만 비효율적인 방법이라 채택하지 않은 것입니다.

gestate의 이미지

local port가 tcp/udp의 port 번호 였다는게 없어서.. port가 그 포트인지 몰랐습니다.

tcp/udp/raw의 함수 차이는 있겠지만 tcp 일 경우에
local port 의 경우 ip 단에서 ip_local_deliver_finish 함수에 의해
각 프로토콜이 정의된 ipprot->handler(skb) 이와 같은 형식으로 handler를 호출합니다.
tcp 일 경우 이 handler는 tcp_v4_rcv라는 함수로 되어 있습니다.
당연히 v6일 경우는. 다른 함수 겠지요..
tcp_v4_rcv를 보면은.

struct sock *sk;
sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source,
skb->nh.iph->daddr, ntohs(th->dest), tcp_v4_iif(skb));

통해 sk를 얻어낸 후에
tcp_prequeue(sk, skb)를 통해 tcp queue에 저장이 됩니다.
그러면.. application에서 read를 통이 이 sk를 통해 해당되는 프로토콜인 tcp queue에서 data를 받아가게 되죠..

그렇다면 님이 말하는 대로 해당 sk에 연결된 프로토콜의 queue가 증가하는지를 검사하면 되겠죠..

해당 sock을 찾기 위해서는. 위에 함수에서 처럼 서버 클라이언트의 ipaddr과 port 번호가 있어야 되구요..

아직도 세상은 살만한 가치가 있나(?)

김경태의 이미지

struct sock *sk;
sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source,
skb->nh.iph->daddr, ntohs(th->dest), tcp_v4_iif(skb));

통해 sk를 얻어낸 후에
tcp_prequeue(sk, skb)를 통해 tcp queue에 저장이 됩니다.
그러면.. application에서 read를 통이 이 sk를 통해 해당되는 프로토콜인 tcp queue에서 data를 받아가게 되죠..

--------------------------------------------------------------

말씀하신대로 하면 port number를 통하여 struct sock sk를 얻어낼 수 있습니다.

따라서 물론 해당하는 socket의 recv queue 데이타를 받아가게 될 수도 있습니다.

제가 궁금했던 첫번째 질문에 대하여 시원스레 대답해 주셨군요.

높은 가르침에 대단히 감사드립니다.

한데....

일단 IP packet이 recv queue에 삽입되었다 하더라도 이 recv queue에 들어가는 IP packet들 자체는 정렬되어 있지 않습니다.

그러므로 recv queue에 들어 있는 IP packet들은 당연히 sk.seq를 이용한 모종의 정렬 작업을 거치고 난후에나 user space에 data를 넘겨줄 수 있습니다.

한데...

제가 열심히 살펴본 바로는 tcp recv 관련 함수인 tcp_v4_rcv, tcp_prequeue, sk_add_backlog, tcp_v4_do_rcv 등을 아무리 살펴봐도 recv buffer에 대한 정렬작업이 어디서 이루어지는지 알수가 없습니다.

recv buffer를 받아가는 tcp_recvmsg에서도 순서대로 recv buffer를 조사하면서 FIN신호가 오거나 혹은 입력된 len만큼의 데이타가 입력되면 이것을 skb_copy_datagram_iovec 를 통하여 user space에 stream 형태로 복사해줄 뿐 특별한 IP packet들에 대한 정렬작업은 하지 않는 것 같습니다.

혹시나 해서 skb_copy_datagram_iovec 함수를 열심히 봤는데도 특별한 sk.seq에 의한 정렬작업은 이루어지는 것 같지 않습니다.

도대체 어느 함수에서 어떤 식으로 recv queue에 들어 있는 packet 자료에 대한 정렬을 하는 것인지 참으로 궁금합니다.

이에 대해 알고 계신 고수분이 계신다면 한수 가르쳐 주시면 감사하겠습니다.

그럼 오늘 하루도 행복하십시요.

gestate의 이미지

sk 라는 것 자체가.. 이미. 해당 소켓에 대한 구조체 이기 때문에..
정렬이 필요 없습니다.
보통 tcp 일 경우에. 소켓 하나는 server socket <=> client socket이 연결 되기 때문에
위에서는 tcp일 경우 tcp queue 라고 얘기를 했지만
해당 프로토콜의 queue에서 데이터를 가져가게끔 되어 있습니다.
그렇기 때문에 queue의 정렬이라는 개념이 필요 없습니다.

다시 말해서 deivce queue에는 모든 프로토콜의 각 port들이 한꺼번에 존재하지만
sk의 프로토콜 queue에는 자신이 open해서 bind 된 socket에 해당하는 data만 존재한다는 것이죠..

아직도 세상은 살만한 가치가 있나(?)

김경태의 이미지

IP단에서는 전혀 packet 순서를 고려하지 않고 IP별로 packet을 전송합니다.

그래서 가령 특정 port에 s1, s2, s3로 소켓이 열려 있다면
s1:1, s1:2, s2:1, s2:3, s1:3, s2:2와 같은 packet 전송이 가능하겠죠.

위의 packet들을 가만 들여다 보면,
s1은 1, 2, 3으로 순서대로 들어오지만
s2는 2, 1, 3으로 순서대로 들어오지 않습니다.

위 packet들이 아무런 정렬없이 TCP buffer로 복사된다고 가정하면
s1같이 순서대로 packet이 들어올 수도 있지만,
s2와 같이 순서가 얽혀서 들어올 수도 있습니다.

그렇다고 본다면 s2에서는 반드시 seq를 통한 정열과정이 TCP에서 어디서든 꼭 필요하게 됩니다.

제가 잘못 생각하였다면 지적해 주시면 감사하겠습니다.

swunk의 이미지

tcp 에서 sequence넘버 확인은 합니다. packet disordering을 막기 위해서죠...

tcp_input.c 화일에 있는 tcp_rcv_established()에서 확인하네요...

   3241         if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
   3242                 TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
익명 사용자의 이미지

자신에게 오지 않는(목적지IP 및 포트가 다른 곳) TCP 트래픽에 대해서도 ...하고 싶은것인가요?
만일, 이런 경우라면 보다 고려사항이 많아질 듯 하군요.

김경태의 이미지

packet의 sequence number check와 연관되어 또하나의 의문점이 생기는 군요.

connection이 맺어진 상태에서 보통 packet을 받아서(recv) TCP data segment를 만들 때는,

1. checksum check
2. sequence number 조합
3. time-out check

을 하게 될 것 같습니다.

1 번은 packet data에 문제점이 있는지 검사하는 것이니 설명이 필요 없을 것입니다.

2 번은 TCP data segment를 만들기 위해 s1:1, s1:3, s1:2의 순서로 왔을 때 s1:1, s1:2, s1:3의 순서대로 reordering하는 것이구요.

3 번은 s1:1, s1:2의 packet이 도착한 후에 아무리 기다려도 s1:3의 packet이 도착하지 않을 때 어떻게 처리하느냐 하는 겁니다.

단순한 생각으로는 무턱대고 다음 packet을 기다리는 것이 아니라 뭔가 time-out이 설정이 되어 time-out 시간이 끝나게 되면 필요없어진 s1:1, s1:2까지 discard 시킨 후 error를 return 하고 다음 data segment를 기다릴 것 같습니다.

제 생각이 맞는지 궁금합니다.

만약 제 생각이 맞다면 time-out 처리를 어느 소스에서 어떤 방식으로 처리해주는지 궁금합니다.

만약 제 생각이 틀리다면 무한정 다음 packet을 기다리게 되었을때 문제점이 없겠습니까?

고수님의 높은 가르침을 부탁드립니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.