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