使用sk_buff添加以太网帧头

我有一个内核模块,可以捕获传出的Internet流量(Netfilter hook:LOCAL_OUT)在这个钩子上,仍然没有以太网头。

我构建了以太网头,它已经可以使用了,但是如何将它附加到skb以便我可以将整个skb结构发送到dev_queue_xmit()

是否有关于如何操作sk_buff数据的指南,您可以提供给我以获取更多信息?

作为样本,我尝试在所有ECHO ICMP流量上做我想做的事情; 这是我的代码。 但是当在另一台机器上检查Wireshark时,我得到了一个工作的以太网头但是一个EMPTY IP数据包……为什么会这样?

static unsigned int post_icmp_check(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 icmphdr *icmph; struct sk_buff *sb; struct ethhdr *ethh; unsigned char *frame = NULL; //Used just to copy the skb->data and replace it, that's all unsigned char *ptr; /* Allocations and initial assignations */ sb = skb_copy(skb, GFP_ATOMIC); /* Making a private copy because we cannot modify all fields in the public one */ iph = ip_hdr(sb); if(iph->protocol == IPPROTO_ICMP){ printk(KERN_ALERT"POST ICMP traffic!\n"); icmph = icmp_hdr(sb); if(icmph->type == ICMP_ECHO){ frame = (unsigned char *)kmalloc(ntohs(iph->tot_len) + (ETH_HLEN*8), GFP_KERNEL); ptr = (frame + (ETH_HLEN * 8)); ethh = (struct ethhdr*) frame; //00:1a:80:7e:96:ba ethh->h_source[0] = 0x00; ethh->h_source[1] = 0x1a; ethh->h_source[2] = 0x80; ethh->h_source[3] = 0x7e; ethh->h_source[4] = 0x96; ethh->h_source[5] = 0xba; ethh->h_dest[0] = 0xff; ethh->h_dest[1] = 0xff; ethh->h_dest[2] = 0xff; ethh->h_dest[3] = 0xff; ethh->h_dest[4] = 0xff; ethh->h_dest[5] = 0xff; ethh->h_proto = htons(ETH_P_IP); memcpy(ptr, skb->data, ntohs(iph->tot_len)); /* Copying the rest of the data from the skb to sb */ sb->data = frame; //icmph = icmp_hdr(sb); //icmph->un.echo.sequence = htons(i++); //icmph->checksum = 0; //icmph->checksum = in_cksum((unsigned short *)icmph, ntohs(iph->tot_len) - sizeof(struct iphdr)); sb->dev = out; printk(KERN_ALERT"%s\n",sb->dev->name); if(sb->dev == NULL) printk(KERN_ALERT"dev is NULL!"); dev_queue_xmit(sb); return NF_STOLEN; } 

编辑:是的,为了简单起见,我正在硬编码我自己的MAC和广播帧。

EDIT2:所以我给这个函数提供net_filter捕获的原始sk_buff和相应的net_device我试着按照你说的去做,并阅读一些关于sK_buff函数的指南。 仍然,当我dev_queue_xmit()返回此函数的sk_buff时,我得到一个完整的内核崩溃。

 static struct sk_buff* set_skb(struct sk_buff *org_skb, struct net_device *dev) { int header_size; unsigned char *data; struct icmphdr *icmph; struct iphdr *iph; struct icmphdr *temp_icmph; struct iphdr *temp_iph; unsigned char myaddr[] = {0x00,0x1a,0x80,0x7e,0x96,0xba}; unsigned char addr [] = {0xff,0xff,0xff,0xff,0xff,0xff}; struct sk_buff *skb; temp_iph = ip_hdr(org_skb); temp_icmph = icmp_hdr(org_skb); skb = alloc_skb(ntohs((temp_iph->tot_len) + (ETH_HLEN*8)), GFP_KERNEL); /* Allocating enough space for everything */ /* icmp_hlen which is always 8, ip_hlen */ header_size = 8 + ntohs(temp_iph->ihl*4); /* reserve headroom This actually allocates the IP and ICMP headers memory */ skb_reserve(skb, header_size); /* payload */ data = skb_put(skb, org_skb->data_len);/* This function allocates room for the data */ memcpy(data, org_skb->data, org_skb->data_len); icmph = (struct icmphdr*)skb_push(skb, 8); /* set up icmp header here */ memcpy(icmph, temp_icmph, 8); iph = (struct iphdr*)skb_push(skb, temp_iph->ihl*4); /* set up ip header here */ memcpy(iph, temp_iph, temp_iph->ihl*4); /* * This function sets up the ethernet header, * destination address addr, source address myaddr */ dev_hard_header(skb, dev, ETH_P_IP, addr, myaddr, dev->addr_len); return skb; } 

EDIT3:

 Apr 20 23:44:09 DHS-1022CYB kernel: [ 1139.520104] Loading Test module... Apr 20 23:44:09 DHS-1022CYB kernel: [ 1139.520168] *********************HERE WE GO********************** Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.760448] PGD 114952067 PUD 12d932067 PMD 0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.760762] CPU 0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.760809] Modules linked in: myModule(P) binfmt_misc rfcomm ppdev sco bridge stp bnep l2cap joydev fbcon tileblit font bitblit softcursor vga16fb vgastate snd_hda_codec_realtek pcmcia arc4 snd_hda_intel snd_hda_codec snd_hwdep snd_pcm_oss snd_mixer_oss snd_pcm snd_seq_dummy snd_seq_oss snd_seq_midi snd_rawmidi snd_seq_midi_event iwlagn snd_seq iwlcore snd_timer radeon ttm drm_kms_helper snd_seq_device mac80211 tifm_7xx1 led_class usbhid yenta_socket hid rsrc_nonstatic btusb bluetooth uvcvideo videodev v4l1_compat v4l2_compat_ioctl32 snd drm tifm_core i2c_algo_bit psmouse sony_laptop pcmcia_core serio_raw cfg80211 soundcore snd_page_alloc video output intel_agp lp parport ohci1394 ieee1394 r8169 mii Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.762642] Pid: 3423, comm: ping Tainted: P 2.6.32-33-generic #70-Ubuntu VGN-CR31Z_R Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.762753] RIP: 0010:[] [] post_icmp_check+0x81/0x1e0 [myModule] Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.762891] RSP: 0018:ffff88011494f948 EFLAGS: 00010246 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.762965] RAX: 0000000000000000 RBX: ffff88013bb62000 RCX: 00000000000000d0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.763059] RDX: 0000000000000000 RSI: ffff88013bb62000 RDI: 0000000000000000 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.763153] RBP: ffff88011494f988 R08: 00000000ffffffff R09: 0000000000000001 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.763248] R10: ffffffff81591000 R11: ffff880137c9c9ef R12: ffff880130ba8100 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.763346] R13: ffffffff81831070 R14: ffff880130ba8100 R15: 0000000000000003 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.763441] FS: 00007f3377ef6700(0000) GS:ffff880028200000(0000) knlGS:0000000000000000 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.763546] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.763626] CR2: 0000000000000000 CR3: 0000000114863000 CR4: 00000000000006f0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.763721] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.763815] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.763910] Process ping (pid: 3423, threadinfo ffff88011494e000, task ffff880139b6c4d0) Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.764052] ffff88011494fde8 0000000000000040 0000000000609420 0000000000000000 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.764195]  ffff88011494fa10 0000000080000000 ffffffff81831070 ffff880130ba8100 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.768380]  ffff88011494f9d8 ffffffff81486f1c ffff88013bb62000 0000000000000000 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] nf_iterate+0x6c/0xb0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ? dst_output+0x0/0x20 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] nf_hook_slow+0x74/0x100 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ? dst_output+0x0/0x20 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] __ip_local_out+0x9f/0xb0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ip_local_out+0x16/0x30 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ip_push_pending_frames+0x28a/0x410 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ? ip_route_output_flow+0x82/0xb0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] raw_sendmsg+0x3a5/0x5c0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] inet_sendmsg+0x29/0x60 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ? apparmor_socket_sendmsg+0x19/0x20 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] sock_sendmsg+0x10b/0x140 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ? autoremove_wake_function+0x0/0x40 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ? move_addr_to_kernel+0x64/0x70 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ? verify_iovec+0x66/0xd0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] sys_sendmsg+0x233/0x3a0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ? __do_fault+0x439/0x500 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ? _spin_lock_irq+0x15/0x20 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ? do_sigaction+0x13e/0x1e0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] ? do_page_fault+0x158/0x3b0 Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] [] system_call_fastpath+0x16/0x1b Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.770015] RSP  Apr 20 23:44:12 DHS-1022CYB kernel: [ 1142.887370] ---[ end trace 404e94883c3bf110 ]--- 

