skb->input_dev 버그

프로그래밍 | 2007/06/13 00:29 | letsme
리눅스 네트웍 코드에서 routing 이후에 skb 구조체의 input_dev 를 확인하여 skb->input_dev 가 NULL 이면 Local 에서 생성된 패킷이고 skb->input_dev 의 값이 채워져 있으면 포워딩된 패킷이라고 판단할 수 있다.

이런 식으로 sk_buff 구조체의 input_dev 필드를 사용할 때 주의할 사항이 있는데 커널 옵션의 네트웍 옵션에서 QoS->Action 옵션을 반드시 켜줘야 한다. 그렇지 않을 경우 input_dev 에 NULL 이 아닌 쓰레기 값이 채워져 있는 경우가 생기게 된다.

그 이유는 skb_clone() 함수에서 앞서 얘기한 옵션이 활성화 되어있지 않을 경우 input_dev 필드를 복사하지 않아 클로닝된 skb 구조체의 input_dev 필드가 쓰레기 값을 가지게 되기 때문이다. 따라서 반드시 해당 옵션을 켜주거나 그렇지 않으면 skb_clone() 함수에서 항상 input_dev 필드를 복사하도록 커널 소스를 수정해야 한다. 해당 커널 코드는 다음과 같다.

net/core/skbuff.c

404 struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
405 {
406         struct sk_buff *n;
407
408         n = skb + 1;
409         if (skb->fclone == SKB_FCLONE_ORIG &
410             n->fclone == SKB_FCLONE_UNAVAILABLE) {
411                 atomic_t *fclone_ref = (atomic_t *) (n + 1);
412                 n->fclone = SKB_FCLONE_CLONE;
413                 atomic_inc(fclone_ref);
414         } else {
            ........
460 #ifdef CONFIG_BRIDGE_NETFILTER
461         C(nf_bridge);
462         nf_bridge_get(skb->nf_bridge);
463 #endif
464 #endif /*CONFIG_NETFILTER*/
465 #ifdef CONFIG_NET_SCHED
466         C(tc_index);
467 #ifdef CONFIG_NET_CLS_ACT
468         n->tc_verd = SET_TC_VERD(skb->tc_verd,0);
469         n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd);
470         n->tc_verd = CLR_TC_MUNGED(n->tc_verd);
471         C(input_dev);
472 #endif
473
474 #endif
475         C(truesize);
             .........
481
482         atomic_inc(&(skb_shinfo(skb)->dataref));
483         skb->cloned = 1;
484
485         return n;
486 }