红联Linux门户
Linux帮助

Linux C原始套接字抓包

发布时间:2015-02-26 16:11:39来源:linux网站作者:linux人

抓包分析主机上网浏览了那些网页,并把浏览网页的网址写入一个文件。

首先我列举下我在写抓包程序所犯下的错误。供大家学习参考。


创建原始套接字失败:

分析原因:刚开始的时候运行程序正常,但是同事覃书芹帮我虚拟机添加了一个虚拟网卡的时候就出现错误了。原因说出来很简单,就是设备名称错误,但是当时我怎么调都调不出来。最后请他们看了下,一下就看出来了。起码让我明白创建套接字的时候要与监听的网卡名称相对应,不然要监听eth1,结果在绑定设备名称的时候绑成了eth0,那就可能出现错误,获得不到效果。


1.写文件总是乱码:

分析原因:这个问题在我进公司前以前就犯过,那时候是用C++写,改正过来比较快。现在在全字符环境下,改了半天,最后发现,在写的时候直接传了地址,而没有加上所传字符串的长度。导致乱码,加上一个sizeof()以后问题解决。


2.浏览部分网页时程序出现段错误:

在C环境下,出现段错误是很常见的,但对于我来说见的很少,所以出现这类问题的时候显得还不到哪错了。原因是我在定位域名字段的时候是以“com\r\n”结束为标记的。因为很多域名都是以.com结尾的,所以就忽略了还有以“.cn”或者以“.net”结尾的域名。我当时就奇怪了,为什么有的网页可以,但是访问有些域名的时候,一点击就出错。当找不到.com的时候就会定位到下一个包,定义到一个不存在的内存区域。所以导致段错误。


3.分析的出是tcp包但是分析不出是http包:

错误原因:这个错误本来应该是不会出现的,就是我把usleep(1000),改为了sleep(1),都是停止一秒钟。在while循环里用sleep(1)可以让程序暂停执行一秒钟效果很明显,但是usleep(1000)就不是很明显了。在while循环里用sleep(1)就明显减慢了抓包的速度,所以就出现抓漏了包的情况。把while循环里的sleep(1)改成usleep(1000);就行了。

程序过程:

首先抓住经过网卡的数据包,首先检测他是不是ip包,如果是剥去包头,然后看是不是tcp包,如果是则检测它的端口是不是80端口。如果是则证明传输的是http协议。然后就可以分析是不是存在“get”字段,是不是存在“host”字段。然后取“host”后面的一个字符串,即我们要得到的主机访问的域名,即上网记录。


具体代码如下:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

#include <net/ethernet.h>

#include <netinet/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_arp.h>

#define NOT_UNICAST(e) ((e[0] & 0x01) != 0)

#define APP_NAME "pppc"
#define APP_VER  "0.1.0"

#define PPPOE_DISCOVER  0x8863
#define PPPOE_SESSION0x8864

#define ETH_ALEN  6
#define NET_FACE_LEN  8

#define TRUE  1
#define FALSE 0

#ifndef ETH_DATA_LEN
#define ETH_DATA_LEN  ETHERMTU
#endif

#pragma pack(1)

typedef struct __st_pconn
{
unsigned char  myName[NET_FACE_LEN];
unsigned char  myEth[ETH_ALEN];
unsigned char  peerEth[ETH_ALEN];

unsigned short session_id;
intnet_socket;

} tPconn;

typedef struct __st_eth_head
{
unsigned char  dst[ETH_ALEN];
unsigned char  src[ETH_ALEN];
unsigned short proto;

} tEthHead;

typedef struct __st_pppoe_head
{
unsigned char  ver:4;
unsigned char  type:4;
unsigned char  code;
unsigned short sid;
unsigned short len;

} tPPPPOEHead;

typedef struct __st_pppoe_pkt_info
{
tEthHead  ethHead;
tPPPPOEHeadpppoeHead;
unsigned char payload[32];

} tPPPOEPkt;

typedef struct __st_ip_pkt_head
{
//unsigned char  hlen:4;
//unsigned char  ver:4;
unsigned char  vhlen;
unsigned char  tos;
unsigned short tlen;
unsigned short ipid;
unsigned short flag;
unsigned char  ttl;
unsigned char  proto;
unsigned short checksum;
unsigned long  sip;
unsigned long  dip;
unsigned char  data[1];
 
} tIPktHead;

typedef struct _st_tcp
{
unsigned short sport;
unsigned short dport;
unsigned long  seq;
unsigned long  ack;
unsigned char  offset;
unsigned char  code;
unsigned short window;
unsigned short cksum;
unsigned short urg;
unsigned char  data[1];

} tTcp;

#pragma pack()

/////////////////////////////// Define public var //////////////////////////////
tPconn myConn;
/////////////////////////// End of Define public var ///////////////////////////

