LINUX.ORG.RU

sk_buff Данные из пакета


0

1

Пишу (пытаюсь) модуль для ядра (анализ пакетов), но знаний в Си и в сетевой подсистеме Linux маловато...
Не могу вытянуть из sk_buff данные пакета. Точнее там какаято чушь...
Кусок кода

unsigned int Hook_Func(uint hooknum,
                        struct sk_buff *skb,
                        const struct net_device *in,
                        const struct net_device *out,
                        int (*okfn)(struct sk_buff *)  )
{
struct iphdr *ip;
struct tcphdr *tcp;
...................
        memcpy(data, skb->data + sizeof(ip) + sizeof(tcp), skb->data_len);
        printk (KERN_INFO "%s\n", data);
        printk (KERN_INFO "%u\n", skb->len);
        printk (KERN_INFO "%u\n", skb->data_len);
...................
    return NF_ACCEPT
...................

пробовал и так: sprintf (data, «%s», (char*)skb->data);
Игрался и с отступом (sizeof(ip) + sizeof(tcp)) и с размером (skb->data_len)
Выдаёт либо «E», либо такую хрень:

[57414.859619] Data:
[57414.859625] W▒▒▒▒
[57414.859626] 150
[57414.859626] 110

А там HTTP передаётся...

Подскажите пожалуйста где загвоздка

Ответ на: комментарий от Inversiya

Я не совсем понял, каким образом вы выводите данные. Тут же нельзя использовать простой printk(%s,data). Пробуйте выводить по байтно в hex, типа

for(i=0; i < skb->len;i++) printk(%x , data[i]);
printk("\n");

Dead ★★★★ ()
Ответ на: комментарий от Dead

попробовал как вы предложили, выводит
«450096cb34400406ceca5bd6f28e57fafa39d9e0506b6d4f9249ecfba150180b7a0eb002010100040c5771e088ffff100000000c5771e088ffff0000000000000000000000008106f00eaffff00006e00000000000000000005e0000000120000000000000»
Если это содержание пакета, то как его привести в читаемый вид...
так как идёт речь о http, то хотелось бы увидеть GET, Host etc

Inversiya ()

Срочно читать википедию про C и IP/TCP пакеты

vasily_pupkin ★★★★★ ()
Ответ на: комментарий от Inversiya

Я в юзерспейсе обычно использую функцию dump(), которую когда-то давно где-то нашел. Вот ее код

/*****************************************************************************/
/**
 *    Convert dump to string
 *
 *    @param[in]  buf_in        Pointer to incoming  buffer
 *    @param[in]  ln_in         Incoming buffer size
 *    @param[out] buf_out       Pointer to  outgoing buffer
 *    @param[out] ln_out        Outgoing buffer size
 */
 char* dump (const char *buf_in, int ln_in, char *buf_out)
{
    static const char *code      = "0123456789ABCDEF";
    static const char dumpline[] = "                                                 | ";
    char *temp = buf_out;
    if (buf_in == NULL) {
        strcpy(buf_out, "<null>\n");
        return buf_out;
    }
    char line[256];
    int addr = 0;


    while (addr < ln_in) {
        sprintf(temp,"%04X: ",addr);
        temp += 6;

        memcpy(line,dumpline,sizeof(dumpline));
        int temp_n;
        int n;
        for ( n = 0, temp_n = sizeof(dumpline) - 1; n < 16 && addr < ln_in; n++, buf_in++, addr++) {
            char ch = *buf_in;
            line[3*n]   = code[(ch>>4)&0xF];
            line[3*n+1] = code[ch&0xF];
            switch (ch){
                case '\n':line[temp_n++]='\\';ch='n'; break;
                case '\t':line[temp_n++]='\\';ch='t'; break;
                case '\r':line[temp_n++]='\\';ch='r'; break;
                case '\a':line[temp_n++]='\\';ch='a'; break;
                default:
                    if (ch < 0x20) ch = '.';
            }

            line[temp_n++] = ch;
        }

        line[temp_n]   = '\n';
        line[temp_n + 1]   = 0;

        strncpy(temp, line, temp_n + 2);
        temp += temp_n + 1;
    }
    return buf_out;
}
 
/*****************************************************************************/



int main(int argc, char *argv[])
{

    char *buf;
    char *dump_text = "abcdef";
    
    
    buf = malloc(strlen(dump_text) * 10);
    printf("%s\n", dump(dump_text, strlen(dump_text), buf));
    
	
}

Попробуйте адаптировать под ядро. Главное, учтите что выходной буфер для dump() должен быть больше чем входной.

Dead ★★★★ ()
Ответ на: комментарий от Dead

Спасибо за Конвертер!!!!
на сколько я понял гугля.. skb->data выглядит так:
skb->data = ip заголовок + tcp заголовок + data (данные в пакете)
skb->len = полный размер пакета
skb->data_len = размер данных в пакете (без заголовков)

Я правильно понимаю????

Inversiya ()
Ответ на: комментарий от Inversiya

Если мне не изменяет память, то там еще должен быть заголовок ethernet пакета.

Dead ★★★★ ()
Ответ на: комментарий от Inversiya

чтобы достучаться до ip хидера, имхо логичнее использовать функцию:

static inline unsigned char *skb_network_header(const struct sk_buff *skb)

Вчера был подобный топик:

Утекает память.

Dead ★★★★ ()
Последнее исправление: Dead (всего исправлений: 1)
Ответ на: комментарий от Dead

Да сдался мне этот ip заголовок... :)
мне данные из пакета нужны...
А по поводу ethernet заголовка... по моему нет, на сколько я начитал...
возможно он в data->head

