Raw 소켓에서 프로토콜 헤더작성시 의문점

bw001730의 이미지

안녕하세요. 질문이 있어서 글을 올려봅니다.

질문은 Raw 소켓에 대한 것인데요..
Raw 소켓으로 IP 헤더를 작성하는 예를 들어보겠습니다.
아래는 리눅스에서 Raw 소켓으로 ICMp Echo 패킷을
작성하는 코드의 일부입니다. 대충 보시면 이해되실것 같습니다.
in_chksum() 함수는 첵섬함수인거 아시죠? ^^

ip->ihl = 5;
ip->version = 4;
ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct icmphdr));
ip->id = htons( getpid() );
ip->check = in_cksum(...);
..................등등..... 이하 생략

icmp->type = ICMP_ECHO;
icmp->un.echo.sequence = getpid();
icmp->un.echo.id = getpid();
icmp->checksum = in_chksum(.... );

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

저는 ip 헤더를 설정하는 것을 보고
왜 Byte order가.....
IP 헤더의 어떤 필드는 Host Order, 어떤 필드는 Network Order일까?
궁금했습니다.
근데...좀더 보니깐..결국 모든 필드가 Network Order 이더군요
어차피 한바이트 이하의 필드는 Order 바꿔야 의미없을테니깐요

그런데.................
왜 ICMP 헤더는 전부... Host Order일까요?

글구... 왜.. 첵섬값은 무조건 호스트 오더인가요?

첵섬값 계산방식은 알고 있습니다만..
(홀수/짝수 바이트 쪼개서, 더하고, Not 연산하는거)

alsong의 이미지

규약이 그런거 아닐까요?
요렇게 저렇게 보내기로 한다.

그나저나 백수 언제 탈출하냐... ㅡㅡ; 배고파라.

bw001730의 이미지

만약
리틀엔디안인 호스트에서 첵섬값을 계산하여 Host Order로 보내고
이것을 빅엔디안 호스트에서 수신한다면..........
빅엔디안 호스트가 계산한 첵섬값과 수신된 첵섬값은 다르게 됩니다.

왜냐하면
1. 빅엔디안에서 패킷을 수신한 후 나름대로 패킷의 첵섬값을 계산하고.
2. 패킷의 첵섬필드의 첵섬값과, 1에서 계산한 첵섬값을 비교할텐데요

3. 첵섬필드의 값은 리틀엔디안인 상태에서 계산한 첵섬값이므로 값이 다르게 될것입니다.

4. 패킷의 첵섬값을 빅엔디안이라 가정하고 비교할테니까요

규약이 어떤 필드는 호스트오더,
어떤 필드는 네트워크 오더로 설정하는 이유는 무엇일까요?

doseon의 이미지

저역시 엔디안만 나오면 너무 헷갈립니다.
특히, 비트필드에서는...^.^
엔디안 문제는 bw001730님께서 말씀하신 것처럼,
Host에서 그 값을 해석할 때 생기는 문제이겠죠.
IP 헤더와 같은 것은 이 패킷을 수신하는 모든 Host가 해석을 해야만 하므로
Big Endian(network order)으로 아예 규정을 해 놓았습니다.

하지만 ICMP의 경우, 아마도 ICMP echo 응답을 하는 측에서는
sequence 와 id에 대해 해석할 필요가 없어서 그런것 같습니다 (억지로 때려 맞추자면 그렇다는.. ^.^).

seqeunce와 id의 경우, 보내는 Host가 여러개의 ping을 보냈을때,
이들 응답을 서로 구분해 주기 위한것이 주 목적이라고 생각합니다.
그 값들이 순전히 Ping request를 보내는 측에게만 의미가 있기 때문에,
ping request를 수신한 Host는 seqeunce와 id를 해석할 필요가 없고
그냥 ping response에 복사하면 된다는 의미죠. 따라서 그 값의 Endian은
Ping request를 보내는 측이 마음대로 결정해도 될것 같습니다.

Sequence가 TCP에 있는 sequence와 같은 용도로 사용되려면,
보내는 측과 받는 측이 ping을 보내기 전에 이에 대한 핸드세이킹이
필요하고, 또 각 ping에대한 state를 송/수신측이 갖고 있어야한다는
오버헤드가 생깁니다.

