2012-10-25 16 views
5

मैं कर्नेल स्पेस में एक पैकेट गूंजना चाहता हूं। मैं पोर्ट 6000 के साथ इस मशीन पर एक गूंज सर्वर चलाता हूं। अब क्लाइंट इको सर्वर पर डेटा भेजने वाली दूसरी मशीन पर चलता है। अब, मैं कर्नेल स्पेस से पैकेट को दोबारा गूंजना चाहता हूं। मैं पैकेट के साथ सर्वर को परेशान नहीं करना चाहता, और इसे कर्नेल स्पेस से चुपचाप प्रतिबिंबित किया जाएगा। मैं नीचे अपने कोड प्रस्तुत कर रहा हूं:netfilter हुक का उपयोग कर कर्नेल स्पेस में पैकेट को कैसे गूंजें?

#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/skbuff.h> 
#include <linux/netfilter.h> 
#include <linux/netdevice.h> 
#include <linux/ip.h> 
#include <linux/udp.h> 
#include <linux/mm.h> 
#include <linux/err.h> 
#include <linux/crypto.h> 
#include <linux/init.h> 
#include <linux/crypto.h> 
#include <linux/scatterlist.h> 
#include <net/ip.h> 
#include <net/udp.h> 
#include <net/route.h> 
#include <net/checksum.h> 
#include <linux/netfilter_ipv4.h> 

#define IP_HDR_LEN 20 
#define UDP_HDR_LEN 8 
#define TOT_HDR_LEN 28 

static unsigned int pkt_echo_begin(unsigned int hooknum, 
         struct sk_buff *skb, 
         const struct net_device *in, 
         const struct net_device *out, 
         int (*okfn)(struct sk_buff *)); 

static struct nf_hook_ops pkt_echo_ops __read_mostly = { 
    .pf = NFPROTO_IPV4, 
    .priority = 1, 
    .hooknum = NF_INET_PRE_ROUTING, 
    .hook = pkt_echo_begin, 
}; 

static int __init pkt_echo_init(void) 
{ 
    printk(KERN_ALERT "\npkt_echo module started ..."); 
    return nf_register_hook(&pkt_echo_ops); 
} 

static void __exit pkt_echo_exit(void) 
{ 
    nf_unregister_hook(&pkt_echo_ops); 
    printk(KERN_ALERT "pkt_echo module stopped ..."); 
} 

static unsigned int pkt_echo_begin (unsigned int hooknum, 
         struct sk_buff *skb, 
         const struct net_device *in, 
         const struct net_device *out, 
         int (*okfn)(struct sk_buff *)) 
{ 
    struct iphdr *iph; 
    struct udphdr *udph; 
    unsigned char *data; 

    unsigned char *temp; 

    __u16 dst_port, src_port; 
    int data_len; 



    if (skb) { 
     iph = (struct iphdr *) skb_header_pointer (skb, 0, 0, NULL); 

     if (iph && iph->protocol &&(iph->protocol == IPPROTO_UDP)) { 
      udph = (struct udphdr *) skb_header_pointer (skb, IP_HDR_LEN, 0, NULL); 
      src_port = ntohs (udph->source); 
      dst_port = ntohs (udph->dest); 

      if (dst_port == 6000) { 
       printk(KERN_ALERT "\nUDP packet goes in"); 

       data = (unsigned char *) skb_header_pointer (skb, TOT_HDR_LEN, 0, NULL); 
       data_len = skb->len - TOT_HDR_LEN; 

       struct sk_buff *newskb; 
       struct iphdr *newiph; 
       struct udphdr *newudph; 
       unsigned char *newdata; 
       unsigned int newdata_len; 

       newskb = skb_copy(skb, GFP_ATOMIC); 
       newiph = (struct iphdr *) skb_header_pointer (newskb, 0, 0, NULL); 
       newudph = (struct udphdr *) skb_header_pointer (newskb, IP_HDR_LEN, 0, NULL); 
       newdata = (unsigned char *) skb_header_pointer (newskb, TOT_HDR_LEN, 0, NULL); 

       newiph->saddr = iph->daddr; 
       newiph->daddr = iph->saddr; 

       newudph->source = udph->dest; 
       newudph->dest = udph->source; 

       struct sk_buff *tempskb; 

       tempskb = skb_copy(skb, GFP_ATOMIC); 

       *tempskb = *skb; 
       *skb = *newskb; 
       *newskb = *tempskb; 

       kfree_skb(newskb); 

      } 
     } 
    } 
    return NF_ACCEPT; 
} 


