1 /*
2  * This file is part of libtrace
3  *
4  * Copyright (c) 2007-2012 The University of Waikato, Hamilton,
5  * New Zealand.
6  *
7  * Authors: Daniel Lawson
8  *          Perry Lorier
9  *          Shane Alcock
10  *
11  * All rights reserved.
12  *
13  * This code has been developed by the University of Waikato WAND
14  * research group. For further information please see http://www.wand.net.nz/
15  *
16  * libtrace is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * libtrace is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with libtrace; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29  *
30  * $Id: protocols_ospf.c 1745 2012-01-10 01:23:53Z salcock $
31  *
32  */
33 
34 #include "libtrace.h"
35 #include "protocols.h"
36 #include <assert.h>
37 #include <stdlib.h>
38 #include <stdio.h> // fprintf
39 
trace_get_ospf_header(libtrace_packet_t * packet,uint8_t * version,uint32_t * remaining)40 DLLEXPORT void *trace_get_ospf_header(libtrace_packet_t *packet,
41                 uint8_t *version, uint32_t *remaining) {
42         uint8_t proto;
43         void *ospf;
44         uint32_t dummy_rem = 0;
45 
46 
47         if (!remaining)
48                 remaining = &dummy_rem;
49 
50         assert(version != NULL && "version may not be NULL when calling trace_get_ospf_header!");
51 
52         ospf = trace_get_transport(packet, &proto, remaining);
53 
54         if (!ospf || proto != TRACE_IPPROTO_OSPF || *remaining == 0)
55                 return NULL;
56 
57         *version = *((uint8_t *)ospf);
58 
59         if (*version == 2 && *remaining < sizeof(libtrace_ospf_v2_t))
60                 return NULL;
61 
62         return ospf;
63 }
64 
trace_get_ospf_contents_v2(libtrace_ospf_v2_t * header,uint8_t * ospf_type,uint32_t * remaining)65 DLLEXPORT void *trace_get_ospf_contents_v2(libtrace_ospf_v2_t *header,
66                 uint8_t *ospf_type, uint32_t *remaining) {
67 
68         uint8_t dummy_type;
69         char *ptr;
70 
71         assert(remaining != NULL && "remaining may not be NULL when calling trace_get_ospf_contents!");
72 
73         if (!ospf_type)
74                 ospf_type = &dummy_type;
75 
76         if (!header || *remaining < sizeof(libtrace_ospf_v2_t)) {
77                 *ospf_type = 0;
78                 *remaining = 0;
79                 return NULL;
80         }
81 
82         *ospf_type = header->type;
83 
84         ptr = ((char *)header) + sizeof(libtrace_ospf_v2_t);
85         *remaining -= sizeof(libtrace_ospf_v2_t);
86 
87         return (void *)ptr;
88 
89 }
90 
trace_get_first_ospf_link_from_router_lsa_v2(libtrace_ospf_router_lsa_v2_t * lsa,uint32_t * remaining)91 DLLEXPORT unsigned char *trace_get_first_ospf_link_from_router_lsa_v2(
92                 libtrace_ospf_router_lsa_v2_t *lsa,
93                 uint32_t *remaining) {
94 
95         unsigned char *link_ptr = NULL;
96         assert(remaining != NULL && "remaining may not be NULL when calling trace_get_first_link_from_router_lsa_v2!");
97 
98         if (!lsa || *remaining < sizeof(libtrace_ospf_router_lsa_v2_t)) {
99                 *remaining = 0;
100                 return NULL;
101         }
102 
103         link_ptr = ((unsigned char *)lsa) + sizeof(libtrace_ospf_router_lsa_v2_t);
104         *remaining -= sizeof(libtrace_ospf_router_lsa_v2_t);
105         return link_ptr;
106 
107 }
108 
trace_get_first_ospf_lsa_from_db_desc_v2(libtrace_ospf_db_desc_v2_t * db_desc,uint32_t * remaining)109 DLLEXPORT unsigned char *trace_get_first_ospf_lsa_from_db_desc_v2(
110                 libtrace_ospf_db_desc_v2_t *db_desc,
111                 uint32_t *remaining) {
112 
113         unsigned char *lsa_ptr = NULL;
114 
115         assert(remaining != NULL && "remaining may not be NULL when calling trace_get_first_ospf_v2_lsa!");
116 
117         if (!db_desc || *remaining < sizeof(libtrace_ospf_db_desc_v2_t)) {
118                 *remaining = 0;
119                 return NULL;
120         }
121 
122         lsa_ptr = ((unsigned char *)db_desc) + sizeof(libtrace_ospf_db_desc_v2_t);
123         *remaining -= sizeof(libtrace_ospf_db_desc_v2_t);
124 
125         return lsa_ptr;
126 }
127 
trace_get_first_ospf_lsa_from_update_v2(libtrace_ospf_ls_update_t * ls_update,uint32_t * remaining)128 DLLEXPORT unsigned char *trace_get_first_ospf_lsa_from_update_v2(
129                 libtrace_ospf_ls_update_t *ls_update,
130                 uint32_t *remaining) {
131 
132         unsigned char *lsa_ptr = NULL;
133 
134         assert(remaining != NULL && "remaining may not be NULL when calling trace_get_first_ospf_v2_lsa!");
135 
136         if (!ls_update || *remaining < sizeof(libtrace_ospf_ls_update_t)) {
137                 *remaining = 0;
138                 return NULL;
139         }
140 
141         lsa_ptr = ((unsigned char *)ls_update) + sizeof(libtrace_ospf_ls_update_t);
142         *remaining -= sizeof(libtrace_ospf_ls_update_t);
143 
144         return lsa_ptr;
145 }
146 
trace_get_ospf_metric_from_as_external_lsa_v2(libtrace_ospf_as_external_lsa_v2_t * as_lsa)147 DLLEXPORT uint32_t trace_get_ospf_metric_from_as_external_lsa_v2(
148                 libtrace_ospf_as_external_lsa_v2_t *as_lsa) {
149 
150         uint32_t metric = 0;
151 
152         assert(as_lsa);
153 
154         metric = as_lsa->metric_a << 16;
155         metric |= (as_lsa->metric_b << 8);
156         metric |= as_lsa->metric_c;
157 
158         return metric;
159 }
160 
trace_get_ospf_metric_from_summary_lsa_v2(libtrace_ospf_summary_lsa_v2_t * sum_lsa)161 DLLEXPORT uint32_t trace_get_ospf_metric_from_summary_lsa_v2(
162                 libtrace_ospf_summary_lsa_v2_t *sum_lsa) {
163 
164         uint32_t metric = 0;
165 
166         assert(sum_lsa);
167 
168         metric = sum_lsa->metric_a << 16;
169         metric |= (sum_lsa->metric_b << 8);
170         metric |= sum_lsa->metric_c;
171 
172         return metric;
173 }
174 
trace_get_next_ospf_link_v2(unsigned char ** current,libtrace_ospf_link_v2_t ** link,uint32_t * remaining,uint32_t * link_len)175 DLLEXPORT int trace_get_next_ospf_link_v2(unsigned char **current,
176                 libtrace_ospf_link_v2_t **link,
177                 uint32_t *remaining,
178                 uint32_t *link_len) {
179 
180         if (*current == NULL || *remaining < sizeof(libtrace_ospf_link_v2_t)) {
181                 *remaining = 0;
182                 *link = NULL;
183                 return 0;
184         }
185 
186         *link = (libtrace_ospf_link_v2_t *)*current;
187 
188         /* XXX The spec allows for multiple metrics for a single link. This
189          * approach won't support this, so we may need to be more intelligent
190          * about this in future */
191         *remaining -= sizeof(libtrace_ospf_link_v2_t);
192         *link_len = sizeof(libtrace_ospf_link_v2_t);
193         *current += sizeof(libtrace_ospf_link_v2_t);
194 
195         return 1;
196 
197 }
198 
trace_get_next_ospf_lsa_header_v2(unsigned char ** current,libtrace_ospf_lsa_v2_t ** lsa_hdr,uint32_t * remaining,uint8_t * lsa_type,uint16_t * lsa_length)199 DLLEXPORT int trace_get_next_ospf_lsa_header_v2(unsigned char **current,
200                 libtrace_ospf_lsa_v2_t **lsa_hdr,
201                 uint32_t *remaining,
202                 uint8_t *lsa_type,
203                 uint16_t *lsa_length) {
204 
205         int valid_lsa = 0;
206 
207         if (*current == NULL || *remaining < sizeof(libtrace_ospf_lsa_v2_t)) {
208                 *lsa_hdr = NULL;
209                 *remaining = 0;
210                 return 0;
211 
212         }
213 
214         *lsa_hdr = (libtrace_ospf_lsa_v2_t *)(*current);
215 
216         /* Check that the LSA type is valid */
217         switch ((*lsa_hdr)->lsa_type) {
218                 case TRACE_OSPF_LS_ROUTER:
219                 case TRACE_OSPF_LS_NETWORK:
220                 case TRACE_OSPF_LS_SUMMARY:
221                 case TRACE_OSPF_LS_ASBR_SUMMARY:
222                 case TRACE_OSPF_LS_EXTERNAL:
223                         valid_lsa = 1;
224                         break;
225         }
226 
227         /* This function is for reading LSA headers only, e.g. those in DB desc
228          * or LS Ack packets. As such, I'm going to set the type and length to
229          * values that should prevent anyone from trying to treat subsequent
230          * payload as an LSA body */
231         *lsa_type = 0;
232         *lsa_length = sizeof(libtrace_ospf_lsa_v2_t);
233 
234         if (!valid_lsa) {
235                 *remaining = 0;
236                 return -1;
237         }
238 
239         *remaining -= *lsa_length;
240         *current += *lsa_length;
241 
242         if (remaining == 0) {
243                 /* No more LSAs */
244                 return 0;
245         }
246         return 1;
247 }
248 
trace_get_next_ospf_lsa_v2(unsigned char ** current,libtrace_ospf_lsa_v2_t ** lsa_hdr,unsigned char ** lsa_body,uint32_t * remaining,uint8_t * lsa_type,uint16_t * lsa_length)249 DLLEXPORT int trace_get_next_ospf_lsa_v2(unsigned char **current,
250                 libtrace_ospf_lsa_v2_t **lsa_hdr,
251                 unsigned char **lsa_body,
252                 uint32_t *remaining,
253                 uint8_t *lsa_type,
254                 uint16_t *lsa_length) {
255 
256         int valid_lsa = 0;
257 
258         if (*current == NULL || *remaining < sizeof(libtrace_ospf_lsa_v2_t)) {
259                 *lsa_hdr = NULL;
260                 *lsa_body = NULL;
261                 *remaining = 0;
262 
263                 return 0;
264 
265         }
266 
267         *lsa_hdr = (libtrace_ospf_lsa_v2_t *)(*current);
268         *lsa_type = (*lsa_hdr)->lsa_type;
269         *lsa_length = ntohs((*lsa_hdr)->length);
270 
271         /* Check that the LSA type is valid */
272         switch (*lsa_type) {
273                 case TRACE_OSPF_LS_ROUTER:
274                 case TRACE_OSPF_LS_NETWORK:
275                 case TRACE_OSPF_LS_SUMMARY:
276                 case TRACE_OSPF_LS_ASBR_SUMMARY:
277                 case TRACE_OSPF_LS_EXTERNAL:
278                         valid_lsa = 1;
279                         break;
280         }
281 
282         if (*lsa_length > *remaining || !valid_lsa) {
283                 /* LSA is incomplete or an invalid type.
284                  *
285                  * If this occurs, you've probably managed to read something
286                  * that is NOT a legit LSA */
287                 *remaining = 0;
288                 *lsa_body = NULL;
289                 return -1;
290         }
291 
292         /* Some OSPF packets, e.g. LS ACKs, only contain LSA headers. If this
293          * is the case, we'll set the body pointer to NULL so the caller
294          * can't read invalid data */
295         if (*lsa_length == sizeof(libtrace_ospf_lsa_v2_t))
296                 *lsa_body = NULL;
297         else
298                 *lsa_body = (*current + sizeof(libtrace_ospf_lsa_v2_t));
299 
300         *remaining -= *lsa_length;
301         *current += *lsa_length;
302 
303         if (remaining == 0) {
304                 /* No more LSAs */
305                 return 0;
306         }
307 
308         return 1;
309 
310 }
311 
312 
313