체크섬은 어떤 의미를 따지는 값(해석해야하는 값)이라기 보다
계산 결과를 단순 비교하는 값입니다.
예를 들어 어떤 패킷의 checksum값이 Big Endian으로 0xab34라고 할때,
Little Endian 호스트의 경우, 헤더에 있는 체크섬값을 읽어 보면 0x34ab로 읽히겠죠. 하지만, Little Endian 호스트가 헤더에 대해 체크섬을 직접 계산해
보면 계산 결과가 똑 같은 값인 0x34ab 됩니다. 즉, 두 결과가
똑 같기 때문에 문제가 되지 않는다는 이야기죠.

으~~ 횡설수설이 되어 버렸네요.

asteroid의 이미지

ICMP메시지도 network byte order를 따릅니다.

말씀하신대로, 대부분 1byte의 값을 가진 정보들이고,

값의 내용을 sequencing하게 처리할 필요가 없기 떄문이지요. :-)

그리고, checksum값도 network byte order를 따라야 합니다.

순서가 바뀌면, 검사에서 잘못된 값이 나오게 되므로

intermediate/destination node에서 버리게됩니다.

bw001730의 이미지

doseon 님께서 쓰신 글을 읽고
아하 그렇군요 했습니다.
또 .. ICMP 에코우 시퀀스번호나 아이디가 수신측에서는 별의미가 없겠네요
아는게 없다보니 정말 많은 도움되었습니다. 무지 감사~~드리옵니다.

asteroid 님도 감사 ^_^ 꾸벅

한가지 첵섬에 대한 부분은..
asteroid 님의 글이 맞는것 같은 생각이 들어지네요

0xab34 로 첵섬값 계산해서 목적지 호스트로 전달했을때...
목적지 호스트에서 계산하면 0x34ab가 나온다면..
두 값은 다른 값이 될 것 같습니다.
송신지에서 의미하는 0xab34가 목적지에서는 0x34ab로 읽혀지게
될것 같은데요..
흠...어쨌든
저도 첵섬에 대한 부분은 asteroid 님의 말씀이 맞는거 같은데요

그렇다면... 왜...

소스 코드에서는 호스트오더로 계산해서 보내는 것일까요?
in_cksum() 함수가 리턴한 값은 분명 호스트오더일텐데요
htons( in_cksum(..) ); 이런식으로 해야할것 같은데...

암튼 두분 답변 정말 감사드립니다.

doseon의 이미지

규약된 모든 필드는 네트워크 오더로 전송되어야 하겠죠..

단지 제가 말씀드리고자 했던것은
ip->check = in_cksum(...);
에서, in_cksum 의 계산 방식이 호스트 방식과는 무관하게
사용될 수 있도록 되어 있다는 것이었습니다.

예를 들어, 다음과 같은 패킷이 있다고 가정하겠습니다.
Packet: {0xa0, 0x40, 0x0b, 0x03} {0xab, 0x34}
-------------------------------- ------------
{데이터 부분} { 체크섬(그냥 2바이트 단위로 더한결과)}

여기서 체크섬방식을, 그냥 '두바이트 단위 더하기 방식'으로 변경했습니다.

이 패킷을 Big 호스트가 받으면,
1) 데이터부분을 체크섬한다. 결과 = 0xab34
2) 체크섬부분을 읽는다. 결과 = 0xab34
3) 위 1), 2) 결과가 같으므로 유효한 데이터이다

이 패킷을 Little 호스트가 받으면,
1) 데이터부분을 체크섬한다. 결과 = (0x40a0 + 0x030b) = 0x43ab
2) 체크섬부분을 읽는다. 결과 = 0x43ab
3) 위 1), 2) 결과가 같으므로 유효한 데이터이다

체크섬 결과는 단지, 위 1), 2) 결과를 비교하는 용도로만 사용되므로
문제가 되지 않을 것 같습니다.

asteroid의 이미지

doseon wrote:
데이터부분을 체크섬한다.

IP헤더의 checksum은 패킷의 데이터 부분에대한 것이 아닙니다.

그리고, checksum은 언급하신 동작방식과 원리적으로 다르죠.

잠깐 잘못 쓰신 것 같습니다.

댓글 달기

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