1*6c731deeSkrw /* $OpenBSD: packet.c,v 1.14 2017/04/18 13:59:09 krw Exp $ */
2e853bc5dShenning
3e853bc5dShenning /* Packet assembly code, originally contributed by Archie Cobbs. */
4e853bc5dShenning
5e853bc5dShenning /*
6e853bc5dShenning * Copyright (c) 1995, 1996, 1999 The Internet Software Consortium.
7e853bc5dShenning * All rights reserved.
8e853bc5dShenning *
9e853bc5dShenning * Redistribution and use in source and binary forms, with or without
10e853bc5dShenning * modification, are permitted provided that the following conditions
11e853bc5dShenning * are met:
12e853bc5dShenning *
13e853bc5dShenning * 1. Redistributions of source code must retain the above copyright
14e853bc5dShenning * notice, this list of conditions and the following disclaimer.
15e853bc5dShenning * 2. Redistributions in binary form must reproduce the above copyright
16e853bc5dShenning * notice, this list of conditions and the following disclaimer in the
17e853bc5dShenning * documentation and/or other materials provided with the distribution.
18e853bc5dShenning * 3. Neither the name of The Internet Software Consortium nor the names
19e853bc5dShenning * of its contributors may be used to endorse or promote products derived
20e853bc5dShenning * from this software without specific prior written permission.
21e853bc5dShenning *
22e853bc5dShenning * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23e853bc5dShenning * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24e853bc5dShenning * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25e853bc5dShenning * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26e853bc5dShenning * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27e853bc5dShenning * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28e853bc5dShenning * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29e853bc5dShenning * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30e853bc5dShenning * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31e853bc5dShenning * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32e853bc5dShenning * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33e853bc5dShenning * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34e853bc5dShenning * SUCH DAMAGE.
35e853bc5dShenning *
36e853bc5dShenning * This software has been written for the Internet Software Consortium
37e853bc5dShenning * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38e853bc5dShenning * Enterprises. To learn more about the Internet Software Consortium,
39e853bc5dShenning * see ``http://www.vix.com/isc''. To learn more about Vixie
40e853bc5dShenning * Enterprises, see ``http://www.vix.com''.
41e853bc5dShenning */
42e853bc5dShenning
43837cddffSkrw #include <sys/types.h>
44837cddffSkrw #include <sys/socket.h>
45e853bc5dShenning
46837cddffSkrw #include <net/if.h>
47837cddffSkrw
48837cddffSkrw #include <netinet/in.h>
49e853bc5dShenning #include <netinet/ip.h>
50e853bc5dShenning #include <netinet/udp.h>
51e853bc5dShenning #include <netinet/if_ether.h>
52e853bc5dShenning
53837cddffSkrw #include <stdio.h>
54837cddffSkrw #include <string.h>
55837cddffSkrw
56837cddffSkrw #include "dhcp.h"
57837cddffSkrw #include "tree.h"
58837cddffSkrw #include "dhcpd.h"
59c525a185Skrw #include "log.h"
60837cddffSkrw
61e853bc5dShenning u_int32_t
checksum(unsigned char * buf,u_int32_t nbytes,u_int32_t sum)62db2d7c0aSkrw checksum(unsigned char *buf, u_int32_t nbytes, u_int32_t sum)
63e853bc5dShenning {
64db2d7c0aSkrw unsigned int i;
65e853bc5dShenning
66e853bc5dShenning /* Checksum all the pairs of bytes first... */
67e853bc5dShenning for (i = 0; i < (nbytes & ~1U); i += 2) {
68e853bc5dShenning sum += (u_int16_t)ntohs(*((u_int16_t *)(buf + i)));
69e853bc5dShenning if (sum > 0xFFFF)
70e853bc5dShenning sum -= 0xFFFF;
71e853bc5dShenning }
72e853bc5dShenning
73e853bc5dShenning /*
74e853bc5dShenning * If there's a single byte left over, checksum it, too.
75e853bc5dShenning * Network byte order is big-endian, so the remaining byte is
76e853bc5dShenning * the high byte.
77e853bc5dShenning */
78e853bc5dShenning if (i < nbytes) {
79e853bc5dShenning sum += buf[i] << 8;
80e853bc5dShenning if (sum > 0xFFFF)
81e853bc5dShenning sum -= 0xFFFF;
82e853bc5dShenning }
83e853bc5dShenning
84e853bc5dShenning return (sum);
85e853bc5dShenning }
86e853bc5dShenning
87e853bc5dShenning u_int32_t
wrapsum(u_int32_t sum)88e853bc5dShenning wrapsum(u_int32_t sum)
89e853bc5dShenning {
90e853bc5dShenning sum = ~sum & 0xFFFF;
91e853bc5dShenning return (htons(sum));
92e853bc5dShenning }
93e853bc5dShenning
94e853bc5dShenning void
assemble_hw_header(struct interface_info * interface,unsigned char * buf,int * bufix,struct hardware * to)95e853bc5dShenning assemble_hw_header(struct interface_info *interface, unsigned char *buf,
96e853bc5dShenning int *bufix, struct hardware *to)
97e853bc5dShenning {
98e853bc5dShenning struct ether_header eh;
99e853bc5dShenning
100e853bc5dShenning if (to != NULL && to->hlen == 6) /* XXX */
101e853bc5dShenning memcpy(eh.ether_dhost, to->haddr, sizeof(eh.ether_dhost));
102e853bc5dShenning else
103e853bc5dShenning memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
104390956b7Scanacar
105390956b7Scanacar /* source address is filled in by the kernel */
106e853bc5dShenning memset(eh.ether_shost, 0x00, sizeof(eh.ether_shost));
107e853bc5dShenning
108e853bc5dShenning eh.ether_type = htons(ETHERTYPE_IP);
109e853bc5dShenning
1103aa1ef9aSkrw memcpy(&buf[*bufix], &eh, ETHER_HDR_LEN);
1113aa1ef9aSkrw *bufix += ETHER_HDR_LEN;
112e853bc5dShenning }
113e853bc5dShenning
114e853bc5dShenning void
assemble_udp_ip_header(struct interface_info * interface,unsigned char * buf,int * bufix,u_int32_t from,u_int32_t to,unsigned int port,unsigned char * data,int len)115e853bc5dShenning assemble_udp_ip_header(struct interface_info *interface, unsigned char *buf,
116e853bc5dShenning int *bufix, u_int32_t from, u_int32_t to, unsigned int port,
117e853bc5dShenning unsigned char *data, int len)
118e853bc5dShenning {
119e853bc5dShenning struct ip ip;
120e853bc5dShenning struct udphdr udp;
121e853bc5dShenning
122e853bc5dShenning ip.ip_v = 4;
123e853bc5dShenning ip.ip_hl = 5;
124e853bc5dShenning ip.ip_tos = IPTOS_LOWDELAY;
125e853bc5dShenning ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len);
126e853bc5dShenning ip.ip_id = 0;
127e853bc5dShenning ip.ip_off = 0;
128e853bc5dShenning ip.ip_ttl = 16;
129e853bc5dShenning ip.ip_p = IPPROTO_UDP;
130e853bc5dShenning ip.ip_sum = 0;
131e853bc5dShenning ip.ip_src.s_addr = from;
132e853bc5dShenning ip.ip_dst.s_addr = to;
133e853bc5dShenning
134e853bc5dShenning ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0));
135e853bc5dShenning memcpy(&buf[*bufix], &ip, sizeof(ip));
136e853bc5dShenning *bufix += sizeof(ip);
137e853bc5dShenning
138390956b7Scanacar udp.uh_sport = server_port; /* XXX */
139e853bc5dShenning udp.uh_dport = port; /* XXX */
140e853bc5dShenning udp.uh_ulen = htons(sizeof(udp) + len);
141e853bc5dShenning memset(&udp.uh_sum, 0, sizeof(udp.uh_sum));
142e853bc5dShenning
143e853bc5dShenning udp.uh_sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp),
144e853bc5dShenning checksum(data, len, checksum((unsigned char *)&ip.ip_src,
145e853bc5dShenning 2 * sizeof(ip.ip_src),
146e853bc5dShenning IPPROTO_UDP + (u_int32_t)ntohs(udp.uh_ulen)))));
147e853bc5dShenning
148e853bc5dShenning memcpy(&buf[*bufix], &udp, sizeof(udp));
149e853bc5dShenning *bufix += sizeof(udp);
150e853bc5dShenning }
151e853bc5dShenning
152e853bc5dShenning ssize_t
decode_hw_header(unsigned char * buf,u_int32_t buflen,struct hardware * from)153*6c731deeSkrw decode_hw_header(unsigned char *buf, u_int32_t buflen, struct hardware *from)
154e853bc5dShenning {
155e853bc5dShenning struct ether_header eh;
156e853bc5dShenning
157*6c731deeSkrw if (buflen < sizeof(eh))
158*6c731deeSkrw return (-1);
159*6c731deeSkrw
160*6c731deeSkrw memcpy(&eh, buf, sizeof(eh));
161e853bc5dShenning
162e853bc5dShenning memcpy(from->haddr, eh.ether_shost, sizeof(eh.ether_shost));
163e853bc5dShenning from->htype = ARPHRD_ETHER;
164e853bc5dShenning from->hlen = sizeof(eh.ether_shost);
165e853bc5dShenning
166e853bc5dShenning return (sizeof(eh));
167e853bc5dShenning }
168e853bc5dShenning
169e853bc5dShenning ssize_t
decode_udp_ip_header(unsigned char * buf,u_int32_t buflen,struct sockaddr_in * from)170*6c731deeSkrw decode_udp_ip_header(unsigned char *buf, u_int32_t buflen,
171*6c731deeSkrw struct sockaddr_in *from)
172e853bc5dShenning {
173e853bc5dShenning struct ip *ip;
174e853bc5dShenning struct udphdr *udp;
1759c0483d2Skrw unsigned char *data;
176b4e2b639Skrw u_int32_t ip_len;
177e853bc5dShenning u_int32_t sum, usum;
178c5b8c7f3Stobias static unsigned int ip_packets_seen;
179c5b8c7f3Stobias static unsigned int ip_packets_bad_checksum;
180c5b8c7f3Stobias static unsigned int udp_packets_seen;
181c5b8c7f3Stobias static unsigned int udp_packets_bad_checksum;
182c5b8c7f3Stobias static unsigned int udp_packets_length_checked;
183c5b8c7f3Stobias static unsigned int udp_packets_length_overflow;
1849c0483d2Skrw int len;
185e853bc5dShenning
186b4e2b639Skrw /* Assure that an entire IP header is within the buffer. */
187b4e2b639Skrw if (sizeof(*ip) > buflen)
188b4e2b639Skrw return (-1);
189*6c731deeSkrw ip_len = (*buf & 0xf) << 2;
190b4e2b639Skrw if (ip_len > buflen)
191b4e2b639Skrw return (-1);
192b4e2b639Skrw
193*6c731deeSkrw ip = (struct ip *)buf;
194b4e2b639Skrw ip_packets_seen++;
195e853bc5dShenning
196e853bc5dShenning /* Check the IP header checksum - it should be zero. */
197*6c731deeSkrw if (wrapsum(checksum((unsigned char *)ip, ip_len, 0)) != 0) {
198e853bc5dShenning ip_packets_bad_checksum++;
1995066e155Stobias if (ip_packets_seen > 4 && ip_packets_bad_checksum != 0 &&
200e853bc5dShenning (ip_packets_seen / ip_packets_bad_checksum) < 2) {
201c525a185Skrw log_info("%u bad IP checksums seen in %u packets",
202e853bc5dShenning ip_packets_bad_checksum, ip_packets_seen);
203e853bc5dShenning ip_packets_seen = ip_packets_bad_checksum = 0;
204e853bc5dShenning }
205e853bc5dShenning return (-1);
206e853bc5dShenning }
207e853bc5dShenning
208b4e2b639Skrw memcpy(&from->sin_addr, &ip->ip_src, sizeof(from->sin_addr));
209b4e2b639Skrw
210b4e2b639Skrw #ifdef DEBUG
211e853bc5dShenning if (ntohs(ip->ip_len) != buflen)
212c525a185Skrw log_debug("ip length %d disagrees with bytes received %d.",
213e853bc5dShenning ntohs(ip->ip_len), buflen);
214b4e2b639Skrw #endif
215e853bc5dShenning
216b4e2b639Skrw
217b4e2b639Skrw /* Assure that the entire IP packet is within the buffer. */
218b4e2b639Skrw if (ntohs(ip->ip_len) > buflen)
219b4e2b639Skrw return (-1);
220b4e2b639Skrw
221b4e2b639Skrw /* Assure that the UDP header is within the buffer. */
222b4e2b639Skrw if (ip_len + sizeof(*udp) > buflen)
223b4e2b639Skrw return (-1);
224*6c731deeSkrw udp = (struct udphdr *)(buf + ip_len);
225b4e2b639Skrw udp_packets_seen++;
226b4e2b639Skrw
227b4e2b639Skrw /* Assure that the entire UDP packet is within the buffer. */
228b4e2b639Skrw if (ip_len + ntohs(udp->uh_ulen) > buflen)
229b4e2b639Skrw return (-1);
230*6c731deeSkrw data = buf + ip_len + sizeof(*udp);
231e853bc5dShenning
232e853bc5dShenning /*
233e853bc5dShenning * Compute UDP checksums, including the ``pseudo-header'', the
234e853bc5dShenning * UDP header and the data. If the UDP checksum field is zero,
235e853bc5dShenning * we're not supposed to do a checksum.
236e853bc5dShenning */
237e853bc5dShenning udp_packets_length_checked++;
238b4e2b639Skrw len = ntohs(udp->uh_ulen) - sizeof(*udp);
239*6c731deeSkrw if ((len < 0) || (len + data > buf + buflen)) {
240e853bc5dShenning udp_packets_length_overflow++;
241e853bc5dShenning if (udp_packets_length_checked > 4 &&
2425066e155Stobias udp_packets_length_overflow != 0 &&
243e853bc5dShenning (udp_packets_length_checked /
244e853bc5dShenning udp_packets_length_overflow) < 2) {
245c525a185Skrw log_info("%u udp packets in %u too long - dropped",
246e853bc5dShenning udp_packets_length_overflow,
247e853bc5dShenning udp_packets_length_checked);
248e853bc5dShenning udp_packets_length_overflow =
249e853bc5dShenning udp_packets_length_checked = 0;
250e853bc5dShenning }
251e853bc5dShenning return (-1);
252e853bc5dShenning }
253*6c731deeSkrw if (len + data != buf + buflen)
254c525a185Skrw log_debug("accepting packet with data after udp payload.");
255e853bc5dShenning
256e853bc5dShenning usum = udp->uh_sum;
257e853bc5dShenning udp->uh_sum = 0;
258e853bc5dShenning
259e853bc5dShenning sum = wrapsum(checksum((unsigned char *)udp, sizeof(*udp),
260e853bc5dShenning checksum(data, len, checksum((unsigned char *)&ip->ip_src,
261e853bc5dShenning 2 * sizeof(ip->ip_src),
262e853bc5dShenning IPPROTO_UDP + (u_int32_t)ntohs(udp->uh_ulen)))));
263e853bc5dShenning
264e853bc5dShenning udp_packets_seen++;
265e853bc5dShenning if (usum && usum != sum) {
266e853bc5dShenning udp_packets_bad_checksum++;
2675066e155Stobias if (udp_packets_seen > 4 && udp_packets_bad_checksum != 0 &&
268e853bc5dShenning (udp_packets_seen / udp_packets_bad_checksum) < 2) {
269c525a185Skrw log_info("%u bad udp checksums in %u packets",
270e853bc5dShenning udp_packets_bad_checksum, udp_packets_seen);
271e853bc5dShenning udp_packets_seen = udp_packets_bad_checksum = 0;
272e853bc5dShenning }
273e853bc5dShenning return (-1);
274e853bc5dShenning }
275e853bc5dShenning
276e853bc5dShenning memcpy(&from->sin_port, &udp->uh_sport, sizeof(udp->uh_sport));
277e853bc5dShenning
278e853bc5dShenning return (ip_len + sizeof(*udp));
279e853bc5dShenning }
280