1 |
|
|
/* $OpenBSD: rthdr.c,v 1.12 2016/09/21 04:38:56 guenther 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 |
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 suppported */ |
54 |
|
|
} |
55 |
|
|
} |
56 |
|
|
DEF_WEAK(inet6_rth_space); |
57 |
|
|
|
58 |
|
|
void * |
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 |
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 |
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 |
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 * |
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 |
|
|
} |