ip netfilter + ip checksum 오류와 관련된 질문입니다.

swunk의 이미지

모듈을 하나 짰습니다.
모듈이 하는 일은 NF_HOOK()등록을 하는데, NF_IP_LOCAL_OUT에서 패킷을 후킹 합니다.
후킹을 해서 하는일은 ip 헤더의 값을(tos값)변경 합니다.

커널 코드(2.4.20)에 보면은 ip 헤더 체크섬을 ip_queue_xmit2()함수에서 수행합니다.
ip_queue_xmit2() 함수는 NF_IP_LOCAL_OUT 뒤에 수행됩니다. 즉, 제가 ip 헤더값을 변경하고 난뒤에 checksum을 계산하기 때문에 checksum오류가 나면 안될것 같은데...오류가 나네요...*^^*

질문을 드리는것은...

(1) checksum 계산(ip_send_check()함수) 전에는 ip 헤더값을 변경해도 checksum오류가 안나느것으로 알고 있습니다. 맞나요?

(2) 1번 질문이 맞다면 저 같은 경우는 뭐가 문제일까요?

답변 부탁드립니다.

albamc의 이미지

1) 맞습니다.

2) checksum을 한번 해보시는게 어떨는지요.
ip_send_check(struct iphdr*) 한번 수행해 주면 될텐데요.

^^*

wfellow의 이미지

근데 요즘에 tos 수정하시는 작업은 처음 봅니다. 사서 고생하시는것은 아니신지... 글구 그런 작업(tos수정)이라면 (통밥을 때려보면)NF_IP_LOCAL_OUT에서 하실 일이 아닐지도 모른다는 생각이 약간 드네염..

albamc wrote:
1) 맞습니다.

2) checksum을 한번 해보시는게 어떨는지요.
ip_send_check(struct iphdr*) 한번 수행해 주면 될텐데요.

예전에 했던것이라서리 기억이 가물가물... :roll:
NF_IP_LOCAL_OUT에서 후킹을 하셔서 처리 후, 건드리셨다면 다시 checksum을 해야 합니다. 구글이에게 아래의 키워드로 검색을 해보셔염..

IP : tos작업후...

TCP
tcp_v4_check()

UDP
csum_tcpudp_magic()

마지막: ip_send_check()

iph의 tos를 변경하신후 간단히 위의 작업으로 mangle이 가능합니다. 위의 함수 인자중 csum_partial()을 넣었던것 같은뎅...

ps: 혹시 2.6이었던가?..하두 급히 해서리,,, 치매인가 봅니다.

-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----

익명 사용자의 이미지

Quote:
근데 요즘에 tos 수정하시는 작업은 처음 봅니다. 사서 고생하시는것은 아니신지... 글구 그런 작업(tos수정)이라면 (통밥을 때려보면)NF_IP_LOCAL_OUT에서 하실 일이 아닐지도 모른다는 생각이 약간 드네염..

지금 개발하는 시스템은 게이트웨이로 동작합니다.
그래서 자기가 생성하는 패킷외에 라우팅되는 패킷에 대해서도 패킷에 수정작업이 가해지기 때문에 원래는 NF_IP_POST_ROUTING 에서 후킹을해서 자기가생성하는 패킷과 라우팅하는 모든 패킷들에 대해서 한번에 해당 작업을 수행하려 했으나 자기가 생성한 패킷의 checksum계산은 ip_queue_xmit2()에서 하기 때문에 그 전에 헤더값을 변경시켜 주려고 했던 것이고 라우팅되는 패킷은 입력단에서 체크섬계산을 하는 것으로 알고 있습니다....그래서 IP_LOCAL_IN(?)에서 잡아서(checksum계산전에) 변경해 주려고 합니다.
이런 이유로 작업을 하려고 하는데 어떤 이유에서 NF_IP_LOCAL_OUT에서 하는일이 아니라고 말씀하신건지 궁금하군요...
Quote:
NF_IP_LOCAL_OUT에서 후킹을 하셔서 처리 후, 건드리셨다면 다시 checksum을 해야 합니다.

