1*9cbab583Srzalamena /* $OpenBSD: packet.c,v 1.1 2017/03/17 14:45:16 rzalamena Exp $ */
2*9cbab583Srzalamena
3*9cbab583Srzalamena /* Packet assembly code, originally contributed by Archie Cobbs. */
4*9cbab583Srzalamena
5*9cbab583Srzalamena /*
6*9cbab583Srzalamena * Copyright (c) 1995, 1996, 1999 The Internet Software Consortium.
7*9cbab583Srzalamena * All rights reserved.
8*9cbab583Srzalamena *
9*9cbab583Srzalamena * Redistribution and use in source and binary forms, with or without
10*9cbab583Srzalamena * modification, are permitted provided that the following conditions
11*9cbab583Srzalamena * are met:
12*9cbab583Srzalamena *
13*9cbab583Srzalamena * 1. Redistributions of source code must retain the above copyright
14*9cbab583Srzalamena * notice, this list of conditions and the following disclaimer.
15*9cbab583Srzalamena * 2. Redistributions in binary form must reproduce the above copyright
16*9cbab583Srzalamena * notice, this list of conditions and the following disclaimer in the
17*9cbab583Srzalamena * documentation and/or other materials provided with the distribution.
18*9cbab583Srzalamena * 3. Neither the name of The Internet Software Consortium nor the names
19*9cbab583Srzalamena * of its contributors may be used to endorse or promote products derived
20*9cbab583Srzalamena * from this software without specific prior written permission.
21*9cbab583Srzalamena *
22*9cbab583Srzalamena * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23*9cbab583Srzalamena * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24*9cbab583Srzalamena * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25*9cbab583Srzalamena * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26*9cbab583Srzalamena * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27*9cbab583Srzalamena * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28*9cbab583Srzalamena * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29*9cbab583Srzalamena * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30*9cbab583Srzalamena * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31*9cbab583Srzalamena * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32*9cbab583Srzalamena * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33*9cbab583Srzalamena * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34*9cbab583Srzalamena * SUCH DAMAGE.
35*9cbab583Srzalamena *
36*9cbab583Srzalamena * This software has been written for the Internet Software Consortium
37*9cbab583Srzalamena * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38*9cbab583Srzalamena * Enterprises. To learn more about the Internet Software Consortium,
39*9cbab583Srzalamena * see ``http://www.vix.com/isc''. To learn more about Vixie
40*9cbab583Srzalamena * Enterprises, see ``http://www.vix.com''.
41*9cbab583Srzalamena */
42*9cbab583Srzalamena
43*9cbab583Srzalamena #include <sys/types.h>
44*9cbab583Srzalamena #include <sys/socket.h>
45*9cbab583Srzalamena
46*9cbab583Srzalamena #include <arpa/inet.h>
47*9cbab583Srzalamena
48*9cbab583Srzalamena #include <net/if.h>
49*9cbab583Srzalamena
50*9cbab583Srzalamena #include <netinet/in.h>
51*9cbab583Srzalamena #include <netinet/ip.h>
52*9cbab583Srzalamena #include <netinet/ip6.h>
53*9cbab583Srzalamena #include <netinet/udp.h>
54*9cbab583Srzalamena #include <netinet/if_ether.h>
55*9cbab583Srzalamena
56*9cbab583Srzalamena #include <string.h>
57*9cbab583Srzalamena
58*9cbab583Srzalamena #include "dhcp.h"
59*9cbab583Srzalamena #include "dhcpd.h"
60*9cbab583Srzalamena #include "log.h"
61*9cbab583Srzalamena
62*9cbab583Srzalamena
63*9cbab583Srzalamena u_int32_t checksum(unsigned char *, unsigned, u_int32_t);
64*9cbab583Srzalamena u_int32_t wrapsum(u_int32_t);
65*9cbab583Srzalamena
66*9cbab583Srzalamena u_int32_t
checksum(unsigned char * buf,unsigned nbytes,u_int32_t sum)67*9cbab583Srzalamena checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum)
68*9cbab583Srzalamena {
69*9cbab583Srzalamena unsigned int i;
70*9cbab583Srzalamena
71*9cbab583Srzalamena /* Checksum all the pairs of bytes first... */
72*9cbab583Srzalamena for (i = 0; i < (nbytes & ~1U); i += 2) {
73*9cbab583Srzalamena sum += (u_int16_t)ntohs(*((u_int16_t *)(buf + i)));
74*9cbab583Srzalamena if (sum > 0xFFFF)
75*9cbab583Srzalamena sum -= 0xFFFF;
76*9cbab583Srzalamena }
77*9cbab583Srzalamena
78*9cbab583Srzalamena /*
79*9cbab583Srzalamena * If there's a single byte left over, checksum it, too.
80*9cbab583Srzalamena * Network byte order is big-endian, so the remaining byte is
81*9cbab583Srzalamena * the high byte.
82*9cbab583Srzalamena */
83*9cbab583Srzalamena if (i < nbytes) {
84*9cbab583Srzalamena sum += buf[i] << 8;
85*9cbab583Srzalamena if (sum > 0xFFFF)
86*9cbab583Srzalamena sum -= 0xFFFF;
87*9cbab583Srzalamena }
88*9cbab583Srzalamena
89*9cbab583Srzalamena return (sum);
90*9cbab583Srzalamena }
91*9cbab583Srzalamena
92*9cbab583Srzalamena u_int32_t
wrapsum(u_int32_t sum)93*9cbab583Srzalamena wrapsum(u_int32_t sum)
94*9cbab583Srzalamena {
95*9cbab583Srzalamena sum = ~sum & 0xFFFF;
96*9cbab583Srzalamena return (htons(sum));
97*9cbab583Srzalamena }
98*9cbab583Srzalamena
99*9cbab583Srzalamena void
assemble_hw_header(unsigned char * buf,int * bufix,struct packet_ctx * pc)100*9cbab583Srzalamena assemble_hw_header(unsigned char *buf, int *bufix, struct packet_ctx *pc)
101*9cbab583Srzalamena {
102*9cbab583Srzalamena struct ether_header eh;
103*9cbab583Srzalamena
104*9cbab583Srzalamena memcpy(eh.ether_shost, pc->pc_smac, ETHER_ADDR_LEN);
105*9cbab583Srzalamena memcpy(eh.ether_dhost, pc->pc_dmac, ETHER_ADDR_LEN);
106*9cbab583Srzalamena eh.ether_type = htons(pc->pc_ethertype);
107*9cbab583Srzalamena
108*9cbab583Srzalamena memcpy(&buf[*bufix], &eh, ETHER_HDR_LEN);
109*9cbab583Srzalamena *bufix += ETHER_HDR_LEN;
110*9cbab583Srzalamena }
111*9cbab583Srzalamena
112*9cbab583Srzalamena void
assemble_udp_ip6_header(unsigned char * p,int * off,struct packet_ctx * pc,unsigned char * payload,int plen)113*9cbab583Srzalamena assemble_udp_ip6_header(unsigned char *p, int *off, struct packet_ctx *pc,
114*9cbab583Srzalamena unsigned char *payload, int plen)
115*9cbab583Srzalamena {
116*9cbab583Srzalamena struct ip6_hdr ip6;
117*9cbab583Srzalamena struct udphdr uh;
118*9cbab583Srzalamena
119*9cbab583Srzalamena memset(&ip6, 0, sizeof(ip6));
120*9cbab583Srzalamena ip6.ip6_vfc = IPV6_VERSION;
121*9cbab583Srzalamena ip6.ip6_nxt = IPPROTO_UDP;
122*9cbab583Srzalamena ip6.ip6_src = ss2sin6(&pc->pc_src)->sin6_addr;
123*9cbab583Srzalamena ip6.ip6_dst = ss2sin6(&pc->pc_dst)->sin6_addr;
124*9cbab583Srzalamena ip6.ip6_plen = htons(sizeof(uh) + plen);
125*9cbab583Srzalamena ip6.ip6_hlim = 64;
126*9cbab583Srzalamena memcpy(&p[*off], &ip6, sizeof(ip6));
127*9cbab583Srzalamena *off += sizeof(ip6);
128*9cbab583Srzalamena
129*9cbab583Srzalamena memset(&uh, 0, sizeof(uh));
130*9cbab583Srzalamena uh.uh_ulen = ip6.ip6_plen;
131*9cbab583Srzalamena uh.uh_sport = ss2sin6(&pc->pc_src)->sin6_port;
132*9cbab583Srzalamena uh.uh_dport = ss2sin6(&pc->pc_dst)->sin6_port;
133*9cbab583Srzalamena uh.uh_sum = wrapsum(
134*9cbab583Srzalamena checksum((unsigned char *)&uh, sizeof(uh),
135*9cbab583Srzalamena checksum(payload, plen,
136*9cbab583Srzalamena checksum((unsigned char *)&ip6.ip6_src, sizeof(ip6.ip6_src),
137*9cbab583Srzalamena checksum((unsigned char *)&ip6.ip6_dst, sizeof(ip6.ip6_dst),
138*9cbab583Srzalamena IPPROTO_UDP + ntohs(ip6.ip6_plen)
139*9cbab583Srzalamena ))))
140*9cbab583Srzalamena );
141*9cbab583Srzalamena memcpy(&p[*off], &uh, sizeof(uh));
142*9cbab583Srzalamena *off += sizeof(uh);
143*9cbab583Srzalamena }
144*9cbab583Srzalamena
145*9cbab583Srzalamena ssize_t
decode_hw_header(unsigned char * buf,int bufix,struct packet_ctx * pc)146*9cbab583Srzalamena decode_hw_header(unsigned char *buf, int bufix, struct packet_ctx *pc)
147*9cbab583Srzalamena {
148*9cbab583Srzalamena struct ether_header *ether;
149*9cbab583Srzalamena
150*9cbab583Srzalamena ether = (struct ether_header *)(buf + bufix);
151*9cbab583Srzalamena memcpy(pc->pc_dmac, ether->ether_dhost, ETHER_ADDR_LEN);
152*9cbab583Srzalamena memcpy(pc->pc_smac, ether->ether_shost, ETHER_ADDR_LEN);
153*9cbab583Srzalamena pc->pc_ethertype = ntohs(ether->ether_type);
154*9cbab583Srzalamena
155*9cbab583Srzalamena pc->pc_htype = ARPHRD_ETHER;
156*9cbab583Srzalamena pc->pc_hlen = ETHER_ADDR_LEN;
157*9cbab583Srzalamena
158*9cbab583Srzalamena return sizeof(struct ether_header);
159*9cbab583Srzalamena }
160*9cbab583Srzalamena
161*9cbab583Srzalamena ssize_t
decode_udp_ip6_header(unsigned char * p,int off,struct packet_ctx * pc,size_t plen)162*9cbab583Srzalamena decode_udp_ip6_header(unsigned char *p, int off, struct packet_ctx *pc,
163*9cbab583Srzalamena size_t plen)
164*9cbab583Srzalamena {
165*9cbab583Srzalamena struct ip6_hdr *ip6;
166*9cbab583Srzalamena struct udphdr *uh;
167*9cbab583Srzalamena struct in6_addr *asrc, *adst;
168*9cbab583Srzalamena size_t ptotal, poff = 0;
169*9cbab583Srzalamena uint16_t ocksum, cksum;
170*9cbab583Srzalamena
171*9cbab583Srzalamena /* Check the IPv6 header. */
172*9cbab583Srzalamena if (plen < sizeof(*ip6)) {
173*9cbab583Srzalamena log_debug("package too small (%ld)", plen);
174*9cbab583Srzalamena return -1;
175*9cbab583Srzalamena }
176*9cbab583Srzalamena
177*9cbab583Srzalamena ip6 = (struct ip6_hdr *)(p + off);
178*9cbab583Srzalamena if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
179*9cbab583Srzalamena log_debug("invalid IPv6 version");
180*9cbab583Srzalamena return -1;
181*9cbab583Srzalamena }
182*9cbab583Srzalamena
183*9cbab583Srzalamena poff += sizeof(*ip6);
184*9cbab583Srzalamena
185*9cbab583Srzalamena ptotal = ntohs(ip6->ip6_plen);
186*9cbab583Srzalamena if (ptotal > plen) {
187*9cbab583Srzalamena log_debug("expected %ld bytes, but got %ld", ptotal, plen);
188*9cbab583Srzalamena return (-1);
189*9cbab583Srzalamena }
190*9cbab583Srzalamena
191*9cbab583Srzalamena pc->pc_src.ss_len = sizeof(struct sockaddr_in6);
192*9cbab583Srzalamena pc->pc_src.ss_family = AF_INET6;
193*9cbab583Srzalamena asrc = &ss2sin6(&pc->pc_src)->sin6_addr;
194*9cbab583Srzalamena memcpy(asrc, &ip6->ip6_src, sizeof(*asrc));
195*9cbab583Srzalamena
196*9cbab583Srzalamena pc->pc_dst.ss_len = sizeof(struct sockaddr_in6);
197*9cbab583Srzalamena pc->pc_dst.ss_family = AF_INET6;
198*9cbab583Srzalamena adst = &ss2sin6(&pc->pc_dst)->sin6_addr;
199*9cbab583Srzalamena memcpy(adst, &ip6->ip6_dst, sizeof(*adst));
200*9cbab583Srzalamena
201*9cbab583Srzalamena /* Deal with the UDP header. */
202*9cbab583Srzalamena if (ip6->ip6_nxt != IPPROTO_UDP) {
203*9cbab583Srzalamena /* We don't support skipping extensions yet. */
204*9cbab583Srzalamena log_debug("expected UDP header, got %#02X", ip6->ip6_nxt);
205*9cbab583Srzalamena return -1;
206*9cbab583Srzalamena }
207*9cbab583Srzalamena
208*9cbab583Srzalamena uh = (struct udphdr *)((uint8_t *)ip6 + sizeof(*ip6));
209*9cbab583Srzalamena ss2sin6(&pc->pc_src)->sin6_port = uh->uh_sport;
210*9cbab583Srzalamena ss2sin6(&pc->pc_dst)->sin6_port = uh->uh_dport;
211*9cbab583Srzalamena ocksum = uh->uh_sum;
212*9cbab583Srzalamena uh->uh_sum = 0;
213*9cbab583Srzalamena poff += sizeof(*uh);
214*9cbab583Srzalamena
215*9cbab583Srzalamena /* Validate the packet. */
216*9cbab583Srzalamena cksum = wrapsum(
217*9cbab583Srzalamena checksum((unsigned char *)asrc, sizeof(*asrc),
218*9cbab583Srzalamena checksum((unsigned char *)adst, sizeof(*adst),
219*9cbab583Srzalamena checksum((unsigned char *)uh, sizeof(*uh),
220*9cbab583Srzalamena checksum(p + off + poff, ptotal - sizeof(*uh),
221*9cbab583Srzalamena IPPROTO_UDP + ntohs(uh->uh_ulen)))))
222*9cbab583Srzalamena );
223*9cbab583Srzalamena
224*9cbab583Srzalamena if (ocksum != cksum) {
225*9cbab583Srzalamena log_debug("checksum invalid (%#04x != %#04x)",
226*9cbab583Srzalamena ocksum, cksum);
227*9cbab583Srzalamena return -1;
228*9cbab583Srzalamena }
229*9cbab583Srzalamena
230*9cbab583Srzalamena return poff;
231*9cbab583Srzalamena }
232