1 /*
2 * libnet
3 * libnet_build_gre.c - GRE packet assembler
4 *
5 * Copyright (c) 2003 Fr�d�ric Raynal <pappy@security-labs.org>
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 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31 #if (HAVE_CONFIG_H)
32 #include "../include/config.h"
33 #endif
34 #if (!(_WIN32) || (__CYGWIN__))
35 #include "../include/libnet.h"
36 #else
37 #include "../include/win32/libnet.h"
38 #endif
39
40 /*
41 * Overall packet
42 *
43 * The entire encapsulated packet would then have the form:
44 *
45 * ---------------------------------
46 * | |
47 * | Delivery Header |
48 * | |
49 * ---------------------------------
50 * | |
51 * | GRE Header |
52 * | |
53 * ---------------------------------
54 * | |
55 * | Payload packet |
56 * | |
57 * ---------------------------------
58 *
59 * RFC 1701 defines a header.
60 * A new RFC (2784) has changed the header and proposed to remove the key
61 * and seqnum.
62 * A newer RFC (2890) has changed the header proposed in RFC 2784 by putting
63 * back key and seqnum.
64 * These will be supported the day IETF'guys stop this mess !
65 *
66 * FR
67 */
68
69
70 /*
71 * Generic Routing Encapsulation (GRE)
72 * RFC 1701 http://www.faqs.org/rfcs/rfc1701.html
73 *
74 *
75 * Packet header
76 *
77 * The GRE packet header has the form:
78 *
79 * 0 1 2 3
80 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
81 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
82 * |C|R|K|S|s|Recur| Flags | Ver | Protocol Type |
83 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84 * | Checksum (optional) | Offset (optional) |
85 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86 * | Key (optional) |
87 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88 * | Sequence Number (optional) |
89 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90 * | Routing (optional) |
91 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92 *
93 * Enhanced GRE header
94 *
95 * See rfc 2637 for details. It is used for PPTP tunneling.
96 *
97 * 0 1 2 3
98 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
99 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100 * |C|R|K|S|s|Recur|A| Flags | Ver | Protocol Type |
101 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102 * | Key (HW) Payload Length | Key (LW) Call ID |
103 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104 * | Sequence Number (Optional) |
105 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106 * | Acknowledgment Number (Optional) |
107 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108 *
109 */
110 #if 0
111 static void
112 __libnet_print_gre_flags_ver(uint16_t fv)
113 {
114 printf("version = %d (%d) -> ",
115 fv & GRE_VERSION_MASK, libnet_getgre_length(fv));
116 if (fv & GRE_CSUM)
117 {
118 printf("CSUM ");
119 }
120 if (fv & GRE_ROUTING)
121 {
122 printf("ROUTING ");
123 }
124 if (fv & GRE_KEY)
125 {
126 printf("KEY ");
127 }
128 if (fv & GRE_SEQ)
129 {
130 printf("SEQ ");
131 }
132 if (fv & GRE_ACK)
133 {
134 printf("ACK ");
135 }
136 printf("\n");
137 }
138 #endif
139
140 /* FIXME: what is the portability of the "((struct libnet_gre_hdr*)0)->" ? */
141 uint32_t
libnet_getgre_length(uint16_t fv)142 libnet_getgre_length(uint16_t fv)
143 {
144
145 uint32_t n = LIBNET_GRE_H;
146 /*
147 * If either the Checksum Present bit or the Routing Present bit are
148 * set, BOTH the Checksum and Offset fields are present in the GRE
149 * packet.
150 */
151
152 if ((!(fv & GRE_VERSION_MASK) && (fv & (GRE_CSUM|GRE_ROUTING))) || /* v0 */
153 (fv & GRE_VERSION_MASK) ) /* v1 */
154 {
155 n += sizeof( ((struct libnet_gre_hdr *)0)->gre_sum) +
156 sizeof( ((struct libnet_gre_hdr *)0)->gre_offset);
157 }
158
159 if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_KEY)) || /* v0 */
160 ( (fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) ) /* v1 */
161 {
162 n += sizeof( ((struct libnet_gre_hdr *)0)->gre_key);
163 }
164
165 if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) || /* v0 */
166 ( (fv & GRE_VERSION_MASK) && (fv & GRE_ACK)) ) /* v1 */
167 {
168 n += sizeof( ((struct libnet_gre_hdr *)0)->gre_seq );
169 }
170
171 return (n);
172 }
173
174 libnet_ptag_t
libnet_build_gre(uint16_t fv,uint16_t type,uint16_t sum,uint16_t offset,uint32_t key,uint32_t seq,uint16_t len,const uint8_t * payload,uint32_t payload_s,libnet_t * l,libnet_ptag_t ptag)175 libnet_build_gre(uint16_t fv, uint16_t type, uint16_t sum,
176 uint16_t offset, uint32_t key, uint32_t seq, uint16_t len,
177 const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
178 {
179 uint32_t n;
180 libnet_pblock_t *p;
181 struct libnet_gre_hdr gre_hdr;
182
183 if (l == NULL)
184 {
185 return (-1);
186 }
187
188 n = libnet_getgre_length(fv) + payload_s;
189
190 /*
191 * Find the existing protocol block if a ptag is specified, or create
192 * a new one.
193 */
194 p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_GRE_H);
195 if (p == NULL)
196 {
197 return (-1);
198 }
199
200 gre_hdr.flags_ver = htons(fv);
201 gre_hdr.type = htons(type);
202 n = libnet_pblock_append(l, p, (uint8_t *)&gre_hdr, LIBNET_GRE_H);
203 if (n == -1)
204 {
205 /* err msg set in libnet_pblock_append() */
206 goto bad;
207 }
208
209 if ((!(fv & GRE_VERSION_MASK) && (fv & (GRE_CSUM|GRE_ROUTING))) || /* v0 */
210 (fv & GRE_VERSION_MASK)) /* v1 */
211 {
212 sum = htons(sum);
213 n = libnet_pblock_append(l, p, (uint8_t*)&sum,
214 sizeof(gre_hdr.gre_sum));
215 if (n == -1)
216 {
217 /* err msg set in libnet_pblock_append() */
218 goto bad;
219 }
220 offset = htons(offset);
221 n = libnet_pblock_append(l, p, (uint8_t*)&offset,
222 sizeof(gre_hdr.gre_offset));
223 if (n == -1)
224 {
225 /* err msg set in libnet_pblock_append() */
226 goto bad;
227 }
228 }
229
230 if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_KEY)) || /* v0 */
231 ( (fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) ) /* v1 */
232 {
233 key = htonl(key);
234 n = libnet_pblock_append(l, p, (uint8_t*)&key,
235 sizeof(gre_hdr.gre_key));
236 if (n == -1)
237 {
238 /* err msg set in libnet_pblock_append() */
239 goto bad;
240 }
241 }
242
243 if ((!(fv & GRE_VERSION_MASK) && (fv & GRE_SEQ)) || /* v0 */
244 ( (fv & GRE_VERSION_MASK) && (fv & GRE_ACK)) ) /* v1 */
245 {
246 seq = htonl(seq);
247 n = libnet_pblock_append(l, p, (uint8_t*)&seq,
248 sizeof(gre_hdr.gre_seq));
249 if (n == -1)
250 {
251 /* err msg set in libnet_pblock_append() */
252 goto bad;
253 }
254 }
255
256 /* boilerplate payload sanity check / append macro */
257 LIBNET_DO_PAYLOAD(l, p);
258
259 if ( (fv & GRE_CSUM) && (!sum) )
260 {
261 libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
262 }
263
264 return (ptag ? ptag : libnet_pblock_update(l, p, len, LIBNET_PBLOCK_GRE_H));
265
266 bad:
267 libnet_pblock_delete(l, p);
268 return (-1);
269 }
270
271 libnet_ptag_t
libnet_build_egre(uint16_t fv,uint16_t type,uint16_t sum,uint16_t offset,uint32_t key,uint32_t seq,uint16_t len,const uint8_t * payload,uint32_t payload_s,libnet_t * l,libnet_ptag_t ptag)272 libnet_build_egre(uint16_t fv, uint16_t type, uint16_t sum,
273 uint16_t offset, uint32_t key, uint32_t seq, uint16_t len,
274 const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
275 {
276 return (libnet_build_gre(fv, type, sum, offset, key, seq, len,
277 payload, payload_s, l, ptag));
278 }
279
280 /*
281 * Routing (variable)
282 *
283 * The Routing field is optional and is present only if the Routing
284 * Present bit is set to 1.
285 *
286 * The Routing field is a list of Source Route Entries (SREs). Each
287 * SRE has the form:
288 *
289 * 0 1 2 3
290 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
291 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
292 * | Address Family | SRE Offset | SRE Length |
293 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
294 * | Routing Information ...
295 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
296 *
297 */
298 libnet_ptag_t
libnet_build_gre_sre(uint16_t af,uint8_t offset,uint8_t length,uint8_t * routing,const uint8_t * payload,uint32_t payload_s,libnet_t * l,libnet_ptag_t ptag)299 libnet_build_gre_sre(uint16_t af, uint8_t offset, uint8_t length,
300 uint8_t *routing, const uint8_t *payload, uint32_t payload_s, libnet_t *l,
301 libnet_ptag_t ptag)
302 {
303 uint32_t n;
304 libnet_pblock_t *p;
305 struct libnet_gre_sre_hdr sre_hdr;
306
307 if (l == NULL)
308 {
309 return (-1);
310 }
311
312 n = LIBNET_GRE_SRE_H + length + payload_s;
313
314 /*
315 * Find the existing protocol block if a ptag is specified, or create
316 * a new one.
317 */
318 p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_GRE_SRE_H);
319 if (p == NULL)
320 {
321 return (-1);
322 }
323 sre_hdr.af = htons(af);
324 sre_hdr.sre_offset = offset;
325 sre_hdr.sre_length = length;
326 n = libnet_pblock_append(l, p, (uint8_t *)&sre_hdr, LIBNET_GRE_SRE_H);
327 if (n == -1)
328 {
329 /* err msg set in libnet_pblock_append() */
330 goto bad;
331 }
332
333 if ((routing && !length) || (!routing && length))
334 {
335 sprintf(l->err_buf, "%s(): routing inconsistency\n", __func__);
336 goto bad;
337 }
338
339 if (routing && length)
340 {
341 n = libnet_pblock_append(l, p, routing, length);
342 if (n == -1)
343 {
344 /* err msg set in libnet_pblock_append() */
345 goto bad;
346 }
347 }
348
349 /* boilerplate payload sanity check / append macro */
350 LIBNET_DO_PAYLOAD(l, p);
351
352 return (ptag ? ptag : libnet_pblock_update(l, p, 0,
353 LIBNET_PBLOCK_GRE_SRE_H));
354
355 bad:
356 libnet_pblock_delete(l, p);
357 return (-1);
358
359 }
360
361 libnet_ptag_t
libnet_build_gre_last_sre(libnet_t * l,libnet_ptag_t ptag)362 libnet_build_gre_last_sre(libnet_t *l, libnet_ptag_t ptag)
363 {
364 uint32_t n, zero = 0;
365 libnet_pblock_t *p;
366
367 if (l == NULL)
368 {
369 return (-1);
370 }
371
372 n = LIBNET_GRE_SRE_H;
373
374 /*
375 * Find the existing protocol block if a ptag is specified, or create
376 * a new one.
377 */
378 p = libnet_pblock_probe(l, ptag, n, LIBNET_PBLOCK_GRE_H);
379 if (p == NULL)
380 {
381 return (-1);
382 }
383
384 n = libnet_pblock_append(l, p, (uint8_t *)&zero, LIBNET_GRE_SRE_H);
385 if (n == -1)
386 {
387 /* err msg set in libnet_pblock_append() */
388 goto bad;
389 }
390
391 return (ptag ? ptag : libnet_pblock_update(l, p, 0,
392 LIBNET_PBLOCK_GRE_SRE_H));
393
394 bad:
395 libnet_pblock_delete(l, p);
396 return (-1);
397
398 }
399 /* EOF */
400