char *inet_htoa(unsigned long ipaddr)
{
static char buf[10][20];
static int  old_index=0;
intindex;
unsigned char  t1;
unsigned char  bFlag = FALSE;
char*pbuf;

index = old_index;
old_index = (old_index+1) % 10;

pbuf  = buf[index];
t1= (ipaddr >> 24) & 0xff;
*pbuf = (t1 / 100);
if (*pbuf != 0)
{
*pbuf += 0x30;
pbuf++;
bFlag = TRUE;
}
*pbuf = ((t1 / 10) % 10);
if (*pbuf != 0)
{
*pbuf += 0x30;
pbuf++;
}
else if (bFlag)
{
*pbuf += 0x30;
  pbuf++;
}
*pbuf++ = (t1 % 10) + 0x30;
*pbuf++ = '.';

/******************************/
bFlag = FALSE;
t1 = (ipaddr >> 16) & 0xff;
*pbuf = (t1 / 100);
if (*pbuf != 0)
{
*pbuf += 0x30;
pbuf++;
bFlag = TRUE;
}
*pbuf = ((t1 / 10) % 10);
if (*pbuf != 0)
{
*pbuf += 0x30;
pbuf++;
}
else if (bFlag)
{
*pbuf += 0x30;
pbuf++;
}
*pbuf++ = (t1 % 10) + 0x30;
*pbuf++ = '.';

/******************************/
bFlag = FALSE;
t1 = (ipaddr >> 8) & 0xff;
*pbuf = (t1 / 100);
if (*pbuf != 0)
{
*pbuf += 0x30;
pbuf++;
bFlag = TRUE;
}
*pbuf = ((t1 / 10) % 10);
if (*pbuf != 0)
{
*pbuf += 0x30;
pbuf++;
}
else if (bFlag)
{
*pbuf += 0x30;
pbuf++;
}
*pbuf++ = (t1 % 10) + 0x30;
*pbuf++ = '.';

/******************************/
bFlag = FALSE;
t1 = ipaddr & 0xff;
*pbuf = (t1 / 100);
if (*pbuf != 0)
{
*pbuf += 0x30;
pbuf++;
bFlag = TRUE;
}
*pbuf = ((t1 / 10) % 10);
if (*pbuf != 0)
{
*pbuf += 0x30;
pbuf++;
}
else if (bFlag)
{
*pbuf += 0x30;
pbuf++;
}
*pbuf++ = (t1 % 10) + 0x30;
*pbuf = '\0';

pbuf= buf[index];
return pbuf;
}

int init_rawsocket(char *dev_name)
{
int raw_sock_fd;
struct sockaddr_ll sll;
struct ifreq ifstruct;

memset(&sll, 0, sizeof(struct sockaddr_ll));
strcpy(ifstruct.ifr_name, dev_name);

raw_sock_fd = socket(PF_PACKET, SOCK_RAW, htons(IPPROTO_RAW));

if (ioctl(raw_sock_fd, SIOCGIFINDEX, &ifstruct) == -1)//指定socket,把信息存入到ifstruct中
{
printf("ioctl SIOCGIFINDEX [%s] Error!!!", dev_name);
close(raw_sock_fd);
exit(1);
return -1;
}

sll.sll_family= PF_PACKET;
sll.sll_ifindex  = ifstruct.ifr_ifindex;
sll.sll_protocol = htons(ETH_P_ALL);
sll.sll_hatype= ARPHRD_ETHER;
sll.sll_pkttype  = PACKET_OTHERHOST;
sll.sll_halen= ETH_ALEN;
sll.sll_addr[6]  = 0;
sll.sll_addr[7]  = 0;

if (ioctl(raw_sock_fd, SIOCGIFHWADDR, &ifstruct) == -1)
{
printf("\nioctl SIOCGIFHWADDR [%s] Error!!!", dev_name);
close(raw_sock_fd);
exit(1);
return -1;
}

if (ioctl(raw_sock_fd, SIOCGIFFLAGS, &ifstruct) < 0)
 {
  printf("ioctl SIOCGIFFLAGS [%s] Error!!!", dev_name);
  close(raw_sock_fd);
exit(1);
  return -1;
 }
#if 1
ifstruct.ifr_flags |= IFF_PROMISC;//set promisc
if (ioctl(raw_sock_fd, SIOCSIFFLAGS, &ifstruct) == -1)
{
printf("Set [%s] promisc error\n", dev_name);
close(raw_sock_fd);
exit(1);
return -1;
}
#endif
if (bind(raw_sock_fd, (struct sockaddr *)&sll, sizeof(struct sockaddr_ll)) == -1)
 {
  printf("Bind %s Error!", dev_name);
  close(raw_sock_fd);
  exit(1);
  return -1;
 }

return raw_sock_fd;

} /* End of init_rawsocket */

