Linux C++实现ping指令

//#include "ping.h"
#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>

#define PACKET_SIZE 4096
#define SEND_DATA_LEN 56
#define ERROR    -1
#define SUCCESS   1
#define MAX_WAIT_TIME 3
#define MAX_NO_PACKETS 4
#define NULL 0

using namespace std;

class Cping
{
	public:
		Cping(const char * ip, int timeout);
		Cping(const Cping& org);
		virtual ~Cping();
	
	private:
		std::string m_strIp;
		std::string m_copy_Ip;
		
		int m_nSend;
		int m_nRecv;
		struct sockaddr_in m_dest_addr;
		struct sockaddr_in m_from_addr;
		
		char m_sendpacket[PACKET_SIZE];
		char m_recvpacket[PACKET_SIZE];
		
		struct timeval m_tvrecv;
		struct timeval m_begin_tvrecv;
		struct timeval m_end_tvrecv;
		double m_dTotalResponseTimes;
		int m_nSocketfd;
		
		int m_nMaxTimeWait;
   public:
		bool ping(int times);
		bool CreateSocket();
		bool CloseSocket();
		
		void send_packet(void);
		void recv_packet(void);
		
		int pack(int pack_no);
		int unpack(char *buf, int len);
		
		void tv_sub(struct timeval *out, struct timeval *in);
		void statistics(int sig);
		
		static unsigned short cal_chksum(unsigned short *addr, int len);
};

Cping::Cping(const char *ip, int timeout)
{
	m_strIp = ip;
	m_copy_Ip = ip;
	
	m_nSend = 0;
	m_nRecv = 0;
	
	m_dTotalResponseTimes = 0;
	
	if(timeout > MAX_WAIT_TIME)
	{
		m_nMaxTimeWait = MAX_WAIT_TIME;
	}
	else
	{
		m_nMaxTimeWait = timeout;
	}
}

Cping::~Cping()
{
	if(!CloseSocket())
	{
		cout << "CloseSocket failed!" << endl;
	}
}

bool Cping::ping(int times)
{
	if(!CreateSocket())
	{
		printf("CreateSocket failed!!!\n");
		return false;
	}
	printf("PING %s(%s): %d bytes data in ICMP packets.\n", m_strIp.c_str(),
					m_copy_Ip.c_str(), SEND_DATA_LEN);
	while(times--)
	{
		send_packet();
		recv_packet();
		sleep(1);
	}
	statistics(SIGINT);
	return true;
}

bool Cping::CreateSocket()
{
	char buf[2048];
	int errnop = 0;
	unsigned long inaddr;
	struct hostent hostinfo, *dest_phost;
	struct protoent *protocol = NULL;
	
	if((protocol = getprotobyname("icmp")) == NULL)
	{
		perror("getprotobyname()");
		printf("CreateSocket : getprotobyname failed:%d\n",errnop);
		return false;
	}
	if(-1 == (m_nSocketfd = socket(AF_INET,SOCK_RAW,protocol->p_proto)))
	{
		perror("socket");
		printf("CreateSocket: create socket failed:%d\n", m_nSocketfd);
		return false;
	}
	setuid(getuid());
	m_dest_addr.sin_family = AF_INET;
	
	bzero(&(m_dest_addr.sin_zero),8);
	
	if((inaddr = inet_addr(m_strIp.c_str())) == INADDR_NONE)
	{
		//if(getprotobyname_r(m_strIp.c_str(), &hostinfo, buf, sizeof(buf), &dest_phost, &errnop))
		//{
		//	printf("CreateSocket: getprotobyname error %s failed:%d\n", m_strIp.c_str(),errnop);
		//	return false;
		//}
		//else
		//{
			m_dest_addr.sin_addr = *((struct in_addr *)dest_phost->h_addr); 
		//}
	}
	else
	{
		m_dest_addr.sin_addr.s_addr = inaddr;
	}
	
	m_copy_Ip = inet_ntoa(m_dest_addr.sin_addr);
	
	return true;
}

