1 /* udp.c - UDP code for sendip
2  * Author: Mike Ricketts <mike@earth.li>
3  * ChangeLog since 2.0 release:
4  * ChangeLog since 2.1 release:
5  * 16/04/2002: Only check one layer of enclosing headers for ip
6  * 16/04/2002: Add support for UDP over IPV6
7  * ChangeLog since 2.4 release:
8  * 21/04/2003: Fix errors found by valgrind
9  */
10 
11 #include <sys/types.h>
12 #include <stdlib.h>
13 #include <netinet/in.h>
14 #include <string.h>
15 #include "sendip_module.h"
16 #include "udp.h"
17 #include "ipv4.h"
18 #include "ipv6.h"
19 
20 /* Character that identifies our options
21  */
22 const char opt_char='u';
23 
udpcsum(sendip_data * ip_hdr,sendip_data * udp_hdr,sendip_data * data)24 static void udpcsum(sendip_data *ip_hdr, sendip_data *udp_hdr,
25 						  sendip_data *data) {
26 	udp_header *udp = (udp_header *)udp_hdr->data;
27 	ip_header  *ip  = (ip_header *)ip_hdr->data;
28 	u_int16_t *buf = malloc(12+udp_hdr->alloc_len+data->alloc_len);
29 	u_int8_t *tempbuf = (u_int8_t *)buf;
30 	udp->check=0;
31 	if(tempbuf == NULL) {
32 		fprintf(stderr,"Out of memory: UDP checksum not computed\n");
33 		return;
34 	}
35 	/* Set up the pseudo header */
36 	memcpy(tempbuf,&(ip->saddr),sizeof(u_int32_t));
37 	memcpy(&(tempbuf[4]),&(ip->daddr),sizeof(u_int32_t));
38 	tempbuf[8]=0;
39 	tempbuf[9]=(u_int16_t)ip->protocol;
40 	tempbuf[10]=(u_int16_t)((udp_hdr->alloc_len+data->alloc_len)&0xFF00)>>8;
41 	tempbuf[11]=(u_int16_t)((udp_hdr->alloc_len+data->alloc_len)&0x00FF);
42 	/* Copy the UDP header and data */
43 	memcpy(tempbuf+12,udp_hdr->data,udp_hdr->alloc_len);
44 	memcpy(tempbuf+12+udp_hdr->alloc_len,data->data,data->alloc_len);
45 	/* CheckSum it */
46 	udp->check = csum(buf,12+udp_hdr->alloc_len+data->alloc_len);
47 	free(buf);
48 }
49 
udp6csum(sendip_data * ipv6_hdr,sendip_data * udp_hdr,sendip_data * data)50 static void udp6csum(sendip_data *ipv6_hdr, sendip_data *udp_hdr,
51 							sendip_data *data) {
52 	udp_header *udp = (udp_header *)udp_hdr->data;
53 	ipv6_header  *ipv6  = (ipv6_header *)ipv6_hdr->data;
54 	struct ipv6_pseudo_hdr phdr;
55 
56 	u_int16_t *buf = malloc(sizeof(phdr)+udp_hdr->alloc_len+data->alloc_len);
57 	u_int8_t *tempbuf = (u_int8_t *)buf;
58 	udp->check=0;
59 	if(tempbuf == NULL) {
60 		fprintf(stderr,"Out of memory: UDP checksum not computed\n");
61 		return;
62 	}
63 
64 	/* Set up the pseudo header */
65 	memset(&phdr,0,sizeof(phdr));
66 	memcpy(&phdr.source,&ipv6->ip6_src,sizeof(struct in6_addr));
67 	memcpy(&phdr.destination,&ipv6->ip6_dst,sizeof(struct in6_addr));
68 	phdr.ulp_length=IPPROTO_UDP;
69 
70 	memcpy(tempbuf,&phdr,sizeof(phdr));
71 
72 	/* Copy the UDP header and data */
73 	memcpy(tempbuf+sizeof(phdr),udp_hdr->data,udp_hdr->alloc_len);
74 	memcpy(tempbuf+sizeof(phdr)+udp_hdr->alloc_len,data->data,data->alloc_len);
75 
76 	/* CheckSum it */
77 	udp->check = csum(buf,sizeof(phdr)+udp_hdr->alloc_len+data->alloc_len);
78 	free(buf);
79 }
80 
initialize(void)81 sendip_data *initialize(void) {
82 	sendip_data *ret = malloc(sizeof(sendip_data));
83 	udp_header *udp = malloc(sizeof(udp_header));
84 	memset(udp,0,sizeof(udp_header));
85 	ret->alloc_len = sizeof(udp_header);
86 	ret->data = (void *)udp;
87 	ret->modified=0;
88 	return ret;
89 }
90 
do_opt(char * opt,char * arg,sendip_data * pack)91 bool do_opt(char *opt, char *arg, sendip_data *pack) {
92 	udp_header *udp = (udp_header *)pack->data;
93 	switch(opt[1]) {
94 	case 's':
95 		udp->source = htons((u_int16_t)strtoul(arg, (char **)NULL, 0));
96 		pack->modified |= UDP_MOD_SOURCE;
97 		break;
98 	case 'd':
99 		udp->dest = htons((u_int16_t)strtoul(arg, (char **)NULL, 0));
100 		pack->modified |= UDP_MOD_DEST;
101 		break;
102 	case 'l':
103 		udp->len = htons((u_int16_t)strtoul(arg, (char **)NULL, 0));
104 		pack->modified |= UDP_MOD_LEN;
105 		break;
106 	case 'c':
107 		udp->check = htons((u_int16_t)strtoul(arg, (char **)NULL, 0));
108 		pack->modified |= UDP_MOD_CHECK;
109 		break;
110 	}
111 	return TRUE;
112 
113 }
114 
finalize(char * hdrs,sendip_data * headers[],sendip_data * data,sendip_data * pack)115 bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data,
116 				  sendip_data *pack) {
117 	udp_header *udp = (udp_header *)pack->data;
118 
119 	/* Set relevant fields */
120 	if(!(pack->modified&UDP_MOD_LEN)) {
121 		udp->len=htons(pack->alloc_len+data->alloc_len);
122 	}
123 
124 	/* Find enclosing IP header and do the checksum */
125 	if(hdrs[strlen(hdrs)-1]=='i') {
126 		int i = strlen(hdrs)-1;
127 		if(!(headers[i]->modified&IP_MOD_PROTOCOL)) {
128 			((ip_header *)(headers[i]->data))->protocol=IPPROTO_UDP;
129 			headers[i]->modified |= IP_MOD_PROTOCOL;
130 		}
131 		if(!(pack->modified&UDP_MOD_CHECK)) {
132 			udpcsum(headers[i],pack,data);
133 		}
134 	} else if(hdrs[strlen(hdrs)-1]=='6') {
135 		int i = strlen(hdrs)-1;
136 		if(!(headers[i]->modified&IPV6_MOD_NXT)) {
137 			((ipv6_header *)(headers[i]->data))->ip6_nxt=IPPROTO_UDP;
138 			headers[i]->modified |= IPV6_MOD_NXT;
139 		}
140 		if(!(pack->modified&UDP_MOD_CHECK)) {
141 			udp6csum(headers[i],pack,data);
142 		}
143 
144 	} else {
145 		if(!(pack->modified&UDP_MOD_CHECK)) {
146 			usage_error("UDP checksum not defined when UDP is not embedded in IP\n");
147 			return FALSE;
148 		}
149 	}
150 
151 	return TRUE;
152 }
153 
num_opts()154 int num_opts() {
155 	return sizeof(udp_opts)/sizeof(sendip_option);
156 }
get_opts()157 sendip_option *get_opts() {
158 	return udp_opts;
159 }
get_optchar()160 char get_optchar() {
161 	return opt_char;
162 }
163