这是崩溃后的内核日志结果。

编辑4:为了使事情更清楚,这是实际调用我的set_skb()的代码的一部分

 if(icmph->type == ICMP_ECHO){ memcpy(dev, out, sizeof(*out)); sb = set_skb(skb, dev); printk(KERN_ALERT"%s\n",sb->dev->name); dev_queue_xmit(sb); return NF_STOLEN; } 

哇,你不这样做。 不要直接搞乱skb内部指针。 只需分配一个skb并将标头和有效负载复制到新的。

假设您要添加ICMP,IP和以太网标头以及从orig_skb复制有效负载。 像这样做:

 struct skbuff *skb = skb_alloc(full_len, GFP_KERNEL); /* icmp_hlen, ip_hlen and payload_size should be known */ int header_size = icmp_hlen + ip_hlen; /* reserve headroom */ skb_reserve(skb, header_size); /* payload */ unsigned char *data = skb_put(skb, payload_size); memcpy(data, orig_skb->data, payload_size); struct icmphdr *icmph = skb_push(skb, icmp_hlen); /* set up icmp header here */ struct iphdr *iph = skb_push(skb, ip_hlen); /* set up ip header here */ /* * This function sets up the ethernet header, * destination address addr, source address myaddr */ dev_hard_header(skb, dev, ETH_P_IP, addr, myaddr, dev->addr_len); 

