sk_buff의 data를 직접 수정하려 하는데 잘 안되네요.
글쓴이: webispy / 작성시간: 목, 2006/08/10 - 6:41오후
안녕하세요
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로 찍어봤을때 변경된 내용은 제대로 나왔습니다.
도움 부탁드립니다..
Forums:
TCP checksum문제인듯
TCP header의 checksum 필드는 segment전체를 가지고 계산을 합니다.
이에반해 IP header의 checksum은 payload는 계산하지 않죠.
tcp_v4_check() 함수등을 써서 payload변경 후 새로운 checksum
을 계산해보세요~
/***************************************
Being the one is just like being in love.
***************************************/
tcp_v4_check에서 base가 무엇인지 잘 모르겠습니다.
답변 감사합니다.
include/net/tcp.h에 보니까
tcp_v4_check()함수가 1줄짜리 return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_TCP, base);로 되어 있더군요.
여기서 base가 무엇인지 잘 모르겠습니다.
csum_partial()로 만든 값을 넣는것 같은데..
제 지식이 얕다보니 어떤 의미인지 정확히 이해가 잘 안가서 이것저것 다른 소스 찾아보면서 테스트해보고 있습니다.
근데 계속 원래의 tcph->check값과 제가 직접 만든 checksum값이 다르게 나오네요..
조금만 더 힌트 부탁드립니다.
코드를 뒤져보면 base
코드를 뒤져보면 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에 정의 되어 있군요...
으아아... 질문내용이 좀 많습니다..
sk_buff의 (*skb)->csum과 tcph->check의 관계(?)에 대해 잘 모르겠습니다.
tcp_v4_check함수를 따라가 보면
*th는 사용하질 않더군요.
이런식으로 되어 있습니다.
그리고 csum_nofold는 아래의 소스코드로 구성되어 있고요.
1. tcp_v4_check()는 결국 payload에 대한 체크섬을 직접 계산하는게 아니라, 단지 계산된 payload의 체크섬을 받아서 거기에 pseudo header정보를 넣어서 체크섬을 계산해 주는 것인가요?
2. (*skb)->csum은 어느것에 관한 체크섬인가요?
3. netfilter를 이용해서 필터링(NF_IP_PRE_ROUTING) 할 때, 직접 payload를 변경한다면, 체크섬 계산을 위해 tcph->check만 변경해 주면 되는 건가요? 아니면, (*skb)->csum도 같이 변경해줘야 하나요?
하아.. 이거가지고 며칠째 밤새도록 헤매고 있습니다. 작은 도움이라도 부탁드립니다.
커널의 net/ipv4/netfilter/ip_nat_helper.c 소스 파일을 참조하세요~
커널의 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.
***************************************/
감사합니다~ 해결했습니다~
kernel/net/ipv4/netfilter/ip_nat_helper.c에 있는 것처럼 하니까 잘 되네요.
도움주신분들 진심으로 감사드립니다.
kernel-2.6.38
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);
}
댓글 달기