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