module_init(pkt_echo_init); 
module_exit(pkt_echo_exit); 

MODULE_AUTHOR("Rifat Rahman Ovi: <[email protected]>"); 
MODULE_DESCRIPTION("Echoing a packet from kernel space."); 
MODULE_LICENSE("GPL"); 

अब मुझे समझ में नहीं आता कि क्या आवश्यक है। मैंने PRE_ROUTING हुक में पैकेट पर कब्जा कर लिया। फिर मैंने एक नया स्कैब बनाया, इसे पुरानी प्राप्त स्कैब से पॉप्युलेट किया, और फिर स्रोत पता (सैडर), गंतव्य पता (डैडर), स्रोत पोर्ट (स्रोत), और गंतव्य पोर्ट (dest) को बदल दिया, ताकि पैकेट को PRE_ROUTING हुक से अग्रेषित किया जा सकता है। रूटिंग पैकेट हुक से गुजरने के बाद निर्णय किए जाते हैं, मैं पैकेट को अपने मूल स्रोत पर अग्रेषित करने के लिए देखता हूं। लेकिन किसी कारण से यह ऐसा नहीं कर रहा है। पैकेट प्राप्त होता है, और सबकुछ बदल जाता है, लेकिन पैकेट पीछे की तरफ नहीं लग रहा है। मुझे समझ में नहीं आता कि क्या गुम है, और इसे काम करने के लिए भी क्या जरूरी है। अधिक विशेष रूप से, PRE_ROUTING हुक से नेटवर्क में पैकेट भेजने के लिए क्या आवश्यक है?

+2

आप कहां फंस गए हैं? क्या काम नहीं कर रहा है ** आपका प्रश्न क्या है? ** ("क्या कोई मेरी मदद कर सकता है?" स्वीकार्य प्रश्न नहीं है) –

+1

संकेतों के लिए धन्यवाद: "" क्या कोई मेरी मदद कर सकता है? "एक स्वीकार्य सवाल नहीं है" ... मैं कभी पोस्ट नहीं करूंगा इस तरह कुछ भी..और जल्द ही मैं विशिष्ट होने के लिए सवाल संपादित कर दूंगा। कोड डालने और मदद मांगने के लिए वास्तव में बकवास है .. –

+0

कर्नेल स्पेस में ऐसा करने का आपका क्या कारण है? या सिर्फ सीख रहे हो? – Fingolfin

उत्तर

5

बहुत कुछ गुम है।

सबसे पहले, नेटफिल्टर हुक आप इस्तेमाल किया पूर्व रूटिंग जो आने वाले पैकेट कैप्चर करता है और इसलिए जब तक आप पैकेट आपके द्वारा बनाई गई संचारित करने के लिए कुछ गिरी फ़ंक्शन का उपयोग करें, लौट NF_ACCEPT केवल दूँगी पैकेट आप बदल (या है नहीं किया) अपने रास्ते पर जारी है (जो स्थानीय प्रणाली के लिए है, न कि इससे)।
dev_queue_xmit(struct sk_buff *) जैसे कार्यों के बारे में पढ़ें लेकिन ध्यान दें कि इस फ़ंक्शन का उपयोग करने से पहले, आपके एसकेबी में लिंक-लेयर हेडर होना चाहिए क्योंकि यह फ़ंक्शन वास्तव में एनआईसी को भेजे जाने के लिए आपके कतार में कतार में कतार लगाता है और यह आपके काम को सेट करने के लिए है लिंक परत पते।

दूसरा, याद रखें कि आईपी-हेडर पते को बदलने के बाद आपको पैकेट के चेकसम की फिर से गणना करना होगा या अन्यथा आपका पैकेट दूसरे छोर पर त्याग दिया जाएगा।

तीसरा, ध्यान दें कि कर्नेल स्पेस में जो करने की कोशिश कर रहे हैं, वह काफी हद तक एक बहुत बुरा अभ्यास माना जाता है। कर्नेल मॉड्यूल एक कारण के लिए मौजूद हैं और यह उनमें से एक नहीं है, नेटफिल्टर एक अच्छा उपकरण है, लेकिन यह वास्तव में सामान्य यातायात भेजने के लिए उपयोग नहीं किया जाना चाहिए।

