📄 110.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://apue.dhs.org"><font face="黑体"><big><big>123</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center"> ● UNIX网络编程 (BM: clown) </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="index.htm">回到开始</a>][<a href="54.htm">上一层</a>][<a href="111.htm">下一篇</a>]
<hr><p align="left"><small>发信人: clown (梧桐叶), 信区: UNP <br>
标 题: 使用IPPROTO_RAW只能发送,不能接受的例子 <br>
发信站: UNIX编程 (2001年11月19日17:21:00 星期一), 站内信件 <br>
<br>
#include <stdio.h> <br>
#include <unistd.h> <br>
#include <stdlib.h> <br>
#include <sys/types.h> <br>
#include <sys/socket.h> <br>
#include <arpa/inet.h> <br>
#include <sys/time.h> <br>
#include <netinet/in.h> <br>
#include <netinet/ip.h> <br>
#include <netinet/ip_icmp.h> <br>
#include <signal.h> <br>
#include <netdb.h> <br>
#include <errno.h> <br>
#include <string.h> <br>
<br>
#define SIZE 60 <br>
<br>
int datalen = 8; //data that goes with ICMP echo request <br>
int sockfd; <br>
int sockfd; <br>
struct sockaddr_in saddr; <br>
int socklen; <br>
<br>
void sig_alarm(int); <br>
void proc(char *, int, struct timeval *); <br>
void sendicmp(); <br>
unsigned short checksum(unsigned short *, int); <br>
<br>
int main(int argc, char **argv) <br>
{ <br>
int clilen, n; <br>
struct hostent *host; <br>
char dest[16], recvbuf[SIZE]; <br>
struct sockaddr cli; <br>
struct timeval tv; <br>
<br>
if(argc != 2) { <br>
printf("Usage: %s <host>\n", argv[0]); <br>
exit(1); <br>
} <br>
errno = 0; <br>
h_errno = 0; <br>
<br>
if((host = gethostbyname(argv[1])) == NULL) { <br>
herror("gethostbyname"); <br>
exit(1); <br>
} <br>
if(host->h_addrtype != AF_INET) { <br>
printf("Unsupported net family %d\n", host->h_addrtype); <br>
exit(1); <br>
} <br>
if(inet_ntop(AF_INET, host->h_addr, dest, sizeof(dest)) == NULL) { <br>
perror("inet_ntop"); <br>
exit(1); <br>
} <br>
<br>
//get the dest address, for the sendicmp() <br>
memset(&saddr, 0, sizeof(struct sockaddr_in)); <br>
saddr.sin_family = AF_INET; <br>
memcpy((void *)&saddr.sin_addr, host->h_addr, host->h_length); <br>
socklen = sizeof(struct sockaddr_in); <br>
<br>
printf("Ping %s(%s): %d bytes data\n", host->h_name, dest, datalen); <br>
//the protocal IPPROTO_RAW only can be used to send packet, and <br>
//user has to construct ip header himself; <br>
//it can't be used to receive packet. <br>
if((sockfd=socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) { <br>
//if((sockfd=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) { <br>
perror("socket"); <br>
exit(1); <br>
} <br>
setuid(getuid()); //don't need root privilege any more. <br>
if(signal(SIGALRM, sig_alarm) == SIG_ERR) { <br>
perror("signal"); <br>
exit(1); <br>
} <br>
sig_alarm(SIGALRM); <br>
while(1) { <br>
clilen = sizeof(struct sockaddr); <br>
memset(recvbuf, 0, sizeof(recvbuf)); <br>
n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, &cli, &clilen); <br>
if(n < 0) { <br>
if(errno == EINTR) <br>
continue; <br>
else { <br>
perror("recvfrom"); <br>
exit(1); <br>
} <br>
} <br>
if(gettimeofday(&tv, NULL) == -1) { <br>
perror("gettimeofday"); <br>
exit(1); <br>
} <br>
//printf("a packet received by SOCK_RAW IPPROTO_ICMP\n"); <br>
proc(recvbuf, n, &tv); <br>
} <br>
return 0; <br>
} <br>
<br>
void sig_alarm(int signo) <br>
{ <br>
sendicmp(); <br>
alarm(1); <br>
return; <br>
} <br>
<br>
/* <br>
* <br>
* <br>
* the packet send and received <br>
* <br>
|---------------------len----------------------------| <br>
|-----------hlen-----------|--------icmplen----------| <br>
<br>
|IPv4 header | IPv4 option | ICMP header | ICMP data | <br>
<br>
|----20B-----|-----0~40B---|-----8B------| <br>
* <br>
*/ <br>
<br>
void proc(char *ptr, int len, struct timeval *tvrecv) <br>
{ <br>
int hlen, icmplen; <br>
double rtt; <br>
struct ip *ip; <br>
struct icmp *icmp; <br>
struct timeval *tvsend; <br>
pid_t pid; <br>
char src[16], dest[16]; <br>
<br>
void timeval_sub(struct timeval *, struct timeval *); <br>
<br>
pid = getpid(); <br>
ip = (struct ip *)ptr; <br>
hlen = ip->ip_hl<<2; //length of IP header <br>
if(inet_ntop(AF_INET, (void *)&ip->ip_src, src, sizeof(src)) == NULL) { <br>
perror("inet_ntop"); <br>
exit(1); <br>
} <br>
if(inet_ntop(AF_INET, (void *)&ip->ip_dst, dest, sizeof(dest)) == NULL) { <br>
perror("inet_ntop"); <br>
exit(1); <br>
} <br>
<br>
if(ip->ip_p != IPPROTO_ICMP) { <br>
printf("*** not a icmp packet ***\n"); <br>
return; <br>
} <br>
icmp = (struct icmp *)(ptr + hlen); <br>
if((icmplen = len-hlen) < 8) { <br>
printf("icmplen: %d < 8\n", icmplen); <br>
exit(1); <br>
} <br>
} <br>
if(icmp->icmp_type == ICMP_ECHOREPLY) { <br>
if(icmp->icmp_id != pid) //not a response to our ECHO_REQUEST <br>
return; <br>
if(icmplen < 16) { <br>
//icmp header: type(1B), code(1B), checksum(2B), <br>
// id(2B), seq(2B); <br>
//data: time(8B); <br>
printf("icmplen: %d < 16\n", icmplen); <br>
exit(1); <br>
} <br>
tvsend = (struct timeval *)icmp->icmp_data; <br>
timeval_sub(tvrecv, tvsend); <br>
rtt = tvrecv->tv_sec*1000.0 + tvrecv->tv_usec/1000.0; //ms <br>
printf("%d bytes from %s: seq=%d, ttl=%d, rtt=%.3fms\n", <br>
icmplen, src, icmp->icmp_seq, ip->ip_ttl, rtt); <br>
} <br>
/* <br>
else { <br>
printf("%d bytes from %s to %s: type=%d, code=%d\n", icmplen, <br>
src, dest, icmp->icmp_type, icmp->icmp_code); <br>
} <br>
*/ <br>
*/ <br>
return; <br>
} <br>
<br>
void timeval_sub(struct timeval *recv, struct timeval *send) <br>
{ <br>
if((recv->tv_usec -= send->tv_usec) < 0) { <br>
recv->tv_sec--; <br>
recv->tv_usec += 1000000; <br>
} <br>
recv->tv_sec -= send->tv_sec; <br>
return; <br>
} <br>
<br>
void sendicmp() <br>
{ <br>
static unsigned short nsend = 0; <br>
int len; <br>
struct ip *ip; <br>
struct icmp *icmp; <br>
unsigned char sendbuf[SIZE]; <br>
<br>
memset(sendbuf, 0, sizeof(sendbuf)); <br>
<br>
ip = (struct ip *)sendbuf; <br>
ip->ip_hl = sizeof(struct ip) >> 2; <br>
ip->ip_v = IPVERSION; <br>
ip->ip_tos = 0; <br>
ip->ip_len = sizeof(struct ip) + sizeof(struct icmp) + datalen; <br>
ip->ip_id = 0; <br>
ip->ip_off = 0; <br>
ip->ip_ttl = MAXTTL; <br>
ip->ip_p = IPPROTO_ICMP; <br>
ip->ip_sum = 0; <br>
inet_pton(AF_INET, "192.168.2.69", &ip->ip_src); <br>
memcpy(&ip->ip_dst, &saddr.sin_addr, sizeof(struct in_addr)); <br>
<br>
icmp = (struct icmp *)(sendbuf + sizeof(struct ip)); <br>
icmp->icmp_type = ICMP_ECHO; <br>
icmp->icmp_code = 0; <br>
icmp->icmp_id = getpid(); <br>
icmp->icmp_seq = nsend++; <br>
<br>
if(gettimeofday((struct timeval *)icmp->icmp_data, NULL) == -1) { <br>
perror("gettimeofday"); <br>
exit(1); <br>
} <br>
<br>
len = sizeof(struct icmp) + datalen; //checksum ICMP header and data <br>
//Does checksum need change to network byte order? <br>
//I don't know, and it seems no matter. <br>
icmp->icmp_cksum = checksum((unsigned short *)icmp, len); <br>
<br>
printf("send icmp packet %d\n", nsend); <br>
sendto(sockfd, sendbuf, len, 0, (struct sockaddr *)&saddr, socklen); <br>
return; <br>
} <br>
<br>
unsigned short checksum(unsigned short *addr, int len) <br>
{ <br>
int nleft = len; <br>
int sum = 0; <br>
unsigned short *w = addr; <br>
unsigned short answer = 0; //16 bits <br>
<br>
while(nleft > 1) { <br>
sum += *w++; <br>
nleft -= 2; <br>
} <br>
if(nleft == 1) { <br>
//the lower 8 bits of answer will be filled with zero <br>
*(unsigned char *)(&answer) = *(unsigned char *)w; <br>
sum += answer; <br>
} <br>
sum = (sum >> 16) + (sum & 0xffff); <br>
sum += (sum >> 16); <br>
answer = ~sum; <br>
//printf("answer %d\n", answer); <br>
return answer; <br>
} <br>
<br>
<br>
<br>
-- <br>
易朽的是生命,似那转瞬即谢的花朵;然而永存的,是对未来的渴望, <br>
是那生生世世传递下来的,不朽的,生的激情。每一朵勇敢开放的花, <br>
都是一个死亡唇边的微笑。 <br>
※ 来源:·UNIX编程 apue.dhs.org·[FROM: 202.114.1.61] <br>
</small><hr>
<p align="center">[<a href="index.htm">回到开始</a>][<a href="54.htm">上一层</a>][<a href="111.htm">下一篇</a>]
<p align="center"><a href="http://cterm.163.net">欢迎访问Cterm主页</a></p>
</table>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -