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