From 02e7b23f38e012d4a93460f85d0f950890f47097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 20 Jul 2010 21:20:36 +0000 Subject: [PATCH] * 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 --- src/tests/kits/net/Jamfile | 1 + src/tests/kits/net/icmp/Jamfile | 22 +++ src/tests/kits/net/icmp/big_datagram.cpp | 155 ++++++++++++++++++++ src/tests/kits/net/icmp/icmp_dumper.cpp | 60 ++++++++ src/tests/kits/net/icmp/tcp_unreachable.cpp | 48 ++++++ src/tests/kits/net/icmp/udp_unreachable.cpp | 65 ++++++++ 6 files changed, 351 insertions(+) create mode 100644 src/tests/kits/net/icmp/Jamfile create mode 100644 src/tests/kits/net/icmp/big_datagram.cpp create mode 100644 src/tests/kits/net/icmp/icmp_dumper.cpp create mode 100644 src/tests/kits/net/icmp/tcp_unreachable.cpp create mode 100644 src/tests/kits/net/icmp/udp_unreachable.cpp diff --git a/src/tests/kits/net/Jamfile b/src/tests/kits/net/Jamfile index 139ad1ccfd..5beb3a8641 100644 --- a/src/tests/kits/net/Jamfile +++ b/src/tests/kits/net/Jamfile @@ -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 ; diff --git a/src/tests/kits/net/icmp/Jamfile b/src/tests/kits/net/icmp/Jamfile new file mode 100644 index 0000000000..34ac958208 --- /dev/null +++ b/src/tests/kits/net/icmp/Jamfile @@ -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 +; + diff --git a/src/tests/kits/net/icmp/big_datagram.cpp b/src/tests/kits/net/icmp/big_datagram.cpp new file mode 100644 index 0000000000..4ed2420588 --- /dev/null +++ b/src/tests/kits/net/icmp/big_datagram.cpp @@ -0,0 +1,155 @@ +/* + * Copyright 2008-2010, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Yin Qiu + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 [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; +} + diff --git a/src/tests/kits/net/icmp/icmp_dumper.cpp b/src/tests/kits/net/icmp/icmp_dumper.cpp new file mode 100644 index 0000000000..c5870f038e --- /dev/null +++ b/src/tests/kits/net/icmp/icmp_dumper.cpp @@ -0,0 +1,60 @@ +/* + * Copyright 2008-2010, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Yin Qiu + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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, ""); + + 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; +} diff --git a/src/tests/kits/net/icmp/tcp_unreachable.cpp b/src/tests/kits/net/icmp/tcp_unreachable.cpp new file mode 100644 index 0000000000..9f196960d9 --- /dev/null +++ b/src/tests/kits/net/icmp/tcp_unreachable.cpp @@ -0,0 +1,48 @@ +/* + * Copyright 2008-2010, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Yin Qiu + */ + + +#include +#include +#include +#include +#include +#include +#include + + +int +main(int argc, char **argv) +{ + int sockfd, status; + struct sockaddr_in serverAddr; + + if (argc != 3) + { + fprintf(stderr, "Usage: %s \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; +} diff --git a/src/tests/kits/net/icmp/udp_unreachable.cpp b/src/tests/kits/net/icmp/udp_unreachable.cpp new file mode 100644 index 0000000000..4e7f5629a6 --- /dev/null +++ b/src/tests/kits/net/icmp/udp_unreachable.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2008-2010, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Yin Qiu + */ + + +#include +#include +#include +#include +#include +#include +#include + + +#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 \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; +}