int init_netface(tPconn *pPconn)
{
struct ifreq ifr;
struct sockaddr_ll pSock;
int optval = 1;

if (!pPconn)
return 0;

 //把创建 的socket套接字传给pCONN
pPconn->net_socket = init_rawsocket(pPconn->myName);
printf("Raw fd [%d]\n", pPconn->net_socket);

strncpy(ifr.ifr_name, pPconn->myName, NET_FACE_LEN); 

//获取网卡的MAC地址
 if (ioctl(pPconn->net_socket, SIOCGIFHWADDR, &ifr) < 0)
 {
 printf("ioctl(SIOCGIFHWADDR) error");
 exit(0);
 }
 memcpy(pPconn->myEth, ifr.ifr_hwaddr.sa_data, ETH_ALEN);

 printf("Get [%s], MAC [%02x:%02x:%02x:%02x:%02x:%02x]\n",
 pPconn->myName, pPconn->myEth[0], pPconn->myEth[1], pPconn->myEth[2],
 pPconn->myEth[3], pPconn->myEth[4], pPconn->myEth[5]);

return 1;

}

int main(int argc, char **argv)
{
int raw_fd = 0;
int rlen= 0;
int n  = 0;
char buff[1500] = {0};
tEthHead *pEth = NULL;
tIPktHead*pOeh = NULL;
tTcp *ptcp = NULL;
char *tcpdata = NULL;
char *tcpdend = NULL;
int  tcpdatalen = 0;
char data [1024]={0} ;
char *host = NULL;
char *hostend = NULL;
char hostdata[1024]={0};
charptjay[30];

memset(&myConn, 0, sizeof(tPconn));

sprintf(myConn.myName, "eth0");
init_netface(&myConn);

printf("%s (v%s) started\n", APP_NAME, APP_VER);

printf("Eth head len %d, PPPOE head len %d, PPPOE pkt len %d\n",
sizeof(tEthHead), sizeof(tPPPPOEHead), sizeof(tPPPOEPkt));

while (1)
{
//send_PADI(&myConn);
rlen = read(myConn.net_socket, buff, 1514);//读取数据报
if (rlen > 0)
{
pEth = (tEthHead *)buff;

// printf("Get a packet, DMAC [%02x:%02x:%02x:%02x:%02x:%02x], SMAC [%02x:%02x:%02x:%02x:%02x:%02x]\n",
//pEth->dst[0], pEth->dst[1],pEth->dst[2],pEth->dst[3],pEth->dst[4],pEth->dst[5],
// pEth->src[0], pEth->src[1],pEth->src[2],pEth->src[3],pEth->src[4],pEth->src[5]);
switch (ntohs(pEth->proto))
{
case 0x0800:
{
pOeh = (tIPktHead*)(buff+sizeof(tEthHead));
// printf("Get a ip packet\n");
// printf("SIP[%s], DIP[%s], ipid [%d], tlen [%d], ver [%d], hlen [%d]\n",
//inet_htoa(ntohl(pOeh->sip)), inet_htoa(ntohl(pOeh->dip)),
//ntohs(pOeh->ipid), ntohs(pOeh->tlen), (pOeh->vhlen&0xf0)>>4, (pOeh->vhlen&0x0f)<<2);
switch (pOeh->proto)
{
case 0x06:
{
  //printf("Get a TCP packet\n");

ptcp = (tTcp*)pOeh->data;
//printf("%d\n",ntohs(ptcp->dport));
if (ntohs(ptcp->dport)==80)
{
 //  printf("Get a http packet\n");

tcpdata = (char*)(ptcp->data); 
if(strncmp(tcpdata, "GET ", 4) == 0)
  {
//printf("Get a get http packet\n");

tcpdend = strstr(ptcp->data, " HTTP/1.1\r\n");

printf("http data is \n");

tcpdata += 4;
tcpdatalen = tcpdend-tcpdata;

printf("%d\n", tcpdatalen);

printf("%s\n", strncpy(data, tcpdata, tcpdatalen));

host = strstr(ptcp->data, "Host: ");
 strncpy(ptjay,host,30);
 printf("测试用的%s\n",ptjay);
hostend = strstr(ptjay, "\r\n");
 strncpy(ptjay,hostend,5);
 printf("测试用的二%s",ptjay);
tcpdatalen = hostend - host;

printf("%s\n",strncpy(hostdata, host, tcpdatalen));
 host=NULL;
 hostend=NULL;
 strncpy(data,"0",1);
 strncpy(ptjay,"0",1);

}
//else
//printf("Get other http packet\n");

 }
// else
//printf("Get not http packet\n");

}
break;

default:
  //  printf("Get not tcp packet\n");
break;
}
}
break;

default:
//printf("Get other packet\n");
break;

}
//printf("Send PADI\n");
//printf("包结束\n");
usleep(1000);
}

}