NF_IP_LOCAL_OUT 후에 checksum계산이 수행되는데 어떤 이유에서 checksum계산을 해야 하는지 궁금합니다. 어차피 checkum 은 이루어 지는데...
제가 살펴본 바로는 제가 살펴보고 있는 코드2.4.20 정확히 말하면 2.4.20-8에서는 NF_IP_LOCAL_OUT 후에 checksum 이 이루어지고 2.4.26인가?(레드헷ES3.0에 기본으로 깔리는 커널)에서는 이와는 달리 NF_IP_LOCAL_OUT 전에 즉, ip_queue_xmit()함수에서 패킷을 후킹하기 전에 checksum계산을 하더군요... 여튼 왜? 다시 checksum을 해야 합니다 말씀 하셨는지 궁금합니다.
Quote:

IP : tos작업후...

TCP
tcp_v4_check()

UDP
csum_tcpudp_magic()

마지막: ip_send_check()

이 말씀은 ip헤더값 수정후에 전송계층의 헤더 체크섬도 다시 수행해야 된다는 말씀인가요? 제가 기억하기로는 전송계층에서는 pseudo header 를 만들어 해당 계층의 정보만 그리고 ip 계층에서는 주소 정보만 가지고 와서 checksum을 수행하기 때문에 레이어별로 다시 할 필요는 없을거라 생각하는데요... 무슨 다른 의미로 말씀하신건지 궁금합니다.

Quote:
의 tos를 변경하신후 간단히 위의 작업으로 mangle이 가능합니다. 위의 함수 인자중 csum_partial()을 넣었던것 같은뎅...

무슨 말씀인지... :roll: mangle이 가능하다라는게 무슨 말인지 모르는데요...

한수 부탁드립니다.

꾸벅

아차차...
질문 드리는 김에 한가지 더 여쭙겠습니다.
위에 말씀 드린데로 결국 제가 하고자 하는 것은 시스템을 지나가는 모든 패킷에 대해서(자기 자신에게 전송되는 데이터는 제외하고) 검사를 하고 헤더를 수정하고자 합니다. 이런경우에는 어디서 패킷을 후킹하고 변경하는게 맞는건가요?
제 생각은 외부에서 들어오는 패킷은 IP_LOCAL_IN에서 그리고 자기가 생성해서 내 보내는 패킷은 IP_LOCAL_OUT에서 하는게 적절하다고 생각하는데요...
한방에 하려면 IP_POST_ROUTING에서 하면 되겠지만 질문 드린것과 같이 checksum 문제가 걸리는것 같고...답변 부탁드립니다.

swunk의 이미지

급하게 적다 보니 잘못 적은 부분이 있군요...위의 글은 로그인을 하고 적지 않아서 변경도 안되고...
여튼 라우팅되는 패킷들은 NF_IP_LOCAL_IN에서 후킹이 아니라 NF_IP_PRE_ROUTING에서 후킹을 하려고 합니다.

익명 사용자의 이미지

struct iphdr *iph = (*pskb)->nh.iph;
.
.
.
           diffs[0] = htons(iph->tos) ^ 0xFFFF;
                iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
                diffs[1] = htons(iph->tos);
                iph->check = csum_fold(csum_partial((char *)diffs,
                                                    sizeof(diffs),
                                                    iph->check^0xFFFF));
                (*pskb)->nfcache |= NFC_ALTERED;

mangle table에서 동작하는 TOS target코드의 일부입니다. TOS값을 수정후에는 check 필드를 다시 계산후에 NFC_ALTERED를 설정하는군요. 이게 관계가 있지 않나 싶습니다.

wfellow의 이미지

Quote:
한수 부탁드립니다.

꾸벅

