xref: /haiku/src/tests/system/network/icmp/big_datagram.cpp (revision 5e54f6d4f9dd607ae2afcea4fe72f2f1763e4b5e)
1 /*
2  * Copyright 2008-2010, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Yin Qiu
7  */
8 
9 
10 #include <errno.h>
11 #include <netdb.h>
12 #include <netinet/in.h>
13 #include <netinet/ip.h>
14 #include <netinet/udp.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/socket.h>
19 #include <sys/types.h>
20 
21 
22 #define DGRM_SIZE 1600 // ought to be large enough
23 
24 
25 struct pseudo_header {
26 	struct in_addr src;
27 	struct in_addr dst;
28 	u_int8_t zero;
29 	u_int8_t protocol;
30 	u_int16_t len;
31 };
32 
33 
34 static u_int16_t
cksum(u_int16_t * buf,int nwords)35 cksum(u_int16_t* buf, int nwords)
36 {
37 	u_int32_t sum;
38 	for (sum = 0; nwords > 0; nwords--)
39 		sum += *(buf++);
40 	sum = (sum >> 16) + (sum & 0xffff);
41 	sum += (sum >> 16);
42 	return ~sum;
43 }
44 
45 
46 static struct addrinfo*
host_serv(const char * host,const char * serv,int family,int socktype)47 host_serv(const char* host, const char* serv, int family, int socktype)
48 {
49 	struct addrinfo hints, *res;
50 	memset(&hints, 0, sizeof(struct addrinfo));
51 	hints.ai_flags = AI_CANONNAME;
52 	hints.ai_family = family;
53 	hints.ai_socktype = socktype;
54 
55 	int n = getaddrinfo(host, serv, &hints, &res);
56 	if (n != 0)
57 		return NULL;
58 
59 	return res;
60 }
61 
62 
63 int
main(int argc,char ** argv)64 main(int argc, char** argv)
65 {
66 	if (argc < 3) {
67 		printf("Usage: %s <ip-address> <port> [nbytes]\n", argv[0]);
68 		return 1;
69 	}
70 
71 	size_t size;
72 	if (argc == 3)
73 		size = DGRM_SIZE;
74 	else
75 		size = atoi(argv[3]);
76 
77 	if (size - sizeof(struct ip) - sizeof(struct udphdr) < 0) {
78 		fprintf(stderr, "Datagram size is too small\n");
79 		return 1;
80 	}
81 
82 	struct addrinfo* ai = host_serv(argv[1], NULL, 0, 0);
83 	if (ai == NULL) {
84 		fprintf(stderr, "Cannot resolve %s\n", argv[1]);
85 		return 1;
86 	}
87 
88 	printf("Using datagram size %zu\n", size);
89 
90 	char* datagram = (char*)malloc(size);
91 	if (datagram == NULL) {
92 		fprintf(stderr, "Out of memory.\n");
93 		return 1;
94 	}
95 
96 	memset(datagram, 0, size);
97 
98 	struct ip* iph = (struct ip*)datagram;
99 	iph->ip_hl = 4;
100 	iph->ip_v = 4;
101 	iph->ip_tos = 0;
102 	iph->ip_len = htons(size);
103 	iph->ip_id = htonl(54321);
104 	iph->ip_off = 0;
105 	iph->ip_ttl = 255;
106 	iph->ip_p = IPPROTO_ICMP;
107 	iph->ip_sum = 0;
108 	iph->ip_src.s_addr = INADDR_ANY;
109 	iph->ip_dst.s_addr = ((struct sockaddr_in*)ai->ai_addr)->sin_addr.s_addr;
110 	// Calculates IP checksum
111 	iph->ip_sum = cksum((unsigned short*)datagram, iph->ip_len >> 1);
112 
113 	struct pseudo_header pHeader; // used to calculate udp checksum
114 
115 	struct udphdr* udp = (struct udphdr*)(datagram + sizeof(struct ip));
116 	udp->uh_sport = 0;
117 	udp->uh_dport = htons(atoi(argv[2]));
118 	udp->uh_ulen = htons(size - sizeof(struct ip));
119 	pHeader.src = iph->ip_src;
120 	pHeader.dst = iph->ip_dst;
121 	pHeader.zero = 0;
122 	pHeader.protocol = iph->ip_p;
123 	pHeader.len = udp->uh_ulen;
124 	udp->uh_sum = cksum((u_int16_t*)&pHeader, 3);
125 
126 	// Send it via a raw socket
127 	int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
128 	if (sockfd < 0) {
129 		fprintf(stderr, "Failed to create raw socket: %s\n", strerror(errno));
130 		free(datagram);
131 		return 1;
132 	}
133 
134 	int one = 1;
135 	const int* val = &one;
136 	if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, val, sizeof(int)) != 0) {
137 		fprintf(stderr, "Failed to set IP_HDRINCL on socket: %s\n",
138 			strerror(errno));
139 		free(datagram);
140 		return 1;
141 	}
142 
143 	int bytesSent = sendto(sockfd, datagram, size, 0, ai->ai_addr,
144 		ai->ai_addrlen);
145 	if (bytesSent < 0) {
146 		fprintf(stderr, "Failed to send the datagram via the raw socket: %s\n",
147 			strerror(errno));
148 		free(datagram);
149 		return 1;
150 	}
151 
152 	printf("Sent %d bytes.\n", bytesSent);
153 	return 0;
154 }
155 
156