armlinux下PF_PACKET socket抓不到eth0发包
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
自己写的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]);
}
}
另:此代码在我pc的fedora core3上可以正常工作
附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;
}
找到问题,是 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;
}
我对内核不太熟悉,请问您可以用 ifconfig eth0 promisc,把 eth0 带进混杂模式吗?如果可以,那么试试看,这样能否抓到。
之前通过设置以太口为混杂模式抓过, 能抓到别人的收发包, 抓不到本机发包. 而且抓自己的发包不需要设成混杂模式吧.
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;
}
找到问题 以太口驱动问题
以太口驱动在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;
}
}
......
那么这个问题如何解决呢?
去掉if ((skb = q->dequeue(q)) != NULL) 这句吗?会不会对其它有影响?