संपादित करें:

अपने नवीनतम टिप्पणी पढ़ना; मेरा सुझाव है कि आप libPCap लाइब्रेरी के बारे में पढ़ लें, यह आपको बहुत अच्छी तरह से सेवा करनी चाहिए और फिर भी अपना काम अपने सही स्थान, उपयोगकर्ता-स्थान पर रखें।

+0

"तीसरा, ध्यान दें कि आप क्या कर रहे हैं कर्नेल अंतरिक्ष में करने की कोशिश कर रहे हैं, इसे काफी खराब अभ्यास माना जाता है। कर्नेल मॉड्यूल एक कारण के लिए मौजूद है और यह उनमें से एक नहीं है, नेटफिल्टर एक अच्छा उपकरण है, लेकिन यह वास्तव में सामान्य यातायात भेजने के लिए उपयोग नहीं किया जाना चाहिए। " यह सिर्फ एक प्रयोग है। मैंने xtables-addons पैकेज सहायक मॉड्यूल के xt_ECHO.c से पैकेट को प्रतिबिंबित किया, और इसे स्क्रैच से कार्यान्वित करने का प्रयास किया, क्योंकि उनके द्वारा उपयोग किए जाने वाले फ़ंक्शन लिनक्स कर्नेल में मौजूद नहीं हैं (किसी भी तरह से मुझे अलग लग रहा था)। तो मैंने कर्नेल में मौजूद कार्यों का उपयोग करके ऐसा करने की कोशिश की। –

+0

ओह यह बहुत अच्छा है। मैं केवल इसका उल्लेख कर रहा हूं क्योंकि मैंने एक गंभीर परियोजना में नेट-फ़िल्टर का उपयोग किया था और यह अभी भी मुझे सिरदर्द दे रहा है। – Fingolfin

+0

असल में, पैकेट गूंजना मेरे प्रोजेक्ट का हिस्सा नहीं है। मेरी प्रोजेक्ट में मुझे एक पैकेट, एन्क्रिप्ट-डिक्रिप्ट पैकेट, विलय-विभाजन पैकेट और इतने सारे पैड पैड करने की आवश्यकता थी। प्रयोगों के लिए, मैंने प्रयोग के लिए गूंजने की कोशिश की। यहां मेरे प्रश्नों के लिंक दिए गए हैं: http://stackoverflow.com/questions/12529497/how-to-append-data-on-a-packet-from- कर्नेल- स्पेस?rq=1 और http: // stackoverflow। com/प्रश्न/12999548/कैसे करने वाली मार्ग-splitted-पैकेट का इस्तेमाल करने वाली-नेटफिल्टर-हुक में कर्नेल-स्थान। हां, यह कर्नेल स्पेस में गैर-मानक चीजों को संभालने के लिए बहुत घृणित है .. –

1

पिछले जवाब के अलावा, एक और तकनीक है कि नेटफिल्टर कॉलबैक से एक यूडीपी पैकेट प्रतिध्वनित करने के लिए इस्तेमाल किया जा सकता है:

पैकेट वापस भेजने, एक नया यूडीपी पैकेट के रूप में, का उपयोग करते हुए:

int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)

जाल में

/socket.c

या भी netpoll लाइब्रेरी का उपयोग कर, जवाब here में कहा के रूप में।

मूल पैकेट को NF_DROP का उपयोग करके छोड़ दिया जा सकता है।

नेटफिल्टर कॉलबैक में, जो "इंटरप्ट संदर्भ" में चलता है, पैकेट भेजने के लिए संभव है, लेकिन उन्हें प्राप्त करना संभव नहीं है (क्योंकि प्रत्येक प्रयास प्रतीक्षा करने के लिए कर्नेल आतंक का कारण बनता है)। इसी कारण से मैंने प्रस्तावित समाधान यूडीपी के साथ काम किया है, लेकिन टीसीपी के साथ काम नहीं कर सकता (टीसीपी हैंडशेक की आवश्यकता है कि एसीके संदेश प्राप्त होना चाहिए)।

वैसे भी, जैसा कि पहले से ही कहा गया है, कर्नेल स्पेस में इस तरह की चीजें करना बीएडी है और केवल सीखने के उद्देश्यों के लिए उपयोग किया जाना चाहिए।