编写源文件goose.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<netinet/ip_icmp.h>
#include<netinet/tcp.h>
#include<netinet/udp.h>
#include<net/if.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/ioctl.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <time.h>
#define BUFFSIZE 8024
struct goose_pkt{
uint8_t dest[6];
uint8_t src[6];
uint16_t type;
//uint32_t vlan;
uint16_t app_id;
uint16_t length;
uint8_t reserve[6 * 16 + 2];
uint16_t sq_num;
}__attribute__((packed));
struct session {
time_t time;
uint16_t seq_num;
uint32_t cnt;
uint32_t time_diff;
};
#define MAX_APP_ID 0x1200
struct session map[MAX_APP_ID];
/*
* return:
* 0 success
* 1 timeout
* -1 fail
*/
int get_goose_massage(int sockfd, uint8_t *buff, uint32_t *length)
{
struct timeval timeout;
int ret = 0;
fd_set rfds;
FD_ZERO(&rfds);//清空描述符集合
FD_SET(0, &rfds);//将标准输入(stdin)添加到集合中
FD_SET(sockfd, &rfds);//将我们的套接字描述符添加到集合中
/*设置超时时间*/
timeout.tv_sec = 10;
timeout.tv_usec = 0;
/*监听套接字是否为可读*/
ret = select(sockfd+1, &rfds, NULL, NULL, &timeout);
//printf("ret:%d\n", ret);
if(ret == -1) {//select 连接失败
perror("select failure ");
return -1;
}
else if(ret == 0) {//超时(timeout)
return 1;
}
if(FD_ISSET(sockfd, &rfds)) {//如果可读
*length = recvfrom(sockfd,buff,BUFFSIZE,0,NULL,NULL);
if(*length<0){
printf("receive error!\n");
return -1;
}
} else {
printf("select failed!\n");
return -1;
}
return 0;
}
int main(){
int rawsock;
uint8_t buff[BUFFSIZE];
int n;
int count = 0;
memset(&map, 0, sizeof(map));
rawsock = socket(PF_PACKET,SOCK_RAW,htons(0x88b8));
//rawsock = socket(PF_PACKET,SOCK_RAW,htons(0x8100));
//rawsock = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
if(rawsock < 0){
printf("raw socket error!\n");
exit(1);
}
#if 0
struct ifreq ifr;
strncpy( ifr.ifr_name, "eth3", IFNAMSIZ );
if( ioctl( rawsock, SIOCGIFFLAGS, &ifr ) == -1 )
{
perror( "SIOCGIFFLAGS" );
exit(EXIT_FAILURE);
}
ifr.ifr_flags |= ( IFF_PROMISC | IFF_UP );
if( ioctl( rawsock, SIOCSIFFLAGS, &ifr ) == -1 )
{
perror( "SIOCSIFFLAGS" );
exit(EXIT_FAILURE);
}
#endif
printf("sizeof: %d\n", sizeof(struct goose_pkt));
while(1){
int ret = get_goose_massage(rawsock, buff, &n);
if (ret == 1) {
printf("timeout\n");
continue;
} else if (ret == -1) {
printf("receive message failed!\n");
continue;
}
struct goose_pkt *pkt = (struct goose_pkt *)buff;
if (ntohs(pkt->type) != 0x88b8) {
continue;
}
//count++;
//printf("%5d recv:%d",count, n);
//printf("\n");
#if 0
int i;
for (i = 0; i < n; i++) {
printf("%02x ", buff[i]);
if ((i % 8) == 7)
printf(" ");
if ((i % 16) == 15)
printf("\n");
}
printf("\n");
#endif
uint16_t app_id = ntohs(pkt->app_id);
//uint16_t seq_num = *(uint16_t *)(buff + 116);
uint16_t seq_num = ntohs(pkt->sq_num);
if (app_id >= MAX_APP_ID) {
printf("error app_id: %04x\n", app_id);
continue;
}
time_t now = time(NULL);
struct session *p_node = &map[app_id];
if (p_node->time != 0) {
if ((now - p_node->time) >= 10) {
printf("node, app_id: %04x timeout!\n", app_id);
}
if (seq_num != (p_node->seq_num + 1)) {
//printf("node, app_id: %04x drop packet!\n", app_id);
}
}
p_node->time_diff = now - p_node->time;
p_node->time = now;
p_node->seq_num = seq_num;
p_node->cnt++;
printf("app_id:%04x, time:%ld, time_diff:%u, sqNum:%5d, cnt:%u\n", app_id, now, p_node->time_diff, seq_num, p_node->cnt);
}
}
编写Makefile
all: goose
echo complete
goose: goose.c
${CC} -o goose goose.c
clean:
rm goose
测试
make
./goose