3 * libnet_build_gre.c - GRE packet assembler
5 * Copyright (c) 2003 Frédéric Raynal <pappy@security-labs.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
32 #include "../include/config.h"
34 #if (!(_WIN32) || (__CYGWIN__))
35 #include "../include/libnet.h"
37 #include "../include/win32/libnet.h"
43 * The entire encapsulated packet would then have the form:
45 * ---------------------------------
49 * ---------------------------------
53 * ---------------------------------
57 * ---------------------------------
59 * RFC 1701 defines a header.
60 * A new RFC (2784) has changed the header and proposed to remove the key
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 !
71 * Generic Routing Encapsulation (GRE)
72 * RFC 1701 http://www.faqs.org/rfcs/rfc1701.html
77 * The GRE packet header has the form:
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88 * | Sequence Number (optional) |
89 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90 * | Routing (optional) |
91 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95 * See rfc 2637 for details. It is used for PPTP tunneling.
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
112 __libnet_print_gre_flags_ver(u_int16_t fv
)
114 printf("version = %d (%d) -> ",
115 fv
& GRE_VERSION_MASK
, libnet_getgre_length(fv
));
120 if (fv
& GRE_ROUTING
)
140 /* FIXME: what is the portability of the "((struct libnet_gre_hdr*)0)->" ? */
142 libnet_getgre_length(u_int16_t fv
)
145 u_int32_t n
= LIBNET_GRE_H
;
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
152 if ((!(fv
& GRE_VERSION_MASK
) && (fv
& (GRE_CSUM
|GRE_ROUTING
))) || /* v0 */
153 (fv
& GRE_VERSION_MASK
) ) /* v1 */
155 n
+= sizeof( ((struct libnet_gre_hdr
*)0)->gre_sum
) +
156 sizeof( ((struct libnet_gre_hdr
*)0)->gre_offset
);
159 if ((!(fv
& GRE_VERSION_MASK
) && (fv
& GRE_KEY
)) || /* v0 */
160 ( (fv
& GRE_VERSION_MASK
) && (fv
& GRE_SEQ
)) ) /* v1 */
162 n
+= sizeof( ((struct libnet_gre_hdr
*)0)->gre_key
);
165 if ((!(fv
& GRE_VERSION_MASK
) && (fv
& GRE_SEQ
)) || /* v0 */
166 ( (fv
& GRE_VERSION_MASK
) && (fv
& GRE_ACK
)) ) /* v1 */
168 n
+= sizeof( ((struct libnet_gre_hdr
*)0)->gre_seq
);
175 libnet_build_gre(u_int16_t fv
, u_int16_t type
, u_int16_t sum
,
176 u_int16_t offset
, u_int32_t key
, u_int32_t seq
, u_int16_t len
,
177 u_int8_t
*payload
, u_int32_t payload_s
, libnet_t
*l
, libnet_ptag_t ptag
)
181 struct libnet_gre_hdr gre_hdr
;
188 n
= libnet_getgre_length(fv
) + payload_s
;
191 * Find the existing protocol block if a ptag is specified, or create
194 p
= libnet_pblock_probe(l
, ptag
, n
, LIBNET_PBLOCK_GRE_H
);
200 gre_hdr
.flags_ver
= htons(fv
);
201 gre_hdr
.type
= htons(type
);
202 n
= libnet_pblock_append(l
, p
, (u_int8_t
*)&gre_hdr
, LIBNET_GRE_H
);
205 /* err msg set in libnet_pblock_append() */
209 if ((!(fv
& GRE_VERSION_MASK
) && (fv
& (GRE_CSUM
|GRE_ROUTING
))) || /* v0 */
210 (fv
& GRE_VERSION_MASK
)) /* v1 */
213 n
= libnet_pblock_append(l
, p
, (u_int8_t
*)&sum
,
214 sizeof(gre_hdr
.gre_sum
));
217 /* err msg set in libnet_pblock_append() */
220 offset
= htons(offset
);
221 n
= libnet_pblock_append(l
, p
, (u_int8_t
*)&offset
,
222 sizeof(gre_hdr
.gre_offset
));
225 /* err msg set in libnet_pblock_append() */
230 if ((!(fv
& GRE_VERSION_MASK
) && (fv
& GRE_KEY
)) || /* v0 */
231 ( (fv
& GRE_VERSION_MASK
) && (fv
& GRE_SEQ
)) ) /* v1 */
234 n
= libnet_pblock_append(l
, p
, (u_int8_t
*)&key
,
235 sizeof(gre_hdr
.gre_key
));
238 /* err msg set in libnet_pblock_append() */
243 if ((!(fv
& GRE_VERSION_MASK
) && (fv
& GRE_SEQ
)) || /* v0 */
244 ( (fv
& GRE_VERSION_MASK
) && (fv
& GRE_ACK
)) ) /* v1 */
247 n
= libnet_pblock_append(l
, p
, (u_int8_t
*)&seq
,
248 sizeof(gre_hdr
.gre_seq
));
251 /* err msg set in libnet_pblock_append() */
256 if ((payload
&& !payload_s
) || (!payload
&& payload_s
))
258 sprintf(l
->err_buf
, "%s(): payload inconsistency\n", __func__
);
262 if (payload
&& payload_s
)
264 n
= libnet_pblock_append(l
, p
, payload
, payload_s
);
267 /* err msg set in libnet_pblock_append() */
272 if ( (fv
& GRE_CSUM
) && (!sum
) )
274 libnet_pblock_setflags(p
, LIBNET_PBLOCK_DO_CHECKSUM
);
277 return (ptag
? ptag
: libnet_pblock_update(l
, p
, len
, LIBNET_PBLOCK_GRE_H
));
280 libnet_pblock_delete(l
, p
);
285 libnet_build_egre(u_int16_t fv
, u_int16_t type
, u_int16_t sum
,
286 u_int16_t offset
, u_int32_t key
, u_int32_t seq
, u_int16_t len
,
287 u_int8_t
*payload
, u_int32_t payload_s
, libnet_t
*l
, libnet_ptag_t ptag
)
289 return (libnet_build_gre(fv
, type
, sum
, offset
, key
, seq
, len
,
290 payload
, payload_s
, l
, ptag
));
296 * The Routing field is optional and is present only if the Routing
297 * Present bit is set to 1.
299 * The Routing field is a list of Source Route Entries (SREs). Each
303 * 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
304 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
305 * | Address Family | SRE Offset | SRE Length |
306 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
307 * | Routing Information ...
308 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
312 libnet_build_gre_sre(u_int16_t af
, u_int8_t offset
, u_int8_t length
,
313 u_int8_t
*routing
, u_int8_t
*payload
, u_int32_t payload_s
, libnet_t
*l
,
318 struct libnet_gre_sre_hdr sre_hdr
;
325 n
= LIBNET_GRE_SRE_H
+ length
+ payload_s
;
328 * Find the existing protocol block if a ptag is specified, or create
331 p
= libnet_pblock_probe(l
, ptag
, n
, LIBNET_PBLOCK_GRE_SRE_H
);
336 sre_hdr
.af
= htons(af
);
337 sre_hdr
.sre_offset
= offset
;
338 sre_hdr
.sre_length
= length
;
339 n
= libnet_pblock_append(l
, p
, (u_int8_t
*)&sre_hdr
, LIBNET_GRE_SRE_H
);
342 /* err msg set in libnet_pblock_append() */
346 if ((routing
&& !length
) || (!routing
&& length
))
348 sprintf(l
->err_buf
, "%s(): routing inconsistency\n", __func__
);
352 if (routing
&& length
)
354 n
= libnet_pblock_append(l
, p
, routing
, length
);
357 /* err msg set in libnet_pblock_append() */
362 if ((payload
&& !payload_s
) || (!payload
&& payload_s
))
364 sprintf(l
->err_buf
, "%s(): payload inconsistency\n", __func__
);
368 if (payload
&& payload_s
)
370 n
= libnet_pblock_append(l
, p
, payload
, payload_s
);
373 /* err msg set in libnet_pblock_append() */
378 return (ptag
? ptag
: libnet_pblock_update(l
, p
, 0,
379 LIBNET_PBLOCK_GRE_SRE_H
));
382 libnet_pblock_delete(l
, p
);
388 libnet_build_gre_last_sre(libnet_t
*l
, libnet_ptag_t ptag
)
390 u_int32_t n
, zero
= 0;
398 n
= LIBNET_GRE_SRE_H
;
401 * Find the existing protocol block if a ptag is specified, or create
404 p
= libnet_pblock_probe(l
, ptag
, n
, LIBNET_PBLOCK_GRE_H
);
410 n
= libnet_pblock_append(l
, p
, (u_int8_t
*)&zero
, LIBNET_GRE_SRE_H
);
413 /* err msg set in libnet_pblock_append() */
417 return (ptag
? ptag
: libnet_pblock_update(l
, p
, 0,
418 LIBNET_PBLOCK_GRE_SRE_H
));
421 libnet_pblock_delete(l
, p
);