앗! 제게 한수를 부탁 하시다니염?? 제가 할 소릴 하시네여..(몸둘바를 몰겠습니다..ㅡ.ㅡ) 제가 이 바닥에서 어둠의 자식(?)이라서리 괜히 다른분들에게 혼란이나 주지 않을까 걱정입니다. 그냥 지나가는 말로 가볍게 생각해 주심 안될까나염?

Quote:
NF_IP_LOCAL_OUT 후에 checksum계산이 수행되는데 어떤 이유에서 checksum계산을 해야 하는지 궁금합니다. 어차피 checkum 은 이루어 지는데...
제가 살펴본 바로는 제가 살펴보고 있는 코드2.4.20 정확히 말하면 2.4.20-8에서는 NF_IP_LOCAL_OUT 후에 checksum 이 이루어지고 2.4.26인가?(레드헷ES3.0에 기본으로 깔리는 커널)에서는 이와는 달리 NF_IP_LOCAL_OUT 전에 즉, ip_queue_xmit()함수에서 패킷을 후킹하기 전에 checksum계산을 하더군요... 여튼 왜? 다시 checksum을 해야 합니다 말씀 하셨는지 궁금합니다.

Quote:
모듈이 하는 일은 NF_HOOK()등록을 하는데, NF_IP_LOCAL_OUT에서 패킷을 후킹 합니다.
후킹을 해서 하는일은 ip 헤더의 값을(tos값)변경 합니다.

NF_IP_LOCAL_OUT에 등록된 후킹함수를 통해서 struct iphdr*의 tos를 수정하신다는 이야기가 아니셨던가염? 만약 그게 아니라면 말씀하신 내용이 맞습니다. 아니라면 (iph->tos를 수정하셨다면) checksum을 해주시는 것이 맞고요. NF_IP_LOCAL_OUT에서 후킹한 후 패킷의 tos를 수정하셨다면 재계산을 해야 합니다.(이후에 checksum을 하지 않습니다.) TCP나 UDP를 나르는 IP레벨의 checksum 알고리즘에서는 protocol data unit을 계산에 사용합니다. 글구 pseudo header도 마찬가지입니다. (제 기억에는 이 말이 맞기는 한데 지금 찾아보려 하니 당최 찾을 수가 없네염...ㅡ.ㅡ;) 그리고 편의상 위에 적어놓은 TCP/UDP별 함수를 이용하여 checksum을 재생산 했었졈.(아니면 낭팬디...) 그리고서 전송..

Quote:
위에 말씀 드린데로 결국 제가 하고자 하는 것은 시스템을 지나가는 모든 패킷에 대해서(자기 자신에게 전송되는 데이터는 제외하고) 검사를 하고 헤더를 수정하고자 합니다. 이런경우에는 어디서 패킷을 후킹하고 변경하는게 맞는건가요?

간단히 생각하면 FORWARD에서만 검사(?)해도 위의 조건을 충족할텐데요..위에 쓰신대로라면 local에서 작성한 것의 응답패킷이 LOCAL_IN으로 올테니 LOCAL_OUT까지 세군데에서 해야하지 않을까요? (점점 네트웍 장비가 되어 가고 있습니다.^^)

Quote:
제 생각은 외부에서 들어오는 패킷은 IP_LOCAL_IN에서 그리고 자기가 생성해서 내 보내는 패킷은 IP_LOCAL_OUT에서 하는게 적절하다고 생각하는데요...
한방에 하려면 IP_POST_ROUTING에서 하면 되겠지만 질문 드린것과 같이 checksum 문제가 걸리는것 같고...답변 부탁드립니다.

검사를 NF_IP_POST_ROUTING에서는 하지 않는다라고 알고 있는데 이유는 잘 기억이 나질 않네요.. 벌써 치매가 도지나 봅니다. (아마도 netfilter이던가 ipq의 어딘가에서 간단한 주석으로 이유를 봤었던 기억이..) 참고로 말씀드리자면 NF_IP_POST_ROUTING에서 하셔도 됩니다. 뭐 SNAT,DNAT의 mangle도 PRE,POST에서 하는게 정석이거든요^^.

