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 25struct 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 34static u_int16_t 35cksum(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 46static struct addrinfo* 47host_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 63int 64main(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