Inversiya ()
Ответ на: комментарий от Inversiya

Если это содержание пакета, то как его привести в читаемый вид...

echo "450096cb..." | xxd -r -p
Deleted ()
Ответ на: комментарий от Dennis7

skb->tail разве не равен skb->data + skb->len ????
если нет, то подскажите как это лучше сделать... пробовал в цикле, меня компилятор обматюкал...

Inversiya ()
Ответ на: комментарий от Dennis7

И ещё не совсем понял про IP адрес, что там имелось ввиду?
Заранее спасибо

Inversiya ()
Ответ на: комментарий от Inversiya

Конечно, там есть i. Его движок форума загамал :)

Для кода используй Lor-code

Dennis7 ()
Ответ на: комментарий от Inversiya

skb->tail разве не равен skb->data + skb->len ????
если нет, то подскажите как это лучше сделать... пробовал в цикле, меня компилятор обматюкал...

По этой теме есть книжка - Understanding linux network internals, лучшее её почтитать. Еще есть вот это. Там схематично показана интересующая тебя структура. Но я не уверен, что там не старая информация, так что лучше все-таки почитать книжку.

По идее надо сделать следующее:

/* взять указатель skb->data и отступить от него заголовки сетевого и транспортного уровней стека TCP/IP */

char *user_data_ptr = (char *)(skb->data+sizeof(struct iphdr)+sizeof(struct tcphdr));
...
/* Затем */
if (user_data_ptr < skb->tail)

while (user_data_ptr < skb->tail) {
    printk("%x", *user_data_ptr);
    user_data_ptr++;
}

Наверно как-то так. Код за тебя тут никто писать не будет (по крайней мере бесплатно).

Dennis7 ()
Ответ на: комментарий от Dennis7

попробовал как вы предложили... компилятор заявил:
comparison between pointer and integer
Посмотрел я в include/linux/skbuff.h и... не понял...

 
............
 *      @head: Head of buffer
 *      @data: Data head pointer
 *      @tail: Tail pointer
............
        /* These elements must be at the end, see alloc_skb() for details.  */
        sk_buff_data_t          tail;
        sk_buff_data_t          end;
        unsigned char           *head,
                                *data;
        unsigned int            truesize;
        atomic_t                users;
............

Напечатав skb->tail он оказался равен 320 ....
Это что смещение от skb->data ??

Inversiya ()
Ответ на: комментарий от Inversiya

И ещё один вопрос.
это типичный GET запрос, взятый с wiki

GET /about.html HTTP/1.1
Host: example.org
User-Agent: MyLonelyBrowser/5.0
Вставив его в HEX редактор, я получил
474554202F61626F75742E68746D6C20
485454502F312E310D0A486F73743A20
6578616D706C652E6F72670D0A557365
722D4167656E743A204D794C6F6E656C
7942726F777365722F352E3000000000
Это ли я должен увидеть в идеале при выводе skb->data + отступ ??

Inversiya ()
Ответ на: комментарий от Inversiya

попробовал как вы предложили... компилятор заявил:
comparison between pointer and integer

Правильно, потомучто...

#if BITS_PER_LONG > 32
#define NET_SKBUFF_DATA_USES_OFFSET 1
#endif

#ifdef NET_SKBUFF_DATA_USES_OFFSET
typedef unsigned int sk_buff_data_t;
#else
typedef unsigned char *sk_buff_data_t;
#endif

