리눅스 커널에서 tcp/udp/raw data checksum() 함수는?

skjean의 이미지

어떤것인지 궁금합니다.
ip header의 checksum을 계산하기 위해서는 ip_send_check()라는
커널 함수를 호출하면 되더군요.. 내부적으로는 아키텍춰에 따라서
어셈블리어로 구현된 ip_csum_fast() 코드를 호출합니다.

그런데.. 전송 계층의 TCP/UDP/RAW에 대해서는 어떤 함수를 호출하여
각 프로토콜 헤더의 Checksum field를 채우는지 찾기가 너무 힘들어요..

아시는 분들의 도움 간절히 부탁드립니다.

yundream의 이미지

skjean wrote:
어떤것인지 궁금합니다.
ip header의 checksum을 계산하기 위해서는 ip_send_check()라는
커널 함수를 호출하면 되더군요.. 내부적으로는 아키텍춰에 따라서
어셈블리어로 구현된 ip_csum_fast() 코드를 호출합니다.

그런데.. 전송 계층의 TCP/UDP/RAW에 대해서는 어떤 함수를 호출하여
각 프로토콜 헤더의 Checksum field를 채우는지 찾기가 너무 힘들어요..

아시는 분들의 도움 간절히 부탁드립니다.

구글에서 icmp_cksum을 키워드로 검색해보시기 바랍니다.
그럼 다음과 같은 코드를 발견할 수 있는데 체크섬을 만들기 위한 공통 함수입니다.

static unsigned short
ipcksum(void *buf, int nbytes)
{
	unsigned long sum;

	sum = 0;
	while (nbytes > 1) {
		sum += *(unsigned short *)buf;
		buf += 2;
		nbytes -= 2;
	}
	/* Add in odd byte if any. */
	if (nbytes == 1)
		sum += *(char *)buf;

	sum = (sum >> 16) + (sum & 0xffff);     /* hi + lo */
	sum += (sum >> 16);                     /* add carry, if any */

	return (~sum);
}
skjean의 이미지

답변 감사드립니다.
그런데, 원했던 답은 아닌듯하구여...

예를들어, 네트워크 드라이버 코드 내에서 전송되는
패킷의 특정 필드(예를 들어, IP Source Address 32 bits)를 변경시키면, 이는 벌써 Checksum이 상위
커널에서 계산되었으므로 변경으로 인해 잘못된
Checksum이 됩니다. 이 경우 IP header에 대해서는
커널의 ip_send_check()를 호출하여 Checksum을
재 계산해주면 되는데, 전송 계층의 tcp/udp에 있는
checksum에 대해서도 다시 특정 함수를 호출하여
Checksum을 다시 계산해 주어야 합니다.

tcp/udp의 경우, pseudo header를 통해서
checksum을 계산하기 때문에, IP header가
변경되어도 기존의 checksum은 엉터리 값이 되고
마는것 같습니다.

실험을 해보니, IP header를 수정한 이후에
ip_send_check()를 호출하지 않고 전송하면
목적지까지 전송이 되지 않습니다.
ip_send_check()를 호출해주면 목적지까지
전송은 됩니다만.. 엉터리 정보가 배달됩니다.

그래서 udp/tcp header에 대해서도 checksum()을
다시 계산해 주어야만 올바른 데이터가 올바른
목적지까지 전송될 것 같습니다. 어떤 함수를 호출해
주어야 할까요.. 헉.. 어려워요...

야튼 이것이 제 질문의 의도입니다.

답변 감사드립니다.... ^^;;

merely_c의 이미지

132 /*
133  * computes the checksum of the TCP/UDP pseudo-header
134  * returns a 16-bit checksum, already complemented
135  */
136 static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
137                                                    unsigned long daddr,
138                                                    unsigned short len,
139                                                    unsigned short proto,
140                                                    unsigned int sum) 
141 {
142         return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
143 }
144 

/include/asm-i386/checksum.h 에 있습니다.

