xref: /openbsd/lib/libc/net/rthdr.c (revision 2c53affb)
1 /*	$OpenBSD: rthdr.c,v 1.13 2022/12/27 17:10:06 jmc Exp $	*/
2 /*	$KAME: rthdr.c,v 1.22 2006/02/09 08:18:58 keiichi Exp $	*/
3 
4 /*
5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 
36 #include <netinet/in.h>
37 #include <netinet/ip6.h>
38 
39 #include <string.h>
40 #include <stdio.h>
41 
42 /*
43  * RFC3542 (2292bis) API
44  */
45 
46 socklen_t
inet6_rth_space(int type,int segments)47 inet6_rth_space(int type, int segments)
48 {
49 	switch (type) {
50 	case IPV6_RTHDR_TYPE_0:
51 		return (((segments * 2) + 1) << 3);
52 	default:
53 		return (0);	/* type not supported */
54 	}
55 }
56 DEF_WEAK(inet6_rth_space);
57 
58 void *
inet6_rth_init(void * bp,socklen_t bp_len,int type,int segments)59 inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
60 {
61 	struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
62 	struct ip6_rthdr0 *rth0;
63 
64 	switch (type) {
65 	case IPV6_RTHDR_TYPE_0:
66 		/* length validation */
67 		if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments))
68 			return (NULL);
69 
70 		memset(bp, 0, bp_len);
71 		rth0 = (struct ip6_rthdr0 *)rth;
72 		rth0->ip6r0_len = segments * 2;
73 		rth0->ip6r0_type = IPV6_RTHDR_TYPE_0;
74 		rth0->ip6r0_segleft = 0;
75 		rth0->ip6r0_reserved = 0;
76 		break;
77 	default:
78 		return (NULL);	/* type not supported */
79 	}
80 
81 	return (bp);
82 }
83 
84 int
inet6_rth_add(void * bp,const struct in6_addr * addr)85 inet6_rth_add(void *bp, const struct in6_addr *addr)
86 {
87 	struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
88 	struct ip6_rthdr0 *rth0;
89 	struct in6_addr *nextaddr;
90 
91 	switch (rth->ip6r_type) {
92 	case IPV6_RTHDR_TYPE_0:
93 		rth0 = (struct ip6_rthdr0 *)rth;
94 		nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft;
95 		*nextaddr = *addr;
96 		rth0->ip6r0_segleft++;
97 		break;
98 	default:
99 		return (-1);	/* type not supported */
100 	}
101 
102 	return (0);
103 }
104 
105 int
inet6_rth_reverse(const void * in,void * out)106 inet6_rth_reverse(const void *in, void *out)
107 {
108 	struct ip6_rthdr *rth_in = (struct ip6_rthdr *)in;
109 	struct ip6_rthdr0 *rth0_in, *rth0_out;
110 	int i, segments;
111 
112 	switch (rth_in->ip6r_type) {
113 	case IPV6_RTHDR_TYPE_0:
114 		rth0_in = (struct ip6_rthdr0 *)in;
115 		rth0_out = (struct ip6_rthdr0 *)out;
116 
117 		/* parameter validation XXX too paranoid? */
118 		if (rth0_in->ip6r0_len % 2)
119 			return (-1);
120 		segments = rth0_in->ip6r0_len / 2;
121 
122 		/* we can't use memcpy here, since in and out may overlap */
123 		memmove(rth0_out, rth0_in, ((rth0_in->ip6r0_len) + 1) << 3);
124 		rth0_out->ip6r0_segleft = segments;
125 
126 		/* reverse the addresses */
127 		for (i = 0; i < segments / 2; i++) {
128 			struct in6_addr addr_tmp, *addr1, *addr2;
129 
130 			addr1 = (struct in6_addr *)(rth0_out + 1) + i;
131 			addr2 = (struct in6_addr *)(rth0_out + 1) +
132 			    (segments - i - 1);
133 			addr_tmp = *addr1;
134 			*addr1 = *addr2;
135 			*addr2 = addr_tmp;
136 		}
137 
138 		break;
139 	default:
140 		return (-1);	/* type not supported */
141 	}
142 
143 	return (0);
144 }
145 
146 int
inet6_rth_segments(const void * bp)147 inet6_rth_segments(const void *bp)
148 {
149 	struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
150 	struct ip6_rthdr0 *rh0;
151 	int addrs;
152 
153 	switch (rh->ip6r_type) {
154 	case IPV6_RTHDR_TYPE_0:
155 		rh0 = (struct ip6_rthdr0 *)bp;
156 
157 		/*
158 		 * Validation for a type-0 routing header.
159 		 * Is this too strict?
160 		 */
161 		if ((rh0->ip6r0_len % 2) != 0 ||
162 		    (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
163 			return (-1);
164 
165 		return (addrs);
166 	default:
167 		return (-1);	/* unknown type */
168 	}
169 }
170 
171 struct in6_addr *
inet6_rth_getaddr(const void * bp,int idx)172 inet6_rth_getaddr(const void *bp, int idx)
173 {
174 	struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
175 	struct ip6_rthdr0 *rh0;
176 	int addrs;
177 
178 	switch (rh->ip6r_type) {
179 	case IPV6_RTHDR_TYPE_0:
180 		 rh0 = (struct ip6_rthdr0 *)bp;
181 
182 		/*
183 		 * Validation for a type-0 routing header.
184 		 * Is this too strict?
185 		 */
186 		if ((rh0->ip6r0_len % 2) != 0 ||
187 		    (addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
188 			return (NULL);
189 
190 		if (idx < 0 || addrs <= idx)
191 			return (NULL);
192 
193 		return (((struct in6_addr *)(rh0 + 1)) + idx);
194 	default:
195 		return (NULL);	/* unknown type */
196 		break;
197 	}
198 }
199