bool Cping::CloseSocket()
{
	bool flag = false;
	if(m_nSocketfd)
	{
		close(m_nSocketfd);
		flag = true;
	}
	return flag;
}

void Cping::send_packet(void)
{
	int packetsize;
	packetsize = pack(m_nSend);
	
	if((sendto(m_nSocketfd, m_sendpacket, packetsize, 0 ,(const struct sockaddr*)&m_dest_addr, sizeof(m_dest_addr))) < 0)
	{
		printf("send_packet: send error :\n");
	}
	m_nSend++;
}

void Cping::recv_packet(void)
{
	int fromlen, packetsize, n;
	while(m_nRecv < m_nSend)
	{
		struct timeval timeout;
		fd_set readfd;
		FD_ZERO(&readfd);
		
		FD_SET(m_nSocketfd, &readfd);
		
		int maxfd = m_nSocketfd + 1;
		timeout.tv_sec = m_nMaxTimeWait;
		
		timeout.tv_usec = 0;
		
		n = select(maxfd, &readfd, NULL, NULL, &timeout);
		
		switch(n)
		{
			case 0:
				printf("recv_packet: select time out: \n");
				break;
			case -1:
				printf("recv_packet: select error: \n");
				break;
			default:
				if(FD_ISSET(m_nSocketfd, &readfd))
				{
					if((packetsize = recvfrom(m_nSocketfd, m_recvpacket, sizeof(m_recvpacket), 0,(struct sockaddr *)&m_from_addr,(socklen_t*)&fromlen)) < 0)
					{
						printf("packetsize = %d\n", packetsize);
						//printf("recv_packet: recv error: %d\n", errno);
						return ;
					}
					gettimeofday(&m_tvrecv, NULL);
					m_end_tvrecv.tv_usec = m_tvrecv.tv_usec;
					m_end_tvrecv.tv_sec = m_tvrecv.tv_sec;
					
					if(unpack(m_recvpacket, packetsize) == -1)
					{
						continue;
					}
					m_nRecv++;
				}
				break;
		}
	}
}

int Cping::pack(int pack_number)
{
	int packsize;
	struct icmp *pIcmp;
	struct timeval *pTime;
	
	pIcmp = (struct icmp*)m_sendpacket;
	
	pIcmp->icmp_type = ICMP_ECHO;
	pIcmp->icmp_code = 0;
	pIcmp->icmp_cksum = 0;
	pIcmp->icmp_seq = pack_number;
	pIcmp->icmp_id = getpid();
	packsize = 8 + SEND_DATA_LEN;
	pTime = (struct timeval *)pIcmp->icmp_data;
	gettimeofday(pTime, NULL);
	if(m_nSend == 0)
	{
		m_begin_tvrecv.tv_usec = pTime->tv_usec;
		m_begin_tvrecv.tv_sec = pTime->tv_sec;
	}
	pIcmp->icmp_cksum = cal_chksum((unsigned short*)pIcmp, packsize);
	return packsize;
}

int Cping::unpack(char *buf, int len)
{
	int i, iphdrlen;
	struct icmp *pIcmp;
	struct timeval *tvsend;
	struct ip* recv_ip = (struct ip*)buf;
	double rtt;
	
	iphdrlen = recv_ip->ip_hl << 2;
	pIcmp = (struct icmp*)(buf + iphdrlen);
	len -= iphdrlen;
	if(len < 8)
	{
		printf("ICMP packets's length is less than 8'");
		return -1;
	}
	
	if((pIcmp->icmp_type == ICMP_ECHOREPLY) && (m_copy_Ip == inet_ntoa(m_from_addr.sin_addr)) && (pIcmp->icmp_id = getpid()) )
	{
		tvsend = (struct timeval *)pIcmp->icmp_data;
		tv_sub(&m_tvrecv, tvsend);
		rtt = m_tvrecv.tv_sec * 1000 + (double)m_tvrecv.tv_usec / 1000;
		
		printf("%d byte from %s : icmp_seq=%u ttl=%d time=%.3fms\n",
			len,
			inet_ntoa(m_from_addr.sin_addr),
			pIcmp->icmp_seq,
			recv_ip->ip_ttl,
			rtt);
	}
	else
	{
		printf("throw away the old package %d\tbyte from %s\t: icmp_seq=%u\t: icmp_seq=%u\t ttl=%u\trtt=%.3f\tms",
		len,
		inet_ntoa(m_from_addr.sin_addr),
		pIcmp->icmp_seq,
		recv_ip->ip_ttl,
		rtt);
		return -1;
	}
	return 1;
}