如果要添加传输,网络等标头,可以推送多个标头。

  unsigned int snoop_hook1( unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int(*okfn)( struct sk_buff * ) ) { int offset, len,tcplen; struct ethhdr *ethh; struct iphdr *iph; struct tcphdr *tcph; uint16_t t; bool flag = false; struct sk_buff *nskb; struct net_device *eth1_dev , *lo_dev; if (!skb) return NF_ACCEPT; iph = ip_hdr(skb); if (!iph) return NF_ACCEPT; tcph = tcp_hdr(skb); /* skip lo packets */ if (iph->saddr == iph->daddr) return NF_ACCEPT; if (tcph->dest == htons(80)) flag=true; // add similar conditions for true flags if(flag != true) return NF_ACCEPT; /* print packet information */ printk(KERN_INFO "HELLO !!!\n"); printk(KERN_INFO "HOOK=NF_INET_LOCAL_OUT"); printk(KERN_INFO "INDEV %s OUTDEV %s",in->name, out->name); printk(KERN_INFO "sk_buff::dev %s",skb->dev->name); //printk(KERN_INFO "MAC ADDRESSES as in eth header %pM->%pM", &(ethh->h_source), &(ethh->h_dest)); printk( KERN_INFO " %pI4->%pI4\n", &(iph->saddr), &(iph->daddr)); printk(KERN_INFO "TCP SRC:%d, TCP DST:%d",ntohs(tcph->source),ntohs(tcph->dest)); // correct the IP checksum printk(KERN_INFO "IP checksum =%d",iph->check); iph->check = 0; ip_send_check (iph); printk(KERN_INFO "IP checksum new =%d",iph->check); //correct the TCP checksum printk(KERN_INFO "TCP checksum =%d",tcph->check); offset = skb_transport_offset(skb); len = skb->len - offset; printk(KERN_INFO "skb->len=%d",skb->len); printk(KERN_INFO "offset=%d",offset); printk(KERN_INFO "len=%d",len); tcph->check = 0; if(skb->len > 60){ tcph->check = csum_tcpudp_magic((iph->saddr), (iph->daddr), len, IPPROTO_TCP, csum_partial((unsigned char *)tcph,len,0)); printk(KERN_INFO "TCP checksum new=%d",tcph->check); } else{ tcph->check = ~csum_tcpudp_magic((iph->saddr), (iph->daddr), len, IPPROTO_TCP, 0); printk(KERN_INFO "TCP checksum new*=%d",tcph->check); } printk(KERN_INFO "************************************************************"); //send to dev eth1_dev = dev_get_by_name(&init_net,"eth1"); lo_dev = dev_get_by_name(&init_net,"lo"); skb->dev = eth1_dev; ethh = (struct ethhdr *) skb_push(skb, ETH_HLEN); skb->protocol = ethh->h_proto = htons(ETH_P_IP); memcpy (ethh->h_source,eth1_dev->dev_addr , ETH_ALEN); memcpy (ethh->h_dest, d_mac, ETH_ALEN); dev_queue_xmit(skb); return NF_STOLEN; } 

这是一个老问题(和答案)。我需要做一些完全相似的事情,我最终得到了这个代码。 想出来帮助别人。 它至少对我有用,我在这里发送相同的skb。 d_mac是网关的mac或局域网中的另一个mac。 它可以从传入的数据包或从arp获得。