* Some ICMP test applications originally written by Yin Qiu as part of

GSoC 2008. I've reworked them a bit to let them compile without warnings
  (or at all), and give better error messages.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37634 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2010-07-20 21:20:36 +00:00
parent 0f9dda9f00
commit 02e7b23f38
6 changed files with 351 additions and 0 deletions

View File

@ -33,3 +33,4 @@ SubInclude HAIKU_TOP src tests kits net preflet ;
SubInclude HAIKU_TOP src tests kits net sock ;
SubInclude HAIKU_TOP src tests kits net tcp_shell ;
SubInclude HAIKU_TOP src tests kits net tcptester ;
SubInclude HAIKU_TOP src tests kits net icmp ;

View File

@ -0,0 +1,22 @@
SubDir HAIKU_TOP src tests kits net icmp ;
SimpleTest big_datagram :
big_datagram.cpp
: libnetwork.so
;
SimpleTest udp_unreachable :
udp_unreachable.cpp
: libnetwork.so
;
SimpleTest tcp_unreachable :
tcp_unreachable.cpp
: libnetwork.so
;
SimpleTest icmp_dumper :
icmp_dumper.cpp
: libnetwork.so
;

View File

@ -0,0 +1,155 @@
/*
* Copyright 2008-2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Yin Qiu
*/
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#define DGRM_SIZE 1600 // ought to be large enough
struct pseudo_header {
struct in_addr src;
struct in_addr dst;
u_int8_t zero;
u_int8_t protocol;
u_int16_t len;
};
static u_int16_t
cksum(u_int16_t* buf, int nwords)
{
u_int32_t sum;
for (sum = 0; nwords > 0; nwords--)
sum += *(buf++);
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}
static struct addrinfo*
host_serv(const char* host, const char* serv, int family, int socktype)
{
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = family;
hints.ai_socktype = socktype;
int n = getaddrinfo(host, serv, &hints, &res);
if (n != 0)
return NULL;
return res;
}
int
main(int argc, char** argv)
{
if (argc < 3) {
printf("Usage: %s <ip-address> <port> [nbytes]\n", argv[0]);
return 1;
}
size_t size;
if (argc == 3)
size = DGRM_SIZE;
else
size = atoi(argv[3]);
if (size - sizeof(struct ip) - sizeof(struct udphdr) < 0) {
fprintf(stderr, "Datagram size is too small\n");
return 1;
}
struct addrinfo* ai = host_serv(argv[1], NULL, 0, 0);
if (ai == NULL) {
fprintf(stderr, "Cannot resolve %s\n", argv[1]);
return 1;
}
printf("Using datagram size %zu\n", size);
char* datagram = (char*)malloc(size);
if (datagram == NULL) {
fprintf(stderr, "Out of memory.\n");
return 1;
}
memset(datagram, 0, size);
struct ip* iph = (struct ip*)datagram;
iph->ip_hl = 4;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = htons(size);
iph->ip_id = htonl(54321);
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = IPPROTO_ICMP;
iph->ip_sum = 0;
iph->ip_src.s_addr = INADDR_ANY;
iph->ip_dst.s_addr = ((struct sockaddr_in*)ai->ai_addr)->sin_addr.s_addr;
// Calculates IP checksum
iph->ip_sum = cksum((unsigned short*)datagram, iph->ip_len >> 1);
struct pseudo_header pHeader; // used to calculate udp checksum
struct udphdr* udp = (struct udphdr*)(datagram + sizeof(struct ip));
udp->uh_sport = 0;
udp->uh_dport = htons(atoi(argv[2]));
udp->uh_ulen = htons(size - sizeof(struct ip));
pHeader.src = iph->ip_src;
pHeader.dst = iph->ip_dst;
pHeader.zero = 0;
pHeader.protocol = iph->ip_p;
pHeader.len = udp->uh_ulen;
udp->uh_sum = cksum((u_int16_t*)&pHeader, 3);
// Send it via a raw socket
int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (sockfd < 0) {
fprintf(stderr, "Failed to create raw socket: %s\n", strerror(errno));
free(datagram);
return 1;
}
int one = 1;
const int* val = &one;
if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, val, sizeof(int)) != 0) {
fprintf(stderr, "Failed to set IP_HDRINCL on socket: %s\n",
strerror(errno));
free(datagram);
return 1;
}
int bytesSent = sendto(sockfd, datagram, size, 0, ai->ai_addr,
ai->ai_addrlen);
if (bytesSent < 0) {
fprintf(stderr, "Failed to send the datagram via the raw socket: %s\n",
strerror(errno));
free(datagram);
return 1;
}
printf("Sent %d bytes.\n", bytesSent);
return 0;
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 2008-2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Yin Qiu
*/
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define MAXLEN 4096
int
main(void)
{
int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sockfd < 0) {
fprintf(stderr, "Could not open raw socket: %s\n", strerror(errno));
return 1;
}
struct sockaddr_in source;
socklen_t addrLen = sizeof(source);
char buf[MAXLEN];
ssize_t nbytes;
while ((nbytes = recvfrom(sockfd, buf, MAXLEN, 0,
(struct sockaddr*)&source, &addrLen)) > 0) {
int ipLen, icmpLen;
char host[128];
if (!inet_ntop(AF_INET, &source.sin_addr, host, sizeof(host)))
strcpy(host, "<unknown host>");
printf("Received %zd bytes of ICMP message from %s\n", nbytes, host);
struct ip* ip = (struct ip*)buf;
ipLen = ip->ip_hl << 2;
if ((icmpLen = nbytes - ipLen) < 8) {
fprintf(stderr, "ICMP len (%d) < 8\n", icmpLen);
exit(1);
}
struct icmp* icmp = (struct icmp*)(buf + ipLen);
printf("Type: %u; Code: %u\n", icmp->icmp_type, icmp->icmp_code);
}
return 0;
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2008-2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Yin Qiu
*/
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
int sockfd, status;
struct sockaddr_in serverAddr;
if (argc != 3)
{
fprintf(stderr, "Usage: %s <ip-address> <port>\n", argv[0]);
exit(1);
}
memset(&serverAddr, 0, sizeof(struct sockaddr_in));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(atoi(argv[2]));
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ((status = connect(sockfd, (struct sockaddr*)&serverAddr,
sizeof(struct sockaddr_in))) < 0) {
int e = errno;
fprintf(stderr, "Connection failed. Status: %d\n", status);
fprintf(stderr, "Error: %s\n", strerror(e));
exit(1);
} else {
printf("Connected to remote server.\n");
close(sockfd);
printf("Socket closed.\n");
}
return 0;
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 2008-2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Yin Qiu
*/
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define MAXLEN 4096
int
main(int argc, char **argv)
{
int sockfd, status;
char *str = "Hello";
char buf[MAXLEN];
struct sockaddr_in serverAddr;
if (argc != 3) {
fprintf(stderr, "Usage: %s <ip-address> <port>\n", argv[0]);
exit(1);
}
memset(&serverAddr, 0, sizeof(struct sockaddr_in));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(atoi(argv[2]));
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// We need to call connect() to receive async ICMP errors
if (connect(sockfd, (struct sockaddr*)&serverAddr,
sizeof(struct sockaddr_in)) < 0) {
fprintf(stderr, "Calling connect() on UDP socket failed\n");
exit(1);
}
if ((status = write(sockfd, str, strlen(str))) < 0) {
int e = errno;
fprintf(stderr, "UDP send failed. Status: %d\n", status);
fprintf(stderr, "Error: %s\n", strerror(e));
exit(1);
} else {
printf("%d bytes sent to remote server.\n", status);
if ((status = read(sockfd, buf, MAXLEN)) > 0) {
printf("Received %d bytes from remote host\n", status);
printf("%s\n", buf);
} else {
// We are expecting this
int e = errno;
printf("Error: %s\n", strerror(e));
}
close(sockfd);
printf("Socket closed.\n");
}
return 0;
}