armlinux下PF_PACKET socket抓不到eth0发包

发布于 2022-09-28 09:02:46 字数 1450 浏览 19 评论 0

os:armlinux-2.4.27
arm-gcc version:3.4.1

用ping测试,pcap库同样抓不到, 只能抓到对方ping包,抓不到本机的echo包

arm_linux#ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:17:7B:00:00:C0  
          inet addr:192.168.15.23  Bcast:192.168.15.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:188014 errors:0 dropped:23 overruns:0 frame:0
          TX packets:30044 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:256
          RX bytes:17253495 (16.4 MiB)  TX bytes:5786117 (5.5 MiB)
arm_linux#./tcpdump -nvi eth0
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 68 bytes
00:53:00.826689 arp who-has 192.168.15.210 tell 192.168.15.180
00:53:04.013880 IP (tos 0x0, ttl  64, id 24184, offset 0, flags [none], proto 1, length: 284) 192.168.15.126 > 192.168.15.23: icmp 9
00:53:18.343214 arp who-has 192.168.15.23 tell 192.168.15.22
00:53:18.345240 IP (tos 0x0, ttl  64, id 0, offset 0, flags [DF], proto 1, length: 104) 192.168.15.22 > 192.168.15.23: icmp 84: ech0

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

长伴 2022-10-05 09:02:46

自己写的PF_PACKET socket抓包 也抓不到以太口发包。
请教有没有遇到同样问题的。谢谢。

附:测试代码(部分):
int main(int argc, char **argv) {
  int sock=-1, device_id=-1, n;
  char buffer[2048];
  unsigned char *iphead, *ethhead;
  char *device = "eth0";

  if ( (sock=socket(PF_PACKET, SOCK_RAW,
                htons(ETH_P_ALL)))<0) {
    perror("socket";
    exit(1);
  }

  while (1) {
    n = recvfrom(sock,buffer,2048,0,NULL,NULL);

    if (n<34) {
      perror("recvfrom():";
      printf("Incomplete packet (errno is %d)\n",errno);
      close(sock);
      exit(0);
    }
    ethhead = buffer;
    printf("----------\n";
    printf("%d bytes read\n",n);
    printf("Dest MAC address: "
           "%02x:%02x:%02x:%02x:%02x:%02x\n",
           ethhead[0],ethhead[1],ethhead[2],
           ethhead[3],ethhead[4],ethhead[5]);
    printf("Source MAC address: "
           "%02x:%02x:%02x:%02x:%02x:%02x\n",
           ethhead[6],ethhead[7],ethhead[8],
           ethhead[9],ethhead[10],ethhead[11]);

    iphead = buffer+14; /* Skip Ethernet header */
    printf("Source host %d.%d.%d.%d\n",
             iphead[12],iphead[13],
             iphead[14],iphead[15]);
    printf("Dest host %d.%d.%d.%d\n",
             iphead[16],iphead[17],
             iphead[18],iphead[19]);
    printf("Source,Dest ports %d,%d\n",
             (iphead[20]<<+iphead[21],
             (iphead[22]<<+iphead[23]);
    printf("Layer-4 protocol %d\n",iphead[9]);
  }
  
}

情深缘浅 2022-10-05 09:02:46

另:此代码在我pc的fedora core3上可以正常工作

走走停停 2022-10-05 09:02:46

附armlinux kernel 中PF_PACKET相关代码
不知是否是kernel原因或以太口问题,我对此部分代码也不熟,请大家指点
拟这几天调试kernel 看看有没有把发包传给PF_SOCKET 。
此帖也在内核分论坛开了连接 请那边的朋友指点。

net/core/dev.c:
void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
{
        struct packet_type *ptype;
        do_gettimeofday(&skb->stamp);

        br_read_lock(BR_NETPROTO_LOCK);
        for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next)
        {
                /* Never send packets back to the socket
                 * they originated from - MvS (miquels@drinkel.ow.org)
                 */
                if ((ptype->dev == dev || !ptype->dev) &&
                        ((struct sock *)ptype->data != skb->sk))
                {
                        struct sk_buff *skb2;
                        if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL)
                                break;

                        /* skb->nh should be correctly
                           set by sender, so that the second statement is
                           just protection against buggy protocols.
                         */
                        skb2->mac.raw = skb2->data;

                        if (skb2->nh.raw < skb2->data || skb2->nh.raw > skb2->tail) {
                                if (net_ratelimit())
                                        printk(KERN_CRIT "protocol %04x is buggy, dev %s\n", skb2->protocol, dev->name);
                                skb2->nh.raw = skb2->data;
                        }

                        skb2->h.raw = skb2->nh.raw;
                        skb2->pkt_type = PACKET_OUTGOING;
                        ptype->func(skb2, skb->dev, ptype);
                }
        }
        br_read_unlock(BR_NETPROTO_LOCK);
}

net/packet/af_packet.c:
static int packet_rcv(struct sk_buff *skb, struct net_device *dev,  struct packet_type *pt)
{
        struct sock *sk;
        struct sockaddr_ll *sll;
        struct packet_opt *po;
        u8 * skb_head = skb->data;
        int skb_len = skb->len;
#ifdef CONFIG_FILTER
        unsigned snaplen;
#endif

        if (skb->pkt_type == PACKET_LOOPBACK)
                goto drop;

        sk = (struct sock *) pt->data;
        po = sk->protinfo.af_packet;

        skb->dev = dev;

        if (dev->hard_header) {
                /* The device has an explicit notion of ll header,
                   exported to higher levels.

                   Otherwise, the device hides datails of it frame
                   structure, so that corresponding packet head
                   never delivered to user.
                 */
                if (sk->type != SOCK_DGRAM)
                        skb_push(skb, skb->data - skb->mac.raw);
                else if (skb->pkt_type == PACKET_OUTGOING) {
                        /* Special case: outgoing packets have ll header at head */
                        skb_pull(skb, skb->nh.raw - skb->data);
                }
        }

#ifdef CONFIG_FILTER
        snaplen = skb->len;

        if (sk->filter) {
                unsigned res = snaplen;
                struct sk_filter *filter;

                bh_lock_sock(sk);
                if ((filter = sk->filter) != NULL)
                        res = sk_run_filter(skb, sk->filter->insns, sk->filter->len);
                bh_unlock_sock(sk);

                if (res == 0)
                        goto drop_n_restore;
                if (snaplen > res)
                        snaplen = res;
        }
#endif /* CONFIG_FILTER */

        if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf)
                goto drop_n_acct;

        if (skb_shared(skb)) {
                struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
                if (nskb == NULL)
                        goto drop_n_acct;

                if (skb_head != skb->data) {
                        skb->data = skb_head;
                        skb->len = skb_len;
                }
                kfree_skb(skb);
                skb = nskb;
        }

        sll = (struct sockaddr_ll*)skb->cb;
        sll->sll_family = AF_PACKET;
        sll->sll_hatype = dev->type;
        sll->sll_protocol = skb->protocol;
        sll->sll_pkttype = skb->pkt_type;
        sll->sll_ifindex = dev->ifindex;
        sll->sll_halen = 0;

        if (dev->hard_header_parse)
                sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);

#ifdef CONFIG_FILTER
        if (pskb_trim(skb, snaplen))
                goto drop_n_acct;
#endif

        skb_set_owner_r(skb, sk);
        skb->dev = NULL;
        spin_lock(&sk->receive_queue.lock);
        po->stats.tp_packets++;
        __skb_queue_tail(&sk->receive_queue, skb);
        spin_unlock(&sk->receive_queue.lock);
        sk->data_ready(sk,skb->len);
        return 0;

drop_n_acct:
        spin_lock(&sk->receive_queue.lock);
        po->stats.tp_drops++;
        spin_unlock(&sk->receive_queue.lock);

#ifdef CONFIG_FILTER
drop_n_restore:
#endif
        if (skb_head != skb->data && skb_shared(skb)) {
                skb->data = skb_head;
                skb->len = skb_len;
        }
drop:
        kfree_skb(skb);
        return 0;
}

娇俏 2022-10-05 09:02:46

找到问题,是 kernel 没有发skb给PF_PACKET, 只是把经过loop 等软接口的skb发给PF_PACKET.
但是简单的把dev_queue_xmit_nit(skb,dev)加上还不行 PF_PACKET收到不完整的包。继续...

net/core/dev.c:
int dev_queue_xmit(struct sk_buff *skb)
{
        struct net_device *dev = skb->dev;
        struct Qdisc  *q;

                ......

        /* Grab device queue */
        spin_lock_bh(&dev->queue_lock);
        q = dev->qdisc;
        if (q->enqueue) {
                int ret = q->enqueue(skb, q);  //应该在这里加上dev_queue_xmit_nit(skb,dev);
                                                                              但是还不知道怎么加

                qdisc_run(dev);

                spin_unlock_bh(&dev->queue_lock);
                return ret == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : ret;
        }

        /* The device has no queue. Common case for software devices:
           loopback, all the sorts of tunnels...

           Really, it is unlikely that xmit_lock protection is necessary here.
           (f.e. loopback and IP tunnels are clean ignoring statistics counters.)
           However, it is possible, that they rely on protection
           made by us here.

           Check this and shot the lock. It is not prone from deadlocks.
           Either shot noqueue qdisc, it is even simpler
         */
        if (dev->flags&IFF_UP) {
                int cpu = smp_processor_id();

                if (dev->xmit_lock_owner != cpu) {
                        spin_unlock(&dev->queue_lock);
                        spin_lock(&dev->xmit_lock);
                        dev->xmit_lock_owner = cpu;

                        if (!netif_queue_stopped(dev)) {
                                if (netdev_nit)
                                        dev_queue_xmit_nit(skb,dev); //只是软接口的skb

                                if (dev->hard_start_xmit(skb, dev) == 0) {
                                        dev->xmit_lock_owner = -1;
                                        spin_unlock_bh(&dev->xmit_lock);
                                        return 0;
                                }
                        }
                        dev->xmit_lock_owner = -1;
                        spin_unlock_bh(&dev->xmit_lock);
                        if (net_ratelimit())
                                printk(KERN_CRIT "Virtual device %s asks to queue packet!\n", dev->name);
                        kfree_skb(skb);
                        return -ENETDOWN;
                } else {
                        /* Recursion is detected! It is possible, unfortunately */
                        if (net_ratelimit())
                                printk(KERN_CRIT "Dead loop on virtual device %s, fix it urgently!\n", dev->name);
                }
        }
        spin_unlock_bh(&dev->queue_lock);

        kfree_skb(skb);
        return -ENETDOWN;
}

献世佛 2022-10-05 09:02:46

我对内核不太熟悉,请问您可以用 ifconfig eth0 promisc,把 eth0 带进混杂模式吗?如果可以,那么试试看,这样能否抓到。

丑疤怪 2022-10-05 09:02:46

之前通过设置以太口为混杂模式抓过, 能抓到别人的收发包, 抓不到本机发包. 而且抓自己的发包不需要设成混杂模式吧.

static int iface_set_promisc(int fd, int dev_id)
{
        struct packet_mreq mr;

        memset(&mr, 0, sizeof(mr));
        mr.mr_ifindex = dev_id;
        mr.mr_type = PACKET_MR_PROMISC;
        if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
                &mr, sizeof(mr)) == -1) {
                return -1;
        }
        return 0;
}