В этом же файле сказано: "...see alloc_skb() for details." Я думаю, что тебе стоит на нее посмотреть, раз ты хочешь разобраться в этом вопросе.

Это что смещение от skb->data ??

Похоже, что ты прав ... так как

#ifdef NET_SKBUFF_DATA_USES_OFFSET
static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
{       
        return skb->head + skb->tail;
}       

static inline void skb_reset_tail_pointer(struct sk_buff *skb)
{       
        skb->tail = skb->data - skb->head;
}       
        
static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
{       
        skb_reset_tail_pointer(skb);
        skb->tail += offset;
}       
#else /* NET_SKBUFF_DATA_USES_OFFSET */

Dennis7 ()
Ответ на: комментарий от Dennis7

Вообще ничего не понимаю....
Все глаза изсмотрел, весь мозг издумал...
при тестовом пакете с GET (wget'ом делаю) запросом, получается как
пакеты у которых data_len равен 0, пропускаю. там остаётся только один пакет с не нулевым data_len
skb->len = 150 // Фактическая длинна пакета
skb->data_len = 110 // Длинна данных в пакете. т.е. получается 40 байт на заголовки
skb->head // Это указатель на служебную информацию для пакета (с какого устройства etc.), он нам не нужен
skb->data // Это указатель на сам пакет! IP заголовок = 20, TCP заголовок = 20, и Данные (GET запрос) = 110
skb->tail = 320 // Смещение относительно skb->head. он нам не особо нужен skb->end = 320 // Это конечный «адрес» skb->tail, подозреваю что тоже смещение относительно skb->head. Он получается 0 длинны... ну и бог с ним.
По разному пробовал и сразу печатал и через memcpy потом печатал выдаёт примерно следующее

020001000100000040b982170088ffff
010000000000000000b982170088ffff
00000000000000000000000000000000
00000000000000006060520000eaffff
000000006e0000000000000000000000
00000000000000000300000000000000
0000000000000000000000000000
Длинна как раз 110 байт (с чего бы ей другой быть), но это ни разу не похоже на пакет который посылается... Вот вчём подвох...

alloc_skb() это как я понял, создание нового буфера, для создания нового пакета

Inversiya ()
Ответ на: комментарий от Inversiya

Слушай, блин, я думал ты уже решил задачу. Не знаю в какие дебри ты залез. Вот тебе код тестового модуля, который я пробовал у себя на виртуальной машине.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/signal.h>
//#include <linux/signalfd.h>
#include <asm/unistd.h>
#include <asm/siginfo.h>
#include <asm/uaccess.h> /* for copy_from_user */
#include <linux/syscalls.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/time.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <net/sock.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netdevice.h>

MODULE_LICENSE("GPL");

struct nf_hook_ops nf_outgoing;

//=================================================
unsigned int main_hook(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out,
		int (*okfn)(struct sk_buff*))
{
	int i;
	char *user_data_ptr;
	struct iphdr *ip = (struct iphdr *)skb->data;

	/* (char *)skb->data+sizeof(struct iphdr)+sizeof(struct tcphdr)); */
	/*printk("In hook: data[0]=%x, len=%d\n",user_data_ptr[0], skb->len);
	for (i=0; i<skb->len; i++, user_data_ptr++) {
		
	}*/

	printk("protocol: %d, saddr: %d.%d.%d.%d : ",ip->protocol, ntohl(ip->saddr)>>24, (ntohl(ip->saddr)>>16)&0x00FF,
					    (ntohl(ip->saddr)>>8)&0x0000FF, (ntohl(ip->saddr))&0x000000FF);
	
	switch (ip->protocol) {
	case IPPROTO_ICMP:
		user_data_ptr = (char *)(skb->data + sizeof(struct iphdr) + sizeof(struct icmphdr));
		break;
	case IPPROTO_TCP:
		user_data_ptr = (char *)(skb->data + sizeof(struct iphdr) + sizeof(struct tcphdr));
		break;
	case IPPROTO_UDP:
		user_data_ptr = (char *)(skb->data + sizeof(struct iphdr) + sizeof(struct udphdr));
	}

	while (*user_data_ptr) {
		//printk("%x", *user_data_ptr);
		if (*user_data_ptr>=97 && *user_data_ptr<=122) printk("%c", *user_data_ptr); else
		if (*user_data_ptr>=65 && *user_data_ptr<=90)  printk("%c", *user_data_ptr); else
		printk("%x", *user_data_ptr);
		user_data_ptr++;
	}
	printk("\n");
	return NF_ACCEPT;
}
//=================================================
static int net_mod_init(void)
{
	printk(KERN_INFO "net_mod init\n");
	nf_outgoing.hook = main_hook;
	nf_outgoing.pf = PF_INET;
	nf_outgoing.hooknum = 4;//NF_IP_PRE_ROUTING;
	nf_outgoing.priority = NF_IP_PRI_FIRST;
	//Registration
	nf_register_hook(&nf_outgoing);

	return 0;
}
//=================================================
static void net_mod_exit(void)
{
	nf_unregister_hook(&nf_outgoing);
	printk(KERN_INFO "net_mod exit\n");
}
//=================================================
module_init(net_mod_init);
module_exit(net_mod_exit);
Вот его тестирование и «выхлоп» в dmesg:
sudo insmod ./nf_hooks.ko
wget http://www.ya.ru
...
dmesg | tail -n 10
[ 1010.331168] protocol: 6, saddr: 10.0.2.15 : 245ffffffb4428a
[ 1010.400429] protocol: 6, saddr: 10.0.2.15 : 
[ 1010.402074] protocol: 6, saddr: 10.0.2.15 : GET202f20HTTP2f312e30daUser2dAgent3a20Wget2f312e31322028linux2dgnu29daAccept3a202a2f2adaHost3a20www2eya2erudaConnection3a20Keep2dAlivedadafd32DKffffff38bffffffe36ffffffc3631ffffffdbpffffffa393337ffffff38343139tffffffc32ffffffe32ffffffd39vffffffb33FBffffffafG3338ffffffcf36l31353237ffffff393337ffffffebF33dffffff38e32ceS323131bffffffe37ffffffa32Iffffffd3432dffffffb31o32ca3230ffffffcaffffffc333232ffffff38cffffffe343232da5b20203534302e3835343531395d20protocol3a20362c20saddr3a2031302e302e322e3135203a20373337ffffffe35Cffffffd39ffffffacffffff39d3630ffffffb33yffffffe33Iffffffd31daf33dab
[ 1010.429224] protocol: 6, saddr: 10.0.2.15 : 
[ 1010.429289] protocol: 6, saddr: 10.0.2.15 : 
[ 1010.429460] protocol: 6, saddr: 10.0.2.15 : 
[ 1010.437097] protocol: 6, saddr: 10.0.2.15 : 
[ 1010.437156] protocol: 6, saddr: 10.0.2.15 : 
[ 1010.437411] protocol: 6, saddr: 10.0.2.15 :
Сейчас-то, я надеюсь, ты уже разберешься.

Dennis7 ()
Ответ на: комментарий от Dennis7

Большое спасибо, пока разбираюсь дальше...
У меня тоже частично получилось... но данные были правильные только до определённого адреса.
И ещё вопрос. в nf_outgoing.hooknum за что отвечает nf_outgoing. ? Просто у меня стоит bundle.hooknum Я брал из примера на каком то сайте..

Inversiya ()
Ответ на: комментарий от Dennis7

прикольно, но у меня вывод совсем другой... (вашего варианта)

[109703.174681] protocol: 6, saddr: x.x.x.x : 245ffffffb4428a1ffffffa1W9
[109703.182548] protocol: 6, saddr: x.x.x.x : cffffffb8zffffff8f33ffffffa0ffffff811bP18hffffffb0nffffffc5
[109703.183746] protocol: 6, saddr: x.x.x.x : 2
Ни чего не менял....

Inversiya ()
Ответ на: комментарий от Inversiya

А что печатает

printk(«%x », *user_data_ptr);

?

Добавь еще вывод номера UDP порта и посмотри в Wireshark что в сети на этом интерфейсе творится

alx777 ()
Ответ на: комментарий от alx777

я пробовал по разному...

и так
for (i=0; i < skb->len; i++)
{
     printk ("%02x", skb->data[i]);
}
и так
memcpy (data, skb->data, skb->len);
for (i=0; i < skb->len; i++)
{
     printk ("%02x", data[i])
}
в общем выводы печальны Увидел я что то похожее на пакет в sk_buff, только в FORWARD..
И там всё не слава богу, данные правильные только до 0x09F а потом такая же чушь...
делаю как, в сети есть комп, я отправляю пакет (GET запрос, браузером). Параллельно пишу wireshark'ом и сравниваю пакет с пакетом из sk_buff
Вот что получается:
[86521.286044] Data:
[86521.286362] 430 // Размер пакета, на клиентской он больше (ровно на 14 байт) из за Ethernet заголовка,
[86521.286666] 286 // Размер данных в пакете !!!Врёт собака!!! 
[86521.287005] 192 // Это skb->tail это вроде смещение, но теперь не понятно относительно чего...
[86521.287306] 192 // Это skb->end 
[86521.287610] 20 // Это размер ip заголовка (int)sizeof(struct iphdr));
[86521.287935] 20 // Это размер tcp заголовка (int)sizeof(struct tcphdr));
[86521.288246] -----DATA-----  // для удобства я разбил на блоки
[86521.288582] 
        0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
0x000  45 00 01 ae 35 c4 40 00 7f 06 d1 e6 0a 0a 96 97 
0x010  57 fa fa 03                                     
// ip заголовок. есть различия в 3 байта по адресам с 0x008 по 
// 0x00A Но это мне кажется нормальным.
0x010              07 36 00 50 b1 d6 15 08 fc 2d a4 8b 
0x020  50 18 80 00 c8 1a 00 00 
// tcp заголовок. они одинаковые
0x020                          47 45 54 20 2f 20 48 54 
// это сами данные в пакете... Здесь начинается веселуха...
// Ровно до 0x090 всё сходится..
0x030  54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 38 37 
0x040  2e 32 35 30 2e 32 35 30 2e 33 0d 0a 43 6f 6e 6e 
0x050  65 63 74 69 6f 6e 3a 20 6b 65 65 70 2d 61 6c 69 
0x060  76 65 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 
0x070  4d 6f 7a 69 6c 6c 61 2f 35 2e 30 20 28 57 69 6e 
0x080  64 6f 77 73 20 4e 54 20 35 2e 31 29 20 41 70 70 
0x090  01 00 00 00 01 00 00 00 00 13 bd 17 00 88 ff ff 
// Вот здесь начинается чушь...
0x0A0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
0x0B0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
0x0C0  00 00 00 00 00 00 00 00 10 15 53 00 00 ea ff ff 
0x0D0  aa 00 00 00 1e 01 00 00 00 00 32 1d 14 26 9c a0 
0x0E0  52 2b d6 ce 3a 96 08 00 45 10 00 5c d2 77 40 00 
0x0F0  40 06 cd cd 5b d6 f2 8e 5b d6 f0 0b 00 16 e2 6d 
0x100  30 c8 d8 44 2a a3 58 21 50 18 02 06 9a 95 00 00 
0x110  01 00 00 00 00 00 00 00 40 45 5e 1e 00 88 ff ff 
0x120  00 00 00 00 00 00 00 00 00 45 5e 1e 00 88 ff ff 
0x130  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
0x140  00 00 00 00 00 00 00 00 b0 75 54 00 00 ea ff ff 
0x150  d5 03 00 00 34 00 00 00 00 00 00 00 00 00 00 00 
0x160  00 00 00 00 00 00 00 00 71 00 00 00 00 00 00 00 
0x170  16 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
0x180  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
0x190  00 00 00 00 00 00 00 00 58 01 00 00 00 00 00 00 
0x1A0  62 00 00 00 00 00 00 00 00 00 00 00 00 00
[86521.289587]

Inversiya ()
Ответ на: комментарий от Dennis7

Код ниже... а какие команды? wget?

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>

#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/tcp.h>

#include <linux/string.h>

MODULE_LICENSE("GPL");

struct nf_hook_ops bundle;

int arrip[4];
unsigned char data[1500];

int update_filter(void)
{
        int i;
        /* Создадим времееный двумерный масив с ip адресами */
        unsigned char arriptmp[][4] = {{8,8,8,8},{91,214,240,3},{87,250,250,3},{0}};
        /* Цикл преобразование ip адресов в десятичный формат */
        for (i=0; arriptmp[i]; i++)
        {
                /* Записываем ip адреса в новый масив */
                arrip[i] = htonl((arriptmp[i][0] << 24) | (arriptmp[i][1] << 16) |
                                (arriptmp[i][2] << 8) | arriptmp[i][3]);
                printk(KERN_INFO "Filtering IP %u\n", arrip[i]);
                if (arriptmp[i][0] == 0)
                {
                        printk(KERN_INFO "end ip block\n");
                        break;
                }
        }
        return 0;
}


unsigned int Hook_Func(uint hooknum,
                        struct sk_buff *skb,
                        const struct net_device *in,
                        const struct net_device *out,
                        int (*okfn)(struct sk_buff *)  )
{

        /* Указатель на структуру заголовка протокола ip в пакете */
        struct iphdr *ip;
        /* Указатель на структуру заголовка протокола tcp в пакете */
        struct tcphdr *tcp;

        /* Проверяем что это IP пакет */
        if (skb->protocol == htons(ETH_P_IP))
        {
                /* Сохраняем указатель на структуру заголовка IP */
                ip = (struct iphdr *)skb_network_header(skb);
                /* Проверяем что это IP версии 4 и внутри TCP пакет */
                if (ip->version == 4 && ip->protocol == IPPROTO_TCP)
                {
                        /* Задаем смещение в байтах для указателя на TCP заголовок */
                        /* ip->ihl - длина IP заголовка в 32-битных словах */
                        skb_set_transport_header(skb, ip->ihl * 4);
                        /* Сохраняем указатель на структуру заголовка TCP */
                        tcp = (struct tcphdr *)skb_transport_header(skb);
                        /* Если пакет идет на 80 порт (HTTP) */
                        if (tcp->dest == htons(80))
                        {
                                int i;
                                int drop = 0;
                                char *p;
                                for (i=0; arrip[i]; i++)
                                {
                                        if (ip->daddr == arrip[i] && skb->data_len != 0)
                                        {
                                                printk(KERN_INFO "Blocked %u.%u.%u.%u\n", (uint8_t)ip->daddr,
                                                                                        (uint8_t)(ip->daddr >> 8),
                                                                                        (uint8_t)(ip->daddr >> 16),
                                                                                        (uint8_t)(ip->daddr >> 24));
                                                drop = 1;

                                                printk (KERN_INFO "Data:\n");

                                                printk (KERN_INFO "%u\n", skb->len);
                                                printk (KERN_INFO "%u\n", skb->data_len);
                                                printk (KERN_INFO "%u\n", skb->tail);
                                                printk (KERN_INFO "%u\n", skb->end);
                                                printk (KERN_INFO "%u\n", (int)sizeof(struct iphdr));
                                                printk (KERN_INFO "%u\n", (int)sizeof(struct tcphdr));

                                                memcpy (data, skb->data, skb->len);

                                                p = strstr(data, "54");
                                                if (p != NULL)
                                                {
                                                        printk("GET - %x %x %x\n", p[0], p[1], p[2]);
                                                }
                                                else {printk("NOT GET");}
                                                printk (KERN_INFO "-----DATA-----\n");
                                                for(i = 0; i < skb->len; i++)
                                                {
                                                        printk("%x ", data[i]);
                                                }

                                                printk (KERN_INFO "\n");
                                        }
                                }
                                if (drop == 1)
                                {
//                                      return NF_DROP;
                                        return NF_ACCEPT;
                                }
                                else {return NF_ACCEPT; }
                        }
                        else {return NF_ACCEPT; }
                }
                else {return NF_ACCEPT; }
        }
        else {return NF_ACCEPT; }

}


int Init(void)
{
        printk(KERN_INFO "Start module url_filter\n");
        update_filter();
        /* Заполняем структуру для регистрации hook функции */
        /* Указываем имя функции, которая будет обрабатывать пакеты */
        bundle.hook = Hook_Func;
        /* Устанавливаем указатель на модуль, создавший hook */
        bundle.owner = THIS_MODULE;
        /* Указываем семейство протоколов */
        bundle.pf = PF_INET;
        /* Указываем, в каком месте будет срабатывать функция */
        /* bundle.hooknum = NF_INET_PRE_ROUTING; */
        bundle.hooknum = NF_INET_FORWARD;
        /* Выставляем самый высокий приоритет для функции */
        bundle.priority = NF_IP_PRI_FIRST;
//      bundle.priority = NF_IP_PRI_LAST;
        /* Регистрируем */
        nf_register_hook(&bundle);

        return 0;
}

void Exit(void)
{
        printk(KERN_INFO "Exit module url_filter\n");
        /* Удаляем из цепочки hook функцию */
        nf_unregister_hook(&bundle);
}

module_init(Init);
module_exit(Exit);
Inversiya ()
Ответ на: комментарий от Inversiya

p = strstr(data, «54»);
if (p != NULL)

Объясни мне, друг любезный, что, с чем и с какой целью ты тут сравниваешь? У тебя сейчас в data весь(!) Ethernet-фрейм, со всеми заголовками в котором нет(!) подстроки «54». ППЦ! man strstr хоть бы почитал, или ты думаешь, что в ядре эта функция ведет себя по-другому. О стиле кода я вообще уже молчу. Читать Documentation/CodingStyle до просветления.

Ты, видимо, не фига не понял из того, что я тебе писал. Зачем ты цепляешься к skb? Используй преобразование типов user_data_ptr = (char *)(skb->data + sizeof(struct iphdr) + sizeof(struct tcphdr));

Короче, вот тебе патч к твоим «художествам»

diff --git a/nf_bad_hooks.c b/nf_bad_hooks.c
index 58fa3f2..4dc6a5d 100644
--- a/nf_bad_hooks.c
+++ b/nf_bad_hooks.c
@@ -50,16 +50,16 @@ unsigned int Hook_Func(uint hooknum,
         /* Указатель на структуру заголовка протокола tcp в пакете */
         struct tcphdr *tcp;
 
+	char *u_data;
+
         /* Проверяем что это IP пакет */
-        if (skb->protocol == htons(ETH_P_IP))
-        {
+        if (skb->protocol == htons(ETH_P_IP)) {
                 /* Сохраняем указатель на структуру заголовка IP */
                 ip = (struct iphdr *)skb_network_header(skb);
                 /* Проверяем что это IP версии 4 и внутри TCP пакет */
-                if (ip->version == 4 && ip->protocol == IPPROTO_TCP)
-                {
+                if (ip->version == 4 && ip->protocol == IPPROTO_TCP) {
                         /* Задаем смещение в байтах для указателя на TCP заголовок */
-                        /* ip->ihl - длина IP заголовка в 32-битных словах */
+                        /* ip->ihl - длина IP заголовка в 32-бтных словах */
                         skb_set_transport_header(skb, ip->ihl * 4);
                         /* Сохраняем указатель на структуру заголовка TCP */
                         tcp = (struct tcphdr *)skb_transport_header(skb);
@@ -69,9 +69,9 @@ unsigned int Hook_Func(uint hooknum,
                                 int i;
                                 int drop = 0;
                                 char *p;
-                                for (i=0; arrip[i]; i++)
-                                {
-                                        if (ip->daddr == arrip[i] && skb->data_len != 0)
+                                
+                                //for (i=0; arrip[i]; i++) {
+                                        //if (ip->daddr == arrip[i] && skb->data_len != 0)
                                         {
                                                 printk(KERN_INFO "Blocked %u.%u.%u.%u\n", (uint8_t)ip->daddr,
                                                                                         (uint8_t)(ip->daddr >> 8),
@@ -90,7 +90,9 @@ unsigned int Hook_Func(uint hooknum,
 
                                                 memcpy (data, skb->data, skb->len);
 
-                                                p = strstr(data, "54");
+                                                //p = strstr(data, "54");  What the FUCK?!
+						u_data = (data+sizeof(struct iphdr)+sizeof(struct tcphdr));
+						p = strstr(u_data, "GET");
                                                 if (p != NULL)
                                                 {
                                                         printk("GET - %x %x %x\n", p[0], p[1], p[2]);
@@ -103,20 +105,22 @@ unsigned int Hook_Func(uint hooknum,
                                                 }
 
                                                 printk (KERN_INFO "\n");
+						memset(data, 0, 1500);
                                         }
-                                }
-                                if (drop == 1)
-                                {
+                                //}
+                                if (drop == 1){
 //                                      return NF_DROP;
-                                        return NF_ACCEPT;
-                                }
-                                else {return NF_ACCEPT; }
-                        }
-                        else {return NF_ACCEPT; }
-                }
-                else {return NF_ACCEPT; }
-        }
-        else {return NF_ACCEPT; }
+                                        return NF_ACCEPT; /* ???? */
+                                } else 
+					return NF_ACCEPT; /* ???? */
+                        } else 
+				return NF_ACCEPT;
+                } else 
+			return NF_ACCEPT;
+        } else {
+		printk("!skb->protocol\n");
+		return NF_ACCEPT;
+	}
 
 }
 
@@ -134,7 +138,7 @@ int Init(void)
         bundle.pf = PF_INET;
         /* Указываем, в каком месте будет срабатывать функция */
         /* bundle.hooknum = NF_INET_PRE_ROUTING; */
-        bundle.hooknum = NF_INET_FORWARD;
+        bundle.hooknum = 4;
         /* Выставляем самый высокий приоритет для функции */
         bundle.priority = NF_IP_PRI_FIRST;
 //      bundle.priority = NF_IP_PRI_LAST;

Примени его и запусти, и там будет равно один запрос GET, как и должно быть.

Dennis7 ()
Ответ на: комментарий от Dennis7

Зачем же так ругаться??!!
Что касается strstr, это я игрался, искал «GET». Цифры у меня там т.к. чистый GET он не находил... вот я и игрался...
Это потом до меня дошло что там нули есть в конце заголовков и дальше их он не пойдёт.
А стиль... это я так понимаю вы про фигурные скобки.... раньше я так и писал, как вы предлагаете, но много раз видел что { ставиться на следующей строке и подумал что так правильнее... а else {return NF_ACCEPT; } сделал потому что их удобней было копировать.... :) вообще это черновой вариант...
Про преобразование типов, я действительно что-то видать не уловил...
СПАСИБО ЗА ПАТЧ!!!! Сейчас опробую...

Inversiya ()
Ответ на: комментарий от Inversiya

Ты если отправляешь кому-нибудь код, делай его читабельным, иначе тебе всегда будут на это указывать и предупреждай что это черновой вариант, а то будут думать, что ты не разбираешься в предмете. А лучше сразу писать все обдуманно и/или не отправлять нетестированный и необдуманный код.

Dennis7 ()
Ответ на: комментарий от Dennis7

Хорошо. Следующий раз учту...
Ну вообщем ситуация не изменилась...
По прежнему данные из пакета правильные только до определённого «адреса»
GET и Host я вижу, но мне интересно почему там не все данные....

Inversiya ()
Ответ на: комментарий от Inversiya

Ну вообщем мне кажется проблема в ядре...
Выглядит, как я и говорил, следующим образом..
В NF_INET_PRE_ROUTING и NF_INET_POST_ROUTING вообще чушь заместо данных.
В NF_INET_FORWARD данные правильные только до определённого адреса.
Было испытано на следующих ядрах:
2.6.32-5 Debian x64 (виртуалка) - НЕ РАБОТАЕТ, ведёт себя как описано выше
2.6.34.14 Debian x64 (виртуалка) - НЕ РАБОТАЕТ, ведёт себя как описано выше
3.0.0-16 Ubuntu x86 (НЕ виртуалка) - НЕ РАБОТАЕТ, ведёт себя как описано выше
3.7.5 Ubuntu x86 (НЕ виртуалка) - РАБОТАЕТ, данные везде целые и правильные

Сейчас компилю 3,7,6 под Debian x64 (виртуалка), посмотрим как там будет.

И собственно вопрос... Проблема действительно в ядре или же в кривых руках/мозгах???

P.S. Уважаемый Dennis7, какое у вас ядро и дистрибутив?

Inversiya ()
16 апреля 2013 г.
Ответ на: комментарий от Inversiya

Привет. В данный момент тоже пытаюсь мастерить что то подобное. Спасибо за код!!!

anonymous ()
Ответ на: комментарий от Inversiya

Подниму тему, столкнулся с той же проблемой. В буфере данных имеется только часть данных.. Не нашлось ли решения? Ядро пробовал обновлять (в данный момент 3.8.1) - увы, не помогло..

anonymous ()
Ответ на: комментарий от anonymous

Снова я подниму тему: нашел кажется причину... хотя до конца так и не разобрался. Если перенести модуль на реальную машину - все работает ОК (ядро 2.6.38.8). Пробовал на виртуалке - skb->data содержит только 255 байт (вместе с IP и TCP заголовками). Испытал на ядрах 2.6.38 и 3.8.1.

anonymous ()
5 июля 2013 г.
Ответ на: комментарий от Inversiya

Привет, мне бы очень помог твой код, не мог бы ты выложить конечную версию?

anonymous ()

Долго промучился с данной темой, пока не нашел эту статью: http://habrahabr.ru/post/138328/ Там есть такая фраза:

В этом месте я хотел бы обратиться к читателю. Мне осталось не совсем понятным, кто именно должен устанавливать указатель transport_header в структуре sk_buff, т.к. в точках NF_INET_PRE_ROUTING и NF_INET_LOCAL_IN (с любыми приоритетами) мне не удалось с помощью skb_transport_header получить структуру на tcp заголовок, хотя в остальных точках это работало прекрасно. Пришлось вручную указывать смещение для transport_header от указателя sk_buff->data, воспользовавшись void skb_set_transport_header(skb, offset).

После добавление 1-ой строчки, всё заработало как надо!

        /* Задаем смещение в байтах для указателя на TCP заголовок */
        /* ip->ihl - длина IP заголовка в 32-битных словах */
        skb_set_transport_header(skb, ip->ihl * 4);
        /* Сохраняем указатель на структуру заголовка TCP */
        tcp = (struct tcphdr *)skb_transport_header(skb);

Всем счастливого программирования!

SoftDed ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.