sk_buff의 data를 직접 수정하려 하는데 잘 안되네요.

webispy의 이미지

안녕하세요

netfilter를 사용하는 모듈안에서 sk_buff의 data영역을 직접 수정하려고 합니다.

사용하는 목적은 HTTP프로토콜같은 데이터의 특정 문자를 다른 것으로 치환하려고 하는 것이고요.
(웹서버 모듈로 만드는게 더 좋겠지만, 여러 웹서버에서 범용적으로 사용하기 위해 직접 커널 모듈단에서 처리하려고 합니다.)

근데 문제가, data에서 원하는 특정 문자를 찾는것 까지는 잘 했습니다만, 그 위치에 다른 글자를 넣으니 문제가 발생하네요.

제가 변경한 data를 무시하고 클라이언트의 웹브라우저가 다시 HTTP 데이터를 보냅니다.

대략적인 소스는
data = ((*skb)->data) + 40(헤더부분 건너띔);
...
HTTP헤더 건너띔(\r\n\r\n까지)
i=HTTP헤더 다음위치
...
printk("before: %s\n", data+i);
...
for(j=i; ... ; j++) {
if( data[j] == 'h' ) {
data[j] = 'i';
}
}
...
printk("after : %s\n", data+i);
...
이렇습니다.
printk로 찍어봤을때 변경된 내용은 제대로 나왔습니다.

도움 부탁드립니다..

prether의 이미지

TCP header의 checksum 필드는 segment전체를 가지고 계산을 합니다.

이에반해 IP header의 checksum은 payload는 계산하지 않죠.

tcp_v4_check() 함수등을 써서 payload변경 후 새로운 checksum
을 계산해보세요~

/***************************************
Being the one is just like being in love.
***************************************/

webispy의 이미지

답변 감사합니다.

include/net/tcp.h에 보니까
tcp_v4_check()함수가 1줄짜리 return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_TCP, base);로 되어 있더군요.

여기서 base가 무엇인지 잘 모르겠습니다.
csum_partial()로 만든 값을 넣는것 같은데..
제 지식이 얕다보니 어떤 의미인지 정확히 이해가 잘 안가서 이것저것 다른 소스 찾아보면서 테스트해보고 있습니다.
근데 계속 원래의 tcph->check값과 제가 직접 만든 checksum값이 다르게 나오네요..

조금만 더 힌트 부탁드립니다.

swunk의 이미지

코드를 뒤져보면 base 라는 값이 skb_checksum()함수의 리턴값임을 알 수 있을겁니다.
코드를 보시면 아시겠지만 unsigned int skb_checksum(const struct sk_buff *skb, int offset, int len, unsigned int csum)함수는 2번째 3번째 파라미터 사이의 skb 영역에 대해서 (skb->data 영역인것 같습니다) checksum을 계산하는 함수 이고 이에 대한 결과값을 리터하는데 그 값이 base 파라미터로 넘어가게 되는것 같습니다.

skb_checksum함수는 sk_buff.c에 정의 되어 있군요...

webispy의 이미지

sk_buff의 (*skb)->csum과 tcph->check의 관계(?)에 대해 잘 모르겠습니다.

tcp_v4_check함수를 따라가 보면

__inline__ u16 tcp_v4_check(*th, len, saddr, daddr, base) {
   return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_TCP, base);
}

*th는 사용하질 않더군요.

unsigned short int csum_tcpudp_magic(saddr, daddr, len, proto, sum) {
   return csum_fold(csum_nofold(saddr,daddr,len,proto,sum));
}

이런식으로 되어 있습니다.

그리고 csum_nofold는 아래의 소스코드로 구성되어 있고요.
{
    __asm__(
        "addl %1, %0    ;\n"
        "adcl %2, %0    ;\n"
        "adcl %3, %0    ;\n"
        "adcl $0, %0    ;\n"
        : "=r" (sum)
        : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum));
    return sum;
}

1. tcp_v4_check()는 결국 payload에 대한 체크섬을 직접 계산하는게 아니라, 단지 계산된 payload의 체크섬을 받아서 거기에 pseudo header정보를 넣어서 체크섬을 계산해 주는 것인가요?

2. (*skb)->csum은 어느것에 관한 체크섬인가요?

3. netfilter를 이용해서 필터링(NF_IP_PRE_ROUTING) 할 때, 직접 payload를 변경한다면, 체크섬 계산을 위해 tcph->check만 변경해 주면 되는 건가요? 아니면, (*skb)->csum도 같이 변경해줘야 하나요?

하아.. 이거가지고 며칠째 밤새도록 헤매고 있습니다. 작은 도움이라도 부탁드립니다.

prether의 이미지

커널의 net/ipv4/netfilter/ip_nat_helper.c 소스 파일을
보면 FTP packet을 NAT하여 content가 바뀐 경우
다시 TCP CS를 계산하는 코드조각이 있습니다.

아래와 같습니다.(일부 생략)

struct iphdr *iph;
struct tcphdr *tcph;
int datalen;

iph = (*pskb)->nh.iph;
tcph = (void *)iph + iph->ihl*4;

datalen = (*pskb)->len - iph->ihl*4;
tcph->check = 0;
tcph->check = tcp_v4_check(tcph, datalen, iph->saddr, iph->daddr,
csum_partial((char *)tcph, datalen, 0));

/***************************************
Being the one is just like being in love.
***************************************/

webispy의 이미지

kernel/net/ipv4/netfilter/ip_nat_helper.c에 있는 것처럼 하니까 잘 되네요.

    /* fix checksum information */
 
    iph->tot_len = htons(newlen);
    (*skb)->csum = csum_partial((char *)tcph + tcph->doff*4,
                    newtcplen - tcph->doff*4, 0);
 
    tcph->check = 0;
    tcph->check = tcp_v4_check(tcph, newtcplen, iph->saddr, iph->daddr,
                   csum_partial((char *)tcph, tcph->doff*4,
                       (*skb)->csum));

도움주신분들 진심으로 감사드립니다.

익명 사용자의 이미지

kernel/net/ipv4/netfilter/nf_nat_helper.c에 있는 nf_nat_csum 함수


static void nf_nat_csum(struct sk_buff *skb, struct iphdr *iph, void *data,
int datalen, __sum16 *check, int oldlen)
{
struct rtable *rt = skb_rtable(skb);

if (skb->ip_summed != CHECKSUM_PARTIAL) {
if (!(rt->rt_flags & RTCF_LOCAL) &&
skb->dev->features & NETIF_F_V4_CSUM) {
skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum_start = skb_headroom(skb) +
skb_network_offset(skb) +
iph->ihl * 4;
skb->csum_offset = (void *)check - data;
*check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
datalen, iph->protocol, 0);
} else {
*check = 0;
*check = csum_tcpudp_magic(iph->saddr, iph->daddr,
datalen, iph->protocol,
csum_partial(data, datalen,
0));
if (iph->protocol == IPPROTO_UDP && !*check)
*check = CSUM_MANGLED_0;
}
} else
inet_proto_csum_replace2(check, skb,
htons(oldlen), htons(datalen), 1);
}

댓글 달기

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