정보공유는 자신감의 표현입니다

skjean의 이미지

헉 .. 저랑 같은 코드를 찾으셨습니다.
다음과 같이 udp checksum 재계산 해주었습니다.
그랬더니.. 값은 다시 계산했어요..

/* Replacement of Source IP Address Header */
iph->saddr = htonl( SourceIp );

/* IP Header checksum recalculation */
ip_send_check( iph );
/* UDP Header checksum recalculation */
printk("UDP CheckSum : before %x\n", skb->h.uh->check);
skb->h.uh->check = csum_tcpudp_magic( iph->saddr, iph->daddr,
                                ntohs(skb->h.uh->len), IPPROTO_UDP, skb->csum );
printk("UDP CheckSum : after  %x\n", skb->h.uh->check);

그런데.. 이 값을 skb->h.uh->check에 치환하고
전송해보았지만... 역시 마찬가지 결과입니다.
(전송은 되는데.. header 정보가 깨져 있습니다.)

** 계산된 udp checksum은 skb->h.uh->check에
넣는것이 맞는지??? 이 부분이 첫번째 의심되는
부분입니다. **

실제 패킷을 캡춰해서 분석해보면
캡춰된 패킷의 udp checksum 값은 여기서 계산된
것과는 전혀 다른 값으로 나왔습니다.

음.. 어렵습니다. 어케 해야 할까요?

답변 대단히 감사드립니다.
좀만 더 도와주세요....

merely_c의 이미지

skjean wrote:
헉 .. 저랑 같은 코드를 찾으셨습니다.
다음과 같이 udp checksum 재계산 해주었습니다.
그랬더니.. 값은 다시 계산했어요..

/* Replacement of Source IP Address Header */
iph->saddr = htonl( SourceIp );

/* IP Header checksum recalculation */
ip_send_check( iph );
/* UDP Header checksum recalculation */
printk("UDP CheckSum : before %x\n", skb->h.uh->check);
skb->h.uh->check = csum_tcpudp_magic( iph->saddr, iph->daddr,
                                ntohs(skb->h.uh->len), IPPROTO_UDP, skb->csum );
printk("UDP CheckSum : after  %x\n", skb->h.uh->check);

그런데.. 이 값을 skb->h.uh->check에 치환하고
전송해보았지만... 역시 마찬가지 결과입니다.
(전송은 되는데.. header 정보가 깨져 있습니다.)

** 계산된 udp checksum은 skb->h.uh->check에
넣는것이 맞는지??? 이 부분이 첫번째 의심되는
부분입니다. **

실제 패킷을 캡춰해서 분석해보면
캡춰된 패킷의 udp checksum 값은 여기서 계산된
것과는 전혀 다른 값으로 나왔습니다.

음.. 어렵습니다. 어케 해야 할까요?

답변 대단히 감사드립니다.
좀만 더 도와주세요....

저두 무작정 코드만 찾아서 올렸는데...그게 아니네요..
곰곰히 생각해 보닌깐...IP 주소를 바꾸면 ip 체크섬만 하면 되는게 아닌가 하는 생각도 들고 ..고민되네요...

우선 디버깅으로 에러나는 제일 첨 방법으로 해서리...
패킷을 받는 호스트의 어디에서 에러가 나는지..체크하심이 어떨런지요..
체크섬 에러가 IP 에서 나는지 UDP 에서 나는지...

혹 ip_fast_csum 함수로 ip_send_check 를 대치하시는 방법도 생각해 보시구요..

대상 호스트가 랜상에 있는지 아니면 라우터를 거치는 지에 따라서 ...
neighbour 관련 함수를 부르는지 ip_route_output 을 부르는지....
거기서 다시 체크섬을 하는것 같드라구요....

도움이 안되는것 같네요...

정보공유는 자신감의 표현입니다

skjean의 이미지

답변 정말 감사드립니다.

참고로 IP header가 바뀌어도 UDP/TCP
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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.