* 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:
@@ -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 sock ;
|
||||||
SubInclude HAIKU_TOP src tests kits net tcp_shell ;
|
SubInclude HAIKU_TOP src tests kits net tcp_shell ;
|
||||||
SubInclude HAIKU_TOP src tests kits net tcptester ;
|
SubInclude HAIKU_TOP src tests kits net tcptester ;
|
||||||
|
SubInclude HAIKU_TOP src tests kits net icmp ;
|
||||||
|
|||||||
@@ -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
|
||||||
|
;
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user