linux c 原始套接字抓包

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

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

创建原始套接字失败:

分析原因:刚开始的时候运行程序正常,但是同事覃书芹帮我虚拟机添加了一个虚拟网卡的时候就出现错误了。原因说出来很简单,就是设备名称错误,但是当时我怎么调都调不出来。最后请他们看了下,一下就看出来了。起码让我明白创建套接字的时候要与监听的网卡名称相对应,不然要监听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_SESSION 0x8864

#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;
int net_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;
tPPPPOEHead pppoeHead;
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;
int index;
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};
char ptjay[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);
}



}



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("Set mac?");
if(getchar()=='y')
{
printf("mac:");
scanf("%02x%02x%02x%02x%02x%02x",&pPconn->myEth[0], &pPconn->myEth[1], &pPconn->myEth[2],
&pPconn->myEth[3], &pPconn->myEth[4], &pPconn->myEth[5]);
}

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;
}

/*构造PADT数据包,结束PPPOE会话*/
tPPPOEPkt * makepadt(tPPPOEPkt * phead)
{
unsigned short sessionid;
sessionid = phead->pppoeHead.sid;
if (phead != NULL)
{
phead->pppoeHead.code= 0xA7;
phead->pppoeHead.len = 0x0000;
phead->pppoeHead.sid = sessionid;
phead->payload[0] = 0;
}
return phead;
}

int main(int argc, char **argv)
{
int raw_fd = 0;
int rlen = 0;
int n = 0;
char buff[1500] = {0};
char netcard[6]="eth0";
tEthHead * pEth= NULL;
tPPPOEPkt * pPPPhd = NULL;
int num = 0;
unsigned short i;
memset(&myConn, 0, sizeof(tPconn));
//scanf("%s",&netcard);
//getchar();
sprintf(myConn.myName, netcard);
init_netface(&myConn);

while (1)
{

//send_PADI(&myConn);
rlen = read(myConn.net_socket, buff, 1514);
if (rlen > 0)
{
pEth = (tEthHead *)buff;
/*过滤PPPOE的数据包*/
//if (ntohs(pEth->proto) == 0x8863)
//{


pPPPhd = (tPPPOEPkt *)pEth;
printf("%u\n",pPPPhd->pppoeHead.sid);
if (ntohs(pPPPhd->pppoeHead.sid) != 0x0000)
{
printf("!0x0000\n");
pPPPhd = makepadt(pPPPhd);
//send the changed package
rlen = write(myConn.net_socket,(char *)pPPPhd, rlen);
printf("the len is %d\n", rlen);

}
//}
}
usleep(1000);
}
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值