void Cping::tv_sub(struct timeval *out, struct timeval *in)
{
	if((out->tv_usec -= in->tv_usec) < 0)
	{
		--out->tv_sec;
		out->tv_usec += 10000000;
	}
	out->tv_sec -= in->tv_sec;
}

void Cping::statistics(int sig)
{
	tv_sub(&m_end_tvrecv, &m_begin_tvrecv);
	m_dTotalResponseTimes = m_end_tvrecv.tv_sec * 1000 + (double)m_end_tvrecv.tv_usec / 1000;
	printf("--------statistics----------\n");
	printf("%d packets transmitted, %d received, %d%% lost, time: %.3lfms\n", m_nSend, m_nRecv,(m_nSend - m_nRecv) / m_nSend*100, m_dTotalResponseTimes);
	close(m_nSocketfd);
}

unsigned short Cping::cal_chksum(unsigned short *addr, int len)
{
	int nleft=len;
	int sum = 0;
	unsigned short *w = addr;
	unsigned short answer = 0;
	
	while(nleft > 1)
	{
		sum += *w++;
		nleft -=2;
	}
	
	if(nleft == 1)
	{
		*(unsigned char *)(&answer) = *(unsigned char *)w;
		sum += answer;
	}
	sum = (sum >> 16) + (sum & 0xffff);
	sum += (sum >> 16);
	answer = ~sum;
	
	return answer;
}

int main(int argc, char *argv[])
{
	Cping Ping(argv[1], 20);
	Ping.ping(3);
}

命名为 myping.cpp
编译命令:sudo g++ -o myping myping.cpp
修改权限:sudo chmod u+s myping
使用:./myping 192.168.1.222

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
PAM (Pluggable Authentication Modules) 是一种在 Linux 上进行身份验证的框架,可以通过编写 PAM 模块来实现不同的身份验证方法。在 C++实现 PAM 指令需要使用 PAM 库,可以按照以下步骤进行: 1. 包含 PAM 库头文件: ```c++ #include <security/pam_appl.h> ``` 2. 定义 PAM 应用程序: ```c++ int pam_func(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { // TODO: 进行身份验证 return PAM_SUCCESS; // 验证成功 } ``` 3. 定义 main 函数: ```c++ int main(int argc, char *argv[]) { const char *service = "pam_service_name"; // PAM 服务名称 const char *user = "pam_username"; // 要验证的用户名 const char *password = "pam_password"; // 要验证的密码 // 初始化 PAM 应用程序 pam_handle_t *pamh = NULL; int retval = pam_start(service, user, &pam_func, &pamh); if (retval != PAM_SUCCESS) { // 初始化失败 fprintf(stderr, "pam_start failed: %s\n", pam_strerror(pamh, retval)); return 1; } // 设置 PAM 验证项 struct pam_conv pamc = { .conv = &pam_stdin }; // 进行身份验证 retval = pam_authenticate(pamh, 0); if (retval != PAM_SUCCESS) { // 验证失败 fprintf(stderr, "pam_authenticate failed: %s\n", pam_strerror(pamh, retval)); pam_end(pamh, retval); return 1; } // 验证成功 printf("Authentication success\n"); // 结束 PAM 应用程序 pam_end(pamh, PAM_SUCCESS); return 0; } ``` 以上代码实现了一个简单的 PAM 指令,可以进行基本的身份验证操作。需要注意的是,需要将 `pam_service_name`、`pam_username` 和 `pam_password` 替换为实际的值。另外,还需要根据具体的需求编写 `pam_func` 函数来进行身份验证。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值