Quote:
지금 개발하는 시스템은 게이트웨이로 동작합니다.
그래서 자기가 생성하는 패킷외에 라우팅되는 패킷에 대해서도 패킷에 수정작업이 가해지기 때문에 원래는 NF_IP_POST_ROUTING 에서 후킹을해서 자기가생성하는 패킷과 라우팅하는 모든 패킷들에 대해서 한번에 해당 작업을 수행하려 했으나 자기가 생성한 패킷의 checksum계산은 ip_queue_xmit2()에서 하기 때문에 그 전에 헤더값을 변경시켜 주려고 했던 것이고 라우팅되는 패킷은 입력단에서 체크섬계산을 하는 것으로 알고 있습니다....그래서 IP_LOCAL_IN(?)에서 잡아서(checksum계산전에) 변경해 주려고 합니다.
이런 이유로 작업을 하려고 하는데 어떤 이유에서 NF_IP_LOCAL_OUT에서 하는일이 아니라고 말씀하신건지 궁금하군요...

이부분은 위의 제가 답변을 드린내용으로 대체합니다.

제가 괜히 중요한 작업을 하시는데 혼란을 드린것이나 아닌지 모르겠습니다. 만약 제가 말씀드린 내용이 맞지 않더라도 키보드로 때리지만 말아주셔염. ㅡ.ㅡ; 어둠의 개발자이다 보니,, 넓으신 이해를 부탁드립니당.

-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----

swunk의 이미지

글로 쓰려니 어렵군요...--;

여튼 답변주셔서 감사합니다.

제 질문이 잘 전달이 안된것 같습니다.

다시 일목 요연하게 정리를 하면...
커널의 어느 지점에서 제가 패킷을 후킹해서 ip 헤더값중 일부(tos 필드)를 수정 했습니다. 커널의 흐름상 제가 수정하고 난 후에 checksum을 수행합니다. 여기서 수행되는 checksum은 제가 호출한 checksum 기능이 아니라 커널에서 호출하는 기능입니다.

예를 들자면 아래와 같은 코드가 있을때...

      :
      :
ip헤더값 확인함수();
ip_checksum수행함수();
      :
      :
이런식으로 커널 코드가 되어 있는데 아래와 같이 바꿨습니다.
      
      :
      :
ip헤더값 확인함수();
tos값 변경 함수
ip_checksum수행함수();
      :
      :

이렇게 했더니 checksum오류가 나는 상황입니다.
이런 상황에서 뭐가 잘못되어서 그런건지 모르겠군요...

제가 잘 이해했는지는 모르겠습니다만..님께서 답변해 주신 말씀은
tos 값 변경 함수 다음에 ip_checkum수행함수()가 호출되어야 한다고 말씀하신것 같은데...위에서와 같이 ip_checksum()수행함수는 헤더값 변경후에 호출이 됩니다.

답변 주시면 감사하겠습니다.

그럼 꾸벅...

swunk의 이미지

아...역시 또 3일동안 삽질을 했군요...

여러분들은 이러지 마세요...

일단 제가 생각했던대로..

커널 2.4.20에서는 NF_IP_LOCAL_OUT에서 패킷을 후킹한 후에 헤더를 수정하고 다시 인위적으로 checksum을 수행할 필요가 없습니다. 어차피 ip_send_chek()가 ip_queue_xmit2()에서 호출되기 때문이조...

그럼 뭐가 문제인가...

음...제가 확인을 icmp(ping 패킷으로)로 계속 확인해 봤거든요..
icmp패킷 같은 경우는 tos 필드가 0x00으로 마킹되어 있어야지 체크섬 에러가 안나더군요...tcp 나 udp 패킷으로 확인해 보니 아무 문제 없이 생각했던 대로 됩니다...

예전에도 이와 비슷한 경우를 당했었는데..역시 정리를 잘 해야 된다는 옛 선현의 말씀이 맞군요...

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.