暮色兮凉城 2022-10-05 09:02:46

找到问题  以太口驱动问题  
以太口驱动在enqueue的时候直接发送了 没有走qdisc_restart中dequeue这一流程
所以没有执行dev_queue_xmit_nit, 所以PF_PACKET没有收到。

int qdisc_restart(struct net_device *dev)
{
        struct Qdisc *q = dev->qdisc;
        struct sk_buff *skb;

        /* Dequeue packet */
        if ((skb = q->dequeue(q)) != NULL) {    //以太口的dequeue取出NULL, 下面没有走到
                if (spin_trylock(&dev->xmit_lock)) {
                        /* Remember that the driver is grabbed by us. */
                        dev->xmit_lock_owner = smp_processor_id();

                        /* And release queue */
                        spin_unlock(&dev->queue_lock);

                        if (!netif_queue_stopped(dev)) {
                                if (netdev_nit
#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
                                    && !(skb->imq_flags & IMQ_F_ENQUEUE)
#endif
                                    )
                                        dev_queue_xmit_nit(skb, dev);  //正常应该走这里

                                if (dev->hard_start_xmit(skb, dev) == 0) {
                                        dev->xmit_lock_owner = -1;
                                        spin_unlock(&dev->xmit_lock);

                                        spin_lock(&dev->queue_lock);
                                        return -1;
                                }
                        }
   ......

娇女薄笑 2022-10-05 09:02:46

那么这个问题如何解决呢?
去掉if ((skb = q->dequeue(q)) != NULL) 这句吗?会不会对其它有影响?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文