1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45 
46 /* -------------------------------------------------------------------------
47  * File               : parse.c
48  * Description        : functions to parse received zebra packets
49  * ------------------------------------------------------------------------- */
50 
51 #include "defs.h"
52 #include "olsr.h"
53 
54 #include "common.h"
55 #include "packet.h"
56 #include "client.h"
57 #include "parse.h"
58 
59 static void free_zroute(struct zroute *);
60 static struct zroute *zparse_route(unsigned char *);
61 
62 static void
free_zroute(struct zroute * r)63 free_zroute(struct zroute *r)
64 {
65 
66   if(r->ifindex_num)
67     free(r->ifindex);
68   if(r->nexthop_num)
69     free(r->nexthop);
70 
71 }
72 
73 static struct zroute
zparse_route(unsigned char * opt)74 *zparse_route(unsigned char *opt)
75 {
76   struct zroute *r;
77   int c;
78   size_t size;
79   uint16_t length;
80   unsigned char *pnt;
81 
82   memcpy(&length, opt, sizeof length);
83   length = ntohs (length);
84 
85   r = olsr_malloc(sizeof *r, "QUAGGA: New zebra route");
86   pnt = &opt[3];
87   switch (zebra.version) {
88   case 0:
89     break;
90   case 1:
91   case 2:
92     pnt = &opt[6];
93     break;
94   default:
95     olsr_exit("QUAGGA: Unsupported zebra packet version", EXIT_FAILURE);
96     break;
97   }
98   r->type = *pnt++;
99   r->flags = *pnt++;
100   r->message = *pnt++;
101   r->prefixlen = *pnt++;
102   size = (r->prefixlen + 7) / 8;
103   memset(&r->prefix, 0, sizeof r->prefix);
104   if (olsr_cnf->ip_version == AF_INET)
105     memcpy(&r->prefix.v4.s_addr, pnt, size);
106   else
107     memcpy(r->prefix.v6.s6_addr, pnt, size);
108   pnt += size;
109 
110   if (r->message & ZAPI_MESSAGE_NEXTHOP) {
111     r->nexthop_num = *pnt++;
112     r->nexthop = olsr_malloc((sizeof *r->nexthop) * r->nexthop_num, "QUAGGA: New zebra route nexthop");
113     for (c = 0; c < r->nexthop_num; c++) {
114       if (olsr_cnf->ip_version == AF_INET) {
115         memcpy(&r->nexthop[c].v4.s_addr, pnt, sizeof r->nexthop[c].v4.s_addr);
116         pnt += sizeof r->nexthop[c].v4.s_addr;
117       } else {
118         memcpy(r->nexthop[c].v6.s6_addr, pnt, sizeof r->nexthop[c].v6.s6_addr);
119         pnt += sizeof r->nexthop[c].v6.s6_addr;
120       }
121     }
122   }
123 
124   if (r->message & ZAPI_MESSAGE_IFINDEX) {
125     r->ifindex_num = *pnt++;
126     r->ifindex = olsr_malloc(sizeof(uint32_t) * r->ifindex_num, "QUAGGA: New zebra route ifindex");
127     for (c = 0; c < r->ifindex_num; c++) {
128       memcpy(&r->ifindex[c], pnt, sizeof r->ifindex[c]);
129       r->ifindex[c] = ntohl (r->ifindex[c]);
130       pnt += sizeof r->ifindex[c];
131     }
132   }
133   switch (zebra.version) {
134   case 0:
135   case 1:
136   case 2:
137     break;
138   default:
139     olsr_exit("QUAGGA: Unsupported zebra packet version", EXIT_FAILURE);
140     break;
141   }
142 
143   if (r->message & ZAPI_MESSAGE_DISTANCE) {
144     r->distance = *pnt++;
145   }
146 
147 // Quagga v0.98.6 BUG workaround: metric is always sent by zebra
148 // even without ZAPI_MESSAGE_METRIC message.
149   if ((r->message & ZAPI_MESSAGE_METRIC) || !zebra.version) {
150     memcpy(&r->metric, pnt, sizeof r->metric);
151     r->metric = ntohl(r->metric);
152     pnt += sizeof r->metric;
153   }
154 
155   if (pnt - opt != length) {
156     olsr_exit("QUAGGA: Length does not match", EXIT_FAILURE);
157   }
158 
159   return r;
160 }
161 
162 void
zparse(void * foo)163 zparse(void *foo __attribute__ ((unused)))
164 {
165   unsigned char *data, *f;
166   uint16_t command;
167   uint16_t length;
168   ssize_t len;
169   struct zroute *route;
170 
171   if (!(zebra.status & STATUS_CONNECTED)) {
172     zclient_reconnect();
173     return;
174   }
175   data = zclient_read(&len);
176   if (data) {
177     f = data;
178     do {
179       length = ntohs(*((uint16_t *)(void *) f));
180       if (!length) { // something weird happened
181         olsr_exit("QUAGGA: Zero message length", EXIT_FAILURE);
182       }
183 
184       /* Zebra Protocol Header
185        *
186        * Version 0: 2 bytes length, 1 byte command
187        *
188        * Version 1: 2 bytes length, 1 byte marker, 1 byte version, 2 bytes command
189        */
190       switch (zebra.version) {
191         case 0:
192           command = f[2];
193           break;
194 
195         case 1:
196         case 2:
197           if ((f[2] != ZEBRA_HEADER_MARKER) || (f[3] != zebra.version)) {
198             olsr_exit("QUAGGA: Invalid zebra header received", EXIT_FAILURE);
199           }
200 
201           command = ntohs(*((uint16_t *)(void *) &f[4]));
202           break;
203 
204         default:
205           olsr_exit("QUAGGA: Unsupported zebra packet version", EXIT_FAILURE);
206           break;
207       }
208 
209       if (olsr_cnf->ip_version == AF_INET) {
210         switch (command) {
211           case ZEBRA_IPV4_ROUTE_ADD:
212             route = zparse_route(f);
213             ip_prefix_list_add(&olsr_cnf->hna_entries, &route->prefix, route->prefixlen);
214             free_zroute(route);
215             free(route);
216             break;
217 
218           case ZEBRA_IPV4_ROUTE_DELETE:
219             route = zparse_route(f);
220             ip_prefix_list_remove(&olsr_cnf->hna_entries, &route->prefix, route->prefixlen);
221             free_zroute(route);
222             free(route);
223             break;
224 
225           default:
226             break;
227         }
228       } else {
229         switch (command) {
230           case ZEBRA_IPV6_ROUTE_ADD:
231             route = zparse_route(f);
232             ip_prefix_list_add(&olsr_cnf->hna_entries, &route->prefix, route->prefixlen);
233             free_zroute(route);
234             free(route);
235             break;
236 
237           case ZEBRA_IPV6_ROUTE_DELETE:
238             route = zparse_route(f);
239             ip_prefix_list_remove(&olsr_cnf->hna_entries, &route->prefix, route->prefixlen);
240             free_zroute(route);
241             free(route);
242             break;
243 
244           default:
245             break;
246         }
247       }
248 
249       f += length;
250     }
251     while ((f - data) < len);
252 
253     free(data);
254   }
255 }
256 
257 /*
258  * Local Variables:
259  * c-basic-offset: 2
260  * indent-tabs-mode: